Skip to content

Commit 4fb70d1

Browse files
authored
feat(cli): ✨ Add option for defining theme name (#2374)
resolves #2334 - Added new option to `--theme` to cli for defining theme name. - Will add new theme or overwrite existing theme. - Added new script in cli (`update:template`) for updating template files from our "master" `design-tokens` in root. - Added textfield in theme-builder tokens modal for defining theme name. - Not a fan of having code, but commented our template generation for `$metadata` and `$themes` as this is an internal improvement that can be done later. - Some updates to components used in theme-builder to get desired user interface.
1 parent b201787 commit 4fb70d1

File tree

20 files changed

+3337
-86
lines changed

20 files changed

+3337
-86
lines changed

apps/_components/src/CodeSnippet/CodeSnippet.tsx

+5-3
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,17 @@ const plugins = [
2727
];
2828

2929
type CodeSnippetProps = {
30-
language?: 'css' | 'html' | 'ts' | 'markdown' | 'js' | 'json' | 'sh';
30+
language?: 'css' | 'html' | 'ts' | 'markdown' | 'json';
3131
children?: string;
3232
className?: string;
33+
syntax?: string;
3334
};
3435

3536
const CodeSnippet = ({
3637
language = 'markdown',
3738
children = '',
3839
className,
40+
syntax = 'js',
3941
}: CodeSnippetProps) => {
4042
const [toolTipText, setToolTipText] = useState('Kopier');
4143
const [snippet, setSnippet] = useState('');
@@ -47,7 +49,7 @@ const CodeSnippet = ({
4749
) {
4850
try {
4951
const formatted = await format(children, {
50-
parser: language === 'ts' ? 'typescript' : language,
52+
parser: language === 'ts' ? 'babel-ts' : language,
5153
plugins,
5254
});
5355
setSnippet(formatted);
@@ -92,7 +94,7 @@ const CodeSnippet = ({
9294
</Tooltip>
9395
<SyntaxHighlighter
9496
style={nightOwl}
95-
language={language}
97+
language={syntax}
9698
customStyle={{
9799
fontSize: '15px',
98100
margin: 0,

apps/theme/components/TokenModal/TokenModal.module.css

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
}
1010

1111
.snippet {
12-
max-height: 350px;
12+
max-height: 250px;
1313
overflow: auto;
1414
}
1515

apps/theme/components/TokenModal/TokenModal.tsx

+21-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
Link,
88
Modal,
99
Paragraph,
10+
Textfield,
1011
} from '@digdir/designsystemet-react';
1112
import { createTokens } from '@digdir/designsystemet/tokens/create.js';
1213
import { CodeSnippet } from '@repo/components';
@@ -38,13 +39,15 @@ export const TokenModal = ({
3839

3940
const [lightThemeSnippet, setLightThemeSnippet] = useState('');
4041
const [darkThemeSnippet, setDarkThemeSnippet] = useState('');
42+
const [themeName, setThemeName] = useState('theme');
4143

4244
const cliSnippet = `npx @digdir/designsystemet tokens create \\
4345
--accent "${accentColor}" \\
4446
--neutral "${neutralColor}" \\
4547
--brand1 "${brand1Color}" \\
4648
--brand2 "${brand2Color}" \\
4749
--brand3 "${brand3Color}" \\
50+
--theme "${themeName}" \\
4851
--write
4952
`;
5053

@@ -58,6 +61,7 @@ export const TokenModal = ({
5861
brand3: brand3Color,
5962
},
6063
typography: { fontFamily: 'Inter' },
64+
themeName: 'theme',
6165
});
6266

6367
setLightThemeSnippet(toFigmaSnippet(tokens.colors.light.theme));
@@ -93,6 +97,20 @@ export const TokenModal = ({
9397
<Heading level={3} size='xs' spacing>
9498
Alt 1. Design tokens
9599
</Heading>
100+
<Textfield
101+
label='Navn på tema'
102+
description="Kun bokstaver, tall og bindestrek. Eks: 'mitt-tema'"
103+
value={themeName}
104+
onChange={(e) => {
105+
const value = e.currentTarget.value
106+
.replace(/\s+/g, '-')
107+
.replace(/[^A-Z0-9-]+/gi, '')
108+
.toLowerCase();
109+
110+
setThemeName(value);
111+
}}
112+
style={{ marginBlock: 'var(--ds-spacing-4)' }}
113+
></Textfield>
96114
<Paragraph spacing>
97115
Kopier kommandosnutten under og kjør på maskinen din for å generere
98116
alle design tokens (json-filer). Sørg for at du har{' '}
@@ -105,7 +123,7 @@ export const TokenModal = ({
105123
className={classes.snippet}
106124
style={{ marginBottom: 'var(--ds-spacing-8)' }}
107125
>
108-
<CodeSnippet language='js'>{cliSnippet}</CodeSnippet>
126+
<CodeSnippet syntax='shell'>{cliSnippet}</CodeSnippet>
109127
</div>
110128
<Heading level={3} size='xs' spacing>
111129
Alt 2. Figma plugin
@@ -138,15 +156,15 @@ export const TokenModal = ({
138156
Light Mode
139157
</Heading>
140158
<div className={classes.snippet}>
141-
<CodeSnippet language='js'>{lightThemeSnippet}</CodeSnippet>
159+
<CodeSnippet language='json'>{lightThemeSnippet}</CodeSnippet>
142160
</div>
143161
</div>
144162
<div className={classes.column}>
145163
<Heading level={4} size='2xs' spacing>
146164
Dark Mode
147165
</Heading>
148166
<div className={classes.snippet}>
149-
<CodeSnippet language='js'>{darkThemeSnippet}</CodeSnippet>
167+
<CodeSnippet language='json'>{darkThemeSnippet}</CodeSnippet>
150168
</div>
151169
</div>
152170
</div>

packages/cli/bin/designsystemet.ts

+17-15
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@ program.name('Designsystemet').description('CLI for working with Designsystemet'
1414

1515
function makeTokenCommands() {
1616
const tokenCmd = createCommand('tokens');
17+
const DEFAULT_TOKENSDIR = './design-tokens';
1718

1819
tokenCmd
1920
.command('build')
2021
.description('Build Designsystemet tokens')
21-
.option('-t, --tokens <string>', `Path to ${chalk.blue('design-tokens')}`, './design-tokens')
22+
.option('-t, --tokens <string>', `Path to ${chalk.blue('design-tokens')}`, DEFAULT_TOKENSDIR)
2223
.option('-o, --out <string>', `Output directory for built ${chalk.blue('design-tokens')}`, './dist/tokens')
2324
.option('-p, --preview', 'Generate preview token.ts files', false)
2425
.action((opts) => {
25-
const tokens = typeof opts.tokens === 'string' ? opts.tokens : './design-tokens';
26+
const tokens = typeof opts.tokens === 'string' ? opts.tokens : DEFAULT_TOKENSDIR;
2627
const out = typeof opts.out === 'string' ? opts.out : './dist/tokens';
2728
const preview = opts.preview;
2829
console.log(`Bulding tokens in ${chalk.green(tokens)}`);
@@ -32,20 +33,21 @@ function makeTokenCommands() {
3233
tokenCmd
3334
.command('create')
3435
.description('Create Designsystemet tokens')
35-
.option('-w, --write [string]', `Output directory for created ${chalk.blue('design-tokens')}`)
36-
.option('-a, --accent <number>', `Accent hex color`)
37-
.option('-n, --neutral <number>', `Neutral hex color`)
38-
.option('-b1, --brand1 <number>', `Brand1 hex color`)
39-
.option('-b2, --brand2 <number>', `Brand2 hex color`)
40-
.option('-b3, --brand3 <number>', `Brand3 hex color`)
41-
.option('-f, --font-family <string>', `Font family`)
36+
.requiredOption('-a, --accent <number>', `Accent hex color`)
37+
.requiredOption('-n, --neutral <number>', `Neutral hex color`)
38+
.requiredOption('-b1, --brand1 <number>', `Brand1 hex color`)
39+
.requiredOption('-b2, --brand2 <number>', `Brand2 hex color`)
40+
.requiredOption('-b3, --brand3 <number>', `Brand3 hex color`)
41+
.option('-w, --write [string]', `Output directory for created ${chalk.blue('design-tokens')}`, DEFAULT_TOKENSDIR)
42+
.option('-f, --font-family <string>', `Font family`, 'Inter')
43+
.option('--theme <string>', `Theme name`, 'theme')
4244
.action(async (opts) => {
43-
// const out = typeof opts.out === 'string' ? opts.out : './dist/tokens';
44-
console.log(`Creating tokens with options ${chalk.green(JSON.stringify(opts))}`);
45-
const family = typeof opts.fontFamily === 'string' ? opts.fontFamily : 'Inter';
46-
const write = typeof opts.write === 'boolean' ? './design-tokens' : opts.write;
45+
const { theme, fontFamily } = opts;
46+
console.log(`Creating tokens with options ${chalk.green(JSON.stringify(opts, null, 2))}`);
47+
const write = typeof opts.write === 'boolean' ? DEFAULT_TOKENSDIR : opts.write;
4748

4849
const props = {
50+
themeName: theme,
4951
colors: {
5052
accent: convertToHex(opts.accent),
5153
neutral: convertToHex(opts.neutral),
@@ -54,14 +56,14 @@ function makeTokenCommands() {
5456
brand3: convertToHex(opts.brand3),
5557
},
5658
typography: {
57-
fontFamily: family,
59+
fontFamily: fontFamily,
5860
},
5961
};
6062

6163
const tokens = createTokens(props);
6264

6365
if (write) {
64-
await writeTokens(write, tokens);
66+
await writeTokens({ writeDir: write, tokens, themeName: theme });
6567
}
6668

6769
return Promise.resolve();

packages/cli/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
"build:swc": "yarn clean && swc src bin --copy-files -d dist && yarn build:types",
3737
"build:types": "tsc --emitDeclarationOnly --declaration",
3838
"clean": "rimraf dist",
39-
"clean:theme": "yarn workspace @digdir/designsystemet-theme clean"
39+
"clean:theme": "yarn workspace @digdir/designsystemet-theme clean",
40+
"update:template": "tsx ./src/tokens/template.ts"
4041
},
4142
"dependencies": {
4243
"@adobe/leonardo-contrast-colors": "^1.0.0",

packages/cli/src/tokens/create.ts

+13-9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { Colors, Tokens, Tokens1ary, TokensSet, Typography } from './types.
55
export type CreateTokensOptions = {
66
colors: Colors;
77
typography: Typography;
8+
themeName: string;
89
};
910

1011
const createColorTokens = (colorArray: ColorInfo[]): Tokens1ary => {
@@ -28,9 +29,9 @@ const createColorTokens = (colorArray: ColorInfo[]): Tokens1ary => {
2829
return obj;
2930
};
3031

31-
const generateTypographyTokens = ({ fontFamily }: Typography): TokensSet => {
32+
const generateTypographyTokens = (themeName: string, { fontFamily }: Typography): TokensSet => {
3233
return {
33-
theme: {
34+
[themeName]: {
3435
main: {
3536
$type: 'fontFamilies',
3637
$value: fontFamily ?? 'Inter',
@@ -51,15 +52,15 @@ const generateTypographyTokens = ({ fontFamily }: Typography): TokensSet => {
5152
};
5253
};
5354

54-
const generateThemeTokens = (theme: ColorMode, colors: Colors): TokensSet => {
55+
const generateThemeTokens = (themeName: string, theme: ColorMode, colors: Colors): TokensSet => {
5556
const accentColors = generateScaleForColor(colors.accent, theme);
5657
const neutralColors = generateScaleForColor(colors.neutral, theme);
5758
const brand1Colors = generateScaleForColor(colors.brand1, theme);
5859
const brand2Colors = generateScaleForColor(colors.brand2, theme);
5960
const brand3Colors = generateScaleForColor(colors.brand3, theme);
6061

6162
return {
62-
theme: {
63+
[themeName]: {
6364
accent: createColorTokens(accentColors),
6465
neutral: createColorTokens(neutralColors),
6566
brand1: createColorTokens(brand1Colors),
@@ -90,19 +91,22 @@ const generateGlobalTokens = (theme: ColorMode) => {
9091
};
9192

9293
export const createTokens = (opts: CreateTokensOptions) => {
93-
const { colors, typography } = opts;
94+
const { colors, typography, themeName: name } = opts;
9495

9596
const tokens: Tokens = {
9697
colors: {
9798
light: {
98-
theme: generateThemeTokens('light', colors),
99+
[name]: generateThemeTokens(name, 'light', colors),
99100
global: generateGlobalTokens('light'),
100101
},
101-
dark: { theme: generateThemeTokens('dark', colors), global: generateGlobalTokens('dark') },
102-
contrast: { theme: generateThemeTokens('contrast', colors), global: generateGlobalTokens('contrast') },
102+
dark: { [name]: generateThemeTokens(name, 'dark', colors), global: generateGlobalTokens('dark') },
103+
contrast: {
104+
[name]: generateThemeTokens(name, 'contrast', colors),
105+
global: generateGlobalTokens('contrast'),
106+
},
103107
},
104108
typography: {
105-
primary: generateTypographyTokens(typography),
109+
primary: generateTypographyTokens(name, typography),
106110
},
107111
};
108112

packages/cli/src/tokens/create/README.md

-3
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"switch": {
3+
"circle": {
4+
"small": {
5+
"$type": "sizing",
6+
"$value": "{sizing.5} - {switch.border}"
7+
},
8+
"medium": {
9+
"$type": "sizing",
10+
"$value": "{sizing.6} - {switch.border}"
11+
},
12+
"large": {
13+
"$type": "sizing",
14+
"$value": "{sizing.7} - {switch.border}"
15+
}
16+
},
17+
"border": {
18+
"$type": "sizing",
19+
"$value": "4"
20+
}
21+
}
22+
}

0 commit comments

Comments
 (0)