diff --git a/images/checkbox.png b/images/checkbox.png deleted file mode 100644 index 0ea9e84..0000000 Binary files a/images/checkbox.png and /dev/null differ diff --git a/images/checkedbox.png b/images/checkedbox.png deleted file mode 100644 index a354faf..0000000 Binary files a/images/checkedbox.png and /dev/null differ diff --git a/images/checkwhite.png b/images/checkwhite.png deleted file mode 100644 index 6eb37e7..0000000 Binary files a/images/checkwhite.png and /dev/null differ diff --git a/images/close.png b/images/close.png deleted file mode 100644 index a16beae..0000000 Binary files a/images/close.png and /dev/null differ diff --git a/images/close.svg b/images/close.svg new file mode 100644 index 0000000..e2144b7 --- /dev/null +++ b/images/close.svg @@ -0,0 +1,13 @@ + + + + diff --git a/images/closeorange.png b/images/closeorange.png deleted file mode 100644 index 9ce56bd..0000000 Binary files a/images/closeorange.png and /dev/null differ diff --git a/images/file.png b/images/file.png deleted file mode 100644 index 6c1293a..0000000 Binary files a/images/file.png and /dev/null differ diff --git a/images/file.svg b/images/file.svg new file mode 100644 index 0000000..0bab034 --- /dev/null +++ b/images/file.svg @@ -0,0 +1,14 @@ + + + + diff --git a/images/menuclose.png b/images/menuclose.png deleted file mode 100644 index 0ead943..0000000 Binary files a/images/menuclose.png and /dev/null differ diff --git a/images/menufile.png b/images/menufile.png deleted file mode 100644 index 2037fd9..0000000 Binary files a/images/menufile.png and /dev/null differ diff --git a/images/menustar.png b/images/menustar.png deleted file mode 100644 index 920757e..0000000 Binary files a/images/menustar.png and /dev/null differ diff --git a/images/star-full.png b/images/star-full.png deleted file mode 100644 index 0ec84aa..0000000 Binary files a/images/star-full.png and /dev/null differ diff --git a/images/star.png b/images/star.png deleted file mode 100644 index 6d48f97..0000000 Binary files a/images/star.png and /dev/null differ diff --git a/images/star.svg b/images/star.svg new file mode 100644 index 0000000..e06d678 --- /dev/null +++ b/images/star.svg @@ -0,0 +1,17 @@ + + + + diff --git a/manifest.json b/manifest.json index fc14941..84ade30 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "name": "Tabzie", - "version": "1.2.2", + "version": "1.2.3", "description": "A minimal tab organizer", "homepage_url": "https://github.com/fgkolf/tabzie", "icons": { diff --git a/popup/index.html b/popup/index.html index 0765c22..4de2d8e 100644 --- a/popup/index.html +++ b/popup/index.html @@ -4,12 +4,17 @@ -
+ +
+ +
{ const menu = document.getElementById('menu'); - const checkboxes = document.getElementsByClassName('checkbox'); + const checkboxes = document.querySelectorAll("input[type='checkbox']"); if (on) { - menu.style.display = 'grid'; + menu.classList.add('open'); Array.prototype.forEach.call(checkboxes, (el) => { - el.style.display = 'block'; + el.style.display = 'grid'; }); } else { - menu.style.display = 'none'; + menu.classList.remove('open'); Array.prototype.forEach.call(checkboxes, (el) => { - el.classList.remove('checked'); + el.checked = false; if (el.id === 'menuCheckbox') { return; } @@ -57,14 +55,12 @@ const onMenuXClicked = () => { const onCheckBoxClicked = (e) => { const { id, url } = e.target.dataset; - if (checkedIds.includes(id)) { - checkedIds.splice(checkedIds.indexOf(id), 1); - checkedUrls.splice(checkedUrls.indexOf(url), 1); - e.target.classList.remove('checked'); - } else { + if (e.target.checked) { checkedIds.push(id); checkedUrls.push(url); - e.target.classList.add('checked'); + } else { + checkedIds.splice(checkedIds.indexOf(id), 1); + checkedUrls.splice(checkedUrls.indexOf(url), 1); } if (checkedIds.length === 0) { @@ -76,24 +72,20 @@ const onCheckBoxClicked = (e) => { }; const onMenuCheckboxClicked = (e) => { - const isChecked = e.target.classList.contains('checked'); - if (isChecked) { - e.target.classList.remove('checked'); - } else { - e.target.classList.add('checked'); - } checkedIds = []; checkedUrls = []; + + if (!e.target.checked) { + setMenuVisibility(false); + return; + } + // eslint-disable-next-line no-undef - const checkboxes = container.getElementsByClassName('checkbox'); + const checkboxes = container.querySelectorAll("input[type='checkbox']"); Array.prototype.forEach.call(checkboxes, (el) => { - if (isChecked) { - setMenuVisibility(false); - } else { - el.setAttribute('class', 'checkbox checked'); - checkedIds.push(el.dataset.id); - checkedUrls.push(el.dataset.url); - } + el.checked = true; + checkedIds.push(el.dataset.id); + checkedUrls.push(el.dataset.url); }); }; @@ -169,10 +161,10 @@ const onStarClicked = async ({ target }) => { const { url } = target.dataset; const bkmNode = await browser.bookmarks.search({ url }); if (bkmNode && bkmNode.length > 0) { - target.style.backgroundImage = starBtnUri; + target.classList.remove('full'); browser.bookmarks.remove(bkmNode[0].id); } else { - target.style.backgroundImage = starBtnFullUri; + target.classList.add('full'); browser.bookmarks.create({ url, title: url, @@ -211,16 +203,16 @@ const onImageEnter = async (e) => { const starButton = document.getElementById(`star_${id}`); const bkmNode = await browser.bookmarks.search({ url }); if (bkmNode && bkmNode.length > 0) { - starButton.style.backgroundImage = starBtnFullUri; + starButton.classList.add('full'); } else { - starButton.style.backgroundImage = starBtnUri; + starButton.classList.remove('full'); } } // if only one tab don't show checkbox // eslint-disable-next-line no-undef if (container.childElementCount > 1) { const checkbox = document.getElementById(`checkbox_${id}`); - checkbox.style.display = 'block'; + checkbox.style.display = 'grid'; } }; diff --git a/scripts/main.js b/scripts/main.js index 1c208af..f20c217 100644 --- a/scripts/main.js +++ b/scripts/main.js @@ -1,5 +1,6 @@ /* eslint-disable no-undef */ const container = document.getElementById('container'); +const loading = document.getElementById('loading'); const addSearchInputChangeListener = () => { document.getElementById('search').addEventListener('input', onInputChange); @@ -39,7 +40,7 @@ const addGridContainerListeners = () => { if (e.target.classList.contains('x')) { onXClicked(e); } - if (e.target.classList.contains('checkbox')) { + if (e.target.type === 'checkbox') { onCheckBoxClicked(e); } e.stopPropagation(); @@ -76,17 +77,21 @@ const createOverlay = ({ url, id, title, windowId }) => { xButton.setAttribute('class', 'btn x'); xButton.setAttribute('data-id', id); - const checkbox = document.createElement('span'); - checkbox.setAttribute('class', 'checkbox'); + const checkboxWrap = document.createElement('label'); + checkboxWrap.setAttribute('class', 'checkbox-wrap'); + checkboxWrap.setAttribute('for', `checkbox_${id}`); + const checkbox = document.createElement('input'); + checkbox.setAttribute('type', 'checkbox'); checkbox.setAttribute('id', `checkbox_${id}`); checkbox.setAttribute('data-id', id); checkbox.setAttribute('data-url', url); + checkboxWrap.appendChild(checkbox); const header = document.createElement('h2'); header.innerText = title; overlay.appendChild(header); - overlay.appendChild(checkbox); + overlay.appendChild(checkboxWrap); overlay.appendChild(starButton); overlay.appendChild(fileButton); overlay.appendChild(xButton); @@ -96,6 +101,7 @@ const createOverlay = ({ url, id, title, windowId }) => { // Image related const createImage = (imageUri) => { const image = document.createElement('img'); + image.setAttribute('loading', 'lazy'); image.setAttribute('src', imageUri); return image; }; @@ -107,30 +113,29 @@ const onCaptured = (imageUri, tab) => { return fragment; }; +const handleLoading = () => { + setTimeout(() => { + container.classList.remove('hidden'); + loading.remove(); + }, 1500); +}; + const urlRegEx = /[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&/=]*)/; const isValidURLFormat = (url) => urlRegEx.test(url); -function* yieldMyTabs(tabs) { - // eslint-disable-next-line no-restricted-syntax - for (const tab of tabs) { - yield tab; - } -} - -const createLazyTabItems = async (tabs) => { - const tabsIterator = yieldMyTabs(tabs); - let nextIteration = tabsIterator.next(); - while (!nextIteration.done) { - const tab = nextIteration.value; - const gridItem = document.createElement('div'); - gridItem.setAttribute('class', 'grid-item'); - gridItem.setAttribute('id', tab.id); - // eslint-disable-next-line no-await-in-loop - const uri = await browser.tabs.captureTab(tab.id); - gridItem.appendChild(onCaptured(uri, tab)); - container.appendChild(gridItem); - nextIteration = tabsIterator.next(); +const createTabItems = (tabs) => { + while (tabs.length) { + const fragment = document.createDocumentFragment(); + tabs.splice(0, 4).forEach(async (tab) => { + const gridItem = document.createElement('div'); + fragment.appendChild(gridItem); + gridItem.setAttribute('class', 'grid-item'); + gridItem.setAttribute('id', tab.id); + const uri = await browser.tabs.captureTab(tab.id); + gridItem.appendChild(onCaptured(uri, tab)); + }); + container.appendChild(fragment); } }; @@ -138,19 +143,19 @@ const getTabs = async () => { const tabs = await browser.tabs.query({ pinned: false }); const validTabs = tabs.filter((tab) => isValidURLFormat(tab.url)); if (validTabs.length > 0) { - createLazyTabItems(validTabs); + handleLoading(); + createTabItems(validTabs); addGridContainerListeners(); } else { - const emptyContainer = document.createElement('div'); - emptyContainer.setAttribute('class', 'grid-item empty'); - emptyContainer.innerText = 'Start browsing and come back!'; - container.appendChild(emptyContainer); + loading.innerText = 'Start browsing and come back!'; } }; const setPopupProperties = (windowInfo) => { if (windowInfo.width < 800) { - document.getElementById('container').setAttribute('class', 'grid-list'); + document + .getElementById('container') + .setAttribute('class', 'grid-list hidden'); document.getElementById('curtain').style.gridTemplateColumns = 'auto'; document.getElementById('search').style.gridArea = '2 / 1'; document.getElementById('search').style.left = '35px'; @@ -165,8 +170,8 @@ const adjustPopup = async () => { }; const loadContent = () => { - adjustPopup(); getTabs(); + adjustPopup(); addCloseBtnListener(); addMenuButtonsListeners(); addSearchInputChangeListener();