Skip to content

Commit

Permalink
fetch colors from Figma
Browse files Browse the repository at this point in the history
  • Loading branch information
matthew44-mappable committed Apr 3, 2024
1 parent 2e11856 commit 12a55d0
Show file tree
Hide file tree
Showing 12 changed files with 504 additions and 345 deletions.
5 changes: 4 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
module.exports = {
extends: ['./node_modules/@mappable-world/mappable-cli/.eslintrc.js']
extends: ['./node_modules/@mappable-world/mappable-cli/.eslintrc.js'],
rules: {
'no-console': 'error'
}
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"start": "webpack serve",
"bump": "npm version prerelease --preid=beta --no-git-tag-version && npm run bump:git",
"bump:git": "git add --all && git commit -m \"New version $npm_package_version\" && git tag $npm_package_version && git push --tags origin HEAD:main",
"sync-icons": "node -r dotenv/config -r ts-node/register ./tools/scripts/sync-icons.ts"
"sync-icons": "node -r dotenv/config -r ts-node/register ./tools/scripts/sync-icons.ts",
"sync-colors": "node -r dotenv/config -r ts-node/register ./tools/scripts/sync-colors.ts"
},
"devDependencies": {
"@mappable-world/mappable-cli": "^0.0.28",
Expand Down
2 changes: 1 addition & 1 deletion src/MMapDefaultMarker/pin.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions src/icons/icon-colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/** Don't edit manually only color names. Generated by script: ./tools/icons/generate-colors.ts */
export const iconColors = {
darkgray: {day: '#ada9a6ff', night: '#6f737aff'},
pink: {day: '#ff8f96ff', night: '#b96066ff'},
seawave: {day: '#62c0c6ff', night: '#468286ff'},
orchid: {day: '#e096d0ff', night: '#916187ff'},
steelblue: {day: '#498ea5ff', night: '#57a8c2ff'},
bluebell: {day: '#9d9dc4ff', night: '#6767a3ff'},
ceil: {day: '#88aecfff', night: '#537695ff'},
green: {day: '#5ebd8cff', night: '#468c68ff'},
darksalmon: {day: '#f09a75ff', night: '#ab6f55ff'}
} as const;
export const glyphColors = {day: '#ffffffff', night: '#303741ff'} as const;
export type IconColor = keyof typeof iconColors;
339 changes: 339 additions & 0 deletions src/icons/icons.ts

Large diffs are not rendered by default.

342 changes: 3 additions & 339 deletions src/icons/index.ts

Large diffs are not rendered by default.

90 changes: 90 additions & 0 deletions tools/icons/fetch-colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import {Color, Api as FigmaApi, Node} from 'figma-api';

/** The name of the canvas in the file from which the colors will be loaded */
const CANVAS_NAME = 'colors';
const PALETTE_NAME = 'rubrics';

const PRIMARY_DAY = 'maps_pin_primary_day';
const PRIMARY_NIGHT = 'maps_pin_primary_night';
const GLYPH_DAY = 'maps_pin_secondary_day';
const GLYPH_NIGHT = 'maps_pin_secondary_night';

type RubricColors = {
rubricName: string;
primaryDay: string;
primaryNight: string;
};

export type MarkerColors = {
day: string;
night: string;
};

export type FetchedColors = {
colors: MarkerColors[];
glyphDay: string;
glyphNight: string;
};

export const fetchFigmaColors = async (): Promise<FetchedColors> => {
const personalAccessToken: string | undefined = process.env.FIGMA_API_TOKEN;
const fileId: string | undefined = process.env.FIGMA_FILE_ID;

if (!personalAccessToken) {
throw new Error('No Figma access token found in environment variable FIGMA_API_TOKEN');
}
if (!fileId) {
throw new Error('No Figma file id found in environment variable FIGMA_FILE_ID');
}

const api = new FigmaApi({personalAccessToken});
const file = await api.getFile(fileId);
const canvas = file.document.children.find((child) => child.name === CANVAS_NAME) as Node<'CANVAS'>;
const rubricsPalette = canvas.children.find((child) => child.name === PALETTE_NAME) as Node<'GROUP'>;
const rubrics = rubricsPalette.children.filter(({name}) => !name.includes('fallback')) as Node<'GROUP'>[];
let glyphDay: string = '';
let glyphNight: string = '';
const rubricColors = rubrics.reduce((rubricColors, {name, children}) => {
const colors = children as Node<'RECTANGLE'>[];

const primaryDay = colors.find((color) => color.name === PRIMARY_DAY)?.fills[0].color;
const primaryNight = colors.find((color) => color.name === PRIMARY_NIGHT)?.fills[0].color;

if (glyphDay.length === 0) {
const glyphDayColor = colors.find((color) => color.name === GLYPH_DAY)?.fills[0].color;
glyphDay = glyphDayColor ? rgbaToHex(glyphDayColor) : glyphDay;
}
if (glyphNight.length === 0) {
const glyphNightColor = colors.find((color) => color.name === GLYPH_NIGHT)?.fills[0].color;
glyphNight = glyphNightColor ? rgbaToHex(glyphNightColor) : glyphNight;
}

if (primaryDay === undefined || primaryNight === undefined) {
return rubricColors;
}

return rubricColors.concat({
rubricName: name,
primaryDay: rgbaToHex(primaryDay),
primaryNight: rgbaToHex(primaryNight)
});
}, [] as RubricColors[]);

const dayNightColorsMap = rubricColors.reduce((colorsMap, {primaryDay, primaryNight}) => {
colorsMap.set(primaryDay, primaryNight);
return colorsMap;
}, new Map<string, string>());

const colors = Array.from(dayNightColorsMap.entries()).map(([day, night]) => ({day, night}));
return {colors, glyphDay, glyphNight};
};

const rgbaToHex = (rgba: Color): string => {
const r255 = Math.floor(rgba.r * 255);
const g255 = Math.floor(rgba.g * 255);
const b255 = Math.floor(rgba.b * 255);
const a255 = Math.floor(rgba.a * 255);
return '#' + componentToHex(r255) + componentToHex(g255) + componentToHex(b255) + componentToHex(a255);
};

const componentToHex = (c: number): string => c.toString(16).padStart(2, '0');
24 changes: 24 additions & 0 deletions tools/icons/generate-colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import fs from 'fs/promises';
import path from 'path';
import {prettierFormat} from '../utils/prettier-format';
import {FetchedColors} from './fetch-colors';
import {SRC_ICONS_PATH} from './paths';

/** Human-readable names for colors. They are selected manually */
const colorNames = ['darkgray', 'pink', 'seawave', 'orchid', 'steelblue', 'bluebell', 'ceil', 'green', 'darksalmon'];

export const generateColorsFile = async (fetchedColors: FetchedColors) => {
const colorsObjectValues = fetchedColors.colors.map(({day, night}, i) => {
return `${colorNames[i]}:{day:'${day}',night:'${night}'},`;
});
const content = `
/** Don't edit manually only color names. Generated by script: ./tools/icons/generate-colors.ts */
export const iconColors = {
${colorsObjectValues.join('\n')}
} as const;
export const glyphColors = {day:'${fetchedColors.glyphDay}',night:'${fetchedColors.glyphNight}'} as const;
export type IconColor = keyof typeof iconColors`;

const formattedContent = await prettierFormat(content, 'typescript');
await fs.writeFile(path.join(SRC_ICONS_PATH, 'icon-colors.ts'), formattedContent);
};
2 changes: 1 addition & 1 deletion tools/icons/generate-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ export const generateIconsDocsList = async (iconNames: string[]) => {
})
.join('\n');
const formattedContent = await prettierFormat(content, 'markdown');
await fs.writeFile(DOCS_FILE_PATH, formattedContent);
await fs.writeFile(path.join(DOCS_FILE_PATH, 'icons.md'), formattedContent);
};
2 changes: 1 addition & 1 deletion tools/icons/generate-imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ export const generateImports = async (iconsDescription: IconDescription[], iconN
${iconNamesObject}
}`;
const formattedContent = await prettierFormat(fileContent, 'typescript');
await fs.writeFile(path.join(SRC_ICONS_PATH, 'index.ts'), formattedContent);
await fs.writeFile(path.join(SRC_ICONS_PATH, 'icons.ts'), formattedContent);
};
2 changes: 1 addition & 1 deletion tools/icons/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ import path from 'path';
export const BASE_DIR = path.join(__dirname, '../../');
export const STATIC_ICONS_PATH = path.join(BASE_DIR, 'static/icons');
export const SRC_ICONS_PATH = path.join(BASE_DIR, 'src/icons');
export const DOCS_FILE_PATH = path.join(BASE_DIR, 'docs/icons.md');
export const DOCS_FILE_PATH = path.join(BASE_DIR, 'docs');
24 changes: 24 additions & 0 deletions tools/scripts/sync-colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {createSpinner} from 'nanospinner';
import {fetchFigmaColors} from '../icons/fetch-colors';
import {generateColorsFile} from '../icons/generate-colors';

async function main() {
const spinner = createSpinner();
try {
spinner.start({text: 'Start sync colors'});

spinner.update({text: 'Getting information about colors from Figma'});
const fetchedColors = await fetchFigmaColors();

spinner.update({text: 'Updating the file with colors'});
await generateColorsFile(fetchedColors);

spinner.success({text: 'Colors are successfully synchronized'});
} catch (error) {
spinner.error({text: error.message || error.toString()});
}
}

main().catch(() => {
process.exit(1);
});

0 comments on commit 12a55d0

Please sign in to comment.