forked from epicweb-dev/epic-stack
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: bring build-icons into the epic stack (epicweb-dev#340)
Co-authored-by: Jacob Paris <[email protected]>
- Loading branch information
1 parent
e3e7ca5
commit 7aa9290
Showing
8 changed files
with
184 additions
and
32 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
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,111 @@ | ||
import * as path from 'node:path' | ||
import { glob } from 'glob' | ||
import fsExtra from 'fs-extra' | ||
import { parse } from 'node-html-parser' | ||
|
||
const cwd = process.cwd() | ||
const inputDir = path.join(cwd, 'other', 'svg-icons') | ||
const inputDirRelative = path.relative(cwd, inputDir) | ||
const outputDir = path.join(cwd, 'app', 'components', 'ui', 'icons') | ||
|
||
const files = glob.sync('**/*.svg', { | ||
cwd: inputDir, | ||
}) | ||
|
||
const shouldVerboseLog = process.argv.includes('--log=verbose') | ||
const logVerbose = shouldVerboseLog ? console.log : () => {} | ||
|
||
if (files.length === 0) { | ||
console.log(`No SVG files found in ${inputDirRelative}`) | ||
} else { | ||
await generateIconFiles() | ||
console.log(`Generated ${files.length} icons`) | ||
} | ||
|
||
async function generateIconFiles() { | ||
logVerbose(`Generating sprite for ${inputDirRelative}`) | ||
await fsExtra.emptyDir(outputDir) | ||
|
||
const spriteFilepath = path.join(outputDir, 'sprite.svg') | ||
await generateSvgSprite({ | ||
files, | ||
inputDir, | ||
outputPath: spriteFilepath, | ||
}) | ||
|
||
for (const file of files) { | ||
logVerbose('✅', file) | ||
} | ||
logVerbose(`Saved to ${path.relative(cwd, spriteFilepath)}`) | ||
|
||
const iconNames = files.map(file => | ||
JSON.stringify(path.basename(file, '.svg')), | ||
) | ||
|
||
const typeOutputFilepath = path.join(outputDir, 'name.d.ts') | ||
const typeOutputContent = `// This file is generated by npm run build:icons | ||
export type IconName = | ||
\t| ${iconNames.join('\n\t| ')}; | ||
` | ||
await fsExtra.writeFile(typeOutputFilepath, typeOutputContent, 'utf8') | ||
|
||
logVerbose(`Manifest saved to ${path.relative(cwd, typeOutputFilepath)}`) | ||
|
||
await fsExtra.writeFile( | ||
path.join(outputDir, 'README.md'), | ||
`# Icons | ||
This directory contains SVG icons that are used by the app. | ||
Everything in this directory is generated by \`npm run build:icons\`. | ||
`, | ||
'utf8', | ||
) | ||
} | ||
|
||
/** | ||
* Creates a single SVG file that contains all the icons | ||
*/ | ||
async function generateSvgSprite({ | ||
files, | ||
inputDir, | ||
outputPath, | ||
}: { | ||
files: string[] | ||
inputDir: string | ||
outputPath: string | ||
}) { | ||
// Each SVG becomes a symbol and we wrap them all in a single SVG | ||
const symbols = await Promise.all( | ||
files.map(async file => { | ||
const input = await fsExtra.readFile(path.join(inputDir, file), 'utf8') | ||
const root = parse(input) | ||
|
||
const svg = root.querySelector('svg') | ||
if (!svg) throw new Error('No SVG element found') | ||
|
||
svg.tagName = 'symbol' | ||
svg.setAttribute('id', file.replace(/\.svg$/, '')) | ||
svg.removeAttribute('xmlns') | ||
svg.removeAttribute('xmlns:xlink') | ||
svg.removeAttribute('version') | ||
svg.removeAttribute('width') | ||
svg.removeAttribute('height') | ||
|
||
return root.toString().trim() | ||
}), | ||
) | ||
|
||
const output = [ | ||
`<?xml version="1.0" encoding="UTF-8"?>`, | ||
`<!-- This file is generated by npm run build:icons -->`, | ||
`<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="0" height="0">`, | ||
`<defs>`, // for semantics: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs | ||
...symbols, | ||
`</defs>`, | ||
`</svg>`, | ||
].join('\n') | ||
|
||
return fsExtra.writeFile(outputPath, output, 'utf8') | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
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,3 @@ | ||
// This file is a fallback until you run npm run build:icons | ||
|
||
export type IconName = string |