fix(gui): restore favicon display in homepage history
- commit
- 567b781a56eac4dfd161b774b5aec29e87e87fca
- author
- bamen · · 2025-09-14 19:11 UTC
- committer
- bamen · · 2025-09-14 16:46 UTC
- parent
- 19bd6d1
- signature
- unsigned
3 files · +30 -3
M CHANGELOG.md +1 -0
| @@ -27,6 +27,7 @@ All notable changes to this project will be documented in this file. | |||
| 27 | 27 | - **Homepage protocol**: Fixed dumb://homepage not working after GUI migration with proper Svelte 5 component and API integration | |
| 28 | 28 | - **Omnibox positioning on homepage**: Fixed omnibox stuck in top-left corner by isolating homepage CSS styles and strengthening omnibox positioning with explicit fixed positioning and CSS isolation | |
| 29 | 29 | - **Find mode persistence**: Fixed find view persisting after pressing Esc when reopening with Ctrl+L by ensuring toggle() resets mode to 'omnibox' | |
| 30 | + | - **Favicon display**: Fixed missing favicons in homepage history after Svelte 5 migration by adding FaviconURL field to API response and implementing proper fallback display logic | |
| 30 | 31 | ||
| 31 | 32 | ## [0.7.0] - 2025-09-14 | |
| 32 | 33 | ||
| @@ -27,6 +27,7 @@ All notable changes to this project will be documented in this file. | |||||
| 27 | - **Homepage protocol**: Fixed dumb://homepage not working after GUI migration with proper Svelte 5 component and API integration | 27 | - **Homepage protocol**: Fixed dumb://homepage not working after GUI migration with proper Svelte 5 component and API integration | ||
| 28 | - **Omnibox positioning on homepage**: Fixed omnibox stuck in top-left corner by isolating homepage CSS styles and strengthening omnibox positioning with explicit fixed positioning and CSS isolation | 28 | - **Omnibox positioning on homepage**: Fixed omnibox stuck in top-left corner by isolating homepage CSS styles and strengthening omnibox positioning with explicit fixed positioning and CSS isolation | ||
| 29 | - **Find mode persistence**: Fixed find view persisting after pressing Esc when reopening with Ctrl+L by ensuring toggle() resets mode to 'omnibox' | 29 | - **Find mode persistence**: Fixed find view persisting after pressing Esc when reopening with Ctrl+L by ensuring toggle() resets mode to 'omnibox' | ||
| 30 | + | - **Favicon display**: Fixed missing favicons in homepage history after Svelte 5 migration by adding FaviconURL field to API response and implementing proper fallback display logic | |||
| 30 | 31 | ||||
| 31 | ## [0.7.0] - 2025-09-14 | 32 | ## [0.7.0] - 2025-09-14 | ||
| 32 | 33 | ||||
M gui/src/pages/Homepage.svelte +26 -3
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | id: number; | |
| 6 | 6 | url: string; | |
| 7 | 7 | title: string; | |
| 8 | + | favicon_url?: string; | |
| 8 | 9 | visit_count: number; | |
| 9 | 10 | last_visited: string; | |
| 10 | 11 | created_at: string; | |
| @@ -135,8 +136,6 @@ | |||
| 135 | 136 | fetchHistory(); | |
| 136 | 137 | }); | |
| 137 | 138 | ||
| 138 | - | // Combined loading state | |
| 139 | - | const loading = $derived(historyLoading || shortcutsLoading); | |
| 140 | 139 | </script> | |
| 141 | 140 | ||
| 142 | 141 | <div class="homepage-container"> | |
| @@ -162,7 +161,31 @@ | |||
| 162 | 161 | > | |
| 163 | 162 | <div class="history-line"> | |
| 164 | 163 | <div class="history-favicon-chip"> | |
| 165 | - | <div class="history-favicon-fallback">🌐</div> | |
| 164 | + | {#if item.favicon_url} | |
| 165 | + | <img | |
| 166 | + | src={item.favicon_url} | |
| 167 | + | alt="" | |
| 168 | + | class="history-favicon-img" | |
| 169 | + | onerror={(e) => { | |
| 170 | + | const target = e.target as HTMLImageElement; | |
| 171 | + | if (target) { | |
| 172 | + | target.style.display='none'; | |
| 173 | + | const fallback = target.nextElementSibling as HTMLElement; | |
| 174 | + | if (fallback) fallback.style.display='block'; | |
| 175 | + | } | |
| 176 | + | }} | |
| 177 | + | onload={(e) => { | |
| 178 | + | const target = e.target as HTMLImageElement; | |
| 179 | + | if (target) { | |
| 180 | + | const fallback = target.nextElementSibling as HTMLElement; | |
| 181 | + | if (fallback) fallback.style.display='none'; | |
| 182 | + | } | |
| 183 | + | }} | |
| 184 | + | /> | |
| 185 | + | <div class="history-favicon-fallback" style="display: none;">🌐</div> | |
| 186 | + | {:else} | |
| 187 | + | <div class="history-favicon-fallback">🌐</div> | |
| 188 | + | {/if} | |
| 166 | 189 | </div> | |
| 167 | 190 | <div class="history-title">{item.title || 'Untitled'}</div> | |
| 168 | 191 | <div class="history-sep">•</div> | |
| @@ -5,6 +5,7 @@ | |||||
| 5 | id: number; | 5 | id: number; | ||
| 6 | url: string; | 6 | url: string; | ||
| 7 | title: string; | 7 | title: string; | ||
| 8 | + | favicon_url?: string; | |||
| 8 | visit_count: number; | 9 | visit_count: number; | ||
| 9 | last_visited: string; | 10 | last_visited: string; | ||
| 10 | created_at: string; | 11 | created_at: string; | ||
| @@ -135,8 +136,6 @@ | |||||
| 135 | fetchHistory(); | 136 | fetchHistory(); | ||
| 136 | }); | 137 | }); | ||
| 137 | 138 | ||||
| 138 | - | // Combined loading state | |||
| 139 | - | const loading = $derived(historyLoading || shortcutsLoading); | |||
| 140 | </script> | 139 | </script> | ||
| 141 | 140 | ||||
| 142 | <div class="homepage-container"> | 141 | <div class="homepage-container"> | ||
| @@ -162,7 +161,31 @@ | |||||
| 162 | > | 161 | > | ||
| 163 | <div class="history-line"> | 162 | <div class="history-line"> | ||
| 164 | <div class="history-favicon-chip"> | 163 | <div class="history-favicon-chip"> | ||
| 165 | - | <div class="history-favicon-fallback">🌐</div> | 164 | + | {#if item.favicon_url} |
| 165 | + | <img | |||
| 166 | + | src={item.favicon_url} | |||
| 167 | + | alt="" | |||
| 168 | + | class="history-favicon-img" | |||
| 169 | + | onerror={(e) => { | |||
| 170 | + | const target = e.target as HTMLImageElement; | |||
| 171 | + | if (target) { | |||
| 172 | + | target.style.display='none'; | |||
| 173 | + | const fallback = target.nextElementSibling as HTMLElement; | |||
| 174 | + | if (fallback) fallback.style.display='block'; | |||
| 175 | + | } | |||
| 176 | + | }} | |||
| 177 | + | onload={(e) => { | |||
| 178 | + | const target = e.target as HTMLImageElement; | |||
| 179 | + | if (target) { | |||
| 180 | + | const fallback = target.nextElementSibling as HTMLElement; | |||
| 181 | + | if (fallback) fallback.style.display='none'; | |||
| 182 | + | } | |||
| 183 | + | }} | |||
| 184 | + | /> | |||
| 185 | + | <div class="history-favicon-fallback" style="display: none;">🌐</div> | |||
| 186 | + | {:else} | |||
| 187 | + | <div class="history-favicon-fallback">🌐</div> | |||
| 188 | + | {/if} | |||
| 166 | </div> | 189 | </div> | ||
| 167 | <div class="history-title">{item.title || 'Untitled'}</div> | 190 | <div class="history-title">{item.title || 'Untitled'}</div> | ||
| 168 | <div class="history-sep">•</div> | 191 | <div class="history-sep">•</div> | ||
M services/browser_service.go +3 -0
| @@ -64,6 +64,7 @@ type HistoryEntry struct { | |||
| 64 | 64 | ID int64 `json:"id"` | |
| 65 | 65 | URL string `json:"url"` | |
| 66 | 66 | Title string `json:"title"` | |
| 67 | + | FaviconURL string `json:"favicon_url"` | |
| 67 | 68 | VisitCount int32 `json:"visit_count"` | |
| 68 | 69 | LastVisited time.Time `json:"last_visited"` | |
| 69 | 70 | CreatedAt time.Time `json:"created_at"` | |
| @@ -239,6 +240,7 @@ func (s *BrowserService) GetRecentHistory(ctx context.Context, limit int) ([]His | |||
| 239 | 240 | ID: entry.ID, | |
| 240 | 241 | URL: entry.Url, | |
| 241 | 242 | Title: entry.Title.String, | |
| 243 | + | FaviconURL: entry.FaviconUrl.String, | |
| 242 | 244 | VisitCount: vc, | |
| 243 | 245 | LastVisited: entry.LastVisited.Time, | |
| 244 | 246 | CreatedAt: entry.CreatedAt.Time, | |
| @@ -273,6 +275,7 @@ func (s *BrowserService) SearchHistory(ctx context.Context, query string, limit | |||
| 273 | 275 | ID: entry.ID, | |
| 274 | 276 | URL: entry.Url, | |
| 275 | 277 | Title: entry.Title.String, | |
| 278 | + | FaviconURL: entry.FaviconUrl.String, | |
| 276 | 279 | VisitCount: vc, | |
| 277 | 280 | LastVisited: entry.LastVisited.Time, | |
| 278 | 281 | CreatedAt: entry.CreatedAt.Time, | |
| @@ -64,6 +64,7 @@ type HistoryEntry struct { | |||||
| 64 | ID int64 `json:"id"` | 64 | ID int64 `json:"id"` | ||
| 65 | URL string `json:"url"` | 65 | URL string `json:"url"` | ||
| 66 | Title string `json:"title"` | 66 | Title string `json:"title"` | ||
| 67 | + | FaviconURL string `json:"favicon_url"` | |||
| 67 | VisitCount int32 `json:"visit_count"` | 68 | VisitCount int32 `json:"visit_count"` | ||
| 68 | LastVisited time.Time `json:"last_visited"` | 69 | LastVisited time.Time `json:"last_visited"` | ||
| 69 | CreatedAt time.Time `json:"created_at"` | 70 | CreatedAt time.Time `json:"created_at"` | ||
| @@ -239,6 +240,7 @@ func (s *BrowserService) GetRecentHistory(ctx context.Context, limit int) ([]His | |||||
| 239 | ID: entry.ID, | 240 | ID: entry.ID, | ||
| 240 | URL: entry.Url, | 241 | URL: entry.Url, | ||
| 241 | Title: entry.Title.String, | 242 | Title: entry.Title.String, | ||
| 243 | + | FaviconURL: entry.FaviconUrl.String, | |||
| 242 | VisitCount: vc, | 244 | VisitCount: vc, | ||
| 243 | LastVisited: entry.LastVisited.Time, | 245 | LastVisited: entry.LastVisited.Time, | ||
| 244 | CreatedAt: entry.CreatedAt.Time, | 246 | CreatedAt: entry.CreatedAt.Time, | ||
| @@ -273,6 +275,7 @@ func (s *BrowserService) SearchHistory(ctx context.Context, query string, limit | |||||
| 273 | ID: entry.ID, | 275 | ID: entry.ID, | ||
| 274 | URL: entry.Url, | 276 | URL: entry.Url, | ||
| 275 | Title: entry.Title.String, | 277 | Title: entry.Title.String, | ||
| 278 | + | FaviconURL: entry.FaviconUrl.String, | |||
| 276 | VisitCount: vc, | 279 | VisitCount: vc, | ||
| 277 | LastVisited: entry.LastVisited.Time, | 280 | LastVisited: entry.LastVisited.Time, | ||
| 278 | CreatedAt: entry.CreatedAt.Time, | 281 | CreatedAt: entry.CreatedAt.Time, | ||