60a321e6f4989fd623aadcab546fbd1548cbc3ce
8
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9b2fa80ab7 |
Drop the product branding: this is just Settings
It is the system settings app for this desktop, so it is named the way one is. The window is "Settings", the titlebar is "Settings", the wordmark above the search field is gone, the sidebar's last row is "About", and the status line reads "Desktop is healthy". Prose followed the same rule. Forty-odd strings explained what "Panama" does -- "Panama never animates while idle", "Restore Panama defaults", "Panama looks in ~/Pictures/Wallpapers" -- which is how a product describes itself, not how a settings panel describes a setting. They now say what happens. No user-visible "Panama" remains anywhere in the app. Two consequences worth naming: The SUPER+I shortcut's description is user-visible, because the Shortcuts page is generated from it, so that is renamed too. Rebindings are keyed by shipped chord rather than description, so no existing override is orphaned by this. Three contracts matched the window by title and one matched that shortcut by description; all four are updated. There are no Hyprland window rules keyed on the title, so nothing about the window's placement changes. The desktop entry is now Name=Settings, but the FILE keeps its panama-settings name, as does the icon: the dock pins applications by desktop id, and renaming the file would silently unpin it. dock-pins-contract covers exactly that. The dated design docs under docs/superpowers keep the old name. They are a record of what was decided when, and editing them to agree with the present would make them lie about the past. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L |
||
|
|
9c574f9eb7 |
Add a light mode that keeps the same identity
Light is Tokyo Night Day, the palette's own light variant, rather than one invented to merely not be dark. Both share the same hues at different lightness, which is what lets the Prism signature survive the switch: blue still leads into orchid, it is simply a darker blue on a lighter ground. Every colour token became a binding on one boolean, so flipping it repaints the whole shell without any component needing to know it happened. That only worked because nothing outside Theme.qml defines a colour; the two places that did are fixed here. Surface alphas differ by scheme. The 0.34 that reads as glass over a dark desktop reads as haze over a light one, and text stops being legible on it. Two things that draw on this desktop do not read Panama's store: GTK applications, which read gsettings, and the compositor, which draws window borders. A toolbar or a border still wearing the other scheme is more jarring than either scheme on its own, so ColorScheme pushes the choice to both. It also pushes at startup, since a scheme chosen in a previous session would otherwise be in effect only for the shell. The unfocused window border follows too. It is a flat neutral, and a dark neutral is invisible against a light desktop. The focused border is the prism gradient and needs no variant. The live preview follows the scheme as well. A preview that stayed dark while the shell around it went light did not read as "your desktop", it read as a screenshot of someone else's. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L |
||
|
|
d1b2cd2083 |
Make typography choosable instead of hardcoded
Theme.qml was the largest remaining thing in this desktop that could only be changed by editing a file, and typeface is the first thing someone changes when they want a desktop to feel like theirs. Interface font, icon font, and the base text size are settings now. The two font choices are deliberately separate lists. Theme.fontMono is used only to draw glyphs -- workspace pills, the status cluster, search icons -- so a plain monospace family there replaces every icon in the shell with tofu. The picker offers only Nerd Fonts for that slot and says why. Candidates are rendered in the family they name. A list of font names set in the current font tells you nothing about what you are choosing. The four type sizes derive from the base rather than being stored separately, so the relationship between body, caption, heading and title survives a change instead of four numbers drifting apart. hypr/looks.lua reads the same key. Following the preference only on the QML side would leave the compositor and the shell disagreeing about the interface font, which nobody notices until a tooltip renders in a different typeface. Only a family this machine reports is accepted: the value reaches hl.config as a string, and a settings file moved between machines will name fonts that are not installed. A missing family is reported rather than silently substituted by fontconfig. Also collapses the wallpaper grid to two rows. Sixty tiles is two screens of pictures on a page that also holds typography, window geometry and effects -- everything below it was unreachable without scrolling past all of them. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L |
||
|
|
d18fe51553 |
Make the weather location and graphics device choosable
The last two values that could only be changed by editing a file. Weather was pinned to hardcoded coordinates, so the card could not be pointed anywhere else. It is a location search now, not latitude and longitude fields: nobody knows their own coordinates, and a control that demands them is one nobody uses. Open-Meteo's geocoding endpoint needs no key, the same reason the forecast already uses them. Only the search term leaves the machine -- the stored place name is a label -- and coordinates are rounded to four decimals, far finer than a weather reading resolves and coarse enough to keep a precise home location out of the settings file. The graphics readout was hardcoded to card1. This machine has two amdgpu cards, discrete and integrated, so that was right only by luck, and the path is meaningless on any other machine. GPUs are enumerated with a readable name from lspci, since sysfs exposes only numeric ids, and the picker appears only when there is more than one to choose between. A stored path the machine does not have is refused and reported rather than silently measuring nothing. Also merges the per-application notification rules UI. Its three commits were believed integrated but the page half was not actually in the tree: main had the service side in Notifs.qml and zero references to setAppRule in NotificationsPage. Ancestry is not content. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L |
||
|
|
2bc12e6022 |
Add wallpaper, power, date, accessibility, and real search
Continues the settings expansion toward replacing GNOME Settings for everything Panama actually owns. Wallpaper. A thumbnail grid rather than a path field: the value of this setting is the picture, so typing a path to something you cannot see is the worst version of it. Two things about hyprpaper 0.8 shaped this. Its IPC is much smaller than older documentation suggests -- preload, listloaded, unload, and reload all answer "invalid hyprpaper request", so setting is a single call with no preload. And the "<empty>,<path>" form that used to mean every output is silently ignored, so a wallpaper set that way appears to succeed and never changes; outputs are walked explicitly instead. hyprpaper.conf lives in the repo through the ~/.config/hypr symlink and so cannot hold machine state, which is why the choice lives in the shared settings store and is re-applied at startup. Power & Lock. hypridle has no IPC for reconfiguration and its config is hyprlang rather than the shared JSON, so scripts/panama-idle generates a config from the settings store and restarts the daemon. The generated file lives under XDG_STATE_HOME for the same symlink reason, with a systemd drop-in pointing hypridle at it. Management is a real state and the page says which one you are in rather than showing sliders that quietly do nothing. Zero means never for all three timers, which a naive template would render as "immediately". Date & Time. Deliberately not stored in Panama's settings: the timezone and network time belong to the machine and are shared with sessions that never see this file. Storing a copy would create a second answer to a question the system already answers. Reads and writes timedatectl directly; a cancelled polkit prompt surfaces as an error rather than as a value that appears to have been accepted. Accessibility. Pointer size and text scale have to agree across three consumers with no shared configuration -- the compositor, GTK, and the shell -- so the store is the source of truth and the values are pushed outward to gsettings and hyprctl setcursor. Search now indexes the schema instead of the twelve page labels. "gaps", "wallpaper", and "screenshot" previously found nothing on an app that has all three, which is the clearest way a settings app feels smaller than it is. Shortcuts are indexed by what they do. A contract asserts every non-internal schema label is reachable, so a new setting cannot be added in an undiscoverable state. The GNOME delegation allow-list was widened to the panel names gnome-control-center actually reports; the previous list contained "users", which is not one of them and so opened nothing. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L |
||
|
|
fe7c85e471 |
Build the settings vocabulary and generate the keymap
Stage 3 and 4 of docs/superpowers/plans/2026-08-17-panama-cohesion.md. Add SettingsPage plus ToggleRow, SliderRow, ChoiceRow, ActionRow, and TextRow. A row names a schema key and needs nothing else: label, detail, range, and unit come from PreferenceSchema, and writes go through SystemSettings.commitPreference, which routes compositor-backed keys through apply-and-verify and local keys straight to the store. The page scaffold that was copy-pasted eleven times is now one component. Rebuild Appearance around a live preview of the real desktop, scaled by the ratio between the preview and the actual monitor so a 10px gap on a 4500px display looks as small as it is. Rebuild Desktop & Dock and Input & Shortcuts on the shared rows, replacing the read-only text that stood in for controls that were merely expensive to add. Generate the shortcut list from hyprctl binds. The page held a hand-typed nineteen entries against a real keymap of a hundred and thirteen; it could not show the rest and went stale whenever a bind changed. Every bind now carries its own description -- backfilled for the twenty-nine that lacked one -- and keybinds-contract.sh fails if any bind lacks one, since undescribed binds are dropped from the page. Make Restore defaults span every store Panama owns. Resetting only the schema store left the Home accessory arrangement customised while claiming to restore defaults, which is worse than no reset because it is silent. Done through HomePreferences' existing public aliases rather than a new API. Four defects found while building: cursor:inactive_timeout is answered by getoption as float, not int. A wrong readAs does not fail loudly; it makes every write to that key look rejected, and the user saw an error for a change that worked. schema-hypr-shape-contract.sh now checks all 23 mapped options against the running compositor. The Settings window is tiled, so implicitWidth is only a hint and rows must survive roughly 400px. SliderRow stacks its control under the label below 520px. Binding an anchor to undefined to switch layouts does not reliably release it. Both row layouts are positioned explicitly. Concurrent compositor writes are queued and merged rather than refused. The startup replay of every compositor-backed preference routinely overlaps a UI change, and refusing left the store and the compositor disagreeing. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L |
||
|
|
00a81edadd |
Make Panama settings one shared source of truth
Panama had grown into three configuration surfaces that only agreed because they had been typed to agree: looks.lua hardcoded values, DesktopPreferences independently defaulted the same values, and SystemSettings replayed them at startup. Nothing kept them in sync, and the Lua side read no shared state at all. This lands the first three stages of docs/superpowers/plans/2026-08-17-panama-cohesion.md. Fix silently failing Hyprland writes. On a Lua-configured Hyprland, hyprctl keyword refuses the write, prints the refusal to stdout, and still exits 0, so the HDR, VRR, and direct-scanout toggles persisted their value and reported success while the compositor never changed. Writes now go through hyprctl eval, which has the same hazard on syntax and runtime errors, so success is defined as reading the value back and finding it equal. The existing contract passed throughout the outage because it re-applied the values already in place; the new one flips each value to something it does not hold. Derive preferences from a schema. Every setting used to be restated four times -- a property alias, a JSON adapter property, a change handler, and a line in reset -- where omitting any one failed silently. PreferenceSchema.qml is now the single source, and persistence, validation, reset, and the Hyprland mapping all derive from it. Unknown keys on disk survive a write so a rollback does not discard a newer build's settings, and a corrupt file falls back to shipped defaults. The store moved to ~/.config/panama/settings.json, migrating from the old state directory without deleting it. Share that file with Hyprland. prefs.lua reads it at config time with every shipped literal kept as the fallback, so the config still stands alone. The Lua is the default, the JSON is the truth, and Settings is the editor. The compositor-adjustable surface goes from 3 keys to 23. Also fixes two test-hygiene bugs found by running the suite end to end for the first time: settings-pages-contract could see the window settings-window-contract leaves behind, and the new write contract was persisting its deliberately-wrong values into the user's real store. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L |
||
|
|
5248883e4b | Build the Panama Hyprland desktop |