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.

153 lines (152 loc) 5.41 kB
import { createServer as createHttpServer } from 'http'; import { resolve, extname, dirname } from 'node:path'; import { readFileSync, existsSync } from 'node:fs'; import { fileURLToPath } from 'node:url'; import { scanIcons } from './iconScanner.js'; let galleryServer = null; // Получаем путь к модулю плагина function getPluginPath() { const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); // Возвращаем путь к dist папке плагина (где находится simpleGalleryServer.js) return __dirname; } function getGalleryDir() { // В проде после сборки галерея лежит в dist/gallery return resolve(getPluginPath(), 'gallery'); } function contentTypeByExt(path) { const ext = extname(path); switch (ext) { case '.html': return 'text/html; charset=utf-8'; case '.css': return 'text/css'; case '.js': return 'application/javascript'; case '.map': return 'application/json'; case '.json': return 'application/json'; case '.svg': return 'image/svg+xml'; case '.png': return 'image/png'; case '.jpg': case '.jpeg': return 'image/jpeg'; case '.ico': return 'image/x-icon'; default: return 'application/octet-stream'; } } async function findAvailablePort(startPort) { return new Promise((resolve, reject) => { const server = createHttpServer(); server.listen(startPort, () => { const port = server.address()?.port; server.close(() => resolve(port)); }); server.on('error', (err) => { if (err.code === 'EADDRINUSE') { findAvailablePort(startPort + 1) .then(resolve) .catch(reject); } else { reject(err); } }); }); } export async function startGalleryServer(options) { const { iconsPath, port: requestedPort, open } = options; if (galleryServer) { console.log(`🎨 Gallery server already running`); return galleryServer; } const availablePort = await findAvailablePort(requestedPort); const icons = scanIcons(iconsPath); galleryServer = createHttpServer((req, res) => { const url = req.url || ''; // API endpoints if (url === '/' || url === '') { const indexPath = resolve(getGalleryDir(), 'index.html'); if (existsSync(indexPath)) { res.setHeader('Content-Type', contentTypeByExt(indexPath)); res.end(readFileSync(indexPath, 'utf-8')); return; } } if (url === '/api/icons') { res.setHeader('Content-Type', 'application/json'); res.setHeader('Access-Control-Allow-Origin', '*'); res.end(JSON.stringify(icons)); return; } if (url.startsWith('/api/icon/')) { const iconName = url.replace('/api/icon/', ''); try { const icon = icons.find((i) => i.name === iconName); if (!icon) { res.statusCode = 404; res.end('Icon not found'); return; } const content = readFileSync(icon.path, 'utf-8'); const svgMatch = content.match(/<svg[^>]*>[\s\S]*?<\/svg>/); if (svgMatch) { res.setHeader('Content-Type', 'image/svg+xml'); res.end(svgMatch[0]); } else { res.statusCode = 404; res.end('SVG not found'); } } catch { res.statusCode = 404; res.end('Icon not found'); } return; } // Static assets from built gallery (dist/gallery) const safeUrl = url.split('?')[0].split('#')[0]; const filePath = resolve(getGalleryDir(), '.' + safeUrl); if (existsSync(filePath)) { res.setHeader('Content-Type', contentTypeByExt(filePath)); res.end(readFileSync(filePath)); return; } res.statusCode = 404; res.end('Not found'); }); await new Promise((resolve, reject) => { galleryServer.listen(availablePort, () => { console.log(`✅ Gallery server started on http://localhost:${availablePort}`); resolve(); }); galleryServer.on('error', reject); }); if (open) { const { exec } = await import('child_process'); const url = `http://localhost:${availablePort}`; const cmd = process.platform === 'win32' ? `start ${url}` : process.platform === 'darwin' ? `open ${url}` : `xdg-open ${url}`; exec(cmd); } return galleryServer; } export async function stopGalleryServer() { if (galleryServer) { await new Promise((resolve, reject) => { galleryServer.close((err) => (err ? reject(err) : resolve())); }); console.log('🛑 Gallery server stopped'); galleryServer = null; } }