v1.0.1: Fix AMO warnings, add extension ID

This commit is contained in:
Bastian Gruber 2026-01-04 22:05:46 -04:00
parent f8f6a95b0f
commit 0fde22d6e2
Signed by: gruberb
GPG key ID: 426AF1CBA0530691
3 changed files with 126 additions and 42 deletions

View file

@ -1,11 +1,21 @@
{ {
"manifest_version": 2, "manifest_version": 2,
"name": "Embermarks", "name": "Embermarks",
"version": "1.0.0", "version": "1.0.1",
"description": "Rediscover your forgotten bookmarks. Surface the ones you never visit.", "description": "Rediscover your forgotten bookmarks. Surface the ones you never visit.",
"author": "Bastian Gruber", "author": "Bastian Gruber",
"homepage_url": "https://github.com/gruberb/embermarks", "homepage_url": "https://github.com/gruberb/embermarks",
"browser_specific_settings": {
"gecko": {
"id": "embermarks@gruberb.dev",
"strict_min_version": "109.0",
"data_collection_permissions": {
"required": false
}
}
},
"icons": { "icons": {
"48": "icons/ember-48.svg", "48": "icons/ember-48.svg",
"96": "icons/ember-96.svg" "96": "icons/ember-96.svg"

View file

@ -20,7 +20,10 @@ document.addEventListener("DOMContentLoaded", async () => {
action: "getBookmarkFolders", action: "getBookmarkFolders",
}); });
folderList.innerHTML = ""; // Clear loading text
while (folderList.firstChild) {
folderList.removeChild(folderList.firstChild);
}
for (const folder of folders) { for (const folder of folders) {
const item = document.createElement("div"); const item = document.createElement("div");
@ -28,11 +31,18 @@ document.addEventListener("DOMContentLoaded", async () => {
const isExcluded = settings.excludedFolders.includes(folder.id); const isExcluded = settings.excludedFolders.includes(folder.id);
item.innerHTML = ` const checkbox = document.createElement("input");
<input type="checkbox" id="folder-${folder.id}" value="${folder.id}" ${isExcluded ? "checked" : ""}> checkbox.type = "checkbox";
<label for="folder-${folder.id}">📁 ${folder.title || "(unnamed)"}</label> checkbox.id = `folder-${folder.id}`;
`; checkbox.value = folder.id;
checkbox.checked = isExcluded;
const label = document.createElement("label");
label.htmlFor = `folder-${folder.id}`;
label.textContent = `📁 ${folder.title || "(unnamed)"}`;
item.appendChild(checkbox);
item.appendChild(label);
folderList.appendChild(item); folderList.appendChild(item);
} }

View file

@ -20,13 +20,6 @@ function formatDaysAgo(days) {
return `${Math.floor(days / 365)}y ago`; return `${Math.floor(days / 365)}y ago`;
} }
// Escape HTML
function escapeHtml(text) {
const div = document.createElement("div");
div.textContent = text;
return div.innerHTML;
}
// Create a bookmark card element // Create a bookmark card element
function createBookmarkCard(bookmark) { function createBookmarkCard(bookmark) {
const card = document.createElement("a"); const card = document.createElement("a");
@ -35,20 +28,47 @@ function createBookmarkCard(bookmark) {
card.target = "_blank"; card.target = "_blank";
card.rel = "noopener"; card.rel = "noopener";
const faviconUrl = getFaviconUrl(bookmark.url); // Favicon container
const favicon = document.createElement("div");
favicon.className = "bookmark-favicon";
card.innerHTML = ` const faviconUrl = getFaviconUrl(bookmark.url);
<div class="bookmark-favicon"> if (faviconUrl) {
${faviconUrl ? `<img src="${faviconUrl}" alt="">` : "🔖"} const img = document.createElement("img");
</div> img.src = faviconUrl;
<div class="bookmark-info"> img.alt = "";
<div class="bookmark-title" title="${escapeHtml(bookmark.title)}">${escapeHtml(bookmark.title)}</div> favicon.appendChild(img);
<div class="bookmark-meta"> } else {
${bookmark.visitCount} visit${bookmark.visitCount !== 1 ? "s" : ""} · Added ${formatDaysAgo(bookmark.daysSinceAdded)} favicon.textContent = "🔖";
</div> }
${bookmark.path ? `<div class="bookmark-folder">${escapeHtml(bookmark.path)}</div>` : ""}
</div> // Info container
`; const info = document.createElement("div");
info.className = "bookmark-info";
const title = document.createElement("div");
title.className = "bookmark-title";
title.title = bookmark.title;
title.textContent = bookmark.title;
const meta = document.createElement("div");
meta.className = "bookmark-meta";
const visitText =
bookmark.visitCount === 1 ? "1 visit" : `${bookmark.visitCount} visits`;
meta.textContent = `${visitText} · Added ${formatDaysAgo(bookmark.daysSinceAdded)}`;
info.appendChild(title);
info.appendChild(meta);
if (bookmark.path) {
const folder = document.createElement("div");
folder.className = "bookmark-folder";
folder.textContent = bookmark.path;
info.appendChild(folder);
}
card.appendChild(favicon);
card.appendChild(info);
return card; return card;
} }
@ -70,18 +90,66 @@ function showEmptyState(container, reason = "none") {
const msg = messages[reason] || messages.none; const msg = messages[reason] || messages.none;
container.innerHTML = ` // Clear container
<div class="empty-state"> while (container.firstChild) {
<div class="icon">${msg.icon}</div> container.removeChild(container.firstChild);
<h2>${msg.title}</h2> }
<p>${msg.text}</p>
</div> const emptyState = document.createElement("div");
`; emptyState.className = "empty-state";
const icon = document.createElement("div");
icon.className = "icon";
icon.textContent = msg.icon;
const heading = document.createElement("h2");
heading.textContent = msg.title;
const paragraph = document.createElement("p");
paragraph.textContent = msg.text;
emptyState.appendChild(icon);
emptyState.appendChild(heading);
emptyState.appendChild(paragraph);
container.appendChild(emptyState);
} }
// Show loading state // Show loading state
function showLoading(container) { function showLoading(container) {
container.innerHTML = '<div class="loading"></div>'; while (container.firstChild) {
container.removeChild(container.firstChild);
}
const loading = document.createElement("div");
loading.className = "loading";
container.appendChild(loading);
}
// Show error state
function showError(container) {
while (container.firstChild) {
container.removeChild(container.firstChild);
}
const emptyState = document.createElement("div");
emptyState.className = "empty-state";
const icon = document.createElement("div");
icon.className = "icon";
icon.textContent = "!";
const heading = document.createElement("h2");
heading.textContent = "Oops";
const paragraph = document.createElement("p");
paragraph.textContent = "Failed to load bookmarks";
emptyState.appendChild(icon);
emptyState.appendChild(heading);
emptyState.appendChild(paragraph);
container.appendChild(emptyState);
} }
// Load and display bookmarks // Load and display bookmarks
@ -93,7 +161,9 @@ async function loadBookmarks(container) {
action: "getForgottenBookmarks", action: "getForgottenBookmarks",
}); });
container.innerHTML = ""; while (container.firstChild) {
container.removeChild(container.firstChild);
}
if (!bookmarks || bookmarks.length === 0) { if (!bookmarks || bookmarks.length === 0) {
showEmptyState(container, "none"); showEmptyState(container, "none");
@ -105,12 +175,6 @@ async function loadBookmarks(container) {
} }
} catch (error) { } catch (error) {
console.error("Failed to load bookmarks:", error); console.error("Failed to load bookmarks:", error);
container.innerHTML = ` showError(container);
<div class="empty-state">
<div class="icon">!</div>
<h2>Oops</h2>
<p>Failed to load bookmarks</p>
</div>
`;
} }
} }