1import type { Plugin } from "vite";
2import { writeFileSync, readFileSync } from "fs";
3import { resolve } from "path";
4
5interface PageConfig {
6 /** Page name (used for filename and script name) */
7 name: string;
8 /** Page title */
9 title: string;
10 /** Script filename (e.g., 'homepage.min.js') */
11 script: string;
12 /** Optional CSS filename */
13 css?: string;
14 /** Target filename (defaults to name + '.html') */
15 filename?: string;
16}
17
18// Load the favicon SVG from assets
19function getFaviconSVG(): string {
20 const logoPath = resolve(__dirname, "..", "assets", "logo.svg");
21 return readFileSync(logoPath, "utf-8");
22}
23
24// Create favicon data URL for inline usage
25function getFaviconDataURL(): string {
26 const svg = getFaviconSVG();
27 const encoded = encodeURIComponent(svg)
28 .replace(/'/g, "%27")
29 .replace(/\(/g, "%28")
30 .replace(/\)/g, "%29");
31 return `data:image/svg+xml;utf8,${encoded}`;
32}
33
34// Generate HTML content for a page
35function generatePageHTML(config: PageConfig): string {
36 const cssLink = config.css
37 ? `<link rel="stylesheet" href="./${config.css}">`
38 : "";
39
40 return `<!DOCTYPE html>
41<html lang="en">
42<head>
43 <meta charset="UTF-8">
44 <meta name="viewport" content="width=device-width, initial-scale=1.0">
45 <title>${config.title}</title>
46 <link rel="icon" type="image/svg+xml" href="${getFaviconDataURL()}">
47 ${cssLink}
48</head>
49<body>
50 <script src="./${config.script}"></script>
51</body>
52</html>`;
53}
54
55/**
56 * Vite plugin to generate dumb:// protocol pages
57 * Supports multiple pages like homepage, config, about, etc.
58 */
59export function pageGenerator(pages: PageConfig[]): Plugin {
60 return {
61 name: "dumb-page-generator",
62 writeBundle() {
63 const assetsDir = resolve(__dirname, "..", "assets", "gui");
64
65 try {
66 // Generate HTML files for each page
67 for (const page of pages) {
68 const htmlContent = generatePageHTML(page);
69 const filename = page.filename || `${page.name}.html`;
70 writeFileSync(resolve(assetsDir, filename), htmlContent);
71 console.log(`✓ Generated ${filename} for dumb://${page.name}`);
72 }
73
74 // Generate favicon.svg for scheme handler lookups
75 const faviconContent = getFaviconSVG();
76 writeFileSync(resolve(assetsDir, "favicon.svg"), faviconContent);
77 console.log("✓ Generated favicon.svg");
78 } catch (error) {
79 console.error("✗ Failed to generate page files:", error);
80 throw error;
81 }
82 },
83 };
84}
85
86/**
87 * Convenience function for homepage generation
88 * @deprecated Use pageGenerator with homepage config instead
89 */
90export function homepageGenerator(): Plugin {
91 return pageGenerator([
92 {
93 name: "homepage",
94 title: "Dumber Browser",
95 script: "homepage.min.js",
96 filename: "index.html", // Special case: homepage uses index.html
97 },
98 ]);
99}