diff --git a/.changeset/light-pandas-perform.md b/.changeset/light-pandas-perform.md new file mode 100644 index 00000000..8571efc9 --- /dev/null +++ b/.changeset/light-pandas-perform.md @@ -0,0 +1,5 @@ +--- +'@propeldata/ui-kit': minor +--- + +Filter out all design variables and tokens not in use diff --git a/app/storybook/documentation/ui-kit/Theming.mdx b/app/storybook/documentation/ui-kit/Theming.mdx index eb3b2a5f..3798aad3 100644 --- a/app/storybook/documentation/ui-kit/Theming.mdx +++ b/app/storybook/documentation/ui-kit/Theming.mdx @@ -3,10 +3,7 @@ import LinkTo from '@storybook/addon-links/react' import { prettier } from '../../src/utils' import { SourceCode } from '../../.storybook/blocks/SourceCode' import * as ThemeProviderStories from '../../../../packages/ui-kit/src/components/ThemeProvider/ThemeProvider.stories' -import rawThemesScss from '!!raw-loader!../../../../packages/ui-kit/src/themes/themes.module.scss' -import rawCommonScss from '!!raw-loader!../../../../packages/ui-kit/src/themes/generated/_tokens.scss' -import rawLightThemeScss from '!!raw-loader!../../../../packages/ui-kit/src/themes/generated/_lightTheme.scss' -import rawDarkThemeScss from '!!raw-loader!../../../../packages/ui-kit/src/themes/generated/_darkTheme.scss' +import rawThemesScss from '!!raw-loader!../../../../packages/ui-kit/src/generated/themes/themes.module.css' @@ -41,25 +38,13 @@ Further details are available in the -The `common.scss` file contains the **common** theme configuration, defining a series of CSS custom properties that are -shared by both the light and dark themes. - - - -The `lightTheme.scss` file sets up the **light theme** for the UI Kit, defining a series of CSS custom properties -specific to this theme. - - - -The `darkTheme.scss` file sets up the **dark theme** for the UI Kit, defining a series of CSS custom properties specific -to this theme. - - - ### Customizing the Theme The `ThemeProvider` component allows theme customization through its `theme` prop. diff --git a/packages/ui-kit/package.json b/packages/ui-kit/package.json index 568806c9..8fb28336 100644 --- a/packages/ui-kit/package.json +++ b/packages/ui-kit/package.json @@ -14,8 +14,8 @@ "test:coverage": "jest --ci --coverage --json --outputFile=coverage/coverage.json", "design-tokens:sync": "yarn design-tokens:clean && tsc -p ./scripts/tsconfig.json && yarn design-tokens:parse && yarn design-tokens:validate", "design-tokens:clean": "rm -rf ./scripts/dist && rm -rf ./src/generated && rm -rf ./src/themes/generated", - "design-tokens:parse": "node ./scripts/dist/parse-design-tokens.mjs", - "design-tokens:validate": "node ./scripts/dist/validate-design-tokens.mjs" + "design-tokens:parse": "node ./scripts/dist/design-tokens/parse.mjs", + "design-tokens:validate": "node ./scripts/dist/design-tokens/validate.mjs" }, "publishConfig": { "access": "public", diff --git a/packages/ui-kit/scripts/parse-design-tokens.mts b/packages/ui-kit/scripts/design-tokens/parse.mts similarity index 84% rename from packages/ui-kit/scripts/parse-design-tokens.mts rename to packages/ui-kit/scripts/design-tokens/parse.mts index e2d96341..95396878 100644 --- a/packages/ui-kit/scripts/parse-design-tokens.mts +++ b/packages/ui-kit/scripts/design-tokens/parse.mts @@ -1,7 +1,9 @@ import fs, { promises as fsPromises } from 'fs' -import path from 'path' -import slugify from 'slugify' import ora from 'ora' +import path from 'path' +import { buildSASSFiles, camelCaseToKebabCase, getCSSVariables, kebabCaseToCamelCase, slugifyStr } from './shared.mjs' + +const env = process.env.NODE_ENV || 'development' const GENERATED_WARNING = 'This file is generated automatically by scripts/parse-design-tokens.js. Do not edit manually.' @@ -60,20 +62,6 @@ type TypographyClassProps = { props: { prop: string; value: string }[] } -// Slugify string with strict mode -export const slugifyStr = (str: string): string => slugify(str.replaceAll('/', '-'), { lower: true, strict: true }) - -// Convert kebab-case to camelCase -export const kebabCaseToCamelCase = (kebabStr: string): string => - kebabStr - .split('-') - .map((word, index) => (index === 0 ? word : word[0].toUpperCase() + word.slice(1))) - .join('') - -// Convert camelCase to kebab-case -export const camelCaseToKebabCase = (camelStr: string): string => - camelStr.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() - // Parse Figma variable value export const parseValue = (variable: VariableProps): string => { const { type, value } = variable @@ -156,8 +144,13 @@ export const getThemeTokens = ({ ) ) -const main = async () => { - const spinner = ora({ text: 'Parsing design variables and tokens...', color: 'yellow' }).start() +const main = async (isProdEnv = false) => { + let succeedMessage = 'Parse design variables and tokens' + + const spinner = ora({ + text: `Parsing design variables and tokens...`, + color: 'yellow' + }).start() try { const variablesJSON = await getJSONFromFile() @@ -167,8 +160,8 @@ const main = async () => { throw new Error('Failed to parse variables.json') } - const variables: TokenDataProps[] = [] - const tokens: TokenDataProps[] = [] + let variables: TokenDataProps[] = [] + let tokens: TokenDataProps[] = [] // Parse variables variablesJSON.collections @@ -240,15 +233,32 @@ const main = async () => { const themes = variablesJSON.collections.find(({ name }) => name === '1. Color Modes')?.modes // Parse theme tokens - const lightTheme = getThemeTokens({ name: 'light', themes, variables, tokens }) - const darkTheme = getThemeTokens({ name: 'dark', themes, variables, tokens }) + let lightTheme = getThemeTokens({ name: 'light', themes, variables, tokens }) + let darkTheme = getThemeTokens({ name: 'dark', themes, variables, tokens }) + + if (isProdEnv) { + await buildSASSFiles(spinner) + + const currentVariablesList = getCSSVariables('./src', 'current') + const statsBefore = { + variables: variables.length, + tokens: tokens.length + } + + variables = variables.filter((variable) => currentVariablesList.includes(variable.cssName)) + tokens = tokens.filter((token) => currentVariablesList.includes(token.cssName)) + lightTheme = lightTheme?.filter((token) => currentVariablesList.includes(token.cssName)) + darkTheme = darkTheme?.filter((token) => currentVariablesList.includes(token.cssName)) + + succeedMessage = `Filter out all design variables (${variables.length} from ${statsBefore.variables}) and tokens (${tokens.length} from ${statsBefore.tokens}) not in use` + } // Generate _variables.scss writeToFileSync( '_variables.scss', [ `// ${GENERATED_WARNING}\n`, - '.variables {', + '%variables {', variables.map(({ cssName, value }) => ` ${cssName}: ${value};`).join('\n'), '}' ].join('\n') @@ -260,15 +270,14 @@ const main = async () => { [ `// ${GENERATED_WARNING}\n`, "@use './variables';\n", - '.tokens {', - ' @extend .variables;\n', + '%tokens {', + ' @extend %variables;\n', tokens.map(({ cssName, value }) => ` ${cssName}: ${value};`).join('\n'), '}\n', typographyClasses .map((typographyClass) => [ - `.${typographyClass.className} {`, - ' @extend .variables;\n', + `%${typographyClass.className} {`, typographyClass.props.map(({ prop, value }) => ` ${prop}: ${value};`).join('\n'), '}\n' ].join('\n') @@ -287,9 +296,7 @@ const main = async () => { `_${name}.scss`, [ `// ${GENERATED_WARNING}\n`, - "@use './tokens';\n", - `.${name} {`, - ' @extend .tokens;\n', + `%${name} {`, theme?.map(({ cssName, value }) => ` ${cssName}: ${value};`).join('\n'), '}' ].join('\n') @@ -338,7 +345,7 @@ const main = async () => { ].join('\n') ) - spinner.succeed('Parse design variables and tokens') + spinner.succeed(succeedMessage) } catch (err) { console.error(err) spinner.fail('Failed to parse design variables and tokens') @@ -346,3 +353,7 @@ const main = async () => { } main() + +if (env === 'production') { + main(true) +} diff --git a/packages/ui-kit/scripts/validate-design-tokens.mts b/packages/ui-kit/scripts/design-tokens/shared.mts similarity index 67% rename from packages/ui-kit/scripts/validate-design-tokens.mts rename to packages/ui-kit/scripts/design-tokens/shared.mts index 6d2ebb40..9739319e 100644 --- a/packages/ui-kit/scripts/validate-design-tokens.mts +++ b/packages/ui-kit/scripts/design-tokens/shared.mts @@ -1,10 +1,23 @@ +import { exec } from 'child_process' import fs from 'fs' +import { Ora } from 'ora' import path from 'path' -import ora, { Ora } from 'ora' -import { exec } from 'child_process' +import slugify from 'slugify' import { promisify } from 'util' -const FAILED_MESSAGE = 'Design tokens validation failed' +// Slugify string with strict mode +export const slugifyStr = (str: string): string => slugify(str.replaceAll('/', '-'), { lower: true, strict: true }) + +// Convert kebab-case to camelCase +export const kebabCaseToCamelCase = (kebabStr: string): string => + kebabStr + .split('-') + .map((word, index) => (index === 0 ? word : word[0].toUpperCase() + word.slice(1))) + .join('') + +// Convert camelCase to kebab-case +export const camelCaseToKebabCase = (camelStr: string): string => + camelStr.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() const execAsync = promisify(exec) @@ -68,39 +81,3 @@ export const buildSASSFiles = async (spinner: Ora): Promise => { throw error } } - -// Compare current and new CSS variables, and log any missing variables -export const validateDesignTokens = (spinner: Ora): void => { - spinner.start('Validating design tokens...') - let validationFailed = false - - const currentVariablesList = getCSSVariables('./src', 'current') - const newVariablesList = getCSSVariables('./src/themes', 'new') - - currentVariablesList.forEach((variable) => { - if (!newVariablesList.includes(variable)) { - spinner.warn(`Design token '${variable}' is not defined`) - validationFailed = true - } - }) - - if (validationFailed) { - throw new Error(FAILED_MESSAGE) - } - - spinner.succeed('Validate design tokens') -} - -async function main() { - const spinner = ora({ text: 'Building SASS files...', color: 'yellow' }).start() - - try { - await buildSASSFiles(spinner) - validateDesignTokens(spinner) - } catch (error) { - spinner.fail(FAILED_MESSAGE) - console.error(error) - } -} - -main() diff --git a/packages/ui-kit/scripts/design-tokens/validate.mts b/packages/ui-kit/scripts/design-tokens/validate.mts new file mode 100644 index 00000000..cf5b0464 --- /dev/null +++ b/packages/ui-kit/scripts/design-tokens/validate.mts @@ -0,0 +1,40 @@ +import ora, { Ora } from 'ora' +import { getCSSVariables, buildSASSFiles } from './shared.mjs' + +const FAILED_MESSAGE = 'Design tokens validation failed' + +// Compare current and new CSS variables, and log any missing variables +export const validateDesignTokens = (spinner: Ora): void => { + spinner.start('Validating design tokens...') + let validationFailed = false + + const currentVariablesList = getCSSVariables('./src', 'current') + const newVariablesList = getCSSVariables('./src/themes', 'new') + + currentVariablesList.forEach((variable) => { + if (!newVariablesList.includes(variable)) { + spinner.warn(`Design token '${variable}' is not defined`) + validationFailed = true + } + }) + + if (validationFailed) { + throw new Error(FAILED_MESSAGE) + } + + spinner.succeed('Validate design tokens') +} + +async function main() { + const spinner = ora({ text: 'Building SASS files...', color: 'yellow' }).start() + + try { + await buildSASSFiles(spinner) + validateDesignTokens(spinner) + } catch (error) { + spinner.fail(FAILED_MESSAGE) + console.error(error) + } +} + +main() diff --git a/packages/ui-kit/scripts/tsconfig.json b/packages/ui-kit/scripts/tsconfig.json index 22405983..96c6d49b 100644 --- a/packages/ui-kit/scripts/tsconfig.json +++ b/packages/ui-kit/scripts/tsconfig.json @@ -5,6 +5,7 @@ "target": "ESNext", "strict": true, "outDir": "dist", + "rootDir": ".", "lib": ["ESNext", "DOM"] }, "include": ["./**/*.mts"], diff --git a/packages/ui-kit/src/components/Button/Button.module.scss b/packages/ui-kit/src/components/Button/Button.module.scss index 2910e7e8..d20fd3d7 100644 --- a/packages/ui-kit/src/components/Button/Button.module.scss +++ b/packages/ui-kit/src/components/Button/Button.module.scss @@ -1,7 +1,7 @@ @use '../../themes/generated/tokens'; .rootButton { - @extend .textMdRegular; + @extend %textMdRegular; padding: var(--propel-spacing-lg) var(--propel-spacing-4xl); gap: var(--propel-spacing-lg); @@ -71,7 +71,7 @@ } &.small { - @extend .textSmSemibold; + @extend %textSmSemibold; padding: var(--propel-spacing-md) var(--propel-spacing-4xl); diff --git a/packages/ui-kit/src/components/Counter/Counter.module.scss b/packages/ui-kit/src/components/Counter/Counter.module.scss index aad5b6c5..13b17a0e 100644 --- a/packages/ui-kit/src/components/Counter/Counter.module.scss +++ b/packages/ui-kit/src/components/Counter/Counter.module.scss @@ -1,7 +1,7 @@ -@use '../../themes/common'; +@use '../../themes/generated/tokens'; .rootCounter { - @extend .displayLgBold; + @extend %displayLgBold; color: var(--propel-text-primary); white-space: nowrap; transition: opacity 0.2s ease-in-out; @@ -13,6 +13,6 @@ } .loader { - @extend .displayLgBold; + @extend %displayLgBold; color: var(--propel-text-secondary); } diff --git a/packages/ui-kit/src/components/ErrorFallback/ErrorFallback.module.scss b/packages/ui-kit/src/components/ErrorFallback/ErrorFallback.module.scss index c3787a22..6e8a9681 100644 --- a/packages/ui-kit/src/components/ErrorFallback/ErrorFallback.module.scss +++ b/packages/ui-kit/src/components/ErrorFallback/ErrorFallback.module.scss @@ -1,7 +1,8 @@ -@use '../../themes/common'; +// @use '../../themes/common'; +@use '../../themes/generated/tokens'; .rootErrorFallback { - @extend .textMdRegular; + @extend %textMdRegular; color: var(--propel-text-secondary); max-width: 263px; height: var(--propel-component-height); diff --git a/packages/ui-kit/src/components/Input/Input.module.scss b/packages/ui-kit/src/components/Input/Input.module.scss index 3068cff1..e57ffcff 100644 --- a/packages/ui-kit/src/components/Input/Input.module.scss +++ b/packages/ui-kit/src/components/Input/Input.module.scss @@ -1,7 +1,7 @@ @use '../../themes/generated/tokens'; .rootInput { - @extend .textMdRegular; + @extend %textMdRegular; padding: var(--propel-spacing-lg) var(--propel-spacing-xl); gap: var(--propel-spacing-lg); @@ -21,7 +21,7 @@ transition: border-color var(--propel-transition-ease-time) ease, box-shadow var(--propel-transition-ease-time) ease; & input { - @extend .textMdRegular; + @extend %textMdRegular; border: none; padding: 0; @@ -67,12 +67,12 @@ } .small { - @extend .textSmRegular; + @extend %textSmRegular; padding: var(--propel-spacing-md) var(--propel-spacing-lg); gap: var(--propel-spacing-md); & input { - @extend .textSmRegular; + @extend %textSmRegular; } } diff --git a/packages/ui-kit/src/components/Leaderboard/Leaderboard.module.scss b/packages/ui-kit/src/components/Leaderboard/Leaderboard.module.scss index c97b2256..16dad810 100644 --- a/packages/ui-kit/src/components/Leaderboard/Leaderboard.module.scss +++ b/packages/ui-kit/src/components/Leaderboard/Leaderboard.module.scss @@ -1,7 +1,8 @@ -@use '../../themes/common'; +// @use '../../themes/common'; +@use '../../themes/generated/tokens'; .rootLeaderboard { - @extend .textXxsRegular; + @extend %textXxsRegular; color: var(--propel-text-secondary); overflow: auto; padding: 0; @@ -68,11 +69,11 @@ text-align: left; padding: var(--propel-spacing-md) var(--propel-spacing-md) var(--propel-spacing-md) 0; color: var(--propel-text-secondary); - @extend .textXsRegular; + @extend %textXsRegular; } td { - @extend .textXsRegular; + @extend %textXsRegular; color: var(--propel-text-secondary); border-bottom: 1px solid var(--propel-border-primary); } diff --git a/packages/ui-kit/src/components/Loader/Loader.module.scss b/packages/ui-kit/src/components/Loader/Loader.module.scss index fceacf32..bdd27256 100644 --- a/packages/ui-kit/src/components/Loader/Loader.module.scss +++ b/packages/ui-kit/src/components/Loader/Loader.module.scss @@ -1,7 +1,8 @@ -@use '../../themes/common'; +// @use '../../themes/common'; +@use '../../themes/generated/tokens'; .rootLoader { - @extend .textMdRegular; + @extend %textMdRegular; color: var(--propel-text-secondary); overflow: auto; width: 100%; diff --git a/packages/ui-kit/src/components/PieChart/PieChart.module.scss b/packages/ui-kit/src/components/PieChart/PieChart.module.scss index 76e462f1..c0ca5954 100644 --- a/packages/ui-kit/src/components/PieChart/PieChart.module.scss +++ b/packages/ui-kit/src/components/PieChart/PieChart.module.scss @@ -1,11 +1,24 @@ -@use '../../themes/common'; +// @use '../../themes/common'; +@use '../../themes/generated/tokens'; .rootPieChart { - @extend .textXxsRegular; + @extend %textXxsRegular; color: var(--propel-text-primary); overflow: auto; padding: 0; + --pie-bg-25: var(--propel-brand-25); + --pie-bg-50: var(--propel-brand-50); + --pie-bg-100: var(--propel-brand-100); + --pie-bg-200: var(--propel-brand-200); + --pie-bg-300: var(--propel-brand-300); + --pie-bg-400: var(--propel-brand-400); + --pie-bg-500: var(--propel-brand-500); + --pie-bg-600: var(--propel-brand-600); + --pie-bg-700: var(--propel-brand-700); + --pie-bg-900: var(--propel-brand-900); + --pie-bg-empty: var(--propel-background-brand-primary); + canvas { height: var(--propel-component-height); } @@ -35,7 +48,7 @@ } .pieChartList { - @extend .textXsRegular; + @extend %textXsRegular; color: var(--propel-text-secondary); margin-top: var(--propel-spacing-xl); diff --git a/packages/ui-kit/src/components/Select/Option/Option.module.scss b/packages/ui-kit/src/components/Select/Option/Option.module.scss index fcbf2921..14ceb179 100644 --- a/packages/ui-kit/src/components/Select/Option/Option.module.scss +++ b/packages/ui-kit/src/components/Select/Option/Option.module.scss @@ -1,7 +1,7 @@ @use '../../../themes/generated/tokens'; .rootOption { - @extend .textMdRegular; + @extend %textMdRegular; padding: var(--propel-spacing-xl) var(--propel-spacing-4xl); margin: 0; diff --git a/packages/ui-kit/src/components/Select/Select.module.scss b/packages/ui-kit/src/components/Select/Select.module.scss index a8c7db80..5441fc63 100644 --- a/packages/ui-kit/src/components/Select/Select.module.scss +++ b/packages/ui-kit/src/components/Select/Select.module.scss @@ -1,10 +1,10 @@ @use '../../themes/generated/tokens'; .rootButton { - @extend .textMdRegular; + @extend %textMdRegular; &.small { - @extend .textSmRegular; + @extend %textSmRegular; } } @@ -35,7 +35,7 @@ .small { ul { li { - @extend .textSmRegular; + @extend %textSmRegular; padding: var(--propel-spacing-md) var(--propel-spacing-xl); gap: var(--propel-spacing-xxs); diff --git a/packages/ui-kit/src/components/TimeRangePicker/TimeRangePicker.module.scss b/packages/ui-kit/src/components/TimeRangePicker/TimeRangePicker.module.scss index eca78df5..30ab4155 100644 --- a/packages/ui-kit/src/components/TimeRangePicker/TimeRangePicker.module.scss +++ b/packages/ui-kit/src/components/TimeRangePicker/TimeRangePicker.module.scss @@ -79,7 +79,7 @@ } .caption_label { - @extend .textSmRegular; + @extend %textSmRegular; position: absolute; left: 0; @@ -92,11 +92,11 @@ } .head_cell { - @extend .textSmRegular; + @extend %textSmRegular; } .cell { - @extend .textSmRegular; + @extend %textSmRegular; } .nav { @@ -118,7 +118,7 @@ } .button { - @extend .textSmRegular; + @extend %textSmRegular; padding: 10px var(--propel-spacing-md); border-width: 1px; diff --git a/packages/ui-kit/src/components/Typography/Typography.module.scss b/packages/ui-kit/src/components/Typography/Typography.module.scss index fb5ca21b..15de2d5a 100644 --- a/packages/ui-kit/src/components/Typography/Typography.module.scss +++ b/packages/ui-kit/src/components/Typography/Typography.module.scss @@ -7,23 +7,23 @@ // Add new variant when needed. Check themes/generated/_tokens.scss for available variants. .textMdRegular { - @extend .textMdRegular; + @extend %textMdRegular; } .textMdSemibold { - @extend .textMdSemibold; + @extend %textMdSemibold; } .textXsRegular { - @extend .textXsRegular; + @extend %textXsRegular; } .textXxsRegular { - @extend .textXxsRegular; + @extend %textXxsRegular; } .textSmRegular { - @extend .textSmRegular; + @extend %textSmRegular; } .block { diff --git a/packages/ui-kit/src/themes/_common.scss b/packages/ui-kit/src/themes/_common.scss index 45914cc9..6eaa805a 100644 --- a/packages/ui-kit/src/themes/_common.scss +++ b/packages/ui-kit/src/themes/_common.scss @@ -1,6 +1,6 @@ @use './generated/tokens'; -.commonTokens { +%commonTokens { --propel-component-height: 300px; --propel-transition-ease-time: 300ms; @@ -64,5 +64,5 @@ --propel-color-blue50: #eff8ff; --propel-color-blue25: #f5faff; - @extend .tokens; + @extend %tokens; } diff --git a/packages/ui-kit/src/themes/_darkTheme.scss b/packages/ui-kit/src/themes/_darkTheme.scss index a6c2c8ef..a0c9ab4a 100644 --- a/packages/ui-kit/src/themes/_darkTheme.scss +++ b/packages/ui-kit/src/themes/_darkTheme.scss @@ -1,11 +1,10 @@ -/** darkTheme.scss */ // @deprecated - all tokens in this file are deprecated in favor of the generated tokens and should be removed in the future @use './common'; @use './generated/darkTheme'; .darkTheme { - @extend .commonTokens; + @extend %commonTokens; --propel-color-primary: #2e90fa; --propel-color-secondary: rgba(46, 144, 250, 0.35); @@ -18,5 +17,5 @@ --propel-color-loader: #2d2d2d; --propel-color-loader-animation: #00000020; - @extend .darkTheme; + @extend %darkTheme; } diff --git a/packages/ui-kit/src/themes/_lightTheme.scss b/packages/ui-kit/src/themes/_lightTheme.scss index fbda3983..36b9763e 100644 --- a/packages/ui-kit/src/themes/_lightTheme.scss +++ b/packages/ui-kit/src/themes/_lightTheme.scss @@ -1,11 +1,10 @@ -/** lightTheme.scss */ // @deprecated - all tokens in this file are deprecated in favor of the generated tokens and should be removed in the future @use './common'; @use './generated/lightTheme'; .lightTheme { - @extend .commonTokens; + @extend %commonTokens; --propel-color-primary: #2e90fa; --propel-color-secondary: #cdd5df; @@ -18,5 +17,5 @@ --propel-color-loader: #e9e9e9; --propel-color-loader-animation: #ffffff20; - @extend .lightTheme; + @extend %lightTheme; } diff --git a/packages/ui-kit/src/themes/themes.module.scss b/packages/ui-kit/src/themes/themes.module.scss index 8a2f86a3..2d510d80 100644 --- a/packages/ui-kit/src/themes/themes.module.scss +++ b/packages/ui-kit/src/themes/themes.module.scss @@ -1,4 +1,2 @@ -/** themes.module.scss */ - @use './lightTheme'; @use './darkTheme';