Files
Panama/config/dot/quickshell/modules/settings/AppearancePage.qml
T
Gabriel Brown 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
2026-08-18 10:08:55 -04:00

193 lines
7.2 KiB
QML

// Appearance — the page the rest of the settings vocabulary was built for.
//
// Before Stage 3 this page adjusted a clock format and three vitals toggles,
// and its "Theme" card was two rows of text pretending to be controls. It now
// drives the compositor directly: every row here is applied through
// `hyprctl eval` and confirmed by reading the value back before it is stored.
//
// The preview is pinned above the controls rather than sitting inline, because
// the numbers are meaningless on their own -- "outer gaps 24" only means
// something once you have watched the windows move apart by that much, at the
// scale of the display you actually use.
import QtQuick
import qs.config
import qs.services
SettingsPage {
id: root
title: "Appearance"
lede: "Drag anything below. The preview above is your real geometry, to scale."
header: Component {
Column {
spacing: 9
DesktopPreview {
width: parent.width
}
Text {
width: parent.width
horizontalAlignment: Text.AlignHCenter
text: SystemSettings.lastError !== ""
? SystemSettings.lastError
: "Live preview — the focused window wears the prism border"
color: SystemSettings.lastError !== "" ? Theme.warn : Theme.fgMuted
font.family: Theme.fontFamily
font.pixelSize: Theme.fontSizeSmall
elide: Text.ElideRight
}
}
}
SettingsCard {
title: "Background"
subtitle: Wallpaper.lastError !== ""
? Wallpaper.lastError
: "Applied to every display. Looked for in ~/Pictures/Wallpapers, ~/Pictures/Backgrounds, ~/.local/share/backgrounds, and /usr/share/backgrounds."
WallpaperPicker {
id: wallpapers
width: parent.width
}
ActionRow {
visible: wallpapers.hidden > 0 || wallpapers.expanded
label: wallpapers.expanded ? "Showing every image" : wallpapers.hidden + " more available"
detail: "The grid is kept short so the rest of this page stays reachable"
action: wallpapers.expanded ? "Show fewer" : "Show all"
onTriggered: wallpapers.expanded = !wallpapers.expanded
}
ActionRow {
label: "Look for new images"
detail: Wallpaper.scanning
? "Scanning…"
: Wallpaper.available.length + " image" + (Wallpaper.available.length === 1 ? "" : "s") + " found"
action: "Rescan"
divider: false
enabled: !Wallpaper.scanning
onTriggered: Wallpaper.rescan()
}
}
SettingsCard {
title: "Colour scheme"
subtitle: ColorScheme.lastError !== ""
? ColorScheme.lastError
: "Light is Tokyo Night Day, the official light variant — the same hues at a different lightness, so the blue-into-orchid signature survives the switch. Applications and window borders follow."
ChoiceRow { setting: "colorScheme"; divider: false }
}
SettingsCard {
title: "Typography"
subtitle: Fonts.lastError !== ""
? Fonts.lastError
: "Every piece of text in the shell. Samples are drawn in the font they name."
SliderRow { setting: "interfaceFontSize" }
TextRow {
label: "Interface font"
detail: Fonts.interfaceMissing
? "Not installed on this machine — fontconfig is substituting something else"
: "Used for all shell text"
value: Fonts.interfaceFont
}
FontPicker {
width: parent.width
families: Fonts.interfaceFonts
current: Fonts.interfaceFont
emptyText: Fonts.scanning ? "Reading installed fonts…" : "No interface fonts found"
onPicked: family => Fonts.setInterface(family)
}
TextRow {
label: "Icon font"
detail: Fonts.iconMissing
? "Not installed — the shell's glyphs will not draw correctly"
: "Draws the shell's glyphs, so only Nerd Fonts are offered"
value: Fonts.iconFont
}
FontPicker {
width: parent.width
families: Fonts.iconFonts
current: Fonts.iconFont
emptyText: "No Nerd Fonts installed"
onPicked: family => Fonts.setIcon(family)
}
}
SettingsCard {
title: "Windows"
subtitle: "Spacing and shape of tiled windows. Each change is applied to the compositor and confirmed before it is saved."
SliderRow { setting: "windowRounding" }
SliderRow { setting: "gapsIn" }
SliderRow { setting: "gapsOut" }
SliderRow { setting: "borderSize"; zeroLabel: "None" }
SliderRow { setting: "inactiveOpacity"; divider: false }
}
SettingsCard {
title: "Effects"
subtitle: "Each of these costs frame time. Turning one off is a legitimate way to buy it back while gaming."
ToggleRow { setting: "blurEnabled" }
SliderRow { setting: "blurSize" }
SliderRow { setting: "blurPasses" }
ToggleRow { setting: "shadowEnabled" }
SliderRow { setting: "shadowRange"; zeroLabel: "None" }
ToggleRow { setting: "glowEnabled" }
SliderRow { setting: "glowRange"; zeroLabel: "None" }
ToggleRow { setting: "animationsEnabled"; divider: false }
}
SettingsCard {
title: "Clock"
ToggleRow { setting: "use24Hour" }
ToggleRow { setting: "showSeconds" }
ToggleRow { setting: "showWeekday"; divider: false }
}
SettingsCard {
title: "System vitals"
subtitle: "Choose what appears beside the workspace indicator."
ToggleRow { setting: "showCpu" }
ToggleRow { setting: "showMemory" }
ToggleRow { setting: "showGpu"; divider: GraphicsDevices.devices.length > 1 || GraphicsDevices.selectionMissing }
// Only worth asking when there is a choice to make.
ChoiceGrid {
visible: GraphicsDevices.devices.length > 1 || GraphicsDevices.selectionMissing
width: parent.width
label: "Graphics device"
detail: GraphicsDevices.selectionMissing
? "The stored device is not present on this machine, so the graphics readout is hidden. Choose one below."
: "Which GPU the graphics readout measures."
options: GraphicsDevices.devices.map(device => ({
value: device.path,
label: GraphicsDevices.shortName(device.name)
}))
current: GraphicsDevices.selectedPath
divider: false
onPicked: value => GraphicsDevices.select(value)
}
}
SettingsCard {
title: "Theme"
subtitle: "This desktop has one curated visual identity rather than a matrix of partially compatible themes. The controls above adjust its parameters — how much space, how soft, how much motion — without replacing it."
TextRow { label: "Color palette"; detail: "Tokyo Night Moon"; value: "Prism" }
TextRow { label: "Interface type"; detail: "Adwaita Sans"; value: "System"; divider: false }
}
}