v0.8.0 0fa6785

vite-plugin-pages.ts RawHistoryFolder

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 ? `<link rel="stylesheet" href="./${config.css}">` : '';
37
38  return `<!DOCTYPE html>
39<html lang="en">
40<head>
41    <meta charset="UTF-8">
42    <meta name="viewport" content="width=device-width, initial-scale=1.0">
43    <title>${config.title}</title>
44    <link rel="icon" type="image/svg+xml" href="${getFaviconDataURL()}">
45    ${cssLink}
46</head>
47<body>
48    <script src="./${config.script}"></script>
49</body>
50</html>`;
51}
52
53/**
54 * Vite plugin to generate dumb:// protocol pages
55 * Supports multiple pages like homepage, config, about, etc.
56 */
57export function pageGenerator(pages: PageConfig[]): Plugin {
58  return {
59    name: 'dumb-page-generator',
60    writeBundle() {
61      const assetsDir = resolve(__dirname, '..', 'assets', 'gui');
62
63      try {
64        // Generate HTML files for each page
65        for (const page of pages) {
66          const htmlContent = generatePageHTML(page);
67          const filename = page.filename || `${page.name}.html`;
68          writeFileSync(resolve(assetsDir, filename), htmlContent);
69          console.log(`✓ Generated ${filename} for dumb://${page.name}`);
70        }
71
72        // Generate favicon.svg for scheme handler lookups
73        const faviconContent = getFaviconSVG();
74        writeFileSync(resolve(assetsDir, 'favicon.svg'), faviconContent);
75        console.log('✓ Generated favicon.svg');
76
77      } catch (error) {
78        console.error('✗ Failed to generate page files:', error);
79        throw error;
80      }
81    }
82  };
83}
84
85/**
86 * Convenience function for homepage generation
87 * @deprecated Use pageGenerator with homepage config instead
88 */
89export function homepageGenerator(): Plugin {
90  return pageGenerator([
91    {
92      name: 'homepage',
93      title: 'Dumber Browser',
94      script: 'homepage.min.js',
95      filename: 'index.html', // Special case: homepage uses index.html
96    }
97  ]);
98}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close