Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit fe7b44c

Browse files
init project
1 parent a68158b commit fe7b44c

File tree

12 files changed

+387
-0
lines changed

12 files changed

+387
-0
lines changed

‎main.ts‎

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// generate-icons.ts
2+
import * as fs from "fs"
3+
import * as path from "path"
4+
import { toPascalCase, extractSvgContent, camelizeSvgAttributes, generateComponent } from "./src/shared"
5+
6+
const SVG_DIR = "src/icons-svg"
7+
const OUTPUT_DIR = "dist/components/icons"
8+
9+
10+
function main() {
11+
if (!fs.existsSync(OUTPUT_DIR)) fs.mkdirSync(OUTPUT_DIR, { recursive: true })
12+
13+
const withSvgSource = path.resolve("src/shared/hoc/withSvg.tsx")
14+
const withSvgTarget = path.resolve("dist/components/icons/withSvg.tsx")
15+
16+
if (!fs.existsSync(withSvgTarget)) {
17+
fs.copyFileSync(withSvgSource, withSvgTarget)
18+
}
19+
const files = fs.readdirSync(SVG_DIR).filter((f) => f.endsWith(".svg"))
20+
const exports: string[] = []
21+
22+
for (const file of files) {
23+
const baseName = path.basename(file)
24+
const componentName = toPascalCase(baseName)
25+
const svgRaw = fs.readFileSync(path.join(SVG_DIR, file), "utf-8")
26+
const svgInner = camelizeSvgAttributes(extractSvgContent(svgRaw))
27+
28+
const componentCode = generateComponent(componentName, svgInner)
29+
const outPath = path.join(OUTPUT_DIR, `${componentName}.tsx`)
30+
fs.writeFileSync(outPath, componentCode)
31+
exports.push(`export { ${componentName} } from "./${componentName}"`)
32+
}
33+
34+
fs.writeFileSync(path.join(OUTPUT_DIR, "index.ts"), exports.join("\n") + "\n")
35+
console.log("✅ Icons generated!")
36+
}
37+
38+
main()

‎package-lock.json‎

Lines changed: 237 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"name": "svg2tsx",
3+
"version": "1.0.0",
4+
"main": "main.ts",
5+
"scripts": {
6+
"convert": "ts-node main.ts"
7+
},
8+
"keywords": [],
9+
"author": "",
10+
"license": "ISC",
11+
"description": "",
12+
"devDependencies": {
13+
"ts-node": "^10.9.2",
14+
"typescript": "^5.8.3"
15+
}
16+
}

‎src/icons-svg/add-01.svg‎

Lines changed: 4 additions & 0 deletions
Loading[フレーム]

‎src/icons-svg/add-02.svg‎

Lines changed: 3 additions & 0 deletions
Loading[フレーム]
Lines changed: 5 additions & 0 deletions
Loading[フレーム]

‎src/icons-svg/add-circle.svg‎

Lines changed: 4 additions & 0 deletions
Loading[フレーム]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const withSvgImport = `import { withSvg } from "./withSvg"\n\n`
2+
3+
/**
4+
* Generates a React component string for an SVG icon
5+
* @param name - The component name
6+
* @param svgContent - The SVG content to wrap
7+
* @returns The complete component code string
8+
*/
9+
export function generateComponent(name: string, svgContent: string): string {
10+
return `${withSvgImport}export const ${name} = withSvg(\n <>${svgContent
11+
.split("\n")
12+
.map((line) => `\n ${line}`)
13+
.join("")}\n </>\n)\n`
14+
}

‎src/shared/functions/string-utils.ts‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* Converts a string to PascalCase and removes .svg extension
3+
* @param str - The string to convert
4+
* @returns The PascalCase string
5+
*/
6+
export function toPascalCase(str: string): string {
7+
return str
8+
.replace(/(^\w|-\w)/g, (match) => match.replace("-", "").toUpperCase())
9+
.replace(/\.svg$/, "")
10+
}

‎src/shared/functions/svg-utils.ts‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* Extracts the inner content of an SVG string (everything between <svg> tags)
3+
* @param svg - The SVG string
4+
* @returns The inner SVG content
5+
*/
6+
export function extractSvgContent(svg: string): string {
7+
const match = svg.match(/<svg[^>]*>([\s\S]*?)<\/svg>/i)
8+
return match ? match[1].trim() : ""
9+
}
10+
11+
/**
12+
* Converts SVG attributes to React camelCase format and forces currentColor for stroke
13+
* @param svg - The SVG string to process
14+
* @returns The processed SVG string with camelCase attributes
15+
*/
16+
export function camelizeSvgAttributes(svg: string): string {
17+
return svg
18+
.replace(/stroke-width/g, "strokeWidth")
19+
.replace(/stroke-linecap/g, "strokeLinecap")
20+
.replace(/stroke-linejoin/g, "strokeLinejoin")
21+
.replace(/fill-rule/g, "fillRule")
22+
.replace(/clip-rule/g, "clipRule")
23+
.replace(/stroke=".*?"/g, 'stroke="currentColor"') // ← force currentColor
24+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /