diff --git a/addons.css b/addons.css index 6523cd8..9b7dedd 100644 --- a/addons.css +++ b/addons.css @@ -1,153 +1,191 @@ /* Making the addons page sidebar compact (expand on hover) and make addons as grid */ /* inspiration from https://github.com/MrOtherGuy/firefox-csshacks/blob/master/content/multi_column_addons.css made available under Mozilla Public License v. 2.0 */ - -@-moz-document url-prefix("about:addons") { - #full { - --sidebar-collapsed-width: 45px; - --sidebar-expanded-width: 200px; - @media -moz-pref("compact-settings.compact-addons.enabled") { +/* Sidebar mirrors the about:preferences treatment (54px strip, 250px hover + flyout, 180ms decelerate, elevation shadow). .category is a light-DOM + button: label is its text, icon is a background-image with + fill: currentColor — so labels are hidden with color: transparent while + the fill is pinned to a concrete token color. That keeps icons solid and + gives labels a real fade. Row height is safe: .category has + min-height: 48px. Flat topology (media query outside @-moz-document) + matches preferences.css, which is known to apply. */ + +@media -moz-pref("compact-settings.compact-addons.enabled") { + @-moz-document url-prefix("about:addons") { + #full { display: block !important; + } + + #full #sidebar { + position: fixed !important; + inset-inline-start: 0 !important; + top: 0 !important; + height: 100vh !important; + z-index: 20 !important; + box-sizing: border-box !important; + width: var(--cs-strip-w, 54px) !important; + overflow: hidden !important; + padding: 0 !important; + margin: 0 !important; + background: var(--background-color-canvas, var(--in-content-page-background)) !important; + } - #sidebar { - position: absolute !important; - z-index: 20 !important; + /* prefers-reduced-motion zeroes --cs-anim (see userContent.css) */ + @media -moz-pref("compact-settings.animation.enabled") { + #full #sidebar { + transition: width var(--cs-anim, 180ms cubic-bezier(0.2, 0, 0, 1)), + box-shadow var(--cs-anim, 180ms cubic-bezier(0.2, 0, 0, 1)) !important; + } + + #full #sidebar .category { + transition: color var(--cs-anim, 180ms cubic-bezier(0.2, 0, 0, 1)) !important; + } - .category, - .sidebar-footer-list { - width: 50px !important; - margin-left: 5px !important; - } + #full #sidebar .sidebar-footer-label { + transition: opacity var(--cs-anim, 180ms cubic-bezier(0.2, 0, 0, 1)) !important; } + } + + #full #sidebar #categories, + #full #sidebar sidebar-footer { + width: auto !important; + } + + #full #sidebar .category { + /* stock margin-inline-start is 30px; 5px puts the 24px icon box at + 15–39px, center 27 = strip center, matching the settings sidebar */ + margin-inline-start: 5px !important; + margin-inline-end: 0 !important; + width: 240px !important; + /* pin the fill so the label can go transparent without the icon */ + fill: var(--icon-color, light-dark(rgb(91, 91, 102), rgb(191, 191, 201))) !important; + } + + #full #sidebar:not(:hover) .category { + color: transparent !important; + } + + /* selected: icon accent in both states; label accent only when the + flyout is open (collapsed labels are transparent) */ + #full #sidebar .category[selected], + #full #sidebar .category[aria-selected="true"] { + fill: var(--cs-accent, var(--zen-primary-color, var(--color-accent-primary))) !important; + } + + #full #sidebar:hover .category[selected], + #full #sidebar:hover .category[aria-selected="true"] { + color: var(--cs-accent, var(--zen-primary-color, var(--color-accent-primary))) !important; + } + + /* footer ("Zen Settings" / "Add-ons Support"): stock indents the list + 30px + icon margin 11.25px, landing icons at x≈41 — half outside the + strip. 8px list margin + stock 11.25px icon margin centers them on + the same 27px column as the category icons. */ + #full #sidebar .sidebar-footer-list { + margin-inline-start: 8px !important; + } + + #full #sidebar .sidebar-footer-link { + width: 235px !important; + } + + /* label is its own element here, so a real opacity fade works */ + #full #sidebar .sidebar-footer-label { + white-space: nowrap !important; + } + + #full #sidebar:not(:hover) .sidebar-footer-label { + opacity: 0 !important; + } - @media (min-width: 830px) { - #sidebar { - position: absolute !important; - width: auto !important; - z-index: 20 !important; - - #categories, - sidebar-footer { - @media -moz-pref("compact-settings.animation.enabled") { - transition: width 100ms ease !important; - } - width: var(--sidebar-collapsed-width) !important; - } - - .category, - .sidebar-footer-list { - width: calc(var(--sidebar-expanded-width) - 20px) !important; - } - - .sidebar-footer-list img { - scale: 1.4 !important; - margin-left: 15px !important; - margin-right: 12px !important; - } - - .category[aria-selected="true"] { - color: var(--zen-primary-color) !important; - } - - &:hover { - #categories { - width: var(--sidebar-expanded-width) !important; - } - } - } + #full #sidebar:hover { + width: var(--cs-flyout-w, 250px) !important; + box-shadow: var(--cs-elevation, + 0 0 0 1px color-mix(in srgb, currentColor 12%, transparent), + 6px 0 24px -8px rgba(0, 0, 0, 0.25)) !important; + } + + #full #content { + margin-inline-start: var(--cs-content-offset, 66px) !important; + max-width: calc(100% - var(--cs-content-offset, 66px) - 8px) !important; + height: 100vh !important; + overflow-y: auto !important; + } + } +} + +@media -moz-pref("compact-settings.addons.grid-enabled") { + @-moz-document url-prefix("about:addons") { + #full #content #main { + width: 90% !important; + max-width: 100vw !important; + padding: 0 !important; + margin: 0 auto !important; + } + + #full #content #main addon-card[expanded="true"] > div { + margin-top: 40px; + } + + #full #content #main addon-list h2 { + grid-area: hd; + } + + #full #content #main addon-list[type="extension"] > section { + display: grid; + grid-auto-columns: 1fr; + gap: 1em; + grid-template-areas: "hd" "cd"; + } + + #full #content #main addon-list[type="extension"] > section addon-card > div { + height: 65% !important; + } + + @media (min-width: 960px) { + #full #content #main addon-list[type="extension"] > section { + grid-template-areas: "hd hd" "cd cd"; } - #content { - margin-left: calc(var(--sidebar-collapsed-width) + 45px) !important; - max-width: calc(100% - var(--sidebar-collapsed-width) - 55px) !important; - /* max-width: 100vw !important; */ - height: 100vh !important; - overflow-y: auto !important; - @media -moz-pref("compact-settings.addons.grid-enabled") { - margin-left: calc(var(--sidebar-collapsed-width) + 15px) !important; - max-width: calc(100% - var(--sidebar-collapsed-width) - 20px) !important; - } + #full #content #main addon-list[type="extension"] > section addon-card > div { + height: 70% !important; } } - @media -moz-pref("compact-settings.addons.grid-enabled") { - #content { - #main { - width: 90% !important; - max-width: 100vw !important; - padding: 0 !important; - margin: 0 auto !important; - - addon-card[expanded="true"] > div { - margin-top: 40px; - } - - addon-list { - h2 { - grid-area: hd; - } - - &[type="extension"] > section { - display: grid; - grid-auto-columns: 1fr; - gap: 1em; - grid-template-areas: "hd" "cd"; - - addon-card > div { - height: 65% !important; - } - - @media (min-width: 960px) { - grid-template-areas: "hd hd" "cd cd"; - - addon-card > div { - height: 70% !important; - } - } - - @media (min-width: 1200px) { - grid-template-areas: "hd hd hd" "cd cd cd"; - - addon-card > div { - height: 80% !important; - } - } - } - - &[type="theme"] > section { - addon-card { - padding: 2px !important; - } - } - - .card-contents { - width: unset !important; - white-space: initial !important; - } - } - } + @media (min-width: 1200px) { + #full #content #main addon-list[type="extension"] > section { + grid-template-areas: "hd hd hd" "cd cd cd"; } - addon-page-header { - .sticky-container { - border-bottom: 4px solid #888888 !important; - position: relative !important; - margin-bottom: 20px !important; - margin: auto !important; - width: calc(100% - 80px) !important; - - .main-heading { - max-width: 100vw !important; - margin: auto !important; - width: 80% !important; - } - - .main-search { - max-width: 100vw !important; - justify-content: center !important; - gap: 30px !important; - } - } + #full #content #main addon-list[type="extension"] > section addon-card > div { + height: 80% !important; } } + + #full #content #main addon-list[type="theme"] > section addon-card { + padding: 2px !important; + } + + #full #content #main addon-list .card-contents { + width: unset !important; + white-space: initial !important; + } + + addon-page-header .sticky-container { + border-bottom: 1px solid var(--border-color, #88888840) !important; + position: relative !important; + margin-bottom: 20px !important; + } + + addon-page-header .sticky-container .main-heading { + max-width: 100vw !important; + margin: auto !important; + width: 80% !important; + } + + addon-page-header .sticky-container .main-search { + max-width: 100vw !important; + justify-content: center !important; + gap: 30px !important; + } } } diff --git a/preferences.css b/preferences.css index 40a0a00..71603fd 100644 --- a/preferences.css +++ b/preferences.css @@ -1,81 +1,88 @@ /* Making the sidebar in settings page compact and expand on hover */ +/* Rewritten for Zen 1.21+ / new Firefox settings sidebar: the old + `vbox.navigation` + richlist markup was replaced by the shadow-DOM + component. It exports no CSS parts, + so shadow internals are unreachable from a user sheet. -@media -moz-pref("compact-settings.enabled") { - @-moz-document url-prefix("about:preferences"), url-prefix("about:settings") { - #preferences-stack { - vbox.navigation { - position: absolute !important; - height: 100vh !important; - z-index: 20 !important; - width: auto !important; - padding: 10px !important; + Approach: labels stay rendered in BOTH states and the host width + does all the work. Collapsed width sits in the gap between icon + and label (icon ends 37.25px, text starts 48.5px), so labels are + fully clipped by overflow: hidden without hiding them. Because nothing about the + text ever changes, row heights are identical in both states and + the expand/collapse is a single smooth width animation. + (Do NOT hide labels with font-size: 0 — the label line box is + taller than the icon, so rows compress ~3px and the list crawls + during the transition. Do NOT use color: transparent — icon fills + ride currentColor and vanish.) - #searchInput, - #categories, - vbox.sidebar-footer-list { - @media -moz-pref("compact-settings.animation.enabled") { - transition: width 150ms ease-in-out !important; - } - width: 40px !important; - white-space: nowrap !important; - } - - #categories, - vbox.sidebar-footer-list { - overflow-x: hidden !important; - } - - .sidebar-footer-label { - @media -moz-pref("compact-settings.animation.enabled") { - transition: opacity 150ms ease-in-out !important; - } - opacity: 0 !important; - } - - #searchInput { - margin: 20px 0 !important; - padding-left: 12px !important; - } + The "Settings" heading is sized by the --font-size-xlarge custom + property (inherits across the shadow boundary); it stays hidden in + both states since it cannot be animated from out here — the logo + remains as the top anchor. */ - #categories { - margin: 0 !important; - padding: 0 !important; - .category { - margin-left: 10px !important; - padding: 0 8px !important; - width: 250px !important; +@media -moz-pref("compact-settings.enabled") { + @-moz-document url-prefix("about:preferences"), url-prefix("about:settings") { + #preferences-stack #categories { + position: fixed !important; + inset-inline-start: 0 !important; + top: 0 !important; + height: 100vh !important; + z-index: 20 !important; + box-sizing: border-box !important; + /* 8px host padding gives icons air from the window edge; icon spans + 19.25–35.25px, center 27.25 = strip center at 54px width. The strip + must stay wider than the heading row's natural width (~51px: padding + + logo 32 + margin 3.25 + flex gap 7.5) or the logo div flex-shrinks + when collapsed and its centered background drifts left. Label text + starts at 46.5px — the fade mask below hides that sliver. */ + width: var(--cs-strip-w, 54px) !important; + overflow: hidden !important; + margin-inline-start: 0 !important; + padding-inline-start: 8px !important; + /* the component's own padding-inline-end (7.5px) shrinks the content + box below the heading row's natural width and the logo squishes + again — drop it while collapsed (right side is clipped anyway) */ + padding-inline-end: 0 !important; + background: var(--in-content-page-background, var(--zen-branding-bg)) !important; + --font-size-xlarge: 0px; + /* fade out the label sliver: logo ends at 43.25px, text starts at + 46.5px — the ramp lives in that window (text ≤14% opacity) */ + mask-image: linear-gradient(to right, black 43px, transparent 47px) !important; - &[selected="true"] { - color: var(--zen-primary-color) !important; - } - } - } + @media -moz-pref("compact-settings.animation.enabled") { + /* decelerate curve: fast start, soft landing — shadow fades with it; + prefers-reduced-motion zeroes --cs-anim (see userContent.css) */ + transition: width var(--cs-anim, 180ms cubic-bezier(0.2, 0, 0, 1)), + box-shadow var(--cs-anim, 180ms cubic-bezier(0.2, 0, 0, 1)) !important; + } - vbox.sidebar-footer-list { - margin-left: 13px !important; - .sidebar-footer-icon { - margin: 0 8px !important; - scale: 1.4 !important; - } + moz-page-nav-button { + width: 225px !important; - .sidebar-footer-label { - font-size: 16px !important; - } + &[selected] { + color: var(--cs-accent, var(--zen-primary-color)) !important; } + } - &:has(#searchInput:focus), - &:hover { - #categories, - #searchInput, - .sidebar-footer-list { - width: 250px !important; - } - - .sidebar-footer-label { - opacity: 1 !important; - } - } + /* hover-only expand: :focus-within would pin the sidebar open after + clicking a category (the button keeps focus), and the components + don't delegate focus, so keyboard-only (:focus-visible) detection + can't cross the shadow boundary */ + &:hover { + width: var(--cs-flyout-w, 250px) !important; + mask-image: none !important; + padding-inline-end: var(--space-small, 7.5px) !important; + /* elevation: the flyout floats OVER content — shadow says so; + a mere border reads as the layout itself shifting */ + box-shadow: var(--cs-elevation, + 0 0 0 1px color-mix(in srgb, currentColor 12%, transparent), + 6px 0 24px -8px rgba(0, 0, 0, 0.25)) !important; } } + + /* keep content clear of the collapsed strip */ + #preferences-stack .main-content { + margin-inline-start: var(--cs-content-offset, 66px) !important; + } } } diff --git a/theme.json b/theme.json index 65f5f6b..2d570a1 100644 --- a/theme.json +++ b/theme.json @@ -4,8 +4,8 @@ "name": "Compact Settings", "description": "Make settings and addons sidebar compact", "author": "Bibek Bhusal", - "version": "1.0.4", - "updatedAt": "2026-06-20", + "version": "1.1.0", + "updatedAt": "2026-07-17", "tags": [ "Settings", "Compact", diff --git a/userContent.css b/userContent.css index 7754dcf..566d859 100644 --- a/userContent.css +++ b/userContent.css @@ -1,2 +1,24 @@ @import "preferences.css"; @import "addons.css"; + +/* Shared design tokens for both sidebars. Inert on other pages (prefixed, + unused); custom properties inherit across the moz-page-nav shadow + boundary. Both stylesheets carry literal fallbacks so they still work + imported standalone. */ +@-moz-document url-prefix("about:preferences"), url-prefix("about:settings"), url-prefix("about:addons") { + :root { + --cs-strip-w: 54px; + --cs-flyout-w: 250px; + --cs-content-offset: 66px; + --cs-anim: 180ms cubic-bezier(0.2, 0, 0, 1); + --cs-elevation: 0 0 0 1px color-mix(in srgb, currentColor 12%, transparent), + 6px 0 24px -8px rgba(0, 0, 0, 0.25); + --cs-accent: var(--zen-primary-color, var(--color-accent-primary)); + } + + @media (prefers-reduced-motion) { + :root { + --cs-anim: 0s; + } + } +}