const express = require('express'); const fs = require('fs'); const path = require('path'); const router = express.Router(); const THEMES_DIR = path.join(__dirname, '..', '..', 'frontend', 'themes'); /* Surface order — themes whose folder name appears here are listed first, in this order. Anything else is appended alphabetically. Lets us keep the built-ins (nebula / dark-blue / light) at the top of the dropdown without hardcoding their existence in the API. */ const PREFERRED_ORDER = ['nebula', 'dark-blue', 'light']; /* ========================= GET /api/themes/list Walks frontend/themes// and returns one entry per directory that contains a theme.css. Optional meta.json supplies a friendlier display name. No hardcoded list — built-ins live in folders just like any custom theme. Public — the list of theme names isn't sensitive and the frontend needs it before login to render the right palette on the login overlay too. ========================= */ router.get('/list', (req, res) => { const themes = []; try { if (fs.existsSync(THEMES_DIR)) { for (const entry of fs.readdirSync(THEMES_DIR, { withFileTypes: true })) { if (!entry.isDirectory()) continue; const name = entry.name; const cssPath = path.join(THEMES_DIR, name, 'theme.css'); if (!fs.existsSync(cssPath)) continue; let displayName = name; let builtin = false; const metaPath = path.join(THEMES_DIR, name, 'meta.json'); if (fs.existsSync(metaPath)) { try { const meta = JSON.parse(fs.readFileSync(metaPath, 'utf8')); if (meta && typeof meta.displayName === 'string' && meta.displayName.trim()) { displayName = meta.displayName.trim(); } if (meta && meta.builtin === true) builtin = true; } catch (_) { /* malformed meta.json — fall back to folder name */ } } themes.push({ name, displayName, css: `/themes/${name}/theme.css`, builtin }); } } } catch (err) { console.error('Error scanning themes directory:', err); } themes.sort((a, b) => { const ai = PREFERRED_ORDER.indexOf(a.name); const bi = PREFERRED_ORDER.indexOf(b.name); if (ai !== -1 && bi !== -1) return ai - bi; if (ai !== -1) return -1; if (bi !== -1) return 1; return a.displayName.localeCompare(b.displayName); }); res.json(themes); }); module.exports = router;