-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Feature] svg 아이콘 컴포넌트 방식 변환 자동화 스크립트 작성 (#31)
* rename: scripts wow-ui 외부로 이동 * chore: eslintcache 파일 삭제 * refactor: 상수값 위치 변경 * chore: tsx 의존성 루트로 이동해서 설치 * feat: svg 파일 리액트 컴포넌트 방식으로 변환하는 스크립트 작성 * feat: svg 파일 삭제 시 변환되어 있는 컴포넌트 파일도 삭제되는 로직 추가 * refactor: 스크립트 리팩토링 * chore: wow-icons 빌드 input 설정 변경 * chore: 빌드 설정 변경 * chore: wow-icons 빌드 설정 변경 * chore: 스크립트 수정 * chore: wow-ui 빌드 시 babel runtime external로 설정하도록 변경 * chore: root에 wowds-tokens dev dependency 설치 * rename: theme 패키지 내부 폴더구조 정리 * chore: theme 패키지 exports 속성 변경 * chore: theme 패키지 tsconfig 수정 * chore: 스크립트 수정 및 적용 * chore: 스크립트 및 아이콘 코드 수정 * chore: root tsconfig에 styled-system exclude하도록 설정 * chore: wow-ui 빌드 설정 변경 * chore: wow-ui preserveModules 설정 추가 * chore: 스크립트 및 아이콘 수정 * chore: wow-icons에 절대 경로 설정 적용 * chore: 함수 이름 변경 * chore: 컴포넌트 디렉토리 존재하지 않는 경우 예외 처리 * chore: wow-icons 롤업 절대 경로 설정 추가 * chore: 의존성 정리 * chore: 아이콘 타입 추론 관련 설정 변경 * chore: stroke/fill 포함 여부에 따라 props 구성하도록 스크립트 수정 * chore: 안 쓰는 import문 삭제 * chore: format 스크립트 변경 * chore: 이미 생성된 컴포넌트는 다시 쓰지 않도록 수정
- Loading branch information
1 parent
acb62fd
commit 379fa1b
Showing
30 changed files
with
396 additions
and
342 deletions.
There are no files selected for viewing
This file was deleted.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ module.exports = { | |
globals: { | ||
React: true, | ||
JSX: true, | ||
console: true, | ||
}, | ||
env: { | ||
browser: true, | ||
|
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 |
---|---|---|
|
@@ -26,13 +26,13 @@ | |
"@changesets/changelog-git": "^0.2.0", | ||
"@changesets/cli": "^2.27.1", | ||
"@pandacss/dev": "^0.39.0", | ||
"@rollup/plugin-alias": "^5.1.0", | ||
"@rollup/plugin-babel": "^6.0.4", | ||
"@rollup/plugin-commonjs": "^25.0.7", | ||
"@rollup/plugin-json": "^6.1.0", | ||
"@rollup/plugin-node-resolve": "^15.2.3", | ||
"@rollup/plugin-terser": "^0.4.4", | ||
"@rollup/plugin-url": "^8.0.2", | ||
"@svgr/rollup": "^8.1.0", | ||
"@testing-library/jest-dom": "^6.4.5", | ||
"@testing-library/react": "^15.0.7", | ||
"@testing-library/user-event": "^14.5.2", | ||
|
@@ -69,11 +69,13 @@ | |
"rollup-plugin-peer-deps-external": "^2.2.4", | ||
"rollup-plugin-preserve-directives": "^0.4.0", | ||
"shared-config": "workspace:^", | ||
"theme": "workspace:*", | ||
"theme": "workspace:^", | ||
"ts-jest": "^29.1.2", | ||
"ts-node": "^10.9.2", | ||
"tsx": "^4.11.0", | ||
"turbo": "latest", | ||
"typescript": "^5.3.3" | ||
"typescript": "^5.3.3", | ||
"wowds-tokens": "workspace:^" | ||
}, | ||
"packageManager": "[email protected]", | ||
"engines": { | ||
|
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,140 @@ | ||
import { existsSync, promises as fs } from "fs"; | ||
import path from "path"; | ||
|
||
const SVG_DIR = "../wow-icons/src/svg"; | ||
const COMPONENT_DIR = "../wow-icons/src/react"; | ||
|
||
type SvgComponentMap = { [key: string]: string }; | ||
|
||
const generateSvgComponentMap = async () => { | ||
const svgFiles = (await fs.readdir(SVG_DIR)).reduce<SvgComponentMap>( | ||
(map, svgFile) => { | ||
const componentName = path | ||
.basename(svgFile, ".svg") | ||
.replace(/(^\w|-\w)/g, (match) => match.replace("-", "").toUpperCase()); | ||
map[componentName] = svgFile; | ||
|
||
return map; | ||
}, | ||
{} | ||
); | ||
|
||
return svgFiles; | ||
}; | ||
|
||
const deleteUnusedComponentFiles = async (svgComponentMap: SvgComponentMap) => { | ||
if (!existsSync(COMPONENT_DIR)) { | ||
fs.mkdir(COMPONENT_DIR); | ||
return; | ||
} | ||
|
||
const componentFiles = await fs.readdir(COMPONENT_DIR); | ||
const componentFilesToDelete = componentFiles.filter((componentFile) => { | ||
const componentName = path.basename(componentFile, ".tsx"); | ||
return !(componentName in svgComponentMap); | ||
}); | ||
|
||
await Promise.all( | ||
componentFilesToDelete.map((file) => { | ||
const componentFilePath = path.resolve(COMPONENT_DIR, file); | ||
return fs.unlink(componentFilePath); | ||
}) | ||
); | ||
}; | ||
|
||
const createComponentContent = ( | ||
componentName: string, | ||
svgContent: string, | ||
svgFile: string | ||
): string => { | ||
const iconName = path.basename(svgFile, ".svg"); | ||
const hasStroke = svgContent.includes("stroke="); | ||
const fillAttributes = (svgContent.match(/fill="([^"]*)"/g) || []).filter( | ||
(attr) => attr !== 'fill="none"' | ||
); | ||
const hasFill = fillAttributes.length; | ||
const propsString = `{ className, width = 24, height = 24, viewBox = "0 0 24 24"${hasStroke || hasFill ? ` ${hasStroke ? ', stroke = "white"' : ""}${hasFill ? ', fill = "white"' : ""}` : ""}, ...rest }`; | ||
const modifiedSvgContent = svgContent | ||
.replace(/-(\w)/g, (_, letter) => letter.toUpperCase()) | ||
.replace(/width="(\d+)"/g, `width={width}`) | ||
.replace(/height="(\d+)"/g, `height={height}`) | ||
.replace(/viewBox="(.*?)"/g, `viewBox={viewBox}`) | ||
.replace(/<svg([^>]*)fill="[^"]*"([^>]*)>/, "<svg$1$2>") | ||
.replace(/fill="([^"]+)"/g, `fill={color[fill]}`) | ||
.replace(/stroke="([^"]+)"/g, `stroke={color[stroke]}`) | ||
.replace( | ||
/<svg([^>]*)>/, | ||
`<svg$1 aria-label="${iconName} icon" fill="none" ref={ref} className={className} {...rest}>` | ||
); | ||
|
||
return ` | ||
import { forwardRef } from 'react'; | ||
import { color } from "wowds-tokens"; | ||
import type { IconProps } from "../types/Icon.ts"; | ||
const ${componentName} = forwardRef<SVGSVGElement, IconProps>( | ||
(${propsString}, ref) => { | ||
return ( | ||
${modifiedSvgContent} | ||
); | ||
} | ||
); | ||
${componentName}.displayName = '${componentName}'; | ||
export default ${componentName}; | ||
`; | ||
}; | ||
|
||
const generateComponentFiles = async (svgComponentMap: SvgComponentMap) => { | ||
const components: string[] = []; | ||
|
||
for (const [componentName, svgFile] of Object.entries(svgComponentMap)) { | ||
const componentFilePath = path.resolve( | ||
COMPONENT_DIR, | ||
`${componentName}.tsx` | ||
); | ||
|
||
if (existsSync(componentFilePath)) { | ||
components.push(componentName); | ||
continue; | ||
} | ||
|
||
const svgFilePath = path.resolve(SVG_DIR, svgFile); | ||
const svgContent = (await fs.readFile(svgFilePath)).toString(); | ||
|
||
const componentContent = createComponentContent( | ||
componentName, | ||
svgContent, | ||
svgFile | ||
); | ||
|
||
await fs.writeFile(componentFilePath, componentContent); | ||
components.push(componentName); | ||
} | ||
|
||
return components; | ||
}; | ||
|
||
const generateExportFile = async (components: string[]) => { | ||
const EXPORT_FILE_PATH = "../wow-icons/src/react/index.ts"; | ||
const exportFileContent = components | ||
.map( | ||
(component) => | ||
`export { default as ${component} } from "./${component}.tsx";` | ||
) | ||
.join("\n"); | ||
|
||
await fs.writeFile(EXPORT_FILE_PATH, exportFileContent); | ||
}; | ||
|
||
(async () => { | ||
try { | ||
const svgComponentMap = await generateSvgComponentMap(); | ||
await deleteUnusedComponentFiles(svgComponentMap); | ||
const components = await generateComponentFiles(svgComponentMap); | ||
await generateExportFile(components); | ||
} catch (error) { | ||
console.log("Error generating components:", 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
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
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,99 @@ | ||
export type ColorToken = | ||
| "red50" | ||
| "red100" | ||
| "red150" | ||
| "red200" | ||
| "red300" | ||
| "red400" | ||
| "red500" | ||
| "red600" | ||
| "red700" | ||
| "red800" | ||
| "red850" | ||
| "red900" | ||
| "red950" | ||
| "blue50" | ||
| "blue100" | ||
| "blue150" | ||
| "blue200" | ||
| "blue300" | ||
| "blue400" | ||
| "blue500" | ||
| "blue600" | ||
| "blue700" | ||
| "blue800" | ||
| "blue850" | ||
| "blue900" | ||
| "blue950" | ||
| "yellow50" | ||
| "yellow100" | ||
| "yellow150" | ||
| "yellow200" | ||
| "yellow300" | ||
| "yellow400" | ||
| "yellow500" | ||
| "yellow600" | ||
| "yellow700" | ||
| "yellow800" | ||
| "yellow850" | ||
| "yellow900" | ||
| "yellow950" | ||
| "green50" | ||
| "green100" | ||
| "green150" | ||
| "green200" | ||
| "green300" | ||
| "green400" | ||
| "green500" | ||
| "green600" | ||
| "green700" | ||
| "green800" | ||
| "green850" | ||
| "green900" | ||
| "green950" | ||
| "mono50" | ||
| "mono100" | ||
| "mono150" | ||
| "mono200" | ||
| "mono300" | ||
| "mono400" | ||
| "mono500" | ||
| "mono600" | ||
| "mono700" | ||
| "mono800" | ||
| "mono850" | ||
| "mono900" | ||
| "mono950" | ||
| "white" | ||
| "black" | ||
| "whiteOpacity20" | ||
| "whiteOpacity40" | ||
| "whiteOpacity60" | ||
| "whiteOpacity80" | ||
| "blackOpacity20" | ||
| "blackOpacity40" | ||
| "blackOpacity60" | ||
| "blackOpacity80" | ||
| "primary" | ||
| "success" | ||
| "error" | ||
| "backgroundNormal" | ||
| "backgroundAlternative" | ||
| "backgroundDimmer" | ||
| "sub" | ||
| "outline" | ||
| "textBlack" | ||
| "textWhite" | ||
| "darkDisabled" | ||
| "lightDisabled" | ||
| "blueHover" | ||
| "monoHover" | ||
| "elevatedHover" | ||
| "bluePressed" | ||
| "blueBackgroundPressed" | ||
| "monoBackgroundPressed" | ||
| "shadowSmall" | ||
| "shadowMedium" | ||
| "blueShadow" | ||
| "discord" | ||
| "github"; |
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 @@ | ||
export * from "./Color.ts"; |
File renamed without changes.
File renamed without changes.
File renamed without changes.
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
Oops, something went wrong.