mirror of
https://github.com/KevinMidboe/seasoned.git
synced 2026-03-11 11:55:38 +00:00
Icon System Infrastructure
Add icon conversion tooling and new icon library - Add icon-converter.mjs script to transform SVG files into Vue components - Converts kebab-case filenames to PascalCase (e.g., clipboard-text.svg → IconClipboardText.vue) - Wraps SVG content in proper Vue template structure - Sets width/height to 100% for consistent sizing - Add 38 new icon components for future use (IconHelm, IconMailboxFull, IconCheck, IconWarning, IconClipboardText, IconExpandVertical, IconShrinkVertical, and more)
This commit is contained in:
70
scripts/convert-svg-to-vue.mjs
Normal file
70
scripts/convert-svg-to-vue.mjs
Normal file
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Usage: node convert-svg-to-svelte.js [inputDir] [outputDir]
|
||||
* Defaults: svgs src/icons
|
||||
*/
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
const INPUT_DIR = process.argv[2] || "svgs";
|
||||
const OUTPUT_DIR = process.argv[3] || "src/icons";
|
||||
|
||||
if (!fs.existsSync(OUTPUT_DIR)) fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
|
||||
function processSvg(svgContent) {
|
||||
// Strip XML/DOCTYPE
|
||||
let out = svgContent
|
||||
.replace(/<\?xml[\s\S]*?\?>\s*/i, "")
|
||||
.replace(/<!DOCTYPE[\s\S]*?>\s*/i, "");
|
||||
|
||||
// Remove ALL comments
|
||||
out = out.replace(/<!--[\s\S]*?-->\s*/g, "");
|
||||
|
||||
// Remove <g id="icomoon-ignore"></g> with any whitespace between tags
|
||||
out = out.replace(/<g\s+id=(["'])icomoon-ignore\1\s*>\s*<\/g>\s*/gi, "");
|
||||
|
||||
// Ensure only width="100%" height="100%" on the <svg> tag
|
||||
out = out.replace(/<svg\b[^>]*>/i, match => {
|
||||
let tag = match
|
||||
.replace(/\s+(width|height)\s*=\s*"[^"]*"/gi, "")
|
||||
.replace(/\s+(width|height)\s*=\s*'[^']*'/gi, "");
|
||||
return tag.replace(/>$/, ' width="100%" height="100%">');
|
||||
});
|
||||
|
||||
// Prepend the single license comment
|
||||
out =
|
||||
"<!-- generated by icomoon.io - licensed Lindua icon -->\n" +
|
||||
out.replace(/^\s+/, "");
|
||||
|
||||
// Wrap with <template> tags
|
||||
out = "<template>\n" + out + "\n</template>";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
function convertSvgs(inputDir = INPUT_DIR, outputDir = OUTPUT_DIR) {
|
||||
if (!fs.existsSync(inputDir)) {
|
||||
console.warn(`Input directory not found: ${inputDir}`);
|
||||
return;
|
||||
}
|
||||
const files = fs
|
||||
.readdirSync(inputDir)
|
||||
.filter(f => f.toLowerCase().endsWith(".svg"));
|
||||
files.forEach(file => {
|
||||
const src = path.join(inputDir, file);
|
||||
const baseName = file.replace(/\.svg$/i, "");
|
||||
// Convert kebab-case to PascalCase (e.g., clipboard-text -> ClipboardText)
|
||||
const pascalCase = baseName
|
||||
.split("-")
|
||||
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join("");
|
||||
const destFileName = `Icon${pascalCase}.vue`;
|
||||
const dest = path.join(outputDir, destFileName);
|
||||
const svgContent = fs.readFileSync(src, "utf8");
|
||||
const processed = processSvg(svgContent);
|
||||
fs.writeFileSync(dest, processed, "utf8");
|
||||
console.log(`Converted: ${file} -> ${path.basename(dest)}`);
|
||||
});
|
||||
}
|
||||
|
||||
convertSvgs();
|
||||
63
scripts/icon-converter.js
Normal file
63
scripts/icon-converter.js
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Usage: node convert-svg-to-svelte.js [inputDir] [outputDir]
|
||||
* Defaults: ./svgs ./svelte
|
||||
*/
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
const INPUT_DIR = process.argv[2] || "../svgs";
|
||||
const OUTPUT_DIR = process.argv[3] || "../src/icons";
|
||||
|
||||
if (!fs.existsSync(OUTPUT_DIR)) fs.mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
|
||||
function processSvg(svgContent) {
|
||||
// Strip XML/DOCTYPE
|
||||
let out = svgContent
|
||||
.replace(/<\?xml[\s\S]*?\?>\s*/i, "")
|
||||
.replace(/<!DOCTYPE[\s\S]*?>\s*/i, "");
|
||||
|
||||
// Remove ALL comments
|
||||
out = out.replace(/<!--[\s\S]*?-->\s*/g, "");
|
||||
|
||||
// Remove <g id="icomoon-ignore"></g> with any whitespace between tags
|
||||
out = out.replace(/<g\s+id=(["'])icomoon-ignore\1\s*>\s*<\/g>\s*/gi, "");
|
||||
|
||||
// Ensure only width="100%" height="100%" on the <svg> tag
|
||||
out = out.replace(/<svg\b[^>]*>/i, match => {
|
||||
let tag = match
|
||||
.replace(/\s+(width|height)\s*=\s*"[^"]*"/gi, "")
|
||||
.replace(/\s+(width|height)\s*=\s*'[^']*'/gi, "");
|
||||
return tag.replace(/>$/, ' width="100%" height="100%">');
|
||||
});
|
||||
|
||||
// Prepend the single license comment
|
||||
out =
|
||||
"<!-- generated by icomoon.io - licensed Lindua icon -->\n" +
|
||||
out.replace(/^\s+/, "");
|
||||
|
||||
// Wrap with <template> tags
|
||||
out = "<template>\n" + out + "\n</template>";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
function convertSvgs(inputDir = INPUT_DIR, outputDir = OUTPUT_DIR) {
|
||||
if (!fs.existsSync(inputDir)) {
|
||||
console.warn(`Input directory not found: ${inputDir}`);
|
||||
return;
|
||||
}
|
||||
const files = fs
|
||||
.readdirSync(inputDir)
|
||||
.filter(f => f.toLowerCase().endsWith(".svg"));
|
||||
files.forEach(file => {
|
||||
const src = path.join(inputDir, file);
|
||||
const dest = path.join(outputDir, file.replace(/\.svg$/i, ".vue"));
|
||||
const svgContent = fs.readFileSync(src, "utf8");
|
||||
const processed = processSvg(svgContent);
|
||||
fs.writeFileSync(dest, processed, "utf8");
|
||||
console.log(`Converted: ${file} -> ${path.basename(dest)}`);
|
||||
});
|
||||
}
|
||||
|
||||
convertSvgs();
|
||||
Reference in New Issue
Block a user