-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
24f6d13
commit dda30de
Showing
17 changed files
with
776 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
/* eslint-disable no-undef */ | ||
/* eslint-disable @typescript-eslint/no-var-requires */ | ||
const api = require("axios"); | ||
|
||
const headers = { | ||
"X-FIGMA-TOKEN": process.env.FIGMA_TOKEN, | ||
}; | ||
/** | ||
* api endpoint for files | ||
* | ||
*/ | ||
const instanceFiles = api.create({ | ||
baseURL: `https://api.figma.com/v1/files/${process.env.FILE_KEY}`, | ||
headers, | ||
}); | ||
/** | ||
* api endpoint for styles | ||
* | ||
*/ | ||
const instanceStyles = api.create({ | ||
baseURL: `https://api.figma.com/v1/files/${process.env.FILE_KEY}/styles`, | ||
headers, | ||
}); | ||
/** | ||
* api endpoint for images | ||
* | ||
*/ | ||
const instanceImages = api.create({ | ||
baseURL: `https://api.figma.com/v1/images/${process.env.FILE_KEY}`, | ||
headers, | ||
}); | ||
/** | ||
* get Figma document info | ||
* | ||
* @return {Promise<Object>} | ||
*/ | ||
const getDocument = async () => instanceFiles.get("/"); | ||
|
||
/** | ||
* get Figma style info | ||
* | ||
* @return {Promise<Object>} | ||
*/ | ||
const getStyles = async () => instanceStyles.get("/"); | ||
/** | ||
* get Figma node info | ||
* | ||
* @param {string} nodeId | ||
* @return {Promise<Object>} | ||
*/ | ||
const getNode = async (nodeId) => | ||
instanceFiles.get(`/nodes?ids=${decodeURIComponent(nodeId)}`); | ||
/** | ||
* get Figma node children | ||
* | ||
* @param {string} nodeId | ||
* @return {Promise<[Object]>} | ||
*/ | ||
const getNodeChildren = async (nodeId) => { | ||
const { | ||
data: { nodes }, | ||
} = await instanceFiles.get(`/nodes?ids=${decodeURIComponent(nodeId)}`); | ||
return nodes[nodeId].document.children; | ||
}; | ||
/** | ||
* get svg image resource url | ||
* | ||
* @param {string} nodeId | ||
* @return {Promise<string>} | ||
*/ | ||
const getSvgImageUrl = async (nodeId) => { | ||
const { | ||
data: { images, err }, | ||
} = await instanceImages.get( | ||
`/?ids=${decodeURIComponent(nodeId)}&format=svg` | ||
); | ||
return images[nodeId]; | ||
}; | ||
/** | ||
* get svg image resource urls | ||
* | ||
* @param {string} nodeId | ||
* @return {Promise<string[]>} | ||
*/ | ||
const getAllSvgImageUrl = async (nodeId) => { | ||
const { | ||
data: { images, err }, | ||
} = await instanceImages.get( | ||
`/?ids=${decodeURIComponent(nodeId)}&format=svg` | ||
); | ||
return images; | ||
}; | ||
const getIconContent = async (url) => api.get(url); | ||
module.exports = { | ||
getDocument, | ||
getNode, | ||
getNodeChildren, | ||
getSvgImageUrl, | ||
getIconContent, | ||
getAllSvgImageUrl, | ||
getStyles, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
/* eslint-disable no-undef */ | ||
/* eslint-disable @typescript-eslint/no-var-requires */ | ||
|
||
const { getDocument, getAllSvgImageUrl, getIconContent } = require("./api"); | ||
const fs = require("fs"); | ||
|
||
function sliceIntoChunks(arr, chunkSize) { | ||
const res = []; | ||
for (let i = 0; i < arr.length; i += chunkSize) { | ||
const chunk = arr.slice(i, i + chunkSize); | ||
res.push(chunk); | ||
} | ||
return res; | ||
} | ||
/** | ||
* Get document of specified file Id | ||
*/ | ||
getDocument() | ||
.then((response) => { | ||
const componetKeys = Object.keys(response.data.components); | ||
const ids = componetKeys.join(","); | ||
|
||
/** | ||
* Components count | ||
*/ | ||
process.stdout.write(`${componetKeys.length} Icons present in Figma! \n`); | ||
|
||
/** | ||
* Storing id to name mapping | ||
*/ | ||
const iconNameMapping = {}; | ||
for (const [id, component] of Object.entries( | ||
Object.entries(response.data.components) | ||
)) { | ||
iconNameMapping[id] = component[1].name; | ||
} | ||
/** | ||
* async/await removed to download asynchronously | ||
*/ | ||
getAllSvgImageUrl(ids) | ||
.then( | ||
async (urls) => { | ||
process.stdout.write( | ||
`\x1b[36m \rDownloading ${componetKeys.length} icons.` | ||
); | ||
|
||
const iconUrls = []; | ||
for (const [id, url] of Object.entries(Object.entries(urls))) { | ||
/** | ||
* Downloading component whose name starts with 'i-' | ||
*/ | ||
if ( | ||
iconNameMapping[id].startsWith("i-") || | ||
iconNameMapping[id].startsWith("p-") | ||
) { | ||
iconUrls.push({ id, url }); | ||
} | ||
} | ||
const batchSize = 10; | ||
const batches = sliceIntoChunks(iconUrls, batchSize); | ||
|
||
for (let i = 0; i < batches.length; i++) { | ||
const promises = []; | ||
process.stdout.write( | ||
`\x1b[36m \rDownloading ${i * batchSize} to ${ | ||
i * batchSize + batchSize | ||
} ...` | ||
); | ||
|
||
batches[i].forEach(({ id, url }) => { | ||
/** | ||
* Downloading component whose name starts with 'i-' | ||
*/ | ||
if ( | ||
iconNameMapping[id].startsWith("i-") || | ||
iconNameMapping[id].startsWith("p-") | ||
) { | ||
promises.push( | ||
getIconContent(url[1]).then( | ||
(icon) => { | ||
/** | ||
* Writing file in svg folder | ||
*/ | ||
fs.writeFileSync( | ||
`${__dirname}/../lib/Icon/svg/${iconNameMapping[id]}.svg`, | ||
icon.data | ||
); | ||
}, | ||
(error) => { | ||
console.log( | ||
`Failed to load svg ${iconNameMapping[id]} - ${url[1]}`, | ||
error.code | ||
); | ||
} | ||
) | ||
); | ||
} | ||
}); | ||
await Promise.all(promises); | ||
} | ||
process.stdout.clearLine(); | ||
process.stdout.write( | ||
`\x1b[36m \r${componetKeys.length} Icons downloaded! \n \n ` | ||
); | ||
}, | ||
(error) => { | ||
console.error(error); | ||
} | ||
) | ||
.catch((error) => { | ||
console.error(error); | ||
}); | ||
}) | ||
.catch((error) => { | ||
console.error(error); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* eslint-disable no-undef */ | ||
/* eslint-disable @typescript-eslint/no-var-requires */ | ||
|
||
const { getStyles, getNode } = require("./api"); | ||
const prettier = require("prettier"); | ||
|
||
const fs = require("fs"); | ||
|
||
const rgbToHex = (r, g, b) => | ||
"#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1); | ||
|
||
function generateTokenScss(colorTokens) { | ||
const tokenFileName = `${__dirname}/../src/shared/_tokens.scss`; | ||
|
||
// let scss = `@layer default,custom; | ||
// @layer default { `; | ||
let scss = ` | ||
@function getHover($value) { | ||
$hover-color: lighten($value, 10%); | ||
@if lightness($value) > 50 { | ||
$hover-color: darken($value, 10%); | ||
} | ||
@return $hover-color; | ||
} | ||
`; | ||
for (const [theme, tokens] of Object.entries(colorTokens)) { | ||
const tokenEntries = Object.entries(tokens); | ||
|
||
scss += ` | ||
[flow-element][theme="${theme}"]{ `; | ||
|
||
for (let [variable, value] of tokenEntries) { | ||
variable = `color-${variable}`; | ||
scss += `$${variable} : ${value} ;\n`; | ||
scss += `--${variable} : #{$${variable}} ;\n`; | ||
scss += `--${variable}-hover : #{getHover($${variable})};\n`; | ||
} | ||
scss += ` | ||
};\n`; | ||
} | ||
// scss += `}`; | ||
try { | ||
fs.writeFileSync( | ||
tokenFileName, | ||
prettier.format(scss, { | ||
printWidth: 100, | ||
singleQuote: true, | ||
tabWidth: 4, | ||
parser: "css", | ||
}) | ||
); | ||
console.log(`\x1b[32m \r ${tokenFileName} generated \u2705 \x1b[0m`); | ||
} catch (e) { | ||
console.log(e); | ||
} | ||
} | ||
/** | ||
* Get document of specified file Id | ||
*/ | ||
getStyles() | ||
.then(async (response) => { | ||
let nodeids = []; | ||
response.data.meta.styles.forEach((element) => { | ||
nodeids.push(element.node_id); | ||
}); | ||
getNode(nodeids.join(",")).then(async (response) => { | ||
const colorTokens = {}; | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
for (const [_id, obj] of Object.entries(response.data.nodes)) { | ||
const { r, g, b } = obj.document.fills[0].color; | ||
|
||
const [theme, token] = obj.document.name.split("/"); | ||
if (!colorTokens[theme]) { | ||
colorTokens[theme] = {}; | ||
} | ||
|
||
colorTokens[theme][token] = rgbToHex( | ||
+(r * 255).toFixed(0), | ||
+(g * 255).toFixed(0), | ||
+(b * 255).toFixed(0) | ||
); | ||
} | ||
generateTokenScss(colorTokens); | ||
}); | ||
console.log("\n"); | ||
}) | ||
.catch((error) => { | ||
console.error(error); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
@use "sass:map"; | ||
@use "sass:math"; | ||
|
||
$states: ( | ||
"primary": var(--color-primary-default), | ||
"subtle": var(--color-success-default), | ||
"success": var(--color-success-default), | ||
"warning": var(--color-warning-default), | ||
"danger": var(--color-danger-default), | ||
); | ||
|
||
$states-hover-colors: ( | ||
"primary": var(--color-primary-default-hover), | ||
"subtle": var(--color-success-default-hover), | ||
"success": var(--color-success-default-hover), | ||
"warning": var(--color-warning-default-hover), | ||
"danger": var(--color-danger-default-hover), | ||
); | ||
|
||
$sizes: ( | ||
"x-small": 20px, | ||
"small": 28px, | ||
"medium": 36px, | ||
"large": 44px, | ||
); | ||
f-button { | ||
cursor: pointer; | ||
display: inline-flex; | ||
align-items: center; | ||
justify-content: center; | ||
padding: 0px 20px; | ||
font-weight: 600; | ||
text-transform: uppercase; | ||
font-size: 14px; | ||
color: var(--color-surface-default); | ||
|
||
@each $state, $color in $states { | ||
&[state="#{$state}"][variant="fill"] { | ||
background-color: $color; | ||
|
||
&:hover { | ||
background-color: map.get($states-hover-colors, $state); | ||
} | ||
} | ||
} | ||
|
||
@each $size, $value in $sizes { | ||
&[size="#{$size}"] { | ||
height: $value; | ||
|
||
&[shape="round"] { | ||
border-radius: math.div($value, 2); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.