v1.0.1: Fix AMO warnings, add extension ID
This commit is contained in:
parent
f8f6a95b0f
commit
0fde22d6e2
3 changed files with 126 additions and 42 deletions
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
136
shared/ui.js
136
shared/ui.js
|
|
@ -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>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue