feat: Add initial Firefox container tab extension with popup UI, background script, manifest, and a comprehensive set of icons.
This commit is contained in:
125
popup/popup.js
Normal file
125
popup/popup.js
Normal file
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* Container Bookmarks - Popup Script
|
||||
*/
|
||||
|
||||
const STORAGE_KEY = 'bookmark_container_mappings';
|
||||
|
||||
// Container color palette (matches Firefox)
|
||||
const CONTAINER_COLORS = {
|
||||
'blue': '#37adff',
|
||||
'turquoise': '#00c79a',
|
||||
'green': '#51cd00',
|
||||
'yellow': '#ffcb00',
|
||||
'orange': '#ff9f00',
|
||||
'red': '#ff613d',
|
||||
'pink': '#ff4bda',
|
||||
'purple': '#af51f5',
|
||||
'toolbar': '#7c7c7d'
|
||||
};
|
||||
|
||||
/**
|
||||
* Get all bookmark-container mappings
|
||||
*/
|
||||
async function getMappings() {
|
||||
const result = await browser.storage.local.get(STORAGE_KEY);
|
||||
return result[STORAGE_KEY] || {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all containers
|
||||
*/
|
||||
async function getContainers() {
|
||||
try {
|
||||
return await browser.contextualIdentities.query({});
|
||||
} catch (error) {
|
||||
console.error('Failed to get containers:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a mapping
|
||||
*/
|
||||
async function removeMapping(bookmarkId) {
|
||||
const mappings = await getMappings();
|
||||
delete mappings[bookmarkId];
|
||||
await browser.storage.local.set({ [STORAGE_KEY]: mappings });
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the mappings list
|
||||
*/
|
||||
async function renderMappings() {
|
||||
const mappingsListEl = document.getElementById('mappings-list');
|
||||
const statsEl = document.getElementById('stats');
|
||||
|
||||
const mappings = await getMappings();
|
||||
const containers = await getContainers();
|
||||
const containerMap = {};
|
||||
containers.forEach(c => containerMap[c.cookieStoreId] = c);
|
||||
|
||||
const entries = Object.entries(mappings);
|
||||
|
||||
if (entries.length === 0) {
|
||||
mappingsListEl.innerHTML = '<p class="empty">No container assignments yet.<br>Right-click a bookmark to get started!</p>';
|
||||
statsEl.textContent = '0 bookmarks assigned';
|
||||
return;
|
||||
}
|
||||
|
||||
mappingsListEl.innerHTML = '';
|
||||
|
||||
for (const [bookmarkId, mapping] of entries) {
|
||||
try {
|
||||
const bookmarks = await browser.bookmarks.get(bookmarkId);
|
||||
if (!bookmarks || bookmarks.length === 0) {
|
||||
// Orphaned mapping, clean up
|
||||
await removeMapping(bookmarkId);
|
||||
continue;
|
||||
}
|
||||
|
||||
const bookmark = bookmarks[0];
|
||||
const container = containerMap[mapping.containerId];
|
||||
const containerColor = container ? CONTAINER_COLORS[container.color] || '#7c7c7d' : '#7c7c7d';
|
||||
const containerName = container ? container.name : mapping.containerName;
|
||||
|
||||
const item = document.createElement('div');
|
||||
item.className = 'mapping-item';
|
||||
item.innerHTML = `
|
||||
<div class="container-indicator" style="background-color: ${containerColor}"></div>
|
||||
<div class="mapping-info">
|
||||
<span class="bookmark-title" title="${bookmark.title}">${truncate(bookmark.title, 30)}</span>
|
||||
<span class="container-name">${containerName}</span>
|
||||
</div>
|
||||
<button class="remove-btn" data-bookmark-id="${bookmarkId}" title="Remove assignment">×</button>
|
||||
`;
|
||||
|
||||
mappingsListEl.appendChild(item);
|
||||
} catch (error) {
|
||||
// Bookmark doesn't exist, clean up
|
||||
await removeMapping(bookmarkId);
|
||||
}
|
||||
}
|
||||
|
||||
const validCount = mappingsListEl.children.length;
|
||||
statsEl.textContent = `${validCount} bookmark${validCount !== 1 ? 's' : ''} assigned`;
|
||||
|
||||
// Add click handlers for remove buttons
|
||||
document.querySelectorAll('.remove-btn').forEach(btn => {
|
||||
btn.addEventListener('click', async (e) => {
|
||||
const bookmarkId = e.target.dataset.bookmarkId;
|
||||
await removeMapping(bookmarkId);
|
||||
renderMappings();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate text with ellipsis
|
||||
*/
|
||||
function truncate(text, maxLength) {
|
||||
if (text.length <= maxLength) return text;
|
||||
return text.substring(0, maxLength - 1) + '…';
|
||||
}
|
||||
|
||||
// Initialize
|
||||
document.addEventListener('DOMContentLoaded', renderMappings);
|
||||
Reference in New Issue
Block a user