vue-icon-gallery
Version:
Vite plugin for Vue 3 that opens a local gallery to preview your SVG icons before using them in templates. Instantly browse, search, and view your icons directly from your dev server — no more guessing by file name.
75 lines (74 loc) • 2.48 kB
JavaScript
import { resolve, extname, basename } from "node:path";
import { readdirSync, readFileSync } from "node:fs";
/**
* Сканирует папку или папки с иконками и возвращает список найденных Vue компонентов
*/
export function scanIcons(iconsPath) {
const roots = (Array.isArray(iconsPath) ? iconsPath : [iconsPath])
.filter((p) => p && typeof p === 'string' && p.trim() !== '')
.map((p) => resolve(process.cwd(), p));
if (roots.length === 0) {
console.warn('[vue-icon-gallery] No valid icon paths provided. Gallery will be empty.');
return [];
}
const ignoreDirs = new Set([
"node_modules",
".git",
".husky",
".next",
"dist",
"build",
".output",
".turbo",
]);
const all = [];
const isIconVueFile = (absolutePath) => {
if (extname(absolutePath) !== ".vue")
return false;
try {
const content = readFileSync(absolutePath, "utf8");
// Heuristic: inline SVG inside <template> section
// - find <template ...> ... </template>
// - check if it contains <svg ...>
const tplMatch = content.match(/<template[\s\S]*?>[\s\S]*?<\/template>/i);
if (!tplMatch)
return false;
return /<svg\b[^>]*>/i.test(tplMatch[0]);
}
catch {
return false;
}
};
const walk = (dir) => {
let entries = [];
try {
entries = readdirSync(dir, { withFileTypes: true });
}
catch {
return;
}
for (const ent of entries) {
const abs = resolve(dir, ent.name);
if (ent.isDirectory()) {
if (ignoreDirs.has(ent.name))
continue;
walk(abs);
}
else if (ent.isFile()) {
if (isIconVueFile(abs)) {
all.push({ name: basename(abs, ".vue"), path: abs });
}
}
}
};
for (const root of roots) {
walk(root);
}
// Удаляем дубликаты по имени и сортируем
const unique = all.reduce((acc, icon) => {
if (!acc.find((e) => e.name === icon.name))
acc.push(icon);
return acc;
}, []);
return unique.sort((a, b) => a.name.localeCompare(b.name));
}