UNPKG

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
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)); }