Make Shell a category, the bar legible, and the dock a real dock

Desktop & Dock becomes Shell — Bar, Dock, Control Center, Tiling,
Workspaces — the home for everything Quickshell draws. The settings-
management cluster moves to System as Sync & Backup, Appearance's
Shell tab dissolves, and 24-hour time finally lives on Date & Time,
which always owned it.

The bar gets what it never had: a way to survive the wallpaper. A
second neutral text family (follow theme, or forced light or dark),
a one-layer shadow under every glyph, and a gradient scrim for
wallpapers nothing else survives — all off by default, pixel-identical
until asked. Widgets earn toggles (weather, media, clipboard, calendar
countdown), the vitals cluster stops leaving a dead pill behind, and
Control Center's sections learn to step aside.

The dock graduates from MVP: a context menu with window rows, pin,
unpin, quit and new-window; scroll an icon to cycle its windows; drag
to reorder on the dock itself; hover previews with one-shot captures;
and "Add App to Dock" in the launcher. Three real bugs died en route —
menus that slid away with the autohide, a readonly-property crash on
every menu open, and a drag that drifted half a slot per icon on side
docks. The pinned-apps editor in Settings becomes a drag strip.

166 contracts; the full suite is green except two live display and
switcher tests that cannot run behind a locked session — re-verified
on unlock.

Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
Gabriel Brown
2026-08-24 04:28:20 -04:00
parent 4d7a194300
commit f8f5b25510
77 changed files with 2982 additions and 800 deletions
@@ -80,12 +80,15 @@ Settings because Fedora's system services own those areas.
## Appearance
Six tabs, in the order the questions are actually asked: **Themes**, **Theme
editor**, **Background**, **Typography**, **Windows**, **Shell**. Themes leads
because light and dark is the control reached most often, and it used to be the
third section down, under a wallpaper grid and the whole lock screen. The old
`theme` section id still resolves to it, so deep links and IPC calls keep
working.
Five tabs, in the order the questions are actually asked: **Themes**, **Theme
editor**, **Background**, **Typography**, **Windows**. Themes leads because
light and dark is the control reached most often, and it used to be the third
section down, under a wallpaper grid and the whole lock screen. The old `theme`
section id still resolves to it, so deep links and IPC calls keep working.
The sixth tab, **Shell**, is gone: its two cards moved to **Shell Bar**, which
is where somebody who wants to change the bar now looks. Appearance answers what
the desktop looks like; Shell answers what the desktop *is*.
### Themes
@@ -145,6 +148,109 @@ and Panama's own Settings titlebar shows one button. `panamaTitlebar` turns
that bar off entirely, leaving the window pure Hyprland: Super+Q closes,
Super+drag moves, Escape still works.
## Shell
Everything Quickshell itself draws, in five tabs: **Bar**, **Dock**, **Control
Center**, **Tiling**, **Workspaces**. The category used to be **Desktop & Dock**,
a single page that held the dock alongside window layout, workspaces, and the
settings-management cluster — three unrelated subjects and a filing cabinet. Its
`desktop` id is retired to `bar`, so old deep links land on the first tab.
The split is by *surface*. If you can point at it on screen, it has a tab.
### Bar
The first settings surface the bar has ever had. Three cards.
**Visibility** exists because the bar is the one thing the shell draws that has
no ground of its own — it floats on the wallpaper, which the theme has never
seen. So a palette that is correct everywhere else can still be unreadable
exactly where the clock is. `barTextTone` (`theme`/`light`/`dark`) drives a
second neutral family in `Theme.qml``barFg`, `barFgDim`, `barFgMuted` — that
thirteen bar widgets bind to instead of `fg`/`fgDim`/`fgMuted`. Left on `theme`
the family *is* the fg family by identity, so nothing changes for anyone who
never asks, and a custom palette still reaches the bar. Semantic tones (warn,
danger, accent, ok) never became bar tones: a battery at 4% is red whatever the
neutrals were forced to.
`barTextShadow` and `barBackdrop` are the two escape hatches for a wallpaper no
tone wins against. The shadow is **one** `layer.effect` MultiEffect over the
whole of `Bar.qml`'s content rather than one per widget, so a widget added
tomorrow picks it up without opting in; the backdrop is a static top-down
gradient Rectangle behind the content rows. Both default off and both are read
from the preference — during the build they briefly landed as literal `true`,
which forced a dark band and an extra compositing layer on everyone.
`tests/quickshell/bar-visibility-contract` pins both bindings for that reason,
along with every widget's use of the bar tones.
**Widgets** is one toggle per thing that earns a place: weather, media,
clipboard, calendar countdown, the three vitals readouts, battery, agent usage.
Each toggle is **ANDed** with the widget's own state condition rather than
replacing it, so switching one on never conjures a pill with nothing in it.
State-driven indicators — health, activity, focus, video wallpaper — get no
toggle: they appear when they have something to say and leave when they are
done. `VitalsWidget` answers for its own pill as well as its three fields,
because an invisible child still occupies its Row and gating the fields alone
left a padded, empty pill in the bar.
**Clock** keeps `showSeconds` and `showWeekday`. `use24Hour` is *not* here: it
drives the date menu, notification timestamps, and the lock screen too, so it
moved to group `datetime` and lives on **System Date & Time**. The card says
so rather than leaving its absence looking like an oversight.
Right-clicking the vitals or agent-usage pill opens this page.
### Dock
Behavior — position, screens, autohide, reveal and hide delays, icon size —
unchanged. **Pinned applications** is now `DockPinsStrip.qml`: the dock's own
row of icons, resolved exactly the way the dock resolves them, drag to reorder,
hover for the unpin ×, `DockAppPicker` search underneath. It replaces a sixteen-
row list of names, which was honest but was not the thing being edited — the
order of a horizontal row of icons was being decided in a vertical column of
text.
Two details make the drag safe: `preventStealing` on the grabbing MouseArea, or
the page's Flickable claims the gesture and the icon never moves; and the order
is held in the strip while the drag runs and written **once** on release, rather
than rewriting `settings.json` a dozen times for one gesture. Every icon is also
a tab stop — Left and Right move it, Delete unpins it — because a drag is not
reachable from the keyboard.
The live dock gained the matching gestures: drag to reorder on the dock itself,
a right-click menu (window rows, pin, unpin, quit, new window, and a **Dock
settings** entry that deep-links here), scroll an icon to cycle its windows, and
hover previews from `DockPreviews.qml`. `DockPickOverlay.qml` plus the `dock`
IPC target back the launcher's **Add App to Dock** command, so pinning never
requires opening Settings at all.
### Control Center
The quick settings panel's first settings surface. **Sections** is one
`ccShow*` bool per real section of `QuickSettingsPanel` — Focus, Home, Phone —
and only for sections that actually exist; a toggle for a section the panel does
not draw is a control that writes a preference nothing reads. Turning one off
hides it from the panel and stops nothing: the page behind it still works.
**Accessories** is a labeled handoff to Home My Home rather than a second copy
of the shelf editor.
### Tiling and Workspaces
Rows moved unchanged. Tiling holds window layout (with the handoff to Appearance
Windows for gaps, corners, and effects), master and stack, window edges, and
the Hyprland notices. Workspaces holds the workspace and focus toggles, focus
session length, and Projects.
## System Sync & Backup
`SyncPage.qml`, the tenth tab of System: **Carry settings to another machine**
(`SettingsSync`), **Settings backups** (`SettingsBackup`), and **Reset**. It was
the settings-management cluster on the old Desktop page, which is the one thing
on that page that was never a surface. Backups is titled that way deliberately
so it stops colliding with the btrfs **Snapshots** tab one along — the two mean
different things and used to share a word. The search index's **Restore
defaults** entry points here.
## Adding a setting
One schema entry. That is the whole job.