Build the Panama Hyprland desktop

This commit is contained in:
Gabriel Brown
2026-08-17 10:32:55 -04:00
parent 67033f2a31
commit 5248883e4b
190 changed files with 18554 additions and 34 deletions
@@ -0,0 +1,120 @@
pragma Singleton
// User choices that Panama Settings may change at runtime. This is deliberately
// separate from Settings.qml: the latter remains the stable public surface used
// by the shell, while this object owns durable mutation and shipped defaults.
import Quickshell
import Quickshell.Io
import QtQuick
Singleton {
id: root
property alias use24Hour: values.use24Hour
property alias showSeconds: values.showSeconds
property alias showWeekday: values.showWeekday
property alias showCpu: values.showCpu
property alias showMemory: values.showMemory
property alias showGpu: values.showGpu
property alias dockAutohide: values.dockAutohide
property alias dockRevealDelayMs: values.dockRevealDelayMs
property alias dockHideDelayMs: values.dockHideDelayMs
property alias focusDurationMinutes: values.focusDurationMinutes
property alias autoHdr: values.autoHdr
property alias vrrPolicy: values.vrrPolicy
property alias directScanoutPolicy: values.directScanoutPolicy
property alias nightLightEnabled: values.nightLightEnabled
property alias nightLightAutomatic: values.nightLightAutomatic
property alias nightLightTemperature: values.nightLightTemperature
property alias lastPage: values.lastPage
FileView {
id: preferencesFile
path: Quickshell.stateDir + "/panama-settings.json"
blockLoading: true
printErrors: false
atomicWrites: true
JsonAdapter {
id: values
property bool use24Hour: false
property bool showSeconds: true
property bool showWeekday: true
property bool showCpu: true
property bool showMemory: true
property bool showGpu: true
property bool dockAutohide: true
property int dockRevealDelayMs: 0
property int dockHideDelayMs: 250
property int focusDurationMinutes: 45
property bool autoHdr: true
property int vrrPolicy: 3
property int directScanoutPolicy: 2
property bool nightLightEnabled: false
property bool nightLightAutomatic: false
property int nightLightTemperature: 3500
property string lastPage: "home"
}
}
// Listen after the adapter has been constructed instead of writing from
// FileView.onAdapterUpdated. The latter also fires for default-property
// initialization, which can overwrite a valid file before it is loaded.
Connections {
target: values
function onUse24HourChanged(): void { persistTimer.restart(); }
function onShowSecondsChanged(): void { persistTimer.restart(); }
function onShowWeekdayChanged(): void { persistTimer.restart(); }
function onShowCpuChanged(): void { persistTimer.restart(); }
function onShowMemoryChanged(): void { persistTimer.restart(); }
function onShowGpuChanged(): void { persistTimer.restart(); }
function onDockAutohideChanged(): void { persistTimer.restart(); }
function onDockRevealDelayMsChanged(): void { persistTimer.restart(); }
function onDockHideDelayMsChanged(): void { persistTimer.restart(); }
function onFocusDurationMinutesChanged(): void { persistTimer.restart(); }
function onAutoHdrChanged(): void { persistTimer.restart(); }
function onVrrPolicyChanged(): void { persistTimer.restart(); }
function onDirectScanoutPolicyChanged(): void { persistTimer.restart(); }
function onNightLightEnabledChanged(): void { persistTimer.restart(); }
function onNightLightAutomaticChanged(): void { persistTimer.restart(); }
function onNightLightTemperatureChanged(): void { persistTimer.restart(); }
function onLastPageChanged(): void { persistTimer.restart(); }
}
// Singleton construction can happen after FileView's preload phase when a
// test or a lazy page first references it. An explicit reload makes the
// durable state authoritative in that case as well as in the main shell.
Component.onCompleted: preferencesFile.reload()
// Coalesce a group of UI changes into one atomic write. Writing from the
// adapter's change signal itself can race a second property assignment and
// reload the older value before the batch has finished.
Timer {
id: persistTimer
interval: 0
onTriggered: preferencesFile.writeAdapter()
}
function resetDesktopDefaults(): void {
values.use24Hour = false;
values.showSeconds = true;
values.showWeekday = true;
values.showCpu = true;
values.showMemory = true;
values.showGpu = true;
values.dockAutohide = true;
values.dockRevealDelayMs = 0;
values.dockHideDelayMs = 250;
values.focusDurationMinutes = 45;
values.autoHdr = true;
values.vrrPolicy = 3;
values.directScanoutPolicy = 2;
values.nightLightEnabled = false;
values.nightLightAutomatic = false;
values.nightLightTemperature = 3500;
values.lastPage = "home";
}
}
+104
View File
@@ -0,0 +1,104 @@
pragma Singleton
// ─────────────────────────────────────────────────────────────────────────────
// User-facing knobs. Everything here is something you might reasonably want to
// change without understanding the rest of the shell.
//
// Theme.qml holds *how it looks*; this holds *what it does*.
// ─────────────────────────────────────────────────────────────────────────────
import Quickshell
import QtQuick
Singleton {
id: root
// ── Clock ───────────────────────────────────────────────────────────────
// Carried over from GNOME: 12-hour, weekday + date shown, seconds on.
readonly property bool use24Hour: DesktopPreferences.use24Hour
readonly property bool showSeconds: DesktopPreferences.showSeconds
readonly property bool showWeekday: DesktopPreferences.showWeekday
// ── Weather ─────────────────────────────────────────────────────────────
// Coordinates taken from the GNOME night-light setting, which had already
// resolved the location. Uses Open-Meteo, which needs no API key.
readonly property real latitude: 27.7375
readonly property real longitude: -82.6861
// Open-Meteo returns coordinates but no friendly place name. Keep the
// label deliberately general rather than exposing precise coordinates in
// the UI or guessing at a city from them.
readonly property string weatherLocation: "Local weather"
readonly property string temperatureUnit: "fahrenheit"
readonly property int weatherRefreshMinutes: 20
// ── Vitals ──────────────────────────────────────────────────────────────
// The GNOME Vitals extension showed processor usage, memory usage and GPU
// usage, in that order. Same here.
readonly property int vitalsIntervalMs: 2000
readonly property bool showCpu: DesktopPreferences.showCpu
readonly property bool showMemory: DesktopPreferences.showMemory
readonly property bool showGpu: DesktopPreferences.showGpu
// amdgpu exposes utilisation here. Verified present on this machine; the
// widget hides itself if the path is missing rather than showing zeros.
readonly property string gpuBusyPath: "/sys/class/drm/card1/device/gpu_busy_percent"
// ── Night light ─────────────────────────────────────────────────────────
// Matches the (disabled) GNOME schedule: 3500K from 17:00 to 10:00.
readonly property int nightLightTemperature: DesktopPreferences.nightLightTemperature
readonly property real nightLightFrom: 17.0
readonly property real nightLightTo: 10.0
readonly property bool nightLightEnabledByDefault: DesktopPreferences.nightLightEnabled
// ── Notifications ───────────────────────────────────────────────────────
readonly property int notificationTimeoutMs: 5000
readonly property int notificationTimeoutCriticalMs: 0 // 0 = never auto-expire
readonly property int notificationHistoryLimit: 100
readonly property int maxVisibleToasts: 4
// ── Focus ──────────────────────────────────────────────────────────────
// One deliberate default rather than a preset picker: quick settings and
// the keyboard shortcut should start a useful session in one action.
readonly property int focusDurationMinutes: DesktopPreferences.focusDurationMinutes
// ── Dock ────────────────────────────────────────────────────────────────
// Pinned apps, in order, taken from the GNOME dash favourites.
readonly property list<string> dockPinned: [
"org.gnome.Settings",
"kitty",
"org.gnome.Nautilus",
"com.bitwarden.desktop",
"org.gnome.Software",
"helium",
"org.mozilla.thunderbird_esr",
"com.slack.Slack",
"app.bluebubbles.BlueBubbles",
"rustdesk",
"io.podman_desktop.PodmanDesktop",
"claude-desktop",
"codex-desktop",
"md.obsidian.Obsidian",
"com.obsproject.Studio",
"steam"
]
// Dash-to-Dock was set to intellihide against all windows: the dock hides
// when any window would overlap it, and comes back on hover.
readonly property bool dockAutohide: DesktopPreferences.dockAutohide
// 0: reveal the instant the pointer reaches the bottom edge. A reveal delay
// is indistinguishable from lag, because the user has already committed to
// the gesture by the time the strip is hit.
readonly property int dockRevealDelayMs: DesktopPreferences.dockRevealDelayMs
// Hiding keeps a delay, so brushing past the bottom edge or crossing the
// gap between two icons doesn't make the dock flicker.
readonly property int dockHideDelayMs: DesktopPreferences.dockHideDelayMs
// ── Capture ─────────────────────────────────────────────────────────────
readonly property string screenshotDir: "Pictures/Screenshots"
readonly property string recordingDir: "Videos/Recordings"
// Passed to wf-recorder. Uses VAAPI on the AMD card so recording does not
// cost CPU while gaming.
readonly property string recorderArgs: "-c h264_vaapi -d /dev/dri/renderD128"
}
+154
View File
@@ -0,0 +1,154 @@
pragma Singleton
// ─────────────────────────────────────────────────────────────────────────────
// Tokyo Night Moon — the single source of truth for every colour, radius,
// duration and font in the shell. Nothing below this file should hardcode a
// colour; if you find yourself writing "#" outside this file, add a token here.
//
// The bar keeps GNOME's 36px information density but sits directly on the
// desktop, edge to edge. The dock retains the former glass vocabulary: bottom,
// 48px icons and dot indicators.
// ─────────────────────────────────────────────────────────────────────────────
import Quickshell
// QtQuick is required even though nothing visual is declared here: `color` is a
// QtQuick value type, and Qt.rgba() lives in its JS namespace.
import QtQuick
Singleton {
id: root
// ── Palette ─────────────────────────────────────────────────────────────
// Canonical Tokyo Night Moon. `accent` matches the GNOME accent exactly.
readonly property color bg: "#222436"
readonly property color bgDark: "#1e2030"
readonly property color bgHighlight: "#2f334d"
readonly property color bgPanel: "#2e2f3d" // dock glass surface
readonly property color bgPopover: "#21212f" // Openbar submenu background
readonly property color fg: "#c8d3f5"
readonly property color fgDim: "#828bb8"
readonly property color fgMuted: "#636da6"
readonly property color gutter: "#3b4261"
// The pair. `accent` is the primary and carries every state meaning
// (focused, active, on). `accentSecondary` is the orchid from the tmux
// theme — it never appears alone, only as the far end of a gradient. That
// restraint is the whole point: the two colours meeting is the signature,
// so the pink stops being special the moment it's used as a flat fill.
readonly property color accent: "#82aaff" // blue
readonly property color accentSecondary: "#b172b0" // orchid, from tmux
readonly property color accentAlt: "#65bcff" // blue1, a lighter blue
readonly property color cyan: "#86e1fc"
readonly property color teal: "#4fd6be"
readonly property color green: "#c3e88d"
readonly property color yellow: "#ffc777"
readonly property color orange: "#ff966c"
readonly property color red: "#ff757f"
readonly property color redDeep: "#c53b53"
readonly property color magenta: "#c099ff"
readonly property color pink: "#fca7ea"
// Semantic aliases — prefer these in widgets so intent survives a repaint.
readonly property color ok: green
readonly property color warn: yellow
readonly property color danger: red
readonly property color urgent: orange
// ── Surface alphas ──────────────────────────────────────────────────────
// The dock sits on compositor blur, so its fill is deliberately very
// translucent. Popovers are near-opaque because they carry text that must
// stay legible. The bar itself has no surface or alpha token.
readonly property real dockAlpha: 0.34
readonly property real popoverAlpha: 0.92
readonly property real overlayAlpha: 0.55
readonly property real hoverAlpha: 0.14
readonly property real activeAlpha: 0.24
// ── Geometry ────────────────────────────────────────────────────────────
readonly property int barHeight: 36
readonly property int barGap: 6 // breathing room below the bar for popovers
readonly property int barSideMargin: 10 // inset for floating popovers
readonly property int dockIconSize: 48
readonly property int dockPadding: 8
readonly property int dockGap: 8
readonly property int dockRadius: 20
readonly property int popoverRadius: 18
readonly property int popoverPadding: 14
readonly property int popoverWidth: 380
readonly property int cardRadius: 12
readonly property int pillRadius: 999
readonly property int itemSpacing: 8
readonly property int sectionSpacing: 14
// ── Type ────────────────────────────────────────────────────────────────
// Adwaita Sans for everything the user reads as text. No exceptions: a
// monospaced clock or percentage reads as a terminal readout pasted into a
// UI, which is the opposite of the intent here.
readonly property string fontFamily: "Adwaita Sans"
// Nerd Font, used ONLY to draw icon glyphs — never for text. It is the
// pragmatic alternative to freedesktop symbolic icons, which ship with a
// hardcoded dark fill Qt will not recolour (see widgets/ThemedIcon.qml).
readonly property string fontMono: "VictorMono Nerd Font"
// Apply to any text whose digits change in place — clocks, percentages,
// elapsed timers, dimension readouts. Tabular figures all share one
// advance width, so the text stops twitching as the numbers tick without
// needing a monospaced face.
//
// font.family: Theme.fontFamily
// font.features: Theme.tabularFigures
readonly property var tabularFigures: ({
"tnum": 1
})
readonly property int fontSize: 13
readonly property int fontSizeSmall: 11
readonly property int fontSizeLarge: 16
readonly property int fontSizeTitle: 20
// ── Motion ──────────────────────────────────────────────────────────────
// Event-driven only. Nothing in this shell animates while idle — no pulse,
// no shimmer, no spinners. These durations are used for open/close/hover.
readonly property int durFast: 120
readonly property int durNormal: 200
readonly property int durSlow: 320
// The dock revealing is the one animation that answers a live pointer
// movement, so it gets its own (much shorter) duration. Anything slower
// reads as the desktop lagging behind the cursor rather than as motion.
readonly property int durDockReveal: 90
// Matches the "snappy" spring curve defined in hypr/looks.lua.
readonly property list<real> easeStandard: [0.05, 0.9, 0.1, 1.0]
readonly property list<real> easeOvershoot: [0.34, 1.56, 0.64, 1.0]
// ── Helpers ─────────────────────────────────────────────────────────────
// Qt.alpha() does not exist; this is the idiomatic way to re-alpha a token.
function alpha(c: color, a: real): color {
return Qt.rgba(c.r, c.g, c.b, a);
}
// Blend two tokens — used for hover/pressed states so we never invent a
// colour that isn't derived from the palette.
function mix(a: color, b: color, ratio: real): color {
return Qt.rgba(a.r + (b.r - a.r) * ratio, a.g + (b.g - a.g) * ratio, a.b + (b.b - a.b) * ratio, a.a + (b.a - a.a) * ratio);
}
// ── The prism ───────────────────────────────────────────────────────────
// Where the two accents meet. Used for the hairline along the top edge of
// every glass surface (widgets/PrismEdge.qml), the focused window border,
// the active workspace pill and slider fills.
//
// Where the gradient runs left-to-right the blue leads, because the eye
// reads left first and blue is the colour that carries meaning.
readonly property real prismStart: 0.22
readonly property real prismEnd: 0.78
// Opacity of the hairline itself. Deliberately below 1: at full strength it
// reads as a drawn line rather than as light catching an edge.
readonly property real prismEdgeAlpha: 0.85
}
+4
View File
@@ -0,0 +1,4 @@
module qs.config
singleton DesktopPreferences 1.0 DesktopPreferences.qml
singleton Settings 1.0 Settings.qml
singleton Theme 1.0 Theme.qml