aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/specs/2026-09-17-sddm-theme-udt-panel-design.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/superpowers/specs/2026-09-17-sddm-theme-udt-panel-design.md')
-rw-r--r--docs/superpowers/specs/2026-09-17-sddm-theme-udt-panel-design.md238
1 files changed, 238 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-09-17-sddm-theme-udt-panel-design.md b/docs/superpowers/specs/2026-09-17-sddm-theme-udt-panel-design.md
new file mode 100644
index 0000000..3a87677
--- /dev/null
+++ b/docs/superpowers/specs/2026-09-17-sddm-theme-udt-panel-design.md
@@ -0,0 +1,238 @@
+# sddm-theme-udt, Left Panel Redesign
+
+Date: 2026-09-17
+Status: approved, not yet implemented
+
+This spec supersedes the greeter layout and interaction sections of
+`2026-09-17-sddm-theme-udt-design.md` (the centered login card, its single
+password flow and its power bar placement). Every other decision there, the
+palette, the live `theme.conf.user` tracking, the per-window screen model, the
+idle fade, the security model and the colour names, still stands.
+
+## Goal
+
+Replace the centered login card with a full-height panel pinned to the left
+edge, about 30% of the screen width, blurred underneath. Top to bottom the
+panel carries a clock and date, a configurable greeting, the avatar, a single
+credential slot that advances from username to password, a row of power
+buttons, and the session selector pinned to the bottom. The power button icons
+follow the icon theme selected in the `appearance` drawer instead of the four
+bundled SVGs, falling back to the bundled set when the theme has no match.
+
+## Problem
+
+The current greeter is one card floating in the middle of the screen. It shows
+username and password side by side, which is more fields than the flow needs,
+and its power icons are fixed line art that does not match the desktop's
+selected icon theme. The user asked for a left panel with a staged login and
+theme-following power icons.
+
+## Decisions
+
+1. **Left panel, flush, square.** The panel is anchored to the left, top and
+ bottom edges of its greeter window, `panelWidth` of the window width, with
+ no rounded corners and no left margin. A 2px `accent` border runs along the
+ exposed edges. The background under it is frosted with the existing
+ `Backdrop` (wallpaper snapshot, blur, tint), masked to the panel rectangle
+ with radius 0. Rejected: a detached card with rounded corners and margins
+ (the user asked for a panel flush to the edge and without rounding).
+
+2. **One credential slot, two stages.** A single field slot shows the username
+ first. Confirming it slides the username out to the left and the password in
+ from the right. Confirming the password logs in. The two fields are never
+ visible at once, so the slot reads as one control that advances. Rejected:
+ keeping both fields stacked (the behaviour the redesign replaces).
+
+3. **Touch-reachable confirm and back.** Besides Enter, each stage has a
+ confirm arrow button. The password stage also shows a back chevron that
+ returns to the username, keeping its text. Rejected: Enter-only (a touch
+ user could not advance) and Esc-only back (the same, for touch).
+
+4. **Power icons resolved by `udt-accent` from gsettings.** The icon theme name
+ is read from `org.gnome.desktop.interface icon-theme` while `udt-accent` runs
+ as the login user. Absolute paths to the four resolved SVGs are written into
+ the generated `~/.local/share/udt/sddm-theme.conf`, next to the palette, so
+ the greeter stays data-only and never reads a file. Empty values fall back to
+ the bundled `theme/icons/*.svg`. Rejected: reading `qt6ct.conf` or gsettings
+ from inside the greeter (the greeter runs as `sddm`, has no `QML` file-read
+ API and no user dconf); resolving FreeDesktop icon lookup in QML (fragile,
+ and the theme spec's decision 1 already closed the file-read path).
+
+5. **Icon theme switching is picked up on the next `udt-accent` run.** A
+ wallpaper change already runs it. Switching the icon theme in the drawer
+ does not, so a manually triggered `udt-accent` is needed until the drawer is
+ wired to call it. Recorded as a TODO in the quickshell repository rather than
+ solved here.
+
+6. **Kept from the original design.** Palette and live tracking through
+ `theme.conf.user`; one greeter window per screen with the panel shown only
+ where `uiScreen` matches, else on the primary window; the 1s clock is the
+ only new timer; `fadeoutMs` idle hide and input wake; `blur`;
+ `EnableAvatars`; the security argument that the only user-writable input is
+ INI data.
+
+## Architecture
+
+```
+wallpaper change
+ wallp -> udt-accent <image>
+ extracts + snaps accent, reads gsettings icon-theme,
+ resolves the four power icon paths, then writes
+ ~/.local/share/udt/sddm-theme.conf (0644, world-readable)
+ palette keys
+ powerIcon / rebootIcon / suspendIcon / hibernateIcon
+ (absolute paths, empty when unresolved)
+
+greeter start (as sddm), one window per screen
+ reads theme.conf + theme.conf.user into `config`
+ wallpaper fills the window
+ panel, blurred, on the uiScreen window only
+```
+
+The root install block is unchanged. Re-running the root copy is only needed
+when theme code changes.
+
+## Panel layout
+
+Anchored inside the panel (`panelWidth` wide, 32px horizontal padding):
+
+| position | element | detail |
+| --- | --- | --- |
+| top | time | `Text`, `timeFormat` (default `HH:mm`), large |
+| | date | `Text`, `dateFormat` (default `dddd, d MMMM`), `subtext0` |
+| | greeting | `Text`, `greeting` (default `hello there`) |
+| | avatar | 96px circle, `accent` ring, face from `userModel`, initials fallback, centered |
+| | credential slot | one field, staged, with confirm arrow and back chevron |
+| | message | login failure (`red`) or Caps Lock hint (`yellow`) |
+| flexible gap | | |
+| bottom | power row | four buttons, centered, ~40px icons on 56px targets |
+| bottom | session selector | full panel width, pinned to the bottom edge |
+
+The clock refreshes from a 1s `Timer` into a `now` property, formatted with
+`Qt.formatDateTime(now, fmt)`.
+
+## Credential flow
+
+- `stage` is `user` or `pass`.
+- `user`: username field prefilled with `userModel.lastUser`; the avatar
+ reflects the current text. Confirm with Enter or the arrow, ignored when
+ empty, advances to `pass`.
+- Transition: username slides to `-slot.width` and fades, password slides from
+ `slot.width` to 0, 220ms `OutCubic`. The slot clips. The avatar remains and
+ follows the confirmed username.
+- `pass`: password field focused. Confirm with Enter or the arrow calls
+ `sddm.login(username, password, sessionBox.currentIndex)`.
+- Back: Esc on the password field or the back chevron returns to `user` and
+ keeps the username; the password is cleared.
+- Failure: `sddm.loginFailed` clears the password, shows `Login failed` in
+ `red`, shakes the panel, and stays in `pass`. Caps Lock shows in `yellow`.
+- Idle hide and wake are unchanged; wake focuses the field for the current
+ stage.
+
+## Config
+
+Added to the root `theme.conf` with these defaults, overridden live in the
+generated `theme.conf.user`:
+
+| key | default | meaning |
+| --- | --- | --- |
+| `panelWidth` | `0.30` | panel width as a fraction of the window width |
+| `timeFormat` | `HH:mm` | Qt time format string |
+| `dateFormat` | `dddd, d MMMM` | Qt date format string |
+| `greeting` | `hello there` | greeting line |
+| `powerIcon` | (empty) | absolute path to the shutdown icon |
+| `rebootIcon` | (empty) | absolute path to the restart icon |
+| `suspendIcon` | (empty) | absolute path to the sleep icon |
+| `hibernateIcon` | (empty) | absolute path to the hibernate icon |
+
+Unchanged: the palette keys, `uiScreen`, `fadeoutMs`, `blur`.
+
+`udt-accent` gains the four icon keys in its emitted key list and writes the
+resolved paths. `theme.conf` keeps them empty so a missing or unreachable icon
+falls back to the bundled SVG.
+
+## Icon resolution in `udt-accent`
+
+1. Read the icon theme name:
+ `gsettings get org.gnome.desktop.interface icon-theme`, strip quotes. An
+ empty or failed read leaves every icon key empty.
+2. FreeDesktop names, with fallbacks:
+ - shutdown: `system-shutdown`
+ - restart: `system-reboot`
+ - sleep: `system-suspend`
+ - hibernate: `system-hibernate`, then `system-suspend-hibernate`
+3. Search `~/.local/share/icons/<theme>` then `/usr/share/icons/<theme>` for
+ `<name>.svg` or `<name>-symbolic.svg`. Prefer a `symbolic` hit, then the
+ largest size directory; a plain recursive search with that ordering is
+ enough and avoids parsing `index.theme`.
+4. Write the absolute path, or leave the key empty when nothing matches.
+
+Icons are drawn as a flat silhouette through the existing `MultiEffect`
+colorization (`subtext0`, `accent` on hover), so the theme icon contributes its
+shape; the UDT palette still supplies the colour.
+
+## Files touched
+
+This repository:
+
+- `theme/Main.qml`: swap `LoginCard` for `Panel`; panel geometry per window.
+- `theme/components/Panel.qml` (new): layout, clock, greeting, avatar, power
+ row, session selector, shake, idle wiring.
+- `theme/components/Credentials.qml` (new): the staged slot and its animation.
+- `theme/components/PowerBar.qml`: read the four config paths, bundled
+ fallback, larger targets.
+- `theme/components/LoginCard.qml`: deleted.
+- `theme/theme.conf`: new keys.
+- `README.md`: describe the panel and the new keys.
+
+Other repositories:
+
+- `unified-desktop-theme/bin/udt-accent`: add the four icon keys to the emitted
+ INI, add the resolver, extend `--selftest`.
+- `quickshell/TODO.md`: record that the appearance drawer should run
+ `udt-accent` when the icon theme changes, so the greeter follows without a
+ wallpaper change.
+
+## Testing
+
+- `unified-desktop-theme/bin/udt-accent --selftest`: the emitted INI contains
+ every key including the four icon keys; with a known theme name the resolver
+ returns an existing readable path for each icon; an unknown theme leaves the
+ keys empty. This is the runnable check for the new logic.
+- `sddm-greeter-qt6 --test-mode --theme <repo>/theme`: layout, blur, clock,
+ greeting, staged field, power icon shapes, session selector.
+- `sudo -u sddm test -r <resolved icon>` for one resolved path, confirming the
+ greeter user can read the theme's icons.
+- Confirm the generated INI still carries every palette key, so the palette
+ path is unregressed.
+
+## Risks
+
+- **Icon theme switch lag.** Until the quickshell TODO lands, a new icon theme
+ reaches the greeter at the next wallpaper change or manual `udt-accent` run.
+- **`gsettings` unavailable.** If the read fails, all four keys are empty and
+ the bundled icons draw. Cosmetic only.
+- **A theme without the expected names.** Some themes omit a symbolic variant
+ or use different names; the fallback list and the bundled set cover the
+ common cases, and the worst case is the bundled icon.
+- **`panelWidth` on very wide screens.** A 30% fraction can be wide. It is a
+ config key, so it can be lowered without a code change.
+- **Date locale in the greeter.** `Qt.formatDateTime` uses the greeter's
+ locale, which may be `C`. If the date must be localized, a future
+ `QLocale`-based format or a fixed numeric format can be added.
+- **Blur needs a working GL context**, as before; the tint alone still reads.
+
+## Out of scope
+
+- Wiring the appearance drawer to run `udt-accent` on icon change (TODO only).
+- Bundling or installing fonts.
+- Displays other than SDDM.
+- Light schemes and per-scheme artwork.
+
+## Development Approach
+
+This project is developed using AI-assisted tools. Code is generated with the help of AI based on human-provided specifications, design decisions, and iterative feedback.
+
+All contributions are reviewed, tested, and curated by the maintainer before being included in the codebase. AI is used as a productivity and exploration tool, while human oversight remains central to all decisions.
+
+The goal is to combine the flexibility of AI-assisted development with standard open-source practices such as transparency, review, and accountability.