added code to sort the containers list including icons (feathericons.com)
This commit is contained in:
parent
41686fdf6c
commit
977617c132
5 changed files with 129 additions and 63 deletions
|
@ -40,6 +40,7 @@ body {
|
||||||
--block-url-label-size: 2rem; /* 24px */
|
--block-url-label-size: 2rem; /* 24px */
|
||||||
--inline-start-size: 1.66rem; /* 20px */
|
--inline-start-size: 1.66rem; /* 20px */
|
||||||
--inline-button-size: 5.833rem; /* 70px */
|
--inline-button-size: 5.833rem; /* 70px */
|
||||||
|
--inline-button-large-size: 11.666rem; /* 140px */
|
||||||
--icon-size: 1.166rem; /* 14px */
|
--icon-size: 1.166rem; /* 14px */
|
||||||
|
|
||||||
--small-text-size: 0.833rem; /* 10px */
|
--small-text-size: 0.833rem; /* 10px */
|
||||||
|
@ -308,6 +309,16 @@ table {
|
||||||
transform: rotate(180deg);
|
transform: rotate(180deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.up-arrow-img {
|
||||||
|
block-size: 16px;
|
||||||
|
inline-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.down-arrow-img {
|
||||||
|
block-size: 16px;
|
||||||
|
inline-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Onboarding styles */
|
/* Onboarding styles */
|
||||||
.onboarding * {
|
.onboarding * {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -452,7 +463,8 @@ manage things like container crud */
|
||||||
margin-inline-start: var(--inline-item-space-size);
|
margin-inline-start: var(--inline-item-space-size);
|
||||||
}
|
}
|
||||||
|
|
||||||
#container-panel #sort-containers-link {
|
#container-panel #sort-containers-link,
|
||||||
|
#container-panel #sort-containers-list-link {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
block-size: var(--block-url-label-size);
|
block-size: var(--block-url-label-size);
|
||||||
border: 1px solid #d8d8d8;
|
border: 1px solid #d8d8d8;
|
||||||
|
@ -460,13 +472,23 @@ manage things like container crud */
|
||||||
color: var(--title-text-color);
|
color: var(--title-text-color);
|
||||||
display: flex;
|
display: flex;
|
||||||
font-size: var(--small-text-size);
|
font-size: var(--small-text-size);
|
||||||
inline-size: var(--inline-button-size);
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#container-panel #sort-containers-link {
|
||||||
|
inline-size: var(--inline-button-size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#container-panel #sort-containers-list-link {
|
||||||
|
inline-size: var(--inline-button-large-size);
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
#container-panel #sort-containers-link:hover,
|
#container-panel #sort-containers-link:hover,
|
||||||
#container-panel #sort-containers-link:focus {
|
#container-panel #sort-containers-link:focus,
|
||||||
|
#container-panel #sort-containers-list-link:hover,
|
||||||
|
#container-panel #sort-containers-list-link:focus {
|
||||||
background: #f2f2f2;
|
background: #f2f2f2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1
src/img/chevron-down.svg
Normal file
1
src/img/chevron-down.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-down"><polyline points="6 9 12 15 18 9"></polyline></svg>
|
After Width: | Height: | Size: 269 B |
1
src/img/chevron-up.svg
Normal file
1
src/img/chevron-up.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-up"><polyline points="18 15 12 9 6 15"></polyline></svg>
|
After Width: | Height: | Size: 268 B |
157
src/js/popup.js
157
src/js/popup.js
|
@ -235,6 +235,23 @@ const Logic = {
|
||||||
moveTabsEl.parentNode.insertBefore(fragment, moveTabsEl.nextSibling);
|
moveTabsEl.parentNode.insertBefore(fragment, moveTabsEl.nextSibling);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
async sortContainerList(list) {
|
||||||
|
const update = [...list];
|
||||||
|
const result = await browser.storage.local.get({containerSortOrder: null});
|
||||||
|
const upArrowElement = document.querySelector("#sort-containers-list-link .up-arrow-img");
|
||||||
|
const downArrowElement = document.querySelector("#sort-containers-list-link .down-arrow-img");
|
||||||
|
if (result.containerSortOrder === "asc") {
|
||||||
|
update.sort((a, b) => (a.name.toLowerCase() > b.name.toLowerCase()) ? 1 : -1);
|
||||||
|
downArrowElement.style.display = "inline";
|
||||||
|
upArrowElement.style.display = "none";
|
||||||
|
} else if (result.containerSortOrder === "desc") {
|
||||||
|
update.sort((a, b) => (a.name.toLowerCase() < b.name.toLowerCase()) ? 1 : -1);
|
||||||
|
upArrowElement.style.display = "inline";
|
||||||
|
downArrowElement.style.display = "none";
|
||||||
|
}
|
||||||
|
return update;
|
||||||
|
},
|
||||||
|
|
||||||
async refreshIdentities() {
|
async refreshIdentities() {
|
||||||
const [identities, state] = await Promise.all([
|
const [identities, state] = await Promise.all([
|
||||||
browser.contextualIdentities.query({}),
|
browser.contextualIdentities.query({}),
|
||||||
|
@ -245,7 +262,7 @@ const Logic = {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
this._identities = identities.map((identity) => {
|
const identitiesList = identities.map((identity) => {
|
||||||
const stateObject = state[identity.cookieStoreId];
|
const stateObject = state[identity.cookieStoreId];
|
||||||
if (stateObject) {
|
if (stateObject) {
|
||||||
identity.hasOpenTabs = stateObject.hasOpenTabs;
|
identity.hasOpenTabs = stateObject.hasOpenTabs;
|
||||||
|
@ -255,6 +272,8 @@ const Logic = {
|
||||||
}
|
}
|
||||||
return identity;
|
return identity;
|
||||||
});
|
});
|
||||||
|
this._identities = await this.sortContainerList(identitiesList);
|
||||||
|
return this._identities;
|
||||||
},
|
},
|
||||||
|
|
||||||
getPanelSelector(panel) {
|
getPanelSelector(panel) {
|
||||||
|
@ -382,6 +401,63 @@ const Logic = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
createContainerList(listParentElement) {
|
||||||
|
const fragment = document.createDocumentFragment();
|
||||||
|
|
||||||
|
Logic.identities().forEach(identity => {
|
||||||
|
const hasTabs = (identity.hasHiddenTabs || identity.hasOpenTabs);
|
||||||
|
const tr = document.createElement("tr");
|
||||||
|
const context = document.createElement("td");
|
||||||
|
const manage = document.createElement("td");
|
||||||
|
|
||||||
|
tr.classList.add("container-panel-row");
|
||||||
|
|
||||||
|
context.classList.add("userContext-wrapper", "open-newtab", "clickable");
|
||||||
|
manage.classList.add("show-tabs", "pop-button");
|
||||||
|
manage.title = escaped`View ${identity.name} container`;
|
||||||
|
context.setAttribute("tabindex", "0");
|
||||||
|
context.title = escaped`Create ${identity.name} tab`;
|
||||||
|
context.innerHTML = escaped`
|
||||||
|
<div class="userContext-icon-wrapper open-newtab">
|
||||||
|
<div class="usercontext-icon"
|
||||||
|
data-identity-icon="${identity.icon}"
|
||||||
|
data-identity-color="${identity.color}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="container-name truncate-text"></div>`;
|
||||||
|
context.querySelector(".container-name").textContent = identity.name;
|
||||||
|
manage.innerHTML = "<img src='/img/container-arrow.svg' class='show-tabs pop-button-image-small' />";
|
||||||
|
|
||||||
|
fragment.appendChild(tr);
|
||||||
|
|
||||||
|
tr.appendChild(context);
|
||||||
|
|
||||||
|
if (hasTabs) {
|
||||||
|
tr.appendChild(manage);
|
||||||
|
}
|
||||||
|
|
||||||
|
Logic.addEnterHandler(tr, async (e) => {
|
||||||
|
if (e.target.matches(".open-newtab")
|
||||||
|
|| e.target.parentNode.matches(".open-newtab")
|
||||||
|
|| e.type === "keydown") {
|
||||||
|
try {
|
||||||
|
browser.tabs.create({
|
||||||
|
cookieStoreId: identity.cookieStoreId
|
||||||
|
});
|
||||||
|
window.close();
|
||||||
|
} catch (e) {
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
} else if (hasTabs) {
|
||||||
|
Logic.showPanel(P_CONTAINER_INFO, identity);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
listParentElement.innerHTML = "";
|
||||||
|
listParentElement.appendChild(fragment);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// P_ONBOARDING_1: First page for Onboarding.
|
// P_ONBOARDING_1: First page for Onboarding.
|
||||||
|
@ -527,6 +603,20 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Logic.addEnterHandler(document.querySelector("#sort-containers-list-link"), async () => {
|
||||||
|
try {
|
||||||
|
const toggle = current => current === "asc" ? "desc": "asc";
|
||||||
|
let result = await browser.storage.local.get({containerSortOrder: null});
|
||||||
|
result = {containerSortOrder: toggle(result.containerSortOrder)};
|
||||||
|
await browser.storage.local.set(result);
|
||||||
|
await Logic.refreshIdentities();
|
||||||
|
const listParentElement = document.querySelector(".identities-list tbody");
|
||||||
|
Logic.createContainerList(listParentElement);
|
||||||
|
} catch (e) {
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
document.addEventListener("keydown", (e) => {
|
document.addEventListener("keydown", (e) => {
|
||||||
const selectables = [...document.querySelectorAll("[tabindex='0'], [tabindex='-1']")];
|
const selectables = [...document.querySelectorAll("[tabindex='0'], [tabindex='-1']")];
|
||||||
const element = document.activeElement;
|
const element = document.activeElement;
|
||||||
|
@ -623,69 +713,16 @@ Logic.registerPanel(P_CONTAINERS_LIST, {
|
||||||
|
|
||||||
// This method is called when the panel is shown.
|
// This method is called when the panel is shown.
|
||||||
async prepare() {
|
async prepare() {
|
||||||
const fragment = document.createDocumentFragment();
|
|
||||||
|
|
||||||
this.prepareCurrentTabHeader();
|
this.prepareCurrentTabHeader();
|
||||||
|
|
||||||
Logic.identities().forEach(identity => {
|
const listParentElement = document.querySelector(".identities-list tbody");
|
||||||
const hasTabs = (identity.hasHiddenTabs || identity.hasOpenTabs);
|
Logic.createContainerList(listParentElement);
|
||||||
const tr = document.createElement("tr");
|
|
||||||
const context = document.createElement("td");
|
|
||||||
const manage = document.createElement("td");
|
|
||||||
|
|
||||||
tr.classList.add("container-panel-row");
|
|
||||||
|
|
||||||
context.classList.add("userContext-wrapper", "open-newtab", "clickable");
|
|
||||||
manage.classList.add("show-tabs", "pop-button");
|
|
||||||
manage.title = escaped`View ${identity.name} container`;
|
|
||||||
context.setAttribute("tabindex", "0");
|
|
||||||
context.title = escaped`Create ${identity.name} tab`;
|
|
||||||
context.innerHTML = escaped`
|
|
||||||
<div class="userContext-icon-wrapper open-newtab">
|
|
||||||
<div class="usercontext-icon"
|
|
||||||
data-identity-icon="${identity.icon}"
|
|
||||||
data-identity-color="${identity.color}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="container-name truncate-text"></div>`;
|
|
||||||
context.querySelector(".container-name").textContent = identity.name;
|
|
||||||
manage.innerHTML = "<img src='/img/container-arrow.svg' class='show-tabs pop-button-image-small' />";
|
|
||||||
|
|
||||||
fragment.appendChild(tr);
|
|
||||||
|
|
||||||
tr.appendChild(context);
|
|
||||||
|
|
||||||
if (hasTabs) {
|
|
||||||
tr.appendChild(manage);
|
|
||||||
}
|
|
||||||
|
|
||||||
Logic.addEnterHandler(tr, async (e) => {
|
|
||||||
if (e.target.matches(".open-newtab")
|
|
||||||
|| e.target.parentNode.matches(".open-newtab")
|
|
||||||
|| e.type === "keydown") {
|
|
||||||
try {
|
|
||||||
browser.tabs.create({
|
|
||||||
cookieStoreId: identity.cookieStoreId
|
|
||||||
});
|
|
||||||
window.close();
|
|
||||||
} catch (e) {
|
|
||||||
window.close();
|
|
||||||
}
|
|
||||||
} else if (hasTabs) {
|
|
||||||
Logic.showPanel(P_CONTAINER_INFO, identity);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const list = document.querySelector(".identities-list tbody");
|
|
||||||
|
|
||||||
list.innerHTML = "";
|
|
||||||
list.appendChild(fragment);
|
|
||||||
/* Not sure why extensions require a focus for the doorhanger,
|
/* Not sure why extensions require a focus for the doorhanger,
|
||||||
however it allows us to have a tabindex before the first selected item
|
however it allows us to have a tabindex before the first selected item
|
||||||
*/
|
*/
|
||||||
const focusHandler = () => {
|
const focusHandler = () => {
|
||||||
list.querySelector("tr .clickable").focus();
|
listParentElement.querySelector("tr .clickable").focus();
|
||||||
document.removeEventListener("focus", focusHandler);
|
document.removeEventListener("focus", focusHandler);
|
||||||
};
|
};
|
||||||
document.addEventListener("focus", focusHandler);
|
document.addEventListener("focus", focusHandler);
|
||||||
|
@ -747,7 +784,7 @@ Logic.registerPanel(P_CONTAINER_INFO, {
|
||||||
return;
|
return;
|
||||||
} else if (numTabs === 1) {
|
} else if (numTabs === 1) {
|
||||||
Logic._disableMoveTabs("Cannot move a tab from a single-tab window.");
|
Logic._disableMoveTabs("Cannot move a tab from a single-tab window.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logic.addEnterHandler(moveTabsEl, async () => {
|
Logic.addEnterHandler(moveTabsEl, async () => {
|
||||||
await browser.runtime.sendMessage({
|
await browser.runtime.sendMessage({
|
||||||
|
@ -808,7 +845,7 @@ Logic.registerPanel(P_CONTAINER_INFO, {
|
||||||
<td class="container-info-tab-title truncate-text" title="${tab.url}" ><div class="container-tab-title">${tab.title}</div></td>`;
|
<td class="container-info-tab-title truncate-text" title="${tab.url}" ><div class="container-tab-title">${tab.title}</div></td>`;
|
||||||
tr.querySelector("td").appendChild(Utils.createFavIconElement(tab.favIconUrl));
|
tr.querySelector("td").appendChild(Utils.createFavIconElement(tab.favIconUrl));
|
||||||
document.getElementById("container-info-table").appendChild(fragment);
|
document.getElementById("container-info-table").appendChild(fragment);
|
||||||
|
|
||||||
// On click, we activate this tab. But only if this tab is active.
|
// On click, we activate this tab. But only if this tab is active.
|
||||||
if (!tab.hiddenState) {
|
if (!tab.hiddenState) {
|
||||||
const closeImage = document.createElement("img");
|
const closeImage = document.createElement("img");
|
||||||
|
@ -842,7 +879,7 @@ Logic.registerPanel(P_CONTAINER_INFO, {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,11 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="container-panel-controls">
|
<div class="container-panel-controls">
|
||||||
<a href="#" class="action-link" id="sort-containers-link" title="Sort tabs into container order">Sort Tabs</a>
|
<a href="#" class="action-link" id="sort-containers-link" title="Sort tabs into container order">Sort Tabs</a>
|
||||||
|
<a href="#" class="action-link" id="sort-containers-list-link" title="Sort containers alphabetically">
|
||||||
|
<span>Sort Containers </span>
|
||||||
|
<img alt="Panel Back Arrow" src="/img/chevron-up.svg" class="up-arrow-img" style="display: none;"/>
|
||||||
|
<img alt="Panel Back Arrow" src="/img/chevron-down.svg" class="down-arrow-img" style="display: none;" />
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="scrollable panel-content" tabindex="-1">
|
<div class="scrollable panel-content" tabindex="-1">
|
||||||
<table class="identities-list">
|
<table class="identities-list">
|
||||||
|
|
Loading…
Add table
Reference in a new issue