Skip to content

Commit

Permalink
chore: add dev scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
DaryaLari committed Jan 16, 2025
1 parent 887c898 commit 7c412d7
Show file tree
Hide file tree
Showing 12 changed files with 310 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ node_modules
/*.js
!/.*.js
storybook-static
templates
8 changes: 8 additions & 0 deletions README-ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,11 @@ import {NotFound} from '@gravity-ui/illustrations';
```js
import notFound from '@gravity-ui/illustrations/svgs/not-found-light.svg';
```

### Разработка

Для обновления иллюстраций в соответствии с новым дизайном, измените контент svg-файлов в светлой теме (`<this-repository-root>/svgs/<illustration-name>-light.svg` файлы) и затем запустите команду:

```shell
npm run generate
```
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,11 @@ import {NotFound} from '@gravity-ui/illustrations';
```js
import notFound from '@gravity-ui/illustrations/svgs/not-found-light.svg';
```

### Development

For updating illustrations according to new design, change the content of svg-s in light theme (`<this-repository-root>/svgs/<illustration-name>-light.svg` files) and then run command:

```shell
npm run generate
```
10 changes: 7 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
"build": "tsc",
"start": "TS_NODE_PROJECT=.storybook/tsconfig.json storybook dev",
"prepublishOnly": "npm run build",
"optimize": "npx svgo svgs/*"
"optimize": "npx svgo -f svgs --multipass",
"generate": "node scripts/generate-templates.mjs && node scripts/generate-components-from-templates.mjs && node scripts/generate-svgs-from-templates.mjs"
},
"devDependencies": {
"@bem-react/classname": "^1.6.0",
Expand All @@ -46,6 +47,7 @@
"@storybook/react": "^8.0.2",
"@storybook/react-webpack5": "^8.0.2",
"@storybook/theming": "^8.0.2",
"@svgr/core": "^8.1.0",
"@svgr/webpack": "^8.1.0",
"@types/react": "^18.2.64",
"@types/react-dom": "^18.2.21",
Expand All @@ -61,6 +63,7 @@
"storybook": "^8.0.2",
"style-loader": "^3.3.4",
"stylelint": "^15.11.0",
"svgo": "^3.3.2",
"typescript": "^5.4.2"
},
"peerDependencies": {
Expand Down
24 changes: 24 additions & 0 deletions scripts/constants.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import path from 'path';
import url from 'url';

const __dirname = path.dirname(url.fileURLToPath(import.meta.url));

export const SVGS_DIR = path.resolve(__dirname, '..', 'svgs');
export const TEMPLATES_DIR = path.resolve(__dirname, '..', 'templates');
export const ICONS_DIR = path.resolve(__dirname, '..', 'src', 'components');
export const META_DATA_PATH = path.resolve(__dirname, '..', 'metadata.json');

export const ILLUSTRATION_NAME_REGEXP = /^([a-z0-9]|[a-z0-9](-?[a-z0-9])*-?[a-z0-9])$/;

export const colorMaps = [
{token: '--gil-color-object-base', lightRegexp: /#FFBE5C/gi},
{token: '--gil-color-object-accent-heavy', lightRegexp: /#D36507/gi},
{token: '--gil-color-object-hightlight', lightRegexp: /#FFD89D/gi},
{token: '--gil-color-shadow-over-object', lightRegexp: /#D39E50/gi},
{token: '--gil-color-background-lines', lightRegexp: /#8C8C8C/gi},
{token: '--gil-color-background-shapes', lightRegexp: /#F2F2F2/gi},
{token: '--gil-color-object-accent-light', lightRegexp: /#FFF(FFF)?/gi},
{token: '--gil-color-object-danger', lightRegexp: /#FF003D/gi},
];

export const themes = ['light', 'dark', 'light-hc', 'dark-hc'];
59 changes: 59 additions & 0 deletions scripts/generate-components-from-templates.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import fs from 'fs/promises';
import path from 'path';

import {transform} from '@svgr/core';

import {ICONS_DIR, META_DATA_PATH, TEMPLATES_DIR} from './constants.mjs';
import {cleanDir, prettify} from './utils.mjs';

async function createIndexFile(files) {
const indexFile = path.join(ICONS_DIR, 'index.ts');
const content = files
.map((file) => {
const name = path.parse(file).name;

return `export {default as ${name}} from './${name}'`;
})
.join('\n');
const prettyContent = await prettify(content, indexFile);
await fs.writeFile(indexFile, prettyContent);
}

async function run() {
await cleanDir(ICONS_DIR);

const metadata = JSON.parse(await fs.readFile(META_DATA_PATH, 'utf8'));

const iconFiles = await Promise.all(
metadata.illustrations.map(async ({svgName, componentName}) => {
const filePath = path.resolve(TEMPLATES_DIR, `${svgName}.svg`);

const code = await fs.readFile(filePath, 'utf8');
try {
await fs.mkdir(path.join(ICONS_DIR));
} catch (_e) {}

const iconFile = path.join(ICONS_DIR, `${componentName}.tsx`);
const content = await transform(
code,
{
typescript: true,
plugins: ['@svgr/plugin-jsx'],
exportType: 'default',
},
{componentName},
);
const prettyContent = await prettify(content, iconFile);

await fs.writeFile(iconFile, prettyContent);

return iconFile;
}),
);
await createIndexFile(iconFiles);
}

run().catch((error) => {
console.error(error);
process.exit(1);
});
40 changes: 40 additions & 0 deletions scripts/generate-svgs-from-templates.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import fsSync from 'fs';
import fs from 'fs/promises';
import path from 'path';

import {META_DATA_PATH, SVGS_DIR, TEMPLATES_DIR, themes} from './constants.mjs';
import colorsConfig from './gravity-colors-config.mjs';
import {svgoTransformer} from './transform-colors.mjs';
import {cleanDir} from './utils.mjs';

async function writeToFile(filePath, fileName, data) {
if (!fsSync.existsSync(filePath)) {
await fs.mkdir(filePath, {recursive: true});
}
await fs.writeFile(path.join(filePath, fileName), data);
}

async function run() {
await cleanDir(SVGS_DIR);

const metadata = JSON.parse(await fs.readFile(META_DATA_PATH, 'utf8'));

metadata.illustrations.forEach(async ({svgName}) => {
const ill = await fs.readFile(path.resolve(TEMPLATES_DIR, `${svgName}.svg`), 'utf8');

themes.forEach(async (theme) => {
const transforms = Object.entries(colorsConfig[theme]).map(([token, color]) => ({
newValue: color,
regexpOrStringToChange: `var(${token})`,
}));
const svg = await svgoTransformer(ill, transforms);

await writeToFile(path.join(SVGS_DIR), `${svgName}-${theme}.svg`, svg);
});
});
}

run().catch((error) => {
console.error(error);
process.exit(1);
});
37 changes: 37 additions & 0 deletions scripts/generate-templates.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import fsSync from 'fs';
import fs from 'fs/promises';
import path from 'path';

import {META_DATA_PATH, SVGS_DIR, TEMPLATES_DIR, colorMaps} from './constants.mjs';
import {svgoTransformer} from './transform-colors.mjs';
import {cleanDir} from './utils.mjs';

const transforms = colorMaps.map(({token, lightRegexp}) => ({
newValue: `var(${token})`,
regexpOrStringToChange: lightRegexp,
}));

async function writeToFile(filePath, fileName, data) {
if (!fsSync.existsSync(filePath)) {
await fs.mkdir(filePath, {recursive: true});
}
await fs.writeFile(path.join(filePath, fileName), data);
}

async function run() {
await cleanDir(TEMPLATES_DIR);

const metadata = JSON.parse(await fs.readFile(META_DATA_PATH, 'utf8'));

metadata.illustrations.forEach(async ({svgName}) => {
const ill = await fs.readFile(path.resolve(SVGS_DIR, `${svgName}-light.svg`), 'utf8');
const svg = svgoTransformer(ill, transforms);

await writeToFile(path.join(TEMPLATES_DIR), `${svgName}.svg`, svg);
});
}

run().catch((error) => {
console.error(error);
process.exit(1);
});
47 changes: 47 additions & 0 deletions scripts/gravity-colors-config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const colorsConfig = {
light: {
'--gil-color-object-base': 'rgb(255, 190, 92)', // --g-color-private-yellow-550-solid
'--gil-color-object-accent-heavy': 'rgb(211, 101, 7)', // --g-color-private-orange-650-solid
'--gil-color-object-hightlight': 'rgb(255, 216, 157)', // --g-color-private-yellow-350-solid
'--gil-color-shadow-over-object': 'rgb(211, 158, 80)', // --g-color-private-yellow-650-solid
'--gil-color-background-lines': 'rgb(140, 140, 140)', // --g-color-private-black-450-solid
'--gil-color-background-shapes': 'rgb(242, 242, 242)', // --g-color-private-black-50-solid
'--gil-color-object-accent-light': 'rgb(255, 255, 255)', // --g-color-private-white-1000-solid
'--gil-color-object-danger': 'rgb(255, 0, 61)', // --g-color-private-red-550-solid
},

dark: {
'--gil-color-object-base': 'rgb(255, 190, 92)', // --g-color-private-yellow-550-solid
'--gil-color-object-accent-heavy': 'rgb(211, 130, 61)', // --g-color-private-orange-650-solid
'--gil-color-object-hightlight': 'rgb(255, 210, 141)', // --g-color-private-yellow-700-solid
'--gil-color-shadow-over-object': 'rgb(233, 174, 86)', // --g-color-private-yellow-500-solid
'--gil-color-background-lines': 'rgb(156, 153, 156)', // --g-color-private-white-550-solid
'--gil-color-background-shapes': 'rgb(78, 74, 78)', // --g-color-private-white-200-solid
'--gil-color-object-accent-light': 'rgb(255, 255, 255)', // --g-color-private-white-1000-solid
'--gil-color-object-danger': 'rgb(229, 50, 93)', // --g-color-private-red-550-solid
},

'light-hc': {
'--gil-color-object-base': 'rgb(255, 190, 92)', // --g-color-private-yellow-550-solid
'--gil-color-object-accent-heavy': 'rgb(208, 99, 4)', // --g-color-private-orange-650-solid
'--gil-color-object-hightlight': 'rgb(255, 216, 157)', // --g-color-private-yellow-350-solid
'--gil-color-shadow-over-object': 'rgb(208, 155, 77)', // --g-color-private-yellow-650-solid
'--gil-color-background-lines': 'rgb(140, 140, 140)', // --g-color-private-black-450-solid
'--gil-color-background-shapes': 'rgb(242, 242, 242)', // --g-color-private-black-50-solid
'--gil-color-object-accent-light': 'rgb(255, 255, 255)', // --g-color-private-white-1000-solid
'--gil-color-object-danger': 'rgb(255, 0, 61)', // --g-color-private-red-550-solid
},

'dark-hc': {
'--gil-color-object-base': 'rgb(255, 190, 92)', // --g-color-private-yellow-550-solid
'--gil-color-object-accent-heavy': 'rgb(211, 130, 61)', // --g-color-private-orange-650-solid
'--gil-color-object-hightlight': 'rgb(255, 210, 141)', // --g-color-private-yellow-700-solid
'--gil-color-shadow-over-object': 'rgb(231, 173, 85)', // --g-color-private-yellow-500-solid
'--gil-color-background-lines': 'rgb(148, 148, 148)', // --g-color-private-white-550-solid
'--gil-color-background-shapes': 'rgb(65, 65, 65)', // --g-color-private-white-200-solid
'--gil-color-object-accent-light': 'rgb(255, 255, 255)', // --g-color-private-white-1000-solid
'--gil-color-object-danger': 'rgb(229, 50, 93)', // --g-color-private-red-550-solid
},
};

export default colorsConfig;
62 changes: 62 additions & 0 deletions scripts/transform-colors.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import {optimize} from 'svgo';
import {colorsProps} from 'svgo/plugins/_collections.js';

function getColorsTransformatorPlagin(transforms) {
return {
name: 'change-colors-to-css-vars',
fn: () => {
return {
element: {
enter: (node) => {
for (const [name, value] of Object.entries(node.attributes)) {
if (colorsProps.has(name)) {
for (const {newValue, regexpOrStringToChange} of transforms) {
const matched =
typeof regexpOrStringToChange === 'string'
? regexpOrStringToChange === value
: regexpOrStringToChange.test(value);

if (matched) {
node.attributes[name] = newValue;
}
}
}
}
return null;
},
},
};
},
};
}

/**
* The complete Triforce, or one or more components of the Triforce.
* @typedef {Object} Transforms
* @property {string} newValue
* @property {(RegExp | string)} regexpOrStringToChange
*/

/**
* @param {string} svgString
* @param {Transforms[]} [transforms]
*
* @return {string}
*/
export function svgoTransformer(svgString, transforms) {
return optimize(svgString, {
multipass: true,
plugins: [
{name: 'removeAttrs', params: {attrs: ['id']}},
transforms ? getColorsTransformatorPlagin(transforms) : undefined,
{
name: 'preset-default',
params: {
overrides: {
removeViewBox: false,
},
},
},
].filter(Boolean),
}).data;
}
13 changes: 13 additions & 0 deletions scripts/utils.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import fs from 'fs/promises';

import prettier from 'prettier';

export async function cleanDir(dir) {
await fs.rm(dir, {recursive: true, force: true});
await fs.mkdir(dir, {recursive: true});
}

export async function prettify(content, filepath) {
const prettierConfig = (await prettier.resolveConfig(filepath)) ?? {};
return prettier.format(content, {...prettierConfig, filepath});
}

0 comments on commit 7c412d7

Please sign in to comment.