From 2ae8f94fc4e278b6951c4492a0780f7326e05428 Mon Sep 17 00:00:00 2001 From: Kshitij Sobti Date: Thu, 9 Nov 2023 18:18:37 +0530 Subject: [PATCH 1/2] feat: Better support for multiple themes This change adds support for two CLI options to the build-tokens command. The first, --all-themes makes the build-tokens command process all themes in the source directory as opposed to specifying all the names via --theme. Secondly, --base-theme allows you to have multiple themes derived from the same common base. If specified, you can have a derived theme that still loads tokens from the light theme. For example, you can have a site theme called 'theme-one' and set the base theme to light so it will reuse the core light theme tokens and layer on changes from 'theme-one'. --- lib/build-tokens.js | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/lib/build-tokens.js b/lib/build-tokens.js index b9916ddb3d..72ddb7e267 100755 --- a/lib/build-tokens.js +++ b/lib/build-tokens.js @@ -1,3 +1,4 @@ +const fs = require('fs'); const path = require('path'); const minimist = require('minimist'); const { StyleDictionary, colorTransform, createCustomCSSVariables } = require('../tokens/style-dictionary'); @@ -9,13 +10,17 @@ const { createIndexCssFile } = require('../tokens/utils'); * @param {string[]} commandArgs - Command line arguments for building tokens. * @param {string} [commandArgs.build-dir='./build/'] - The directory where the build output will be placed. * @param {string} [commandArgs.source] - The source directory containing JSON token files. + * @param {string} [commandArgs.base-theme] - The base theme to use from Paragon if named differently than the theme. * @param {boolean} [commandArgs.source-tokens-only=false] - Indicates whether to include only source tokens. * @param {string|string[]} [commandArgs.themes=['light']] - The themes (variants) for which to build tokens. + * @param {boolean} [commandArgs.all-themes] - Indicated whether to process all themes. */ async function buildTokensCommand(commandArgs) { const defaultParams = { - themes: ['light'], + themes: 'light', + 'base-theme': null, 'build-dir': './build/', + 'all-themes': false, }; const alias = { @@ -28,7 +33,20 @@ async function buildTokensCommand(commandArgs) { source: tokensSource, 'source-tokens-only': hasSourceTokensOnly, themes, - } = minimist(commandArgs, { alias, default: defaultParams, boolean: 'source-tokens-only' }); + 'base-theme': baseTheme, + 'all-themes': allThemes, + } = minimist(commandArgs, { alias, default: defaultParams, boolean: ['source-tokens-only', 'all-themes'] }); + + let themesToProcess = null; + + if (allThemes) { + themesToProcess = fs + .readdirSync(`${tokensSource}/themes/`, { withFileTypes: true }) + .filter(entry => entry.isDirectory()) + .map(entry => entry.name); + } else { + themesToProcess = themes.split(' '); + } const coreConfig = { include: [path.resolve(__dirname, '../tokens/src/core/**/*.json')], @@ -65,9 +83,9 @@ async function buildTokensCommand(commandArgs) { }, }; - const getStyleDictionaryConfig = (themeVariant) => ({ + const getStyleDictionaryConfig = (themeVariant, baseThemeVariant) => ({ ...coreConfig, - include: [...coreConfig.include, path.resolve(__dirname, `../tokens/src/themes/${themeVariant}/**/*.json`)], + include: [...coreConfig.include, path.resolve(__dirname, `../tokens/src/themes/${baseThemeVariant}/**/*.json`)], source: tokensSource ? [`${tokensSource}/themes/${themeVariant}/**/*.json`] : [], transform: { 'color/sass-color-functions': { @@ -109,8 +127,8 @@ async function buildTokensCommand(commandArgs) { StyleDictionary.extend(coreConfig).buildAllPlatforms(); createIndexCssFile({ buildDir, isTheme: false }); - themes.forEach((themeVariant) => { - const config = getStyleDictionaryConfig(themeVariant); + themesToProcess.forEach((themeVariant) => { + const config = getStyleDictionaryConfig(themeVariant, baseTheme || themeVariant); StyleDictionary.extend(config).buildAllPlatforms(); createIndexCssFile({ buildDir, isTheme: true, themeVariant }); }); From fd4d634c9df33aa085182020e50342ca30d43d1f Mon Sep 17 00:00:00 2001 From: Kshitij Sobti Date: Thu, 4 Jan 2024 14:01:45 +0530 Subject: [PATCH 2/2] fixup!: Review feedback add help etc --- bin/paragon-scripts.js | 12 +++++++++++- lib/build-tokens.js | 7 +++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/bin/paragon-scripts.js b/bin/paragon-scripts.js index 75e08a9cd8..9c28f5be3e 100755 --- a/bin/paragon-scripts.js +++ b/bin/paragon-scripts.js @@ -75,9 +75,19 @@ const COMMANDS = { }, { name: '-t, --themes', - description: 'Specify themes to include in the token build.', + description: 'Specify themes to include in the token build. Eg. light,dark or "light dark"', defaultValue: 'light', }, + { + name: '--base-theme', + description: 'Specify the base theme to use in the token build. For example, to build the "high-contrast" theme on top of the ligth theme use "--theme high-contrast --base-theme light".', + defaultValue: 'Same as theme', + }, + { + name: '--all-themes', + description: 'Build tokens for all themes in the source directory.', + defaultValue: false, + }, ], }, 'replace-variables': { diff --git a/lib/build-tokens.js b/lib/build-tokens.js index 72ddb7e267..8378696656 100755 --- a/lib/build-tokens.js +++ b/lib/build-tokens.js @@ -40,12 +40,15 @@ async function buildTokensCommand(commandArgs) { let themesToProcess = null; if (allThemes) { + const tokensPath = tokensSource || path.resolve(__dirname, '../tokens/src'); themesToProcess = fs - .readdirSync(`${tokensSource}/themes/`, { withFileTypes: true }) + .readdirSync(`${tokensPath}/themes/`, { withFileTypes: true }) .filter(entry => entry.isDirectory()) .map(entry => entry.name); + } else if (Array.isArray(themes)) { + themesToProcess = themes; } else { - themesToProcess = themes.split(' '); + themesToProcess = themes.split(/[\s,]/); } const coreConfig = {