feat(privacy): replace Google Favicons with local letter icons

Remove getFaviconUrl() and all external network requests. Bookmarks now
show a colored letter icon with deterministic hue based on title.
Eliminates privacy leak and Brave Shields compatibility issues.
This commit is contained in:
2026-04-16 20:22:18 +02:00
parent a3e21a760f
commit 6704f4c955
3 changed files with 11 additions and 28 deletions
+6 -5
View File
@@ -562,12 +562,13 @@ html, body {
body.compact .bm-item { padding: var(--spacing-compact) 10px; } body.compact .bm-item { padding: var(--spacing-compact) 10px; }
.bm-favicon { width: 14px; height: 14px; flex-shrink: 0; border-radius: 2px; opacity: 0.85; } .bm-favicon-local {
.bm-favicon-fallback { width: 16px; height: 16px; flex-shrink: 0;
width: 14px; height: 14px; flex-shrink: 0; border-radius: 3px;
background: var(--accent-dim); border-radius: 2px;
display: flex; align-items: center; justify-content: center; display: flex; align-items: center; justify-content: center;
font-size: 8px; color: var(--accent); font-size: 9px; font-weight: 600;
color: #fff;
line-height: 1;
} }
.bm-text { flex: 1; min-width: 0; } .bm-text { flex: 1; min-width: 0; }
.bm-title { font-size: 12px; font-weight: 400; color: var(--text-primary); line-height: 1.3; } .bm-title { font-size: 12px; font-weight: 400; color: var(--text-primary); line-height: 1.3; }
+5 -14
View File
@@ -215,19 +215,11 @@ function createBmEl(bm) {
li.dataset.bmUrl = bm.url; li.dataset.bmUrl = bm.url;
li.draggable = true; li.draggable = true;
const favicon = document.createElement('img'); const favicon = document.createElement('div');
favicon.className = 'bm-favicon'; favicon.className = 'bm-favicon-local';
favicon.width = 14; favicon.textContent = bm.title.charAt(0).toUpperCase();
favicon.height = 14; const hue = (bm.title.charCodeAt(0) * 137) % 360;
favicon.src = getFaviconUrl(bm.url); favicon.style.backgroundColor = `hsl(${hue}, 45%, 35%)`;
favicon.addEventListener('error', function() {
this.classList.add('hidden');
this.nextElementSibling.classList.remove('hidden');
});
const fallback = document.createElement('div');
fallback.className = 'bm-favicon-fallback hidden';
fallback.textContent = bm.title.charAt(0).toUpperCase();
const textDiv = document.createElement('div'); const textDiv = document.createElement('div');
textDiv.className = 'bm-text'; textDiv.className = 'bm-text';
@@ -247,7 +239,6 @@ function createBmEl(bm) {
deleteBtn.textContent = '✕'; deleteBtn.textContent = '✕';
li.appendChild(favicon); li.appendChild(favicon);
li.appendChild(fallback);
li.appendChild(textDiv); li.appendChild(textDiv);
li.appendChild(deleteBtn); li.appendChild(deleteBtn);
-9
View File
@@ -33,15 +33,6 @@ function escHtml(str) {
.replace(/"/g, '"'); .replace(/"/g, '"');
} }
function getFaviconUrl(url) {
try {
const u = new URL(url);
return `https://www.google.com/s2/favicons?domain=${u.hostname}&sz=16`;
} catch {
return '';
}
}
function getDefaultBoards() { function getDefaultBoards() {
return [ return [
{ {