detached 225efeb

refactor(build): migrate from gui/ to webui/ directory and update assets

Completes the frontend migration by:
- Removing old gui/ directory with legacy Svelte/Vite structure
- Adding new webui/ directory with updated build configuration
- Replacing gui_embed.go with webui_embed.go for asset embedding
- Updating .gitignore and Makefile for new frontend location

This migration supports the new architecture where frontend components
are injected into web content via WebKit's content injection APIs.
commit
225efeb366d68bd439243ce04c89887b2c179ec8
author
brice · · 2025-12-11 18:03 UTC
committer
brice · · 2025-12-11 21:42 UTC
parent
a970f83
signature
unsigned
86 files · +131 -111
M .gitignore +1 -1
@@ -62,7 +62,7 @@ config.local.*
6262 tmp/go-cache/
6363 tmp/go-mod/
6464 tmp/
65-assets/gui
65+assets/webui
6666
6767 # Node/TypeScript related
6868 node_modules/
@@ -62,7 +62,7 @@ config.local.*
62 tmp/go-cache/62 tmp/go-cache/
63 tmp/go-mod/63 tmp/go-mod/
64 tmp/64 tmp/
65-assets/gui65+assets/webui
66 66
67 # Node/TypeScript related67 # Node/TypeScript related
68 node_modules/68 node_modules/
M Makefile +8 -3
@@ -38,7 +38,7 @@ build: build-frontend ## Build the application (pure Go, no CGO)
3838
3939 build-frontend: ## Build Svelte GUI with Tailwind CSS and main-world script
4040 @echo "Building Svelte GUI with Tailwind CSS..."
41- @cd gui && npm install --silent && npm run build
41+ @cd webui && npm install --silent && npm run build
4242 @echo "GUI build complete"
4343
4444 build-quick: ## Build without frontend (faster for backend development)
@@ -61,6 +61,11 @@ generate: ## Generate code (SQLC)
6161 sqlc generate
6262 @echo "Code generation complete"
6363
64+mocks: ## Generate mock implementations with mockery
65+ @echo "Generating mocks with mockery..."
66+ mockery
67+ @echo "Mock generation complete"
68+
6469 # Testing
6570 test: ## Run tests
6671 @echo "Running tests..."
@@ -102,8 +107,8 @@ clean: ## Clean build artifacts
102107 @echo "Cleaning build artifacts..."
103108 rm -rf $(DIST_DIR)
104109 rm -f $(BINARY_NAME)
105- rm -rf gui/dist gui/node_modules
106- rm -f assets/gui/gui.min.js assets/gui/homepage.min.js assets/gui/homepage.css assets/gui/main-world.min.js assets/gui/color-scheme.js
110+ rm -rf webui/dist webui/node_modules
111+ rm -f assets/webui/gui.min.js assets/webui/homepage.min.js assets/webui/homepage.css assets/webui/main-world.min.js assets/webui/color-scheme.js
107112 rm -f coverage.out coverage.html
108113 go clean -cache
109114 go clean -testcache
@@ -38,7 +38,7 @@ build: build-frontend ## Build the application (pure Go, no CGO)
38 38
39 build-frontend: ## Build Svelte GUI with Tailwind CSS and main-world script39 build-frontend: ## Build Svelte GUI with Tailwind CSS and main-world script
40 @echo "Building Svelte GUI with Tailwind CSS..."40 @echo "Building Svelte GUI with Tailwind CSS..."
41- @cd gui && npm install --silent && npm run build41+ @cd webui && npm install --silent && npm run build
42 @echo "GUI build complete"42 @echo "GUI build complete"
43 43
44 build-quick: ## Build without frontend (faster for backend development)44 build-quick: ## Build without frontend (faster for backend development)
@@ -61,6 +61,11 @@ generate: ## Generate code (SQLC)
61 sqlc generate61 sqlc generate
62 @echo "Code generation complete"62 @echo "Code generation complete"
63 63
64+mocks: ## Generate mock implementations with mockery
65+ @echo "Generating mocks with mockery..."
66+ mockery
67+ @echo "Mock generation complete"
68+
64 # Testing69 # Testing
65 test: ## Run tests70 test: ## Run tests
66 @echo "Running tests..."71 @echo "Running tests..."
@@ -102,8 +107,8 @@ clean: ## Clean build artifacts
102 @echo "Cleaning build artifacts..."107 @echo "Cleaning build artifacts..."
103 rm -rf $(DIST_DIR)108 rm -rf $(DIST_DIR)
104 rm -f $(BINARY_NAME)109 rm -f $(BINARY_NAME)
105- rm -rf gui/dist gui/node_modules110+ rm -rf webui/dist webui/node_modules
106- rm -f assets/gui/gui.min.js assets/gui/homepage.min.js assets/gui/homepage.css assets/gui/main-world.min.js assets/gui/color-scheme.js111+ rm -f assets/webui/gui.min.js assets/webui/homepage.min.js assets/webui/homepage.css assets/webui/main-world.min.js assets/webui/color-scheme.js
107 rm -f coverage.out coverage.html112 rm -f coverage.out coverage.html
108 go clean -cache113 go clean -cache
109 go clean -testcache114 go clean -testcache
R assets/gui_embed.go → assets/webui_embed.go +5 -5 renamed, 61% similar
@@ -2,19 +2,19 @@ package assets
22
33 import _ "embed"
44
5-// GUI scripts embedded at compile time
5+// WebUI scripts embedded at compile time
66
7-//go:embed gui/main-world.min.js
7+//go:embed webui/main-world.min.js
88 var MainWorldScript string
99
10-//go:embed gui/gui.min.js
10+//go:embed webui/gui.min.js
1111 var GUIScript string
1212
13-//go:embed gui/color-scheme.js
13+//go:embed webui/color-scheme.js
1414 var ColorSchemeScript string
1515
1616 // GUI component styles extracted from Svelte components
1717 // These are injected into the isolated world using UserStyleSheet
1818 //
19-//go:embed gui/gui.min.css
19+//go:embed webui/gui.min.css
2020 var ComponentStyles string
@@ -2,19 +2,19 @@ package assets
2 2
3 import _ "embed"3 import _ "embed"
4 4
5-// GUI scripts embedded at compile time5+// WebUI scripts embedded at compile time
6 6
7-//go:embed gui/main-world.min.js7+//go:embed webui/main-world.min.js
8 var MainWorldScript string8 var MainWorldScript string
9 9
10-//go:embed gui/gui.min.js10+//go:embed webui/gui.min.js
11 var GUIScript string11 var GUIScript string
12 12
13-//go:embed gui/color-scheme.js13+//go:embed webui/color-scheme.js
14 var ColorSchemeScript string14 var ColorSchemeScript string
15 15
16 // GUI component styles extracted from Svelte components16 // GUI component styles extracted from Svelte components
17 // These are injected into the isolated world using UserStyleSheet17 // These are injected into the isolated world using UserStyleSheet
18 //18 //
19-//go:embed gui/gui.min.css19+//go:embed webui/gui.min.css
20 var ComponentStyles string20 var ComponentStyles string
R gui/eslint.config.js → webui/eslint.config.js +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/package-lock.json → webui/package-lock.json +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/package.json → webui/package.json +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/postcss.config.js → webui/postcss.config.js +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/components/Footer.svelte → webui/src/components/Footer.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/components/omnibox/Omnibox.svelte → webui/src/components/omnibox/Omnibox.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/components/omnibox/OmniboxFind.svelte → webui/src/components/omnibox/OmniboxFind.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/components/omnibox/OmniboxInput.svelte → webui/src/components/omnibox/OmniboxInput.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/components/omnibox/OmniboxSuggestions.svelte → webui/src/components/omnibox/OmniboxSuggestions.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/components/omnibox/find.ts → webui/src/components/omnibox/find.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/components/omnibox/index.ts → webui/src/components/omnibox/index.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/components/omnibox/messaging.ts → webui/src/components/omnibox/messaging.ts +11 -7 renamed, 96% similar
@@ -13,9 +13,14 @@ export class OmniboxBridge implements OmniboxMessageBridge {
1313 postMessage(msg: OmniboxMessage): void {
1414 console.log("📤 [DEBUG] Posting message to backend via bridge:", msg);
1515 try {
16+ // Include webview_id for message routing
17+ const payload = {
18+ ...msg,
19+ webview_id: (window as any).__dumber_webview_id ?? 0,
20+ };
1621 // Dispatch CustomEvent that main-world bridge will listen to
1722 document.dispatchEvent(new CustomEvent("dumber:isolated-message", {
18- detail: { payload: msg }
23+ detail: { payload }
1924 }));
2025 console.log("✅ [DEBUG] Dispatched isolated message event");
2126 } catch (e) {
@@ -117,11 +122,10 @@ export class OmniboxBridge implements OmniboxMessageBridge {
117122 // Send message to Go backend
118123 const bridge = window.webkit?.messageHandlers?.dumber;
119124 if (bridge && typeof bridge.postMessage === "function") {
120- bridge.postMessage(
121- JSON.stringify({
122- type: "get_search_shortcuts",
123- }),
124- );
125+ bridge.postMessage({
126+ type: "get_search_shortcuts",
127+ webview_id: (window as any).__dumber_webview_id ?? 0,
128+ });
125129 } else {
126130 reject(new Error("WebKit message handler not available"));
127131 }
@@ -307,7 +311,7 @@ declare global {
307311 webkit?: {
308312 messageHandlers?: {
309313 dumber?: {
310- postMessage: (message: string) => void;
314+ postMessage: (message: unknown) => void;
311315 };
312316 };
313317 };
@@ -13,9 +13,14 @@ export class OmniboxBridge implements OmniboxMessageBridge {
13 postMessage(msg: OmniboxMessage): void {13 postMessage(msg: OmniboxMessage): void {
14 console.log("📤 [DEBUG] Posting message to backend via bridge:", msg);14 console.log("📤 [DEBUG] Posting message to backend via bridge:", msg);
15 try {15 try {
16+ // Include webview_id for message routing
17+ const payload = {
18+ ...msg,
19+ webview_id: (window as any).__dumber_webview_id ?? 0,
20+ };
16 // Dispatch CustomEvent that main-world bridge will listen to21 // Dispatch CustomEvent that main-world bridge will listen to
17 document.dispatchEvent(new CustomEvent("dumber:isolated-message", {22 document.dispatchEvent(new CustomEvent("dumber:isolated-message", {
18- detail: { payload: msg }23+ detail: { payload }
19 }));24 }));
20 console.log("✅ [DEBUG] Dispatched isolated message event");25 console.log("✅ [DEBUG] Dispatched isolated message event");
21 } catch (e) {26 } catch (e) {
@@ -117,11 +122,10 @@ export class OmniboxBridge implements OmniboxMessageBridge {
117 // Send message to Go backend122 // Send message to Go backend
118 const bridge = window.webkit?.messageHandlers?.dumber;123 const bridge = window.webkit?.messageHandlers?.dumber;
119 if (bridge && typeof bridge.postMessage === "function") {124 if (bridge && typeof bridge.postMessage === "function") {
120- bridge.postMessage(125+ bridge.postMessage({
121- JSON.stringify({126+ type: "get_search_shortcuts",
122- type: "get_search_shortcuts",127+ webview_id: (window as any).__dumber_webview_id ?? 0,
123- }),128+ });
124- );
125 } else {129 } else {
126 reject(new Error("WebKit message handler not available"));130 reject(new Error("WebKit message handler not available"));
127 }131 }
@@ -307,7 +311,7 @@ declare global {
307 webkit?: {311 webkit?: {
308 messageHandlers?: {312 messageHandlers?: {
309 dumber?: {313 dumber?: {
310- postMessage: (message: string) => void;314+ postMessage: (message: unknown) => void;
311 };315 };
312 };316 };
313 };317 };
R gui/src/components/omnibox/stores.svelte.ts → webui/src/components/omnibox/stores.svelte.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/components/omnibox/types.ts → webui/src/components/omnibox/types.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/components/toast/Toast.svelte → webui/src/components/toast/Toast.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/components/toast/ToastContainer.svelte → webui/src/components/toast/ToastContainer.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/injected/bootstrap.ts → webui/src/injected/bootstrap.ts +35 -6 renamed, 89% similar
@@ -41,6 +41,14 @@ declare global {
4141 __dumber_find_query?: (query: string) => void;
4242 __dumber_dismissToast?: (id: number) => void;
4343 __dumber_clearToasts?: () => void;
44+ webkit?: {
45+ messageHandlers?: {
46+ dumber?: {
47+ postMessage: (message: unknown) => void;
48+ };
49+ };
50+ };
51+ __dumber_webview_id?: number | string;
4452 }
4553 }
4654
@@ -108,6 +116,28 @@ export function bootstrapGUI(): void {
108116 // Ignore environments without pagehide support
109117 }
110118
119+ // Request color palettes from Go backend
120+ // The isolated world has access to webkit.messageHandlers, main world does not.
121+ // Main world has set up the __dumber_color_palettes callback handler.
122+ const requestColorPalettes = () => {
123+ try {
124+ const bridge = window.webkit?.messageHandlers?.dumber;
125+ if (bridge && typeof bridge.postMessage === "function") {
126+ const webviewId = window.__dumber_webview_id;
127+ console.log("[dumber-palette] Requesting color palettes from backend, webview_id:", webviewId);
128+ bridge.postMessage({
129+ type: "get_color_palettes",
130+ webview_id: typeof webviewId === "number" ? webviewId : 0,
131+ });
132+ } else {
133+ console.warn("[dumber-palette] WebKit message handler not available");
134+ }
135+ } catch (err) {
136+ console.error("[dumber-palette] Failed to request color palettes:", err);
137+ }
138+ };
139+ requestColorPalettes();
140+
111141 let workspaceHasFocus = false;
112142 const initialRawWebViewId = window.__dumber_webview_id;
113143 let currentWebViewId = normalizeWebviewId(initialRawWebViewId);
@@ -119,12 +149,11 @@ export function bootstrapGUI(): void {
119149 if (currentWebViewId === null) {
120150 console.log("[workspace] WebView ID unknown, requesting from Go backend");
121151 if (window.webkit?.messageHandlers?.dumber) {
122- window.webkit.messageHandlers.dumber.postMessage(
123- JSON.stringify({
124- type: "request-webview-id",
125- payload: { timestamp: Date.now() },
126- }),
127- );
152+ window.webkit.messageHandlers.dumber.postMessage({
153+ type: "request-webview-id",
154+ webview_id: 0,
155+ payload: { timestamp: Date.now() },
156+ });
128157 }
129158 }
130159
@@ -41,6 +41,14 @@ declare global {
41 __dumber_find_query?: (query: string) => void;41 __dumber_find_query?: (query: string) => void;
42 __dumber_dismissToast?: (id: number) => void;42 __dumber_dismissToast?: (id: number) => void;
43 __dumber_clearToasts?: () => void;43 __dumber_clearToasts?: () => void;
44+ webkit?: {
45+ messageHandlers?: {
46+ dumber?: {
47+ postMessage: (message: unknown) => void;
48+ };
49+ };
50+ };
51+ __dumber_webview_id?: number | string;
44 }52 }
45 }53 }
46 54
@@ -108,6 +116,28 @@ export function bootstrapGUI(): void {
108 // Ignore environments without pagehide support116 // Ignore environments without pagehide support
109 }117 }
110 118
119+ // Request color palettes from Go backend
120+ // The isolated world has access to webkit.messageHandlers, main world does not.
121+ // Main world has set up the __dumber_color_palettes callback handler.
122+ const requestColorPalettes = () => {
123+ try {
124+ const bridge = window.webkit?.messageHandlers?.dumber;
125+ if (bridge && typeof bridge.postMessage === "function") {
126+ const webviewId = window.__dumber_webview_id;
127+ console.log("[dumber-palette] Requesting color palettes from backend, webview_id:", webviewId);
128+ bridge.postMessage({
129+ type: "get_color_palettes",
130+ webview_id: typeof webviewId === "number" ? webviewId : 0,
131+ });
132+ } else {
133+ console.warn("[dumber-palette] WebKit message handler not available");
134+ }
135+ } catch (err) {
136+ console.error("[dumber-palette] Failed to request color palettes:", err);
137+ }
138+ };
139+ requestColorPalettes();
140+
111 let workspaceHasFocus = false;141 let workspaceHasFocus = false;
112 const initialRawWebViewId = window.__dumber_webview_id;142 const initialRawWebViewId = window.__dumber_webview_id;
113 let currentWebViewId = normalizeWebviewId(initialRawWebViewId);143 let currentWebViewId = normalizeWebviewId(initialRawWebViewId);
@@ -119,12 +149,11 @@ export function bootstrapGUI(): void {
119 if (currentWebViewId === null) {149 if (currentWebViewId === null) {
120 console.log("[workspace] WebView ID unknown, requesting from Go backend");150 console.log("[workspace] WebView ID unknown, requesting from Go backend");
121 if (window.webkit?.messageHandlers?.dumber) {151 if (window.webkit?.messageHandlers?.dumber) {
122- window.webkit.messageHandlers.dumber.postMessage(152+ window.webkit.messageHandlers.dumber.postMessage({
123- JSON.stringify({153+ type: "request-webview-id",
124- type: "request-webview-id",154+ webview_id: 0,
125- payload: { timestamp: Date.now() },155+ payload: { timestamp: Date.now() },
126- }),156+ });
127- );
128 }157 }
129 }158 }
130 159
R gui/src/injected/gui.ts → webui/src/injected/gui.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/injected/main-world.ts → webui/src/injected/main-world.ts +56 -73 renamed, 90% similar
@@ -46,7 +46,7 @@ declare global {
4646 webkit?: {
4747 messageHandlers?: {
4848 dumber?: {
49- postMessage: (message: string) => void;
49+ postMessage: (message: unknown) => void;
5050 };
5151 };
5252 };
@@ -88,73 +88,58 @@ interface DumberAPI {
8888 window.__dumber_is_active = "__WEBVIEW_ACTIVE__" as unknown as boolean;
8989 }
9090
91- // Request color palettes from Go backend
92- try {
93- console.log("[dumber-palette] Initializing color palette loading");
94- const bridge = window.webkit?.messageHandlers?.dumber;
95-
96- if (!bridge || typeof bridge.postMessage !== "function") {
97- console.error("[dumber-palette] ERROR: No webkit message bridge available");
98- return;
99- }
100-
101- console.log("[dumber-palette] WebKit bridge found, setting up handlers");
102-
103- // Set up callback handler before requesting
104- window.__dumber_color_palettes = (palettes: unknown) => {
105- console.log("[dumber-palette] Received palettes from backend:", palettes);
106- try {
107- // Type guard to ensure palettes is a valid object
108- if (typeof palettes !== "object" || palettes === null) {
109- console.error("[dumber-palette] ERROR: Invalid palettes received - type:", typeof palettes);
110- return;
111- }
91+ // Set up color palette callback handlers (will be called from isolated world via CustomEvent)
92+ window.__dumber_color_palettes = (palettes: unknown) => {
93+ console.log("[dumber-palette] Received palettes from backend:", palettes);
94+ try {
95+ // Type guard to ensure palettes is a valid object
96+ if (typeof palettes !== "object" || palettes === null) {
97+ console.error("[dumber-palette] ERROR: Invalid palettes received - type:", typeof palettes);
98+ return;
99+ }
112100
113- window.__dumber_palette = palettes as Record<string, Record<string, string>>;
114- console.log("[dumber-palette] Palette keys:", Object.keys(window.__dumber_palette || {}));
115-
116- // Normalize palette keys to lowercase
117- const normalized: Record<string, Record<string, string>> = {};
118- if (window.__dumber_palette) {
119- for (const key in window.__dumber_palette) {
120- if (Object.prototype.hasOwnProperty.call(window.__dumber_palette, key)) {
121- const paletteValue = window.__dumber_palette[key];
122- if (paletteValue) {
123- normalized[key.toLowerCase()] = paletteValue;
124- console.log(`[dumber-palette] Normalized: ${key} -> ${key.toLowerCase()}, colors:`, Object.keys(paletteValue));
125- }
101+ window.__dumber_palette = palettes as Record<string, Record<string, string>>;
102+ console.log("[dumber-palette] Palette keys:", Object.keys(window.__dumber_palette || {}));
103+
104+ // Normalize palette keys to lowercase
105+ const normalized: Record<string, Record<string, string>> = {};
106+ if (window.__dumber_palette) {
107+ for (const key in window.__dumber_palette) {
108+ if (Object.prototype.hasOwnProperty.call(window.__dumber_palette, key)) {
109+ const paletteValue = window.__dumber_palette[key];
110+ if (paletteValue) {
111+ normalized[key.toLowerCase()] = paletteValue;
112+ console.log(`[dumber-palette] Normalized: ${key} -> ${key.toLowerCase()}, colors:`, Object.keys(paletteValue));
126113 }
127114 }
128- window.__dumber_palette = normalized;
129115 }
116+ window.__dumber_palette = normalized;
117+ }
130118
131- // Apply palette now that we have it
132- const initialTheme: "light" | "dark" = document.documentElement.classList.contains("dark") ? "dark" : "light";
133- console.log(`[dumber-palette] Initial theme detected: ${initialTheme}`);
134- window.__dumber_initial_theme = initialTheme;
119+ // Apply palette now that we have it
120+ const initialTheme: "light" | "dark" = document.documentElement.classList.contains("dark") ? "dark" : "light";
121+ console.log(`[dumber-palette] Initial theme detected: ${initialTheme}`);
122+ window.__dumber_initial_theme = initialTheme;
135123
136- if (window.__dumber_applyPalette) {
137- console.log("[dumber-palette] Applying palette...");
138- window.__dumber_applyPalette(initialTheme);
139- } else {
140- console.error("[dumber-palette] ERROR: __dumber_applyPalette function not found");
141- }
142- } catch (err) {
143- console.error("[dumber-palette] ERROR: Failed to apply received palette:", err);
124+ if (window.__dumber_applyPalette) {
125+ console.log("[dumber-palette] Applying palette...");
126+ window.__dumber_applyPalette(initialTheme);
127+ } else {
128+ console.error("[dumber-palette] ERROR: __dumber_applyPalette function not found");
144129 }
145- };
130+ } catch (err) {
131+ console.error("[dumber-palette] ERROR: Failed to apply received palette:", err);
132+ }
133+ };
146134
147- window.__dumber_color_palettes_error = (error: string) => {
148- console.error("[dumber-palette] ERROR from backend:", error);
149- };
135+ window.__dumber_color_palettes_error = (error: string) => {
136+ console.error("[dumber-palette] ERROR from backend:", error);
137+ };
150138
151- // Request color palettes
152- console.log("[dumber-palette] Sending get_color_palettes request to backend");
153- bridge.postMessage(JSON.stringify({ type: "get_color_palettes" }));
154- console.log("[dumber-palette] Request sent, waiting for response...");
155- } catch (err) {
156- console.error("[dumber-palette] EXCEPTION requesting color palettes:", err);
157- }
139+ // Request color palettes from Go backend via isolated world bridge
140+ // Note: webkit.messageHandlers.dumber is only available in the isolated world,
141+ // not in the main world. The request will be sent from the isolated world (gui.ts).
142+ console.log("[dumber-palette] Color palette handlers registered, waiting for isolated world to request palettes");
158143
159144 // Palette application function
160145 window.__dumber_applyPalette = (theme: "light" | "dark") => {
@@ -684,7 +669,7 @@ interface DumberAPI {
684669 `[dumber-parent] Sending popup close request:`,
685670 closeMessage,
686671 );
687- bridge.postMessage(JSON.stringify(closeMessage));
672+ bridge.postMessage(closeMessage);
688673 } catch (err) {
689674 console.warn(
690675 `[dumber-parent] Failed to send popup close request:`,
@@ -821,7 +806,7 @@ interface DumberAPI {
821806 `[oauth-callback] Sending popup close request:`,
822807 closeMessage,
823808 );
824- bridge.postMessage(JSON.stringify(closeMessage));
809+ bridge.postMessage(closeMessage);
825810 } catch (err) {
826811 console.warn(
827812 `[oauth-callback] Failed to send popup close request:`,
@@ -939,17 +924,15 @@ interface DumberAPI {
939924
940925 // Send to Go via existing message handler
941926 if (window.webkit?.messageHandlers?.dumber) {
942- window.webkit.messageHandlers.dumber.postMessage(
943- JSON.stringify({
944- type: "console-message",
945- payload: {
946- level,
947- message: formattedMessage,
948- url: window.location.href,
949- webviewId: window.__dumber_webview_id,
950- },
951- }),
952- );
927+ window.webkit.messageHandlers.dumber.postMessage({
928+ type: "console-message",
929+ payload: {
930+ level,
931+ message: formattedMessage,
932+ url: window.location.href,
933+ webviewId: window.__dumber_webview_id,
934+ },
935+ });
953936 }
954937 } catch {
955938 // Silently ignore errors in console capture to avoid infinite loops
@@ -989,7 +972,7 @@ interface DumberAPI {
989972 try {
990973 const { payload } = event.detail;
991974 if (window.webkit?.messageHandlers?.dumber) {
992- window.webkit.messageHandlers.dumber.postMessage(JSON.stringify(payload));
975+ window.webkit.messageHandlers.dumber.postMessage(payload);
993976 console.log("[dumber-bridge] Forwarded isolated world message:", payload.type);
994977 } else {
995978 console.warn("[dumber-bridge] webkit message handler not available");
@@ -46,7 +46,7 @@ declare global {
46 webkit?: {46 webkit?: {
47 messageHandlers?: {47 messageHandlers?: {
48 dumber?: {48 dumber?: {
49- postMessage: (message: string) => void;49+ postMessage: (message: unknown) => void;
50 };50 };
51 };51 };
52 };52 };
@@ -88,73 +88,58 @@ interface DumberAPI {
88 window.__dumber_is_active = "__WEBVIEW_ACTIVE__" as unknown as boolean;88 window.__dumber_is_active = "__WEBVIEW_ACTIVE__" as unknown as boolean;
89 }89 }
90 90
91- // Request color palettes from Go backend91+ // Set up color palette callback handlers (will be called from isolated world via CustomEvent)
92- try {92+ window.__dumber_color_palettes = (palettes: unknown) => {
93- console.log("[dumber-palette] Initializing color palette loading");93+ console.log("[dumber-palette] Received palettes from backend:", palettes);
94- const bridge = window.webkit?.messageHandlers?.dumber;94+ try {
95-95+ // Type guard to ensure palettes is a valid object
96- if (!bridge || typeof bridge.postMessage !== "function") {96+ if (typeof palettes !== "object" || palettes === null) {
97- console.error("[dumber-palette] ERROR: No webkit message bridge available");97+ console.error("[dumber-palette] ERROR: Invalid palettes received - type:", typeof palettes);
98- return;98+ return;
99- }99+ }
100-
101- console.log("[dumber-palette] WebKit bridge found, setting up handlers");
102-
103- // Set up callback handler before requesting
104- window.__dumber_color_palettes = (palettes: unknown) => {
105- console.log("[dumber-palette] Received palettes from backend:", palettes);
106- try {
107- // Type guard to ensure palettes is a valid object
108- if (typeof palettes !== "object" || palettes === null) {
109- console.error("[dumber-palette] ERROR: Invalid palettes received - type:", typeof palettes);
110- return;
111- }
112 100
113- window.__dumber_palette = palettes as Record<string, Record<string, string>>;101+ window.__dumber_palette = palettes as Record<string, Record<string, string>>;
114- console.log("[dumber-palette] Palette keys:", Object.keys(window.__dumber_palette || {}));102+ console.log("[dumber-palette] Palette keys:", Object.keys(window.__dumber_palette || {}));
115-103+
116- // Normalize palette keys to lowercase104+ // Normalize palette keys to lowercase
117- const normalized: Record<string, Record<string, string>> = {};105+ const normalized: Record<string, Record<string, string>> = {};
118- if (window.__dumber_palette) {106+ if (window.__dumber_palette) {
119- for (const key in window.__dumber_palette) {107+ for (const key in window.__dumber_palette) {
120- if (Object.prototype.hasOwnProperty.call(window.__dumber_palette, key)) {108+ if (Object.prototype.hasOwnProperty.call(window.__dumber_palette, key)) {
121- const paletteValue = window.__dumber_palette[key];109+ const paletteValue = window.__dumber_palette[key];
122- if (paletteValue) {110+ if (paletteValue) {
123- normalized[key.toLowerCase()] = paletteValue;111+ normalized[key.toLowerCase()] = paletteValue;
124- console.log(`[dumber-palette] Normalized: ${key} -> ${key.toLowerCase()}, colors:`, Object.keys(paletteValue));112+ console.log(`[dumber-palette] Normalized: ${key} -> ${key.toLowerCase()}, colors:`, Object.keys(paletteValue));
125- }
126 }113 }
127 }114 }
128- window.__dumber_palette = normalized;
129 }115 }
116+ window.__dumber_palette = normalized;
117+ }
130 118
131- // Apply palette now that we have it119+ // Apply palette now that we have it
132- const initialTheme: "light" | "dark" = document.documentElement.classList.contains("dark") ? "dark" : "light";120+ const initialTheme: "light" | "dark" = document.documentElement.classList.contains("dark") ? "dark" : "light";
133- console.log(`[dumber-palette] Initial theme detected: ${initialTheme}`);121+ console.log(`[dumber-palette] Initial theme detected: ${initialTheme}`);
134- window.__dumber_initial_theme = initialTheme;122+ window.__dumber_initial_theme = initialTheme;
135 123
136- if (window.__dumber_applyPalette) {124+ if (window.__dumber_applyPalette) {
137- console.log("[dumber-palette] Applying palette...");125+ console.log("[dumber-palette] Applying palette...");
138- window.__dumber_applyPalette(initialTheme);126+ window.__dumber_applyPalette(initialTheme);
139- } else {127+ } else {
140- console.error("[dumber-palette] ERROR: __dumber_applyPalette function not found");128+ console.error("[dumber-palette] ERROR: __dumber_applyPalette function not found");
141- }
142- } catch (err) {
143- console.error("[dumber-palette] ERROR: Failed to apply received palette:", err);
144 }129 }
145- };130+ } catch (err) {
131+ console.error("[dumber-palette] ERROR: Failed to apply received palette:", err);
132+ }
133+ };
146 134
147- window.__dumber_color_palettes_error = (error: string) => {135+ window.__dumber_color_palettes_error = (error: string) => {
148- console.error("[dumber-palette] ERROR from backend:", error);136+ console.error("[dumber-palette] ERROR from backend:", error);
149- };137+ };
150 138
151- // Request color palettes139+ // Request color palettes from Go backend via isolated world bridge
152- console.log("[dumber-palette] Sending get_color_palettes request to backend");140+ // Note: webkit.messageHandlers.dumber is only available in the isolated world,
153- bridge.postMessage(JSON.stringify({ type: "get_color_palettes" }));141+ // not in the main world. The request will be sent from the isolated world (gui.ts).
154- console.log("[dumber-palette] Request sent, waiting for response...");142+ console.log("[dumber-palette] Color palette handlers registered, waiting for isolated world to request palettes");
155- } catch (err) {
156- console.error("[dumber-palette] EXCEPTION requesting color palettes:", err);
157- }
158 143
159 // Palette application function144 // Palette application function
160 window.__dumber_applyPalette = (theme: "light" | "dark") => {145 window.__dumber_applyPalette = (theme: "light" | "dark") => {
@@ -684,7 +669,7 @@ interface DumberAPI {
684 `[dumber-parent] Sending popup close request:`,669 `[dumber-parent] Sending popup close request:`,
685 closeMessage,670 closeMessage,
686 );671 );
687- bridge.postMessage(JSON.stringify(closeMessage));672+ bridge.postMessage(closeMessage);
688 } catch (err) {673 } catch (err) {
689 console.warn(674 console.warn(
690 `[dumber-parent] Failed to send popup close request:`,675 `[dumber-parent] Failed to send popup close request:`,
@@ -821,7 +806,7 @@ interface DumberAPI {
821 `[oauth-callback] Sending popup close request:`,806 `[oauth-callback] Sending popup close request:`,
822 closeMessage,807 closeMessage,
823 );808 );
824- bridge.postMessage(JSON.stringify(closeMessage));809+ bridge.postMessage(closeMessage);
825 } catch (err) {810 } catch (err) {
826 console.warn(811 console.warn(
827 `[oauth-callback] Failed to send popup close request:`,812 `[oauth-callback] Failed to send popup close request:`,
@@ -939,17 +924,15 @@ interface DumberAPI {
939 924
940 // Send to Go via existing message handler925 // Send to Go via existing message handler
941 if (window.webkit?.messageHandlers?.dumber) {926 if (window.webkit?.messageHandlers?.dumber) {
942- window.webkit.messageHandlers.dumber.postMessage(927+ window.webkit.messageHandlers.dumber.postMessage({
943- JSON.stringify({928+ type: "console-message",
944- type: "console-message",929+ payload: {
945- payload: {930+ level,
946- level,931+ message: formattedMessage,
947- message: formattedMessage,932+ url: window.location.href,
948- url: window.location.href,933+ webviewId: window.__dumber_webview_id,
949- webviewId: window.__dumber_webview_id,934+ },
950- },935+ });
951- }),
952- );
953 }936 }
954 } catch {937 } catch {
955 // Silently ignore errors in console capture to avoid infinite loops938 // Silently ignore errors in console capture to avoid infinite loops
@@ -989,7 +972,7 @@ interface DumberAPI {
989 try {972 try {
990 const { payload } = event.detail;973 const { payload } = event.detail;
991 if (window.webkit?.messageHandlers?.dumber) {974 if (window.webkit?.messageHandlers?.dumber) {
992- window.webkit.messageHandlers.dumber.postMessage(JSON.stringify(payload));975+ window.webkit.messageHandlers.dumber.postMessage(payload);
993 console.log("[dumber-bridge] Forwarded isolated world message:", payload.type);976 console.log("[dumber-bridge] Forwarded isolated world message:", payload.type);
994 } else {977 } else {
995 console.warn("[dumber-bridge] webkit message handler not available");978 console.warn("[dumber-bridge] webkit message handler not available");
R gui/src/injected/modules/color-scheme.ts → webui/src/injected/modules/color-scheme.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/injected/modules/omnibox.ts → webui/src/injected/modules/omnibox.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/injected/modules/shadowHost.ts → webui/src/injected/modules/shadowHost.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/injected/modules/toast.ts → webui/src/injected/modules/toast.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/injected/modules/workspace.ts → webui/src/injected/modules/workspace.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/injected/styles-entry.css → webui/src/injected/styles-entry.css +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/lib/keyboard/KeyboardService.ts → webui/src/lib/keyboard/KeyboardService.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/lib/keyboard/index.ts → webui/src/lib/keyboard/index.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/lib/keyboard/types.ts → webui/src/lib/keyboard/types.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/lib/styles.css → webui/src/lib/styles.css +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/lib/types.ts → webui/src/lib/types.ts +1 -1 renamed, 97% similar
@@ -36,7 +36,7 @@ declare global {
3636 webkit?: {
3737 messageHandlers?: {
3838 dumber?: {
39- postMessage: (message: string) => void;
39+ postMessage: (message: unknown) => void;
4040 };
4141 };
4242 };
@@ -36,7 +36,7 @@ declare global {
36 webkit?: {36 webkit?: {
37 messageHandlers?: {37 messageHandlers?: {
38 dumber?: {38 dumber?: {
39- postMessage: (message: string) => void;39+ postMessage: (message: unknown) => void;
40 };40 };
41 };41 };
42 };42 };
R gui/src/pages/BlockedPage.svelte → webui/src/pages/BlockedPage.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/Homepage.svelte → webui/src/pages/Homepage.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/blocked.ts → webui/src/pages/blocked.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage.ts → webui/src/pages/homepage.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/analytics/DailyVisitsChart.svelte → webui/src/pages/homepage/analytics/DailyVisitsChart.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/analytics/HourlyActivityChart.svelte → webui/src/pages/homepage/analytics/HourlyActivityChart.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/analytics/index.ts → webui/src/pages/homepage/analytics/index.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/favorites/FavoriteCard.svelte → webui/src/pages/homepage/favorites/FavoriteCard.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/favorites/FavoriteEditor.svelte → webui/src/pages/homepage/favorites/FavoriteEditor.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/favorites/FavoriteGrid.svelte → webui/src/pages/homepage/favorites/FavoriteGrid.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/favorites/FolderList.svelte → webui/src/pages/homepage/favorites/FolderList.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/favorites/TagCloud.svelte → webui/src/pages/homepage/favorites/TagCloud.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/favorites/index.ts → webui/src/pages/homepage/favorites/index.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/history/HistoryCleanup.svelte → webui/src/pages/homepage/history/HistoryCleanup.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/history/HistoryFilters.svelte → webui/src/pages/homepage/history/HistoryFilters.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/history/HistoryItem.svelte → webui/src/pages/homepage/history/HistoryItem.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/history/HistorySearch.svelte → webui/src/pages/homepage/history/HistorySearch.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/history/HistoryTimeline.svelte → webui/src/pages/homepage/history/HistoryTimeline.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/history/index.ts → webui/src/pages/homepage/history/index.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/keyboard.ts → webui/src/pages/homepage/keyboard.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/messaging.ts → webui/src/pages/homepage/messaging.ts +3 -3 renamed, 99% similar
@@ -38,7 +38,7 @@ let callbacksInitialized = false;
3838 // WEBKIT BRIDGE UTILITIES
3939 // ═══════════════════════════════════════════════════════════════════════════════
4040
41-function getWebKitBridge(): { postMessage: (msg: string) => void } | null {
41+function getWebKitBridge(): { postMessage: (msg: unknown) => void } | null {
4242 const bridge = (window as any).webkit?.messageHandlers?.dumber;
4343 if (bridge && typeof bridge.postMessage === 'function') {
4444 return bridge;
@@ -167,11 +167,11 @@ async function sendMessage<T = unknown>(
167167 pendingRequests.set(requestId, { resolve: resolve as any, reject, timeout });
168168
169169 try {
170- bridge.postMessage(JSON.stringify({
170+ bridge.postMessage({
171171 type,
172172 requestId,
173173 ...payload,
174- }));
174+ });
175175 } catch (error) {
176176 clearTimeout(timeout);
177177 pendingRequests.delete(requestId);
@@ -38,7 +38,7 @@ let callbacksInitialized = false;
38 // WEBKIT BRIDGE UTILITIES38 // WEBKIT BRIDGE UTILITIES
39 // ═══════════════════════════════════════════════════════════════════════════════39 // ═══════════════════════════════════════════════════════════════════════════════
40 40
41-function getWebKitBridge(): { postMessage: (msg: string) => void } | null {41+function getWebKitBridge(): { postMessage: (msg: unknown) => void } | null {
42 const bridge = (window as any).webkit?.messageHandlers?.dumber;42 const bridge = (window as any).webkit?.messageHandlers?.dumber;
43 if (bridge && typeof bridge.postMessage === 'function') {43 if (bridge && typeof bridge.postMessage === 'function') {
44 return bridge;44 return bridge;
@@ -167,11 +167,11 @@ async function sendMessage<T = unknown>(
167 pendingRequests.set(requestId, { resolve: resolve as any, reject, timeout });167 pendingRequests.set(requestId, { resolve: resolve as any, reject, timeout });
168 168
169 try {169 try {
170- bridge.postMessage(JSON.stringify({170+ bridge.postMessage({
171 type,171 type,
172 requestId,172 requestId,
173 ...payload,173 ...payload,
174- }));174+ });
175 } catch (error) {175 } catch (error) {
176 clearTimeout(timeout);176 clearTimeout(timeout);
177 pendingRequests.delete(requestId);177 pendingRequests.delete(requestId);
R gui/src/pages/homepage/panels/AnalyticsPanel.svelte → webui/src/pages/homepage/panels/AnalyticsPanel.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/panels/FavoritesPanel.svelte → webui/src/pages/homepage/panels/FavoritesPanel.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/panels/HistoryPanel.svelte → webui/src/pages/homepage/panels/HistoryPanel.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/panels/index.ts → webui/src/pages/homepage/panels/index.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/shell/CommandPalette.svelte → webui/src/pages/homepage/shell/CommandPalette.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/shell/HomepageShell.svelte → webui/src/pages/homepage/shell/HomepageShell.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/shell/KeyboardHints.svelte → webui/src/pages/homepage/shell/KeyboardHints.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/shell/StatusBar.svelte → webui/src/pages/homepage/shell/StatusBar.svelte +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/shell/index.ts → webui/src/pages/homepage/shell/index.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/state.svelte.ts → webui/src/pages/homepage/state.svelte.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/pages/homepage/types.ts → webui/src/pages/homepage/types.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/services/app.ts → webui/src/services/app.ts +4 -5 renamed, 96% similar
@@ -112,11 +112,10 @@ export class AppService {
112112 // Send message to Go backend
113113 const bridge = window.webkit?.messageHandlers?.dumber;
114114 if (bridge && typeof bridge.postMessage === "function") {
115- bridge.postMessage(
116- JSON.stringify({
117- type: "get_search_shortcuts",
118- }),
119- );
115+ bridge.postMessage({
116+ type: "get_search_shortcuts",
117+ webview_id: (window as any).__dumber_webview_id ?? 0,
118+ });
120119 } else {
121120 reject(new Error("WebKit message handler not available"));
122121 }
@@ -112,11 +112,10 @@ export class AppService {
112 // Send message to Go backend112 // Send message to Go backend
113 const bridge = window.webkit?.messageHandlers?.dumber;113 const bridge = window.webkit?.messageHandlers?.dumber;
114 if (bridge && typeof bridge.postMessage === "function") {114 if (bridge && typeof bridge.postMessage === "function") {
115- bridge.postMessage(115+ bridge.postMessage({
116- JSON.stringify({116+ type: "get_search_shortcuts",
117- type: "get_search_shortcuts",117+ webview_id: (window as any).__dumber_webview_id ?? 0,
118- }),118+ });
119- );
120 } else {119 } else {
121 reject(new Error("WebKit message handler not available"));120 reject(new Error("WebKit message handler not available"));
122 }121 }
R gui/src/services/browser-controls.ts → webui/src/services/browser-controls.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/services/debug-console.ts → webui/src/services/debug-console.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/services/notifications.ts → webui/src/services/notifications.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/styles/design-tokens.css → webui/src/styles/design-tokens.css +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/styles/tailwind.css → webui/src/styles/tailwind.css +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/types/app.ts → webui/src/types/app.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/types/frappe-charts.d.ts → webui/src/types/frappe-charts.d.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/types/generated.ts → webui/src/types/generated.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/types/inline-css.d.ts → webui/src/types/inline-css.d.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/types/raw-css.d.ts → webui/src/types/raw-css.d.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/src/utils/dom.ts → webui/src/utils/dom.ts +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/svelte.config.js → webui/svelte.config.js +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/tailwind.config.js → webui/tailwind.config.js +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/tsconfig.json → webui/tsconfig.json +0 -0 renamed, 100% similar

renamed, 100% similar

R gui/vite-plugin-pages.ts → webui/vite-plugin-pages.ts +2 -2 renamed, 95% similar
@@ -50,7 +50,7 @@ export function pageGenerator(pages: PageConfig[]): Plugin {
5050 return {
5151 name: "dumb-page-generator",
5252 writeBundle() {
53- const assetsDir = resolve(__dirname, "..", "assets", "gui");
53+ const assetsDir = resolve(__dirname, "..", "assets", "webui");
5454
5555 try {
5656 // Generate HTML files for each page
@@ -67,7 +67,7 @@ export function pageGenerator(pages: PageConfig[]): Plugin {
6767 console.log("✓ Generated favicon.svg");
6868
6969 // Copy pre-generated PNG and ICO favicons if they exist
70- const sourceDir = resolve(__dirname, "..", "assets", "gui");
70+ const sourceDir = resolve(__dirname, "..", "assets", "webui");
7171 try {
7272 const pngPath = resolve(sourceDir, "favicon.png");
7373 const icoPath = resolve(sourceDir, "favicon.ico");
@@ -50,7 +50,7 @@ export function pageGenerator(pages: PageConfig[]): Plugin {
50 return {50 return {
51 name: "dumb-page-generator",51 name: "dumb-page-generator",
52 writeBundle() {52 writeBundle() {
53- const assetsDir = resolve(__dirname, "..", "assets", "gui");53+ const assetsDir = resolve(__dirname, "..", "assets", "webui");
54 54
55 try {55 try {
56 // Generate HTML files for each page56 // Generate HTML files for each page
@@ -67,7 +67,7 @@ export function pageGenerator(pages: PageConfig[]): Plugin {
67 console.log("✓ Generated favicon.svg");67 console.log("✓ Generated favicon.svg");
68 68
69 // Copy pre-generated PNG and ICO favicons if they exist69 // Copy pre-generated PNG and ICO favicons if they exist
70- const sourceDir = resolve(__dirname, "..", "assets", "gui");70+ const sourceDir = resolve(__dirname, "..", "assets", "webui");
71 try {71 try {
72 const pngPath = resolve(sourceDir, "favicon.png");72 const pngPath = resolve(sourceDir, "favicon.png");
73 const icoPath = resolve(sourceDir, "favicon.ico");73 const icoPath = resolve(sourceDir, "favicon.ico");
R gui/vite.config.blocked.ts → webui/vite.config.blocked.ts +1 -1 renamed, 97% similar
@@ -21,7 +21,7 @@ export default defineConfig({
2121 rollupOptions: {
2222 input: resolve(__dirname, "src/pages/blocked.ts"),
2323 output: {
24- dir: "../assets/gui",
24+ dir: "../assets/webui",
2525 entryFileNames: "blocked.min.js",
2626 chunkFileNames: "[name].js",
2727 assetFileNames: "[name].[ext]",
@@ -21,7 +21,7 @@ export default defineConfig({
21 rollupOptions: {21 rollupOptions: {
22 input: resolve(__dirname, "src/pages/blocked.ts"),22 input: resolve(__dirname, "src/pages/blocked.ts"),
23 output: {23 output: {
24- dir: "../assets/gui",24+ dir: "../assets/webui",
25 entryFileNames: "blocked.min.js",25 entryFileNames: "blocked.min.js",
26 chunkFileNames: "[name].js",26 chunkFileNames: "[name].js",
27 assetFileNames: "[name].[ext]",27 assetFileNames: "[name].[ext]",
R gui/vite.config.color-scheme.ts → webui/vite.config.color-scheme.ts +1 -1 renamed, 95% similar
@@ -6,7 +6,7 @@ export default defineConfig({
66 rollupOptions: {
77 input: resolve(__dirname, "src/injected/modules/color-scheme.ts"),
88 output: {
9- dir: "../assets/gui",
9+ dir: "../assets/webui",
1010 format: "iife",
1111 entryFileNames: "color-scheme.js",
1212 inlineDynamicImports: true,
@@ -6,7 +6,7 @@ export default defineConfig({
6 rollupOptions: {6 rollupOptions: {
7 input: resolve(__dirname, "src/injected/modules/color-scheme.ts"),7 input: resolve(__dirname, "src/injected/modules/color-scheme.ts"),
8 output: {8 output: {
9- dir: "../assets/gui",9+ dir: "../assets/webui",
10 format: "iife",10 format: "iife",
11 entryFileNames: "color-scheme.js",11 entryFileNames: "color-scheme.js",
12 inlineDynamicImports: true,12 inlineDynamicImports: true,
R gui/vite.config.gui.ts → webui/vite.config.gui.ts +1 -1 renamed, 97% similar
@@ -12,7 +12,7 @@ export default defineConfig({
1212 rollupOptions: {
1313 input: resolve(__dirname, "src/injected/gui.ts"),
1414 output: {
15- dir: "../assets/gui",
15+ dir: "../assets/webui",
1616 format: "iife",
1717 entryFileNames: "gui.min.js",
1818 name: "__dumberGUI",
@@ -12,7 +12,7 @@ export default defineConfig({
12 rollupOptions: {12 rollupOptions: {
13 input: resolve(__dirname, "src/injected/gui.ts"),13 input: resolve(__dirname, "src/injected/gui.ts"),
14 output: {14 output: {
15- dir: "../assets/gui",15+ dir: "../assets/webui",
16 format: "iife",16 format: "iife",
17 entryFileNames: "gui.min.js",17 entryFileNames: "gui.min.js",
18 name: "__dumberGUI",18 name: "__dumberGUI",
R gui/vite.config.homepage.ts → webui/vite.config.homepage.ts +1 -1 renamed, 97% similar
@@ -21,7 +21,7 @@ export default defineConfig({
2121 rollupOptions: {
2222 input: resolve(__dirname, "src/pages/homepage.ts"),
2323 output: {
24- dir: "../assets/gui",
24+ dir: "../assets/webui",
2525 entryFileNames: "homepage.min.js",
2626 chunkFileNames: "[name].js",
2727 assetFileNames: "[name].[ext]",
@@ -21,7 +21,7 @@ export default defineConfig({
21 rollupOptions: {21 rollupOptions: {
22 input: resolve(__dirname, "src/pages/homepage.ts"),22 input: resolve(__dirname, "src/pages/homepage.ts"),
23 output: {23 output: {
24- dir: "../assets/gui",24+ dir: "../assets/webui",
25 entryFileNames: "homepage.min.js",25 entryFileNames: "homepage.min.js",
26 chunkFileNames: "[name].js",26 chunkFileNames: "[name].js",
27 assetFileNames: "[name].[ext]",27 assetFileNames: "[name].[ext]",
R gui/vite.config.main-world.ts → webui/vite.config.main-world.ts +1 -1 renamed, 95% similar
@@ -6,7 +6,7 @@ export default defineConfig({
66 rollupOptions: {
77 input: resolve(__dirname, "src/injected/main-world.ts"),
88 output: {
9- dir: "../assets/gui",
9+ dir: "../assets/webui",
1010 format: "iife",
1111 entryFileNames: "main-world.min.js",
1212 name: "__dumberMainWorld",
@@ -6,7 +6,7 @@ export default defineConfig({
6 rollupOptions: {6 rollupOptions: {
7 input: resolve(__dirname, "src/injected/main-world.ts"),7 input: resolve(__dirname, "src/injected/main-world.ts"),
8 output: {8 output: {
9- dir: "../assets/gui",9+ dir: "../assets/webui",
10 format: "iife",10 format: "iife",
11 entryFileNames: "main-world.min.js",11 entryFileNames: "main-world.min.js",
12 name: "__dumberMainWorld",12 name: "__dumberMainWorld",

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