diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index cbf5943..8257f03 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -91,6 +91,10 @@ "message": "Compact Mode" }, + "optionsCompactPins": { + "message": "Compact Pinned Tabs" + }, + "optionsDarkTheme": { "message": "Dark Theme" }, diff --git a/src/img/glyph-pin-pinned-12.svg b/src/img/glyph-pin-pinned-12.svg new file mode 100644 index 0000000..4e93758 --- /dev/null +++ b/src/img/glyph-pin-pinned-12.svg @@ -0,0 +1,24 @@ + + + \ No newline at end of file diff --git a/src/options/options.html b/src/options/options.html index d9918e8..f5938c2 100644 --- a/src/options/options.html +++ b/src/options/options.html @@ -9,6 +9,8 @@
diff --git a/src/options/options.js b/src/options/options.js index 9b8d994..a2c8926 100644 --- a/src/options/options.js +++ b/src/options/options.js @@ -5,8 +5,9 @@ function TabCenterOptions() { TabCenterOptions.prototype = { setupLabels() { - const options = ["optionsTitle", "optionsCompactMode", "optionsDarkTheme", - "optionsAdvancedTitle", "optionsCustomCSS", "optionsSaveCustomCSS"]; + const options = ["optionsTitle", "optionsCompactMode", + "optionsCompactPins", "optionsDarkTheme", "optionsAdvancedTitle", + "optionsCustomCSS", "optionsSaveCustomCSS"]; for (let opt of options) { this._setupTextContentLabel(opt); } @@ -16,17 +17,19 @@ TabCenterOptions.prototype = { }, setupStateAndListeners() { this._setupCheckboxOption("compactMode", "compactMode"); + this._setupCheckboxOption("compactPins", "compactPins"); this._setupCheckboxOption("darkTheme", "darkTheme"); - // Custom CSS browser.storage.local.get({ - ["customCSS"]: "" + "compactPins": true, + "customCSS": "" }).then(prefs => { document.getElementById("customCSS").value = prefs["customCSS"]; + document.getElementById("compactPins").checked = prefs["compactPins"]; }); document.getElementById("optionsSaveCustomCSS").addEventListener("click", () => { browser.storage.local.set({ - ["customCSS"]: document.getElementById("customCSS").value + "customCSS": document.getElementById("customCSS").value }); }); }, diff --git a/src/tab.js b/src/tab.js index 7777908..99cead9 100644 --- a/src/tab.js +++ b/src/tab.js @@ -19,7 +19,7 @@ SideTab.prototype = { this.updateURL(tabInfo.url); this.updateAudible(tabInfo.audible); this.updatedMuted(tabInfo.mutedInfo.muted); - this.updateIcon(tabInfo.favIconUrl); + this.updateIcon(tabInfo.hasOwnProperty("favIconUrl") ? tabInfo.favIconUrl : null); this.updatePinned(tabInfo.pinned); if (tabInfo.cookieStoreId) { // This work is done in the background on purpose: making create() async @@ -67,6 +67,9 @@ SideTab.prototype = { titleWrapper.appendChild(host); this._hostView = host; + const pin = document.createElement("div"); + pin.className = "tab-pin"; + const close = document.createElement("div"); close.className = "tab-close clickable"; close.title = browser.i18n.getMessage("closeTabButtonTooltip"); @@ -75,6 +78,7 @@ SideTab.prototype = { tab.appendChild(iconOverlay); tab.appendChild(metaImage); tab.appendChild(titleWrapper); + tab.appendChild(pin); tab.appendChild(close); }, updateTitle(title) { @@ -131,9 +135,6 @@ SideTab.prototype = { updatePinned(pinned) { this.pinned = pinned; toggleClass(this.view, "pinned", pinned); - if (pinned) { - this.resetThumbnail(); - } }, updateContext(context) { if (!context) { @@ -145,10 +146,6 @@ SideTab.prototype = { updateThumbnail(thumbnail) { this._metaImageView.style.backgroundImage = `url(${thumbnail})`; this._metaImageView.classList.add("has-thumbnail"); - }, - resetThumbnail() { - this._metaImageView.style.backgroundImage = ""; - this._metaImageView.classList.remove("has-thumbnail"); } }; diff --git a/src/tabcenter.css b/src/tabcenter.css index 0a86dc3..c1d1f39 100644 --- a/src/tabcenter.css +++ b/src/tabcenter.css @@ -2,6 +2,7 @@ :root { --tab-background-normal: 0, 0%, 99%; + --tab-background-pinned: 0, 0%, 97%; --tab-background-active: 0, 0%, 87%; --tab-background-hover: 0, 0%, 91%; } @@ -246,11 +247,11 @@ img, .tab *:not(.clickable) { overflow-y: auto; } -#tablist { +.tablist { overflow-x: hidden; } -.tab:not(.pinned) { +.tablist:not(.compact) .tab { display: flex; align-items: center; height: 56px; @@ -306,7 +307,7 @@ img, .tab *:not(.clickable) { box-shadow: 0 1px 0 hsla(0, 0%, 0%, 0.5); } -#tablist.shrinked .tab-icon-overlay { +.tablist.shrinked .tab-icon-overlay { width: 13px; height: 13px; margin: 0 0 -13px -13px; @@ -326,7 +327,7 @@ img, .tab *:not(.clickable) { background-image: url("img/tab-audio-small.svg#tab-audio-muted"); } -#tablist:not(.shrinked) .tab-meta-image { +.tablist:not(.shrinked):not(.compact) .tab-meta-image { margin: 6px; min-width: 54px; height: 40px; @@ -338,8 +339,11 @@ img, .tab *:not(.clickable) { box-shadow: 0 0 2px 2px hsla(0, 0%, 0%, 0.02), 0 2px 0 hsla(0, 0%, 0%, 0.05), 0 0 0 1px hsla(0, 0%, 0%, 0.2); } -#tablist.shrinked .tab-meta-image { +.tablist.shrinked .tab-meta-image, .tablist.pinned.compact .tab-meta-image { background: none !important; /* Because the JS script sets it manually */ +} + +.tablist.shrinked:not(.compact) .tab-meta-image { /* Make it the same size as the favicon it contains */ height: 20px; width: 20px; @@ -352,7 +356,7 @@ img, .tab *:not(.clickable) { image-rendering: -moz-crisp-edges; } -#tablist:not(.shrinked) .tab-icon { +.tablist:not(.shrinked):not(.compact) .tab-icon { margin-left: 0px; margin-top: 20px; border-radius :2px; @@ -360,10 +364,10 @@ img, .tab *:not(.clickable) { box-shadow: 0 0 2px hsla(0, 0%, 0%, 0.08), 0 0 0 1px hsla(0, 0%, 0%, 0.08); } -#tablist:not(.shrinked) .tab-meta-image.has-thumbnail { +.tablist:not(.shrinked):not(.compact) .tab-meta-image.has-thumbnail { border: 2px solid white; } -#tablist:not(.shrinked) .tab-meta-image.has-thumbnail > .tab-icon { +.tablist:not(.shrinked):not(.compact) .tab-meta-image.has-thumbnail > .tab-icon { margin-left: -2px; margin-top: 18px; } @@ -375,7 +379,7 @@ img, .tab *:not(.clickable) { flex-direction: column; } -#tablist.shrinked .tab-title-wrapper { +.tablist.shrinked:not(.compact) .tab-title-wrapper { margin-left: 6px; } @@ -388,7 +392,7 @@ img, .tab *:not(.clickable) { color: rgb(127, 127, 127); } -#tablist.shrinked .tab-host { +.tablist.shrinked:not(.compact) .tab-host { display: none; } @@ -404,6 +408,10 @@ img, .tab *:not(.clickable) { transform: translateX(36px); } +.tablist.pinned .tab-title-wrapper::after { + --tab-background: var(--tab-background-pinned); +} + .tab.active > .tab-title-wrapper::after { --tab-background: var(--tab-background-active); } @@ -416,6 +424,26 @@ img, .tab *:not(.clickable) { transform: translateX(0); } +.tablist:not(.compact) .tab.pinned > .tab-title-wrapper::after { + transform: translateX(8px); +} + +.tab-pin { + display: none; +} + +.tablist:not(.compact) .tab.pinned .tab-pin { + min-width: 16px; + height: 16px; + margin-right: 12px; + display: block; + background-image: url("img/glyph-pin-pinned-12.svg#standard"); + background-position: center center; + background-repeat: no-repeat; + background-size: 12px; + z-index: 0; +} + .tab-close { position: absolute; display: block; @@ -434,6 +462,10 @@ img, .tab *:not(.clickable) { opacity: 0; } +.tab.pinned .tab-close { + display: none; +} + .tab:hover > .tab-close { opacity: 1; } @@ -445,21 +477,25 @@ img, .tab *:not(.clickable) { background-color: hsla(0, 0%, 0%, 0.2) !important; } -#tablist.shrinked .tab { +.tablist.shrinked:not(.compact) .tab { height: 35px; } -#pinnedtablist { +.tablist.pinned { + flex-shrink: 0; + background-color: hsl(var(--tab-background-pinned)); +} + +.tablist.pinned.compact { display: flex; flex-wrap: wrap; - background-color: hsla(0, 0%, 0%, 0.02); } -#pinnedtablist:empty { +.tablist.pinned:empty { display: none; } -.tab.pinned > .tab-icon-overlay { +.tablist.pinned.compact .tab.pinned > .tab-icon-overlay { width: 13px; height: 13px; margin: 0 0 -13px 0px; @@ -469,21 +505,21 @@ img, .tab *:not(.clickable) { right: -13px; } -.tab.pinned > .tab-meta-image { +.tablist.pinned.compact .tab.pinned > .tab-meta-image { display: flex; justify-content: center; align-items: center; } -.tab.pinned .tab-icon { +.tablist.pinned.compact .tab.pinned .tab-icon { width: 22px; height: 22px; margin: 2px; } -.tab.pinned > .tab-context, -.tab.pinned > .tab-title-wrapper, -.tab.pinned > .tab-close { +.tablist.pinned.compact .tab.pinned > .tab-context, +.tablist.pinned.compact .tab.pinned > .tab-title-wrapper, +.tablist.pinned.compact .tab.pinned > .tab-close { display: none; } @@ -509,6 +545,7 @@ img, .tab *:not(.clickable) { /* DARK THEME CUSTOMIZATIONS */ body.dark-theme { --tab-background-normal: 223, 15.2%, 18%; + --tab-background-pinned: 221, 18%, 21%; --tab-background-active: 221, 41.4%, 33.1%; --tab-background-hover: 222, 28.3%, 25.55%; color: #c0c0c0; @@ -566,19 +603,23 @@ body.dark-theme .tab-icon-overlay { } body.dark-theme #newtab-icon { - filter: brightness(200%); + filter: brightness(200%); } body.dark-theme #settings { background-image: url("img/settings.svg#inverted"); } +body.dark-theme .tablist:not(.compact) .tab.pinned .tab-pin { + background-image: url("img/glyph-pin-pinned-12.svg#inverted"); +} + body.dark-theme .tab-close { background-image: url("img/glyph-close-16.svg#inverted"); } -body.dark-theme #tablist.shrinked .tab:hover .tab-icon, -body.dark-theme #pinnedtablist .tab:hover .tab-icon { +body.dark-theme .tablist.shrinked .tab:hover .tab-icon, +body.dark-theme .tablist.compact .tab:hover .tab-icon { background-color: #e6e6e6; filter: brightness(75%); } @@ -591,7 +632,8 @@ body.dark-theme .tab.active { color: #fff; } -body.dark-theme #tablist.shrinked .tab.active .tab-icon { +body.dark-theme .tablist.shrinked .tab.active .tab-icon, +body.dark-theme .tablist.compact .tab.active .tab-icon { background-color: #fff; filter: brightness(100%); } @@ -600,7 +642,3 @@ body.dark-theme #topmenu { background-color: #393f4c; } -body.dark-theme #pinnedtablist { - background-color: #2c323f; -} - diff --git a/src/tabcenter.html b/src/tabcenter.html index 2c3cc97..26236a9 100644 --- a/src/tabcenter.html +++ b/src/tabcenter.html @@ -18,8 +18,8 @@