diff --git a/manifest.json b/manifest.json
index df24ab9..e86b09c 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,11 +1,21 @@
{
"manifest_version": 2,
"name": "Embermarks",
- "version": "1.0.0",
+ "version": "1.0.1",
"description": "Rediscover your forgotten bookmarks. Surface the ones you never visit.",
"author": "Bastian Gruber",
"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": {
"48": "icons/ember-48.svg",
"96": "icons/ember-96.svg"
diff --git a/options/options.js b/options/options.js
index c2263a1..42676a0 100644
--- a/options/options.js
+++ b/options/options.js
@@ -20,7 +20,10 @@ document.addEventListener("DOMContentLoaded", async () => {
action: "getBookmarkFolders",
});
- folderList.innerHTML = "";
+ // Clear loading text
+ while (folderList.firstChild) {
+ folderList.removeChild(folderList.firstChild);
+ }
for (const folder of folders) {
const item = document.createElement("div");
@@ -28,11 +31,18 @@ document.addEventListener("DOMContentLoaded", async () => {
const isExcluded = settings.excludedFolders.includes(folder.id);
- item.innerHTML = `
-
-
- `;
+ const checkbox = document.createElement("input");
+ checkbox.type = "checkbox";
+ 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);
}
diff --git a/shared/ui.js b/shared/ui.js
index 26bdb5b..04968bb 100644
--- a/shared/ui.js
+++ b/shared/ui.js
@@ -20,13 +20,6 @@ function formatDaysAgo(days) {
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
function createBookmarkCard(bookmark) {
const card = document.createElement("a");
@@ -35,20 +28,47 @@ function createBookmarkCard(bookmark) {
card.target = "_blank";
card.rel = "noopener";
- const faviconUrl = getFaviconUrl(bookmark.url);
+ // Favicon container
+ const favicon = document.createElement("div");
+ favicon.className = "bookmark-favicon";
- card.innerHTML = `
-
- ${faviconUrl ? `

` : "๐"}
-
-
-
${escapeHtml(bookmark.title)}
-
- ${bookmark.visitCount} visit${bookmark.visitCount !== 1 ? "s" : ""} ยท Added ${formatDaysAgo(bookmark.daysSinceAdded)}
-
- ${bookmark.path ? `
${escapeHtml(bookmark.path)}
` : ""}
-
- `;
+ const faviconUrl = getFaviconUrl(bookmark.url);
+ if (faviconUrl) {
+ const img = document.createElement("img");
+ img.src = faviconUrl;
+ img.alt = "";
+ favicon.appendChild(img);
+ } else {
+ favicon.textContent = "๐";
+ }
+
+ // 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;
}
@@ -70,18 +90,66 @@ function showEmptyState(container, reason = "none") {
const msg = messages[reason] || messages.none;
- container.innerHTML = `
-
-
${msg.icon}
-
${msg.title}
-
${msg.text}
-
- `;
+ // Clear 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 = 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
function showLoading(container) {
- container.innerHTML = '';
+ 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
@@ -93,7 +161,9 @@ async function loadBookmarks(container) {
action: "getForgottenBookmarks",
});
- container.innerHTML = "";
+ while (container.firstChild) {
+ container.removeChild(container.firstChild);
+ }
if (!bookmarks || bookmarks.length === 0) {
showEmptyState(container, "none");
@@ -105,12 +175,6 @@ async function loadBookmarks(container) {
}
} catch (error) {
console.error("Failed to load bookmarks:", error);
- container.innerHTML = `
-
-
!
-
Oops
-
Failed to load bookmarks
-
- `;
+ showError(container);
}
}