Skip to content

Commit

Permalink
feat(design-tokens): add bin command to generate custom design tokens
Browse files Browse the repository at this point in the history
  • Loading branch information
borisdiakur authored and renet committed Nov 25, 2021
1 parent 60afed0 commit 2ea32c1
Show file tree
Hide file tree
Showing 14 changed files with 304 additions and 52 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules
bin
dist
dist_docs
coverage
Expand Down
1 change: 1 addition & 0 deletions .eleventyignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.github
.stencil
bin
coverage
dist
dist_docs
Expand Down
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules
bin
dist
dist_docs
coverage
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
bin/
!bin/.gitkeep
dist/
dist_docs/

Expand Down
Empty file added bin/.gitkeep
Empty file.
11 changes: 8 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"yarn": ">=1.22.10"
},
"author": "User Experience Strategy & Design unit, part of the Chief Digital Organization at EMD Group <liquid@emdgroup.com> (https://github.com/emdgroup-liquid)",
"bin": "./bin/cli.js",
"main": "dist/index.cjs.js",
"module": "dist/custom-elements/index.js",
"es2015": "dist/esm/index.mjs",
Expand All @@ -25,10 +26,15 @@
"collection:main": "dist/collection/index.js",
"unpkg": "dist/liquid/liquid.esm.js",
"files": [
"bin/",
"dist/"
],
"scripts": {
"build": "run-s build:stencil:components build:stencil:react build:styles build:copy_design_tokens build:copy_tailwind_preset",
"apply_design_tokens": "dotenv -e .env -- ts-node scripts/applyDesignTokens.ts",
"build": "run-s build:stencil:components build:stencil:react build:styles build:copy_design_tokens build:tailwind_preset build:bin",
"build:bin": "run-p build:bin:*",
"build:bin:cli": "tsc scripts/cli.ts --moduleResolution node --target esnext --outfile bin/cli.js",
"build:bin:apply_design_tokens": "tsc scripts/applyDesignTokens.ts --moduleResolution node --target esnext --outfile bin/applyDesignTokens.js",
"build:docs": "run-s build:stencil:docs build:eleventy build:styles:docs:*",
"build:eleventy": "dotenv -e .env -- npx @11ty/eleventy",
"build:stencil:components": "stencil build && shx mv tmp/web-components.html-data.json dist/web-components.html-data.json && shx rm -r tmp",
Expand All @@ -41,7 +47,7 @@
"build:styles:docs:liquid": "postcss src/liquid/global/styles/global.css --config=postcss.config.docs.js -m -o dist_docs/dist/build/liquid.css",
"build:styles:docs:docs": "postcss src/docs/global/styles/global.css --config=postcss.config.docs.js -m -o dist_docs/docs.css",
"build:copy_design_tokens": "shx cp src/liquid/global/styles/design-tokens.json dist/css/design-tokens.json",
"build:copy_tailwind_preset": "tsc src/liquid/global/styles/tailwindPreset.ts --moduleResolution node --target esnext --outfile dist/css/tailwind-preset.js",
"build:tailwind_preset": "tsc src/liquid/global/styles/tailwindPreset.ts --moduleResolution node --target esnext --outfile dist/css/tailwind-preset.js",
"generate": "stencil generate",
"lint": "run-s lint:ts lint:eslint lint:styles",
"lint:eslint": "eslint .",
Expand All @@ -61,7 +67,6 @@
"test:unit": "stencil test --spec --coverage",
"test:watch": "stencil test --spec --e2e --watchAll",
"test:compare_screenshots": "live-server --port=4000 --open=compare.html screenshot --quiet --mount=/node_modules:./node_modules --mount=/.stencil:./.stencil",
"update_design_tokens": "dotenv -e .env -- ts-node scripts/updateDesignTokens.ts",
"update_icons": "dotenv -e .env -- ts-node scripts/updateIcons.ts",
"watch:eleventy": "dotenv -e .env -- npx @11ty/eleventy --watch",
"watch:global_styles:liquid": "chokidar src/liquid/global/styles/**/*.css -c 'yarn build:styles:docs:liquid'",
Expand Down
125 changes: 86 additions & 39 deletions scripts/updateDesignTokens.ts → scripts/applyDesignTokens.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const nodeFetch = require('node-fetch')
const { writeFile } = require('fs').promises
const https = require('https')
const { existsSync } = require('fs')
const { mkdir, writeFile } = require('fs').promises
const { join, dirname } = require('path')

const isBin = __filename.endsWith('.js')
const stylesDir = isBin ? './liquid_tmp/styles' : './src/liquid/global/styles'

type TypoToken = {
fontFamily: string
Expand All @@ -9,6 +14,13 @@ type TypoToken = {
lineHeight: string
}

async function ensureWriteFile(path, data, options) {
const dir = dirname(path)
if (!existsSync(dir)) await mkdir(dir, { recursive: true })

return writeFile(path, data, options)
}

function pxToRem(px: string | number) {
return parseInt(px + '') / 16 + 'rem'
}
Expand Down Expand Up @@ -158,12 +170,8 @@ function parseTypography(items, styles) {
.toLowerCase()
.replace(/^pg-/, 'body-')
.replace(/^caption-/, 'cap-')
const {
fontFamily,
fontSize,
fontWeight,
lineHeightPercentFontSize,
} = item.style
const { fontFamily, fontSize, fontWeight, lineHeightPercentFontSize } =
item.style
const baseFontName =
fontFamily === 'Merck'
? 'MWeb'
Expand Down Expand Up @@ -196,20 +204,50 @@ function parseSpacings(items) {
return spacings
}

async function getTokensFromFigma(
figmaId = 'JcDMeUwec9e185HfBgT9XE',
nodeId = '2615:28396'
) {
const result = await nodeFetch(
`https://api.figma.com/v1/files/${figmaId}/nodes?ids=${nodeId}`,
{
method: 'GET',
headers: {
'X-Figma-Token': process.env.FIGMA_API_KEY,
},
}
)
const { document, styles } = (await result.json()).nodes[nodeId]
async function getTokensFromFigma(figmaFileURL: string) {
let figmaId
let nodeId
try {
const url = new URL(figmaFileURL)
figmaId = url.pathname.split('/file/')[1].split('/')[0]
nodeId = url.searchParams.get('node-id')
} catch (err) {
console.error('Failed to parse Figma file URL.')
throw err
}

if (!figmaId || !nodeId) {
throw new Error('Failed to parse Figma file URL.')
}

const result = await new Promise((resolve, reject) => {
https
.get(
`https://api.figma.com/v1/files/${figmaId}/nodes?ids=${nodeId}`,
{
headers: {
'Content-Type': 'application/json',
'X-Figma-Token': process.env.FIGMA_API_KEY,
},
},
(resp) => {
let data = ''

resp.on('data', (chunk) => {
data += chunk
})

resp.on('end', () => {
resolve(JSON.parse(data))
})
}
)
.on('error', (err) => {
reject(err)
})
})

const { document, styles } = (result as { nodes }).nodes[nodeId]
const { children: figmaData } = document

const tokens = {
Expand Down Expand Up @@ -257,8 +295,8 @@ function boxShadowToDropShadow(boxShadow: string): string {
}

function generateShadows(tokens) {
return writeFile(
'./src/liquid/global/styles/shadows/shadows.css',
return ensureWriteFile(
join(stylesDir, 'shadows/shadows.css'),
'/* autogenerated */\n:root {\n' +
Object.keys(tokens)
.sort()
Expand Down Expand Up @@ -301,8 +339,8 @@ function generateColors(colorTokens) {
}
})

return writeFile(
'./src/liquid/global/styles/colors/colors.css',
return ensureWriteFile(
join(stylesDir, 'colors/colors.css'),
['/* autogenerated */', ':root {', ...colorVariables.sort(), '}', ''].join(
'\n'
),
Expand All @@ -311,8 +349,8 @@ function generateColors(colorTokens) {
}

function generateSpacings(tokens) {
return writeFile(
'./src/liquid/global/styles/spacings/spacings.css',
return ensureWriteFile(
join(stylesDir, 'spacings/spacings.css'),
'/* autogenerated */\n:root {\n' +
Object.keys(tokens)
.sort((key) => parseInt(key))
Expand Down Expand Up @@ -363,8 +401,8 @@ function generateTheming(themes) {
themeSelectors.push(`}`)
})

return writeFile(
'./src/liquid/global/styles/theming/theming.css',
return ensureWriteFile(
join(stylesDir, 'theming/theming.css'),
[
'/* autogenerated */',
':root {',
Expand All @@ -386,8 +424,8 @@ function generateTypography(tokens: TypoToken[]) {
const nonBodyTypoEntry = tokenEntries.find(
([, value]) => value.fontFamily !== bodyFontFamily
)
return writeFile(
'./src/liquid/global/styles/typography/typography.css',
return ensureWriteFile(
join(stylesDir, 'typography/typography.css'),
'/* autogenerated */\n:root {\n' +
// This expect to have at least one headline and one paragraph typo defined
` --ld-font-body: ${bodyFontFamily};\n` +
Expand All @@ -409,8 +447,8 @@ function generateTypography(tokens: TypoToken[]) {
}

function generateBorderRadii(tokens) {
return writeFile(
'./src/liquid/global/styles/border-radius/border-radius.css',
return ensureWriteFile(
join(stylesDir, 'border-radius/border-radius.css'),
'/* autogenerated */\n:root {\n' +
Object.keys(tokens)
.sort((key) => parseInt(key))
Expand All @@ -433,19 +471,28 @@ function generateCSSTokenFiles(tokenCollection) {
}

function generateJSONTokenFile(tokenCollection) {
writeFile(
'./src/liquid/global/styles/design-tokens.json',
return ensureWriteFile(
join(stylesDir, 'design-tokens.json'),
JSON.stringify(tokenCollection, null, 2),
'utf8'
)
}

;(async () => {
async function applyDesignTokens(
figmaFileURL = process.env.FIGMA_FILE_URL ||
'https://www.figma.com/file/JcDMeUwec9e185HfBgT9XE/Liquid-Oxygen?node-id=2615%3A28396'
) {
try {
const tokenCollection = await getTokensFromFigma()
const tokenCollection = await getTokensFromFigma(figmaFileURL)
await generateJSONTokenFile(tokenCollection)
await generateCSSTokenFiles(tokenCollection)
} catch (err) {
console.error('error', err)
}
})()
}

if (!isBin) {
applyDesignTokens()
}

module.exports = applyDesignTokens
Loading

0 comments on commit 2ea32c1

Please sign in to comment.