refactor(types): align homepage services with generated models
- commit
- e7ca9814d74e728946394ec3b476c18da6fdfb4e
- author
- bamen · · 2025-09-17 05:17 UTC
- parent
- 8775e93
- signature
- unsigned
5 files · +46 -37
M gui/src/lib/types.ts +10 -0
| @@ -1,3 +1,5 @@ | |||
| 1 | + | import type { HistoryEntry, SearchShortcut } from '../types/generated.js'; | |
| 2 | + | ||
| 1 | 3 | // Global window API types for browser integration | |
| 2 | 4 | declare global { | |
| 3 | 5 | interface Window { | |
| @@ -12,6 +14,14 @@ declare global { | |||
| 12 | 14 | __dumber_initial_theme?: string; | |
| 13 | 15 | __dumber_setTheme?: (theme: 'light' | 'dark') => void; | |
| 14 | 16 | ||
| 17 | + | // History callbacks | |
| 18 | + | __dumber_history_recent?: (data: HistoryEntry[]) => void; | |
| 19 | + | __dumber_history_error?: (error: string) => void; | |
| 20 | + | ||
| 21 | + | // Shortcuts callbacks | |
| 22 | + | __dumber_shortcuts_loaded?: (data: Record<string, SearchShortcut>) => void; | |
| 23 | + | __dumber_shortcuts_error?: (error: string) => void; | |
| 24 | + | ||
| 15 | 25 | // WebKit message handler | |
| 16 | 26 | webkit?: { | |
| 17 | 27 | messageHandlers?: { | |
| @@ -1,3 +1,5 @@ | |||||
| 1 | + | import type { HistoryEntry, SearchShortcut } from '../types/generated.js'; | |||
| 2 | + | ||||
| 1 | // Global window API types for browser integration | 3 | // Global window API types for browser integration | ||
| 2 | declare global { | 4 | declare global { | ||
| 3 | interface Window { | 5 | interface Window { | ||
| @@ -12,6 +14,14 @@ declare global { | |||||
| 12 | __dumber_initial_theme?: string; | 14 | __dumber_initial_theme?: string; | ||
| 13 | __dumber_setTheme?: (theme: 'light' | 'dark') => void; | 15 | __dumber_setTheme?: (theme: 'light' | 'dark') => void; | ||
| 14 | 16 | ||||
| 17 | + | // History callbacks | |||
| 18 | + | __dumber_history_recent?: (data: HistoryEntry[]) => void; | |||
| 19 | + | __dumber_history_error?: (error: string) => void; | |||
| 20 | + | ||||
| 21 | + | // Shortcuts callbacks | |||
| 22 | + | __dumber_shortcuts_loaded?: (data: Record<string, SearchShortcut>) => void; | |||
| 23 | + | __dumber_shortcuts_error?: (error: string) => void; | |||
| 24 | + | ||||
| 15 | // WebKit message handler | 25 | // WebKit message handler | ||
| 16 | webkit?: { | 26 | webkit?: { | ||
| 17 | messageHandlers?: { | 27 | messageHandlers?: { | ||
M gui/src/services/app.ts +17 -21
| @@ -1,15 +1,8 @@ | |||
| 1 | - | type HistoryEntry = { | |
| 2 | - | id: number; | |
| 3 | - | url: string; | |
| 4 | - | title: string; | |
| 5 | - | visit_count: number; | |
| 6 | - | last_visited: string | null; | |
| 7 | - | created_at: string | null; | |
| 8 | - | } | |
| 1 | + | import type { HistoryEntry, SearchShortcut } from '../types/generated.js'; | |
| 9 | 2 | ||
| 10 | 3 | export class AppService { | |
| 11 | 4 | private history: HistoryEntry[] = []; | |
| 12 | - | private shortcuts: Record<string, any> = {}; | |
| 5 | + | private shortcuts: Record<string, SearchShortcut> = {}; | |
| 13 | 6 | ||
| 14 | 7 | constructor() {} | |
| 15 | 8 | ||
| @@ -29,18 +22,18 @@ export class AppService { | |||
| 29 | 22 | // Use message bridge instead of fetch | |
| 30 | 23 | return new Promise((resolve, reject) => { | |
| 31 | 24 | // Set up response handler | |
| 32 | - | (window as any).__dumber_history_recent = (data: HistoryEntry[]) => { | |
| 25 | + | window.__dumber_history_recent = (data: HistoryEntry[]) => { | |
| 33 | 26 | this.history = Array.isArray(data) ? data : []; | |
| 34 | 27 | resolve(); | |
| 35 | 28 | }; | |
| 36 | 29 | ||
| 37 | - | (window as any).__dumber_history_error = (error: string) => { | |
| 30 | + | window.__dumber_history_error = (error: string) => { | |
| 38 | 31 | console.error('Failed to load history:', error); | |
| 39 | 32 | reject(new Error(error)); | |
| 40 | 33 | }; | |
| 41 | 34 | ||
| 42 | 35 | // Send message to Go backend | |
| 43 | - | const bridge = (window as any).webkit?.messageHandlers?.dumber; | |
| 36 | + | const bridge = window.webkit?.messageHandlers?.dumber; | |
| 44 | 37 | if (bridge && typeof bridge.postMessage === 'function') { | |
| 45 | 38 | bridge.postMessage(JSON.stringify({ | |
| 46 | 39 | type: 'history_recent', | |
| @@ -88,12 +81,15 @@ export class AppService { | |||
| 88 | 81 | const cfg = await fetch('/api/config').then(r => r.json()); | |
| 89 | 82 | const raw = cfg?.search_shortcuts || {}; | |
| 90 | 83 | // Normalize field casing from backend (supports URL/Description and url/description) | |
| 91 | - | const normalized: Record<string, { description: string; url: string }> = {}; | |
| 84 | + | const normalized: Record<string, SearchShortcut> = {}; | |
| 92 | 85 | for (const [key, value] of Object.entries(raw)) { | |
| 93 | - | const v: any = value as any; | |
| 86 | + | const v = value as Record<string, unknown>; | |
| 94 | 87 | normalized[key] = { | |
| 95 | - | description: v.description ?? v.Description ?? '', | |
| 96 | - | url: v.url ?? v.URL ?? '' | |
| 88 | + | id: 0, | |
| 89 | + | shortcut: key, | |
| 90 | + | url_template: (v.url ?? v.URL ?? '') as string, | |
| 91 | + | description: (v.description ?? v.Description ?? '') as string, | |
| 92 | + | created_at: null | |
| 97 | 93 | }; | |
| 98 | 94 | } | |
| 99 | 95 | this.shortcuts = normalized; | |
| @@ -101,10 +97,10 @@ export class AppService { | |||
| 101 | 97 | console.error('Failed to load shortcuts:', error); | |
| 102 | 98 | // Mock shortcuts for development/fallback | |
| 103 | 99 | this.shortcuts = { | |
| 104 | - | 'g': { description: 'Google Search', url: 'https://google.com/search?q={query}' }, | |
| 105 | - | 'gh': { description: 'GitHub Search', url: 'https://github.com/search?q={query}' }, | |
| 106 | - | 'so': { description: 'Stack Overflow', url: 'https://stackoverflow.com/search?q={query}' }, | |
| 107 | - | 'w': { description: 'Wikipedia', url: 'https://en.wikipedia.org/wiki/Special:Search?search={query}' } | |
| 100 | + | 'g': { id: 0, shortcut: 'g', url_template: 'https://google.com/search?q={query}', description: 'Google Search', created_at: null }, | |
| 101 | + | 'gh': { id: 0, shortcut: 'gh', url_template: 'https://github.com/search?q={query}', description: 'GitHub Search', created_at: null }, | |
| 102 | + | 'so': { id: 0, shortcut: 'so', url_template: 'https://stackoverflow.com/search?q={query}', description: 'Stack Overflow', created_at: null }, | |
| 103 | + | 'w': { id: 0, shortcut: 'w', url_template: 'https://en.wikipedia.org/wiki/Special:Search?search={query}', description: 'Wikipedia', created_at: null } | |
| 108 | 104 | }; | |
| 109 | 105 | } | |
| 110 | 106 | } | |
| @@ -113,7 +109,7 @@ export class AppService { | |||
| 113 | 109 | return this.history; | |
| 114 | 110 | } | |
| 115 | 111 | ||
| 116 | - | getShortcuts(): Record<string, any> { | |
| 112 | + | getShortcuts(): Record<string, SearchShortcut> { | |
| 117 | 113 | return this.shortcuts; | |
| 118 | 114 | } | |
| 119 | 115 | ||
| @@ -1,15 +1,8 @@ | |||||
| 1 | - | type HistoryEntry = { | 1 | + | import type { HistoryEntry, SearchShortcut } from '../types/generated.js'; |
| 2 | - | id: number; | |||
| 3 | - | url: string; | |||
| 4 | - | title: string; | |||
| 5 | - | visit_count: number; | |||
| 6 | - | last_visited: string | null; | |||
| 7 | - | created_at: string | null; | |||
| 8 | - | } | |||
| 9 | 2 | ||||
| 10 | export class AppService { | 3 | export class AppService { | ||
| 11 | private history: HistoryEntry[] = []; | 4 | private history: HistoryEntry[] = []; | ||
| 12 | - | private shortcuts: Record<string, any> = {}; | 5 | + | private shortcuts: Record<string, SearchShortcut> = {}; |
| 13 | 6 | ||||
| 14 | constructor() {} | 7 | constructor() {} | ||
| 15 | 8 | ||||
| @@ -29,18 +22,18 @@ export class AppService { | |||||
| 29 | // Use message bridge instead of fetch | 22 | // Use message bridge instead of fetch | ||
| 30 | return new Promise((resolve, reject) => { | 23 | return new Promise((resolve, reject) => { | ||
| 31 | // Set up response handler | 24 | // Set up response handler | ||
| 32 | - | (window as any).__dumber_history_recent = (data: HistoryEntry[]) => { | 25 | + | window.__dumber_history_recent = (data: HistoryEntry[]) => { |
| 33 | this.history = Array.isArray(data) ? data : []; | 26 | this.history = Array.isArray(data) ? data : []; | ||
| 34 | resolve(); | 27 | resolve(); | ||
| 35 | }; | 28 | }; | ||
| 36 | 29 | ||||
| 37 | - | (window as any).__dumber_history_error = (error: string) => { | 30 | + | window.__dumber_history_error = (error: string) => { |
| 38 | console.error('Failed to load history:', error); | 31 | console.error('Failed to load history:', error); | ||
| 39 | reject(new Error(error)); | 32 | reject(new Error(error)); | ||
| 40 | }; | 33 | }; | ||
| 41 | 34 | ||||
| 42 | // Send message to Go backend | 35 | // Send message to Go backend | ||
| 43 | - | const bridge = (window as any).webkit?.messageHandlers?.dumber; | 36 | + | const bridge = window.webkit?.messageHandlers?.dumber; |
| 44 | if (bridge && typeof bridge.postMessage === 'function') { | 37 | if (bridge && typeof bridge.postMessage === 'function') { | ||
| 45 | bridge.postMessage(JSON.stringify({ | 38 | bridge.postMessage(JSON.stringify({ | ||
| 46 | type: 'history_recent', | 39 | type: 'history_recent', | ||
| @@ -88,12 +81,15 @@ export class AppService { | |||||
| 88 | const cfg = await fetch('/api/config').then(r => r.json()); | 81 | const cfg = await fetch('/api/config').then(r => r.json()); | ||
| 89 | const raw = cfg?.search_shortcuts || {}; | 82 | const raw = cfg?.search_shortcuts || {}; | ||
| 90 | // Normalize field casing from backend (supports URL/Description and url/description) | 83 | // Normalize field casing from backend (supports URL/Description and url/description) | ||
| 91 | - | const normalized: Record<string, { description: string; url: string }> = {}; | 84 | + | const normalized: Record<string, SearchShortcut> = {}; |
| 92 | for (const [key, value] of Object.entries(raw)) { | 85 | for (const [key, value] of Object.entries(raw)) { | ||
| 93 | - | const v: any = value as any; | 86 | + | const v = value as Record<string, unknown>; |
| 94 | normalized[key] = { | 87 | normalized[key] = { | ||
| 95 | - | description: v.description ?? v.Description ?? '', | 88 | + | id: 0, |
| 96 | - | url: v.url ?? v.URL ?? '' | 89 | + | shortcut: key, |
| 90 | + | url_template: (v.url ?? v.URL ?? '') as string, | |||
| 91 | + | description: (v.description ?? v.Description ?? '') as string, | |||
| 92 | + | created_at: null | |||
| 97 | }; | 93 | }; | ||
| 98 | } | 94 | } | ||
| 99 | this.shortcuts = normalized; | 95 | this.shortcuts = normalized; | ||
| @@ -101,10 +97,10 @@ export class AppService { | |||||
| 101 | console.error('Failed to load shortcuts:', error); | 97 | console.error('Failed to load shortcuts:', error); | ||
| 102 | // Mock shortcuts for development/fallback | 98 | // Mock shortcuts for development/fallback | ||
| 103 | this.shortcuts = { | 99 | this.shortcuts = { | ||
| 104 | - | 'g': { description: 'Google Search', url: 'https://google.com/search?q={query}' }, | 100 | + | 'g': { id: 0, shortcut: 'g', url_template: 'https://google.com/search?q={query}', description: 'Google Search', created_at: null }, |
| 105 | - | 'gh': { description: 'GitHub Search', url: 'https://github.com/search?q={query}' }, | 101 | + | 'gh': { id: 0, shortcut: 'gh', url_template: 'https://github.com/search?q={query}', description: 'GitHub Search', created_at: null }, |
| 106 | - | 'so': { description: 'Stack Overflow', url: 'https://stackoverflow.com/search?q={query}' }, | 102 | + | 'so': { id: 0, shortcut: 'so', url_template: 'https://stackoverflow.com/search?q={query}', description: 'Stack Overflow', created_at: null }, |
| 107 | - | 'w': { description: 'Wikipedia', url: 'https://en.wikipedia.org/wiki/Special:Search?search={query}' } | 103 | + | 'w': { id: 0, shortcut: 'w', url_template: 'https://en.wikipedia.org/wiki/Special:Search?search={query}', description: 'Wikipedia', created_at: null } |
| 108 | }; | 104 | }; | ||
| 109 | } | 105 | } | ||
| 110 | } | 106 | } | ||
| @@ -113,7 +109,7 @@ export class AppService { | |||||
| 113 | return this.history; | 109 | return this.history; | ||
| 114 | } | 110 | } | ||
| 115 | 111 | ||||
| 116 | - | getShortcuts(): Record<string, any> { | 112 | + | getShortcuts(): Record<string, SearchShortcut> { |
| 117 | return this.shortcuts; | 113 | return this.shortcuts; | ||
| 118 | } | 114 | } | ||
| 119 | 115 | ||||
M gui/src/services/debug-console.ts +4 -4
| @@ -4,7 +4,7 @@ export interface DebugLogEntry { | |||
| 4 | 4 | source: 'frontend' | 'backend'; | |
| 5 | 5 | category: string; | |
| 6 | 6 | message: string; | |
| 7 | - | data?: any; | |
| 7 | + | data?: unknown; | |
| 8 | 8 | } | |
| 9 | 9 | ||
| 10 | 10 | export class DebugConsoleService { | |
| @@ -121,7 +121,7 @@ export class DebugConsoleService { | |||
| 121 | 121 | }; | |
| 122 | 122 | } | |
| 123 | 123 | ||
| 124 | - | public addLog(level: DebugLogEntry['level'], source: DebugLogEntry['source'], category: string, message: string, data?: any): void { | |
| 124 | + | public addLog(level: DebugLogEntry['level'], source: DebugLogEntry['source'], category: string, message: string, data?: unknown): void { | |
| 125 | 125 | const entry: DebugLogEntry = { | |
| 126 | 126 | timestamp: new Date().toISOString().split('T')[1]?.split('.')[0] || '', // HH:MM:SS format | |
| 127 | 127 | level, | |
| @@ -205,7 +205,7 @@ export class DebugConsoleService { | |||
| 205 | 205 | }); | |
| 206 | 206 | } | |
| 207 | 207 | ||
| 208 | - | public logServiceCall(serviceName: string, methodName: string, params: any[], result?: any, error?: Error): void { | |
| 208 | + | public logServiceCall(serviceName: string, methodName: string, params: unknown[], result?: unknown, error?: Error): void { | |
| 209 | 209 | if (error) { | |
| 210 | 210 | this.addLog('error', 'frontend', 'service', `${serviceName}.${methodName}() failed`, { | |
| 211 | 211 | params, | |
| @@ -219,7 +219,7 @@ export class DebugConsoleService { | |||
| 219 | 219 | } | |
| 220 | 220 | } | |
| 221 | 221 | ||
| 222 | - | public logBackendMessage(message: string, data?: any): void { | |
| 222 | + | public logBackendMessage(message: string, data?: unknown): void { | |
| 223 | 223 | this.addLog('info', 'backend', 'service', message, data); | |
| 224 | 224 | } | |
| 225 | 225 | ||
| @@ -4,7 +4,7 @@ export interface DebugLogEntry { | |||||
| 4 | source: 'frontend' | 'backend'; | 4 | source: 'frontend' | 'backend'; | ||
| 5 | category: string; | 5 | category: string; | ||
| 6 | message: string; | 6 | message: string; | ||
| 7 | - | data?: any; | 7 | + | data?: unknown; |
| 8 | } | 8 | } | ||
| 9 | 9 | ||||
| 10 | export class DebugConsoleService { | 10 | export class DebugConsoleService { | ||
| @@ -121,7 +121,7 @@ export class DebugConsoleService { | |||||
| 121 | }; | 121 | }; | ||
| 122 | } | 122 | } | ||
| 123 | 123 | ||||
| 124 | - | public addLog(level: DebugLogEntry['level'], source: DebugLogEntry['source'], category: string, message: string, data?: any): void { | 124 | + | public addLog(level: DebugLogEntry['level'], source: DebugLogEntry['source'], category: string, message: string, data?: unknown): void { |
| 125 | const entry: DebugLogEntry = { | 125 | const entry: DebugLogEntry = { | ||
| 126 | timestamp: new Date().toISOString().split('T')[1]?.split('.')[0] || '', // HH:MM:SS format | 126 | timestamp: new Date().toISOString().split('T')[1]?.split('.')[0] || '', // HH:MM:SS format | ||
| 127 | level, | 127 | level, | ||
| @@ -205,7 +205,7 @@ export class DebugConsoleService { | |||||
| 205 | }); | 205 | }); | ||
| 206 | } | 206 | } | ||
| 207 | 207 | ||||
| 208 | - | public logServiceCall(serviceName: string, methodName: string, params: any[], result?: any, error?: Error): void { | 208 | + | public logServiceCall(serviceName: string, methodName: string, params: unknown[], result?: unknown, error?: Error): void { |
| 209 | if (error) { | 209 | if (error) { | ||
| 210 | this.addLog('error', 'frontend', 'service', `${serviceName}.${methodName}() failed`, { | 210 | this.addLog('error', 'frontend', 'service', `${serviceName}.${methodName}() failed`, { | ||
| 211 | params, | 211 | params, | ||
| @@ -219,7 +219,7 @@ export class DebugConsoleService { | |||||
| 219 | } | 219 | } | ||
| 220 | } | 220 | } | ||
| 221 | 221 | ||||
| 222 | - | public logBackendMessage(message: string, data?: any): void { | 222 | + | public logBackendMessage(message: string, data?: unknown): void { |
| 223 | this.addLog('info', 'backend', 'service', message, data); | 223 | this.addLog('info', 'backend', 'service', message, data); | ||
| 224 | } | 224 | } | ||
| 225 | 225 | ||||
M gui/src/services/notifications.ts +8 -4
| @@ -1,5 +1,9 @@ | |||
| 1 | 1 | import type { NotificationOptions } from '../types/app.js'; | |
| 2 | 2 | ||
| 3 | + | interface TimerElement extends HTMLElement { | |
| 4 | + | timeout?: ReturnType<typeof setTimeout>; | |
| 5 | + | } | |
| 6 | + | ||
| 3 | 7 | export class NotificationService { | |
| 4 | 8 | private zoomNotification: HTMLElement | null = null; | |
| 5 | 9 | private generalNotification: HTMLElement | null = null; | |
| @@ -63,13 +67,13 @@ export class NotificationService { | |||
| 63 | 67 | element.style.opacity = '1'; | |
| 64 | 68 | ||
| 65 | 69 | // Clear any existing timeout | |
| 66 | - | const existingTimeout = (element as any).timeout; | |
| 67 | - | if (existingTimeout) { | |
| 68 | - | clearTimeout(existingTimeout); | |
| 70 | + | const timerElement = element as TimerElement; | |
| 71 | + | if (timerElement.timeout) { | |
| 72 | + | clearTimeout(timerElement.timeout); | |
| 69 | 73 | } | |
| 70 | 74 | ||
| 71 | 75 | // Hide after duration | |
| 72 | - | (element as any).timeout = setTimeout(() => { | |
| 76 | + | timerElement.timeout = setTimeout(() => { | |
| 73 | 77 | element.style.opacity = '0'; | |
| 74 | 78 | }, duration); | |
| 75 | 79 | } | |
| @@ -1,5 +1,9 @@ | |||||
| 1 | import type { NotificationOptions } from '../types/app.js'; | 1 | import type { NotificationOptions } from '../types/app.js'; | ||
| 2 | 2 | ||||
| 3 | + | interface TimerElement extends HTMLElement { | |||
| 4 | + | timeout?: ReturnType<typeof setTimeout>; | |||
| 5 | + | } | |||
| 6 | + | ||||
| 3 | export class NotificationService { | 7 | export class NotificationService { | ||
| 4 | private zoomNotification: HTMLElement | null = null; | 8 | private zoomNotification: HTMLElement | null = null; | ||
| 5 | private generalNotification: HTMLElement | null = null; | 9 | private generalNotification: HTMLElement | null = null; | ||
| @@ -63,13 +67,13 @@ export class NotificationService { | |||||
| 63 | element.style.opacity = '1'; | 67 | element.style.opacity = '1'; | ||
| 64 | 68 | ||||
| 65 | // Clear any existing timeout | 69 | // Clear any existing timeout | ||
| 66 | - | const existingTimeout = (element as any).timeout; | 70 | + | const timerElement = element as TimerElement; |
| 67 | - | if (existingTimeout) { | 71 | + | if (timerElement.timeout) { |
| 68 | - | clearTimeout(existingTimeout); | 72 | + | clearTimeout(timerElement.timeout); |
| 69 | } | 73 | } | ||
| 70 | 74 | ||||
| 71 | // Hide after duration | 75 | // Hide after duration | ||
| 72 | - | (element as any).timeout = setTimeout(() => { | 76 | + | timerElement.timeout = setTimeout(() => { |
| 73 | element.style.opacity = '0'; | 77 | element.style.opacity = '0'; | ||
| 74 | }, duration); | 78 | }, duration); | ||
| 75 | } | 79 | } | ||
M gui/src/utils/dom.ts +7 -8
| @@ -1,5 +1,4 @@ | |||
| 1 | - | type HistoryEntry = { id: number; url: string; title: string }; | |
| 2 | - | type SearchShortcut = { description: string; url: string }; | |
| 1 | + | import type { History, Shortcut } from '../types/generated.js'; | |
| 3 | 2 | ||
| 4 | 3 | export class DOMRenderer { | |
| 5 | 4 | private historyListElement: HTMLElement | null = null; | |
| @@ -10,7 +9,7 @@ export class DOMRenderer { | |||
| 10 | 9 | this.shortcutsElement = document.getElementById('shortcuts'); | |
| 11 | 10 | } | |
| 12 | 11 | ||
| 13 | - | displayHistory(historyEntries: HistoryEntry[]): void { | |
| 12 | + | displayHistory(historyEntries: History[]): void { | |
| 14 | 13 | if (!this.historyListElement) return; | |
| 15 | 14 | ||
| 16 | 15 | if (!historyEntries || historyEntries.length === 0) { | |
| @@ -30,7 +29,7 @@ export class DOMRenderer { | |||
| 30 | 29 | }); | |
| 31 | 30 | } | |
| 32 | 31 | ||
| 33 | - | displayShortcuts(shortcutsData: Record<string, SearchShortcut>): void { | |
| 32 | + | displayShortcuts(shortcutsData: Record<string, Shortcut>): void { | |
| 34 | 33 | if (!this.shortcutsElement) return; | |
| 35 | 34 | ||
| 36 | 35 | if (!shortcutsData || Object.keys(shortcutsData).length === 0) { | |
| @@ -69,7 +68,7 @@ export class DOMRenderer { | |||
| 69 | 68 | } | |
| 70 | 69 | } | |
| 71 | 70 | ||
| 72 | - | private createHistoryItem(item: HistoryEntry): HTMLElement { | |
| 71 | + | private createHistoryItem(item: History): HTMLElement { | |
| 73 | 72 | const historyItem = document.createElement('div'); | |
| 74 | 73 | historyItem.className = 'history-item'; | |
| 75 | 74 | const parsed = this.safeParseURL(item.url); | |
| @@ -126,17 +125,17 @@ export class DOMRenderer { | |||
| 126 | 125 | return historyItem; | |
| 127 | 126 | } | |
| 128 | 127 | ||
| 129 | - | private createShortcutElement(key: string, shortcut: SearchShortcut): HTMLElement { | |
| 128 | + | private createShortcutElement(key: string, shortcut: Shortcut): HTMLElement { | |
| 130 | 129 | const shortcutEl = document.createElement('div'); | |
| 131 | 130 | shortcutEl.className = 'shortcut'; | |
| 132 | 131 | shortcutEl.innerHTML = ` | |
| 133 | 132 | <div class="shortcut-key">${this.escapeHtml(key)}:</div> | |
| 134 | - | <div class="shortcut-desc">${this.escapeHtml(shortcut.description)}</div> | |
| 133 | + | <div class="shortcut-desc">${this.escapeHtml(shortcut.description || 'No description')}</div> | |
| 135 | 134 | `; | |
| 136 | 135 | ||
| 137 | 136 | shortcutEl.addEventListener('click', () => { | |
| 138 | 137 | // Navigate to the base URL of the shortcut (remove %s template parameter) | |
| 139 | - | const baseUrl = this.extractBaseUrl(shortcut.url); | |
| 138 | + | const baseUrl = this.extractBaseUrl(shortcut.url_template); | |
| 140 | 139 | this.navigateToUrl(baseUrl); | |
| 141 | 140 | }); | |
| 142 | 141 | ||
| @@ -1,5 +1,4 @@ | |||||
| 1 | - | type HistoryEntry = { id: number; url: string; title: string }; | 1 | + | import type { History, Shortcut } from '../types/generated.js'; |
| 2 | - | type SearchShortcut = { description: string; url: string }; | |||
| 3 | 2 | ||||
| 4 | export class DOMRenderer { | 3 | export class DOMRenderer { | ||
| 5 | private historyListElement: HTMLElement | null = null; | 4 | private historyListElement: HTMLElement | null = null; | ||
| @@ -10,7 +9,7 @@ export class DOMRenderer { | |||||
| 10 | this.shortcutsElement = document.getElementById('shortcuts'); | 9 | this.shortcutsElement = document.getElementById('shortcuts'); | ||
| 11 | } | 10 | } | ||
| 12 | 11 | ||||
| 13 | - | displayHistory(historyEntries: HistoryEntry[]): void { | 12 | + | displayHistory(historyEntries: History[]): void { |
| 14 | if (!this.historyListElement) return; | 13 | if (!this.historyListElement) return; | ||
| 15 | 14 | ||||
| 16 | if (!historyEntries || historyEntries.length === 0) { | 15 | if (!historyEntries || historyEntries.length === 0) { | ||
| @@ -30,7 +29,7 @@ export class DOMRenderer { | |||||
| 30 | }); | 29 | }); | ||
| 31 | } | 30 | } | ||
| 32 | 31 | ||||
| 33 | - | displayShortcuts(shortcutsData: Record<string, SearchShortcut>): void { | 32 | + | displayShortcuts(shortcutsData: Record<string, Shortcut>): void { |
| 34 | if (!this.shortcutsElement) return; | 33 | if (!this.shortcutsElement) return; | ||
| 35 | 34 | ||||
| 36 | if (!shortcutsData || Object.keys(shortcutsData).length === 0) { | 35 | if (!shortcutsData || Object.keys(shortcutsData).length === 0) { | ||
| @@ -69,7 +68,7 @@ export class DOMRenderer { | |||||
| 69 | } | 68 | } | ||
| 70 | } | 69 | } | ||
| 71 | 70 | ||||
| 72 | - | private createHistoryItem(item: HistoryEntry): HTMLElement { | 71 | + | private createHistoryItem(item: History): HTMLElement { |
| 73 | const historyItem = document.createElement('div'); | 72 | const historyItem = document.createElement('div'); | ||
| 74 | historyItem.className = 'history-item'; | 73 | historyItem.className = 'history-item'; | ||
| 75 | const parsed = this.safeParseURL(item.url); | 74 | const parsed = this.safeParseURL(item.url); | ||
| @@ -126,17 +125,17 @@ export class DOMRenderer { | |||||
| 126 | return historyItem; | 125 | return historyItem; | ||
| 127 | } | 126 | } | ||
| 128 | 127 | ||||
| 129 | - | private createShortcutElement(key: string, shortcut: SearchShortcut): HTMLElement { | 128 | + | private createShortcutElement(key: string, shortcut: Shortcut): HTMLElement { |
| 130 | const shortcutEl = document.createElement('div'); | 129 | const shortcutEl = document.createElement('div'); | ||
| 131 | shortcutEl.className = 'shortcut'; | 130 | shortcutEl.className = 'shortcut'; | ||
| 132 | shortcutEl.innerHTML = ` | 131 | shortcutEl.innerHTML = ` | ||
| 133 | <div class="shortcut-key">${this.escapeHtml(key)}:</div> | 132 | <div class="shortcut-key">${this.escapeHtml(key)}:</div> | ||
| 134 | - | <div class="shortcut-desc">${this.escapeHtml(shortcut.description)}</div> | 133 | + | <div class="shortcut-desc">${this.escapeHtml(shortcut.description || 'No description')}</div> |
| 135 | `; | 134 | `; | ||
| 136 | 135 | ||||
| 137 | shortcutEl.addEventListener('click', () => { | 136 | shortcutEl.addEventListener('click', () => { | ||
| 138 | // Navigate to the base URL of the shortcut (remove %s template parameter) | 137 | // Navigate to the base URL of the shortcut (remove %s template parameter) | ||
| 139 | - | const baseUrl = this.extractBaseUrl(shortcut.url); | 138 | + | const baseUrl = this.extractBaseUrl(shortcut.url_template); |
| 140 | this.navigateToUrl(baseUrl); | 139 | this.navigateToUrl(baseUrl); | ||
| 141 | }); | 140 | }); | ||
| 142 | 141 | ||||