pavel edfdfd6dbc
2.0 (#523)
* set up tailwind

* add typography tokens

* add shadows tokens

* add border radius tokens

* add react-aria

* update tailwind config

* update tokens

* fix deps

* add blur variant

* update tw config

* upgrade storybook

* update storybook config

* add inter

* wip button

* wip input

* wip tabs

* update typography tokens

* u storybook

* add types to src root

* update storybook config

* add sb type

* u storybook

* add icon button

* add input

* add checkbox

* add counter

* update checkbox

* add dropdown

* update button

* f storybook types

* u deps

* update base config

* update icon imports

* add text

* update colors build output

* fix import

* update colors format

* add .vsode setting

* update components buidl

* mv

* u button

* add popover

* u

* add types

* u shortcut

* fix icons attributes

* f

* mv

* u

* add toast

* update tw formatting

* rm apps

* rm examples

* rm tamagui

* dist tailwind config

* rm more

* stricter tsconfig

* add source field

* remove tokens

* rm tamagui files

* add prettier config to components

* u text props

* add tooltip

* u toast

* do not pass props

* u icon buton

* u dropdown button

* add icon only to button

* u type

* checkbox

* wip

* fix build

* fix components build

* u tooltip

* add theme

* add input

* u checkbox

* update dropdown-button

* add dropdown menu

* move input to be reviewew

* u dropdown button

* u

* u popover

* u tabs

* mv IconComponent -> IconElement

* u tag

* u context tag

* u

* fix context tag story

* add provider

* u button

* u avatar

* f avatar

* a opacity to avatar

* f prettier

* f avatar

* f

* f

* rm old setting

* fix button props

* skeleton wip

* rm config

* a dropdown submenu

* add blur variant

* add step

* add step to tabs

* add blur to context tag

* u

* add 80 to community

* u tw config

* add type

* u checkbox

* fix dropdown menu checkbox item

* u button

* unify content

* customize color globally

* add icons stories

* add colors story

* rm

* u

* rm dep

* cleanup

* u tsconfig

* f opacity for emoji

* remove "web#build" task from turbo.json

* f dropdown menu

* u tw export

* add license

* add changeset

* update readme

* f steps

* f tag

* f button

* udpate colors format

* update customisation color tailwind config

* fix opacity

* add shadow dark mode

* u readme

* u

---------

Co-authored-by: Jakub Kotula <520927+jkbktl@users.noreply.github.com>
Co-authored-by: Felicio Mununga <felicio@users.noreply.github.com>
2024-09-25 17:17:58 +02:00

187 lines
5.0 KiB
TypeScript

import { isCancel, log, outro, spinner, text } from '@clack/prompts'
import { transform } from '@svgr/core'
import * as Figma from 'figma-api'
import fs from 'fs-extra'
import pMap from 'p-map'
import path from 'path'
const SVG_DIR = path.resolve(__dirname, '../svg')
await fs.ensureDir(SVG_DIR)
function toKebabCase(str: string): string {
return str
.replace(/([a-z])([A-Z])/g, '$1-$2') // convert camel case to kebab case
.replace(/[\s_]+/g, '-') // replace spaces and underscores with hyphens
.toLowerCase()
}
const personalAccessToken = await text({
message: 'Your personal Figma access token:',
validate(value) {
if (value.length === 0) return `required`
},
})
if (isCancel(personalAccessToken)) {
outro('Bye!')
process.exit(0)
}
// https://www.figma.com/file/qLLuMLfpGxK9OfpIavwsmK/Iconset?node-id=3239-987
const FILE_KEY = 'qLLuMLfpGxK9OfpIavwsmK'
const NODE_IDS = {
// currently generates only set of size 20
// https://github.com/status-im/status-web/issues/466
'3239:987': {
name: 'icons-20',
folder: '20',
},
'3239:1440': {
name: 'icons-16',
folder: '16',
},
'3239:3712': {
name: 'icons-12',
folder: '12',
},
'3227:1083': {
name: 'social',
folder: 'social',
},
'942:77': {
name: 'reactions',
folder: 'reactions',
},
}
const figma = new Figma.Api({
personalAccessToken,
})
const s1 = spinner()
s1.start('Fetching Figma file nodes')
const { nodes } = await figma.getFileNodes(FILE_KEY, Object.keys(NODE_IDS))
// console.log('🚀 ~ nodes:', nodes)
s1.stop('Done!')
for (const [nodeId, { name, folder }] of Object.entries(NODE_IDS)) {
const s2 = spinner()
s2.start(`Fetching SVG images for ${name}`)
const { components } = nodes[nodeId]!
const nodeIds = Object.keys(components)
const { err, images } = await figma.getImage(FILE_KEY, {
ids: nodeIds.join(','),
format: 'svg',
scale: 1,
})
if (err) {
s2.stop('Error!')
console.error(err)
process.exit(1)
}
s2.stop('Done!')
log.info(`Generating SVGs for ${name}`)
await pMap(
Object.entries(images),
async ([nodeId, image]) => {
const icon = components[nodeId]!
const svgRaw = await fetch(image!)
.then(res => res.text())
.catch(() => {
log.error(`Failed to fetch SVG for ${icon.name}`)
return
})
// note: probably a wrapper layer for https://www.figma.com/file/qLLuMLfpGxK9OfpIavwsmK/Iconset?type=design&node-id=4408-955&mode=dev, thus skipping
// icon:: {
// key: 'c73f7bad669c2696c2158cef34967a20cc0f0f0f',
// name: 'Use=Default, Typo=False, Style=Gradient',
// description: '',
// remote: true,
// componentSetId: '4819:992',
// documentationLinks: []
// }
// raw::
// transform::
// icon:: {
// key: '53e1bc9f7ee455bc6cc38b90a9b7614ef64afe4e',
// name: '20/status-logo',
// description: '',
// remote: false,
// documentationLinks: []
// }
if (!svgRaw) {
log.error(`Failed to fetch SVG for ${icon.name}`)
return
}
const svg = await transform(svgRaw, {
plugins: ['@svgr/plugin-svgo'],
svgoConfig: {
plugins: [
{
name: 'replace-attributes',
fn: () => {
return {
element: {
enter: node => {
if (node.attributes.fill === '#09101C') {
node.attributes.fill = 'currentColor'
} else if (node.attributes.stroke === '#09101C') {
node.attributes.stroke = 'currentColor'
} else if (node.attributes.fill === '#2A4AF5') {
node.attributes.fill =
'var(--customisation-50, #2A4AF5)'
} else if (node.attributes.stroke === '#2A4AF5') {
node.attributes.stroke =
'var(--customisation-50, #2A4AF5)'
}
},
},
}
},
},
{
name: 'preset-default',
params: {
overrides: {
cleanupIds: {
minify: false,
},
// viewBox is required to resize SVGs with CSS.
// @see https://github.com/svg/svgo/issues/1128
removeViewBox: false,
},
},
},
'prefixIds',
],
},
})
const nameParts = icon.name.replace(' / ', '/').split('/')
const iconName = nameParts.at(-1)!
const fileName = `${toKebabCase(iconName)}-icon.svg`
const filePath = path.resolve(SVG_DIR, folder, fileName)
await fs.ensureDir(path.dirname(filePath))
await fs.writeFile(filePath, svg, { encoding: 'utf8' })
// log.success(filePath)
},
{ concurrency: 5 },
)
log.success(`${Object.keys(images).length} SVGs generated`)
}