✨(tokens) add scss generator
Add a Sass generator which generate a scss file declaring colors, font families, weights, sizes and spacings as maps.
This commit is contained in:
committed by
Jean-Baptiste PENRATH
parent
72091eecbc
commit
1667d9b501
5
.changeset/pink-fishes-jump.md
Normal file
5
.changeset/pink-fishes-jump.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@openfun/cunningham-tokens": minor
|
||||
---
|
||||
|
||||
Add a sass generator
|
||||
@@ -28,7 +28,7 @@
|
||||
"build-bin": "cd src/bin && tsc -p tsconfig.json && tsc-alias && chmod +x ../../dist/bin/Main.js",
|
||||
"build-lib": "cp dist/cunningham-tokens.ts src/lib && cd src/lib && tsc -p tsconfig.json",
|
||||
"build": "yarn build-bin && yarn build-default-theme && yarn build-lib && cd ../.. && ln -sf ../../packages/tokens/dist/bin/Main.js node_modules/.bin/cunningham",
|
||||
"build-default-theme": "./dist/bin/Main.js -o dist -s html -g css,js,ts --utility-classes",
|
||||
"build-default-theme": "./dist/bin/Main.js -o dist -s html -g scss,css,js,ts --utility-classes",
|
||||
"test": "FORCE_COLOR=1 jest --runInBand --verbose src"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
50
packages/tokens/src/bin/Generators/SassGenerator.spec.ts
Normal file
50
packages/tokens/src/bin/Generators/SassGenerator.spec.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import Config from "Config";
|
||||
import { run } from "ThemeGenerator";
|
||||
import { cleanup } from "tests/Utils";
|
||||
|
||||
jest.mock("../Paths", () => ({
|
||||
workPath: () => __dirname,
|
||||
}));
|
||||
|
||||
describe("SassGenerator", () => {
|
||||
beforeAll(() => {
|
||||
jest.spyOn(console, "log").mockImplementation(() => {});
|
||||
cleanup(__dirname);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
cleanup(__dirname);
|
||||
});
|
||||
|
||||
it("generates valid Sass file", async () => {
|
||||
const sassFile = path.join(__dirname, Config.tokenFilename + ".scss");
|
||||
expect(fs.existsSync(sassFile)).toEqual(false);
|
||||
await run(["", "", "-g", "scss"]);
|
||||
|
||||
expect(fs.existsSync(sassFile)).toEqual(true);
|
||||
expect(fs.readFileSync(sassFile).toString()).toMatchInlineSnapshot(`
|
||||
"$colors: (
|
||||
primary: #055FD2,
|
||||
secondary: #DA0000
|
||||
);
|
||||
$fontFamilies: (
|
||||
base: Roboto
|
||||
);
|
||||
$fontSizes: (
|
||||
m: 1rem
|
||||
);
|
||||
$fontWeights: (
|
||||
medium: 400
|
||||
);
|
||||
$spacings: (
|
||||
s: 1rem
|
||||
);
|
||||
$transitions: (
|
||||
ease: linear
|
||||
);
|
||||
"
|
||||
`);
|
||||
});
|
||||
});
|
||||
80
packages/tokens/src/bin/Generators/SassGenerator.ts
Normal file
80
packages/tokens/src/bin/Generators/SassGenerator.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
import path from "path";
|
||||
import { Generator } from "Generators/index";
|
||||
import Config from "Config";
|
||||
import { put } from "Utils/Files";
|
||||
import { Tokens } from "TokensGenerator";
|
||||
|
||||
export const sassGenerator: Generator = async (tokens, opts) => {
|
||||
const sassContent = generateSassMaps(tokens);
|
||||
const outputPath = path.join(opts.path, Config.tokenFilename + ".scss");
|
||||
put(outputPath, sassContent);
|
||||
};
|
||||
|
||||
const generateSassMaps = (tokens: Tokens) => {
|
||||
return [
|
||||
generateColorsSassMap(tokens),
|
||||
generateFontSassMap(tokens),
|
||||
generateSpacingsSassMap(tokens),
|
||||
generateTransitionsSassMap(tokens),
|
||||
].join("\n");
|
||||
};
|
||||
|
||||
// Generate colors sass map with the ability to create sub map
|
||||
// for a color with shades.
|
||||
// Example: `primary-500: #000` will return `primary: (500: #000)`
|
||||
const generateColorsSassMap = (tokens: Tokens) => {
|
||||
const colors = Object.entries(tokens.theme.colors).reduce(
|
||||
propertiesReducer,
|
||||
{}
|
||||
);
|
||||
|
||||
return `$colors: ${JSONToSassMap(colors)};`;
|
||||
};
|
||||
const generateFontSassMap = (tokens: Tokens) => {
|
||||
return [
|
||||
generateFontFamiliesSassMap(tokens),
|
||||
generateFontSizesSassMap(tokens),
|
||||
generateFontWeightsSassMap(tokens),
|
||||
].join("\n");
|
||||
};
|
||||
const generateFontFamiliesSassMap = (tokens: Tokens) => {
|
||||
return `$fontFamilies: ${JSONToSassMap(tokens.theme.font.families)};`;
|
||||
};
|
||||
const generateFontSizesSassMap = (tokens: Tokens) => {
|
||||
return `$fontSizes: ${JSONToSassMap(tokens.theme.font.sizes)};`;
|
||||
};
|
||||
const generateFontWeightsSassMap = (tokens: Tokens) => {
|
||||
return `$fontWeights: ${JSONToSassMap(tokens.theme.font.weights)};`;
|
||||
};
|
||||
const generateSpacingsSassMap = (tokens: Tokens) => {
|
||||
return `$spacings: ${JSONToSassMap(tokens.theme.spacings)};`;
|
||||
};
|
||||
|
||||
const generateTransitionsSassMap = (tokens: Tokens) => {
|
||||
return `$transitions: ${JSONToSassMap(tokens.theme.transitions)};`;
|
||||
};
|
||||
|
||||
function JSONToSassMap(json: Object) {
|
||||
return JSON.stringify(json, null, 2)
|
||||
.replace(/{/g, "(")
|
||||
.replace(/}/g, ")")
|
||||
.replace(/"/g, "");
|
||||
}
|
||||
|
||||
function propertiesReducer(
|
||||
propertyMap: Record<string, string | Record<string, string>>,
|
||||
[key, value]: [string, string]
|
||||
) {
|
||||
const [property, subProperty] = key.split("-");
|
||||
|
||||
if (subProperty) {
|
||||
if (propertyMap[property] === undefined) {
|
||||
propertyMap[property] = {};
|
||||
}
|
||||
(propertyMap[property] as Record<string, string>)[subProperty] = value;
|
||||
} else {
|
||||
propertyMap[property] = value;
|
||||
}
|
||||
|
||||
return propertyMap;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { cssGenerator } from "Generators/CssGenerator";
|
||||
import { sassGenerator } from "Generators/SassGenerator";
|
||||
import { jsGenerator } from "Generators/JsGenerator";
|
||||
import { Tokens } from "TokensGenerator";
|
||||
import { tsGenerator } from "Generators/TsGenerator";
|
||||
@@ -9,6 +10,7 @@ export type Generator = (
|
||||
) => Promise<void>;
|
||||
|
||||
export const Generators: Record<string, Generator> = {
|
||||
scss: sassGenerator,
|
||||
css: cssGenerator,
|
||||
js: jsGenerator,
|
||||
ts: tsGenerator,
|
||||
|
||||
@@ -18,5 +18,8 @@ module.exports = {
|
||||
spacings: {
|
||||
s: "1rem",
|
||||
},
|
||||
transitions: {
|
||||
ease: "linear",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -5,4 +5,5 @@
|
||||
--c--theme--font--weights--medium: 400;
|
||||
--c--theme--font--families--base: Roboto;
|
||||
--c--theme--spacings--s: 1rem;
|
||||
--c--theme--transitions--ease: linear;
|
||||
}
|
||||
|
||||
@@ -5,4 +5,5 @@
|
||||
--c--theme--font--weights--medium: 400;
|
||||
--c--theme--font--families--base: Roboto;
|
||||
--c--theme--spacings--s: 1rem;
|
||||
--c--theme--transitions--ease: linear;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
--c--theme--font--weights--medium: 400;
|
||||
--c--theme--font--families--base: Roboto;
|
||||
--c--theme--spacings--s: 1rem;
|
||||
--c--theme--transitions--ease: linear;
|
||||
} .clr-primary { color: var(--c--theme--colors--primary); }
|
||||
.clr-secondary { color: var(--c--theme--colors--secondary); }
|
||||
.bg-primary { background-color: var(--c--theme--colors--primary); }
|
||||
|
||||
Reference in New Issue
Block a user