theme: soften the YoRHa shapes; SUPER+D opens the dashboard

The square markers, block meters and hard-cornered fills read as boxy
next to the porthole. The desktop is now soft throughout: the porthole
is the shape everything is built around and every smaller surface echoes
it.

- Theme gains radiusS / radiusM / radiusL. radiusL is frameRadius - padS,
  so anything inset padS inside one of the frame's curves is concentric
  with it.
- P5Panel and Skew draw rounded rectangles (Geom.roundedRect) whenever
  they neither lean nor are chopped, which is always now; the polygon
  path is kept for shapes brought back on purpose.
- Markers are dots; workspace pips, toggles, transport and media chips,
  notification actions and today's date are pills or discs; the slider
  handle is round. Meters are one continuous rounded line that glides to
  its level instead of a row of segments.
- Album art is rounded with ClippingRectangle in the bar, the media
  popout and the dashboard.
- Free-standing panels (launcher, ask) drop the corner brackets and take
  the frame radius.
- Fix: a hovered notification's wash was a full-bleed square, so in the
  drawer's bottom corner it ran past the drawer's curve. It is inset by
  padS/2 and rounded by radiusL, which keeps it inside the curve.

Hyprland: the discord special workspace and its window rule are gone,
SUPER+S stays the only scratchpad, and SUPER+D now opens the dashboard
(it was on SUPER+I).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
nvrlandClaude Opus 5.5 committed 2026-10-04 20:56:43 +02:00
1 parent d6de04eaaf
commit a8c19961e2
24 files changed
+184 -106

No files matched your search

+1 -1
View File
@@ -9,7 +9,7 @@ end
shell("lock", { key = mod .. " + CTRL + L", description = "lock screen" })
shell("power", { key = mod .. " + P", description = "power menu" })
shell("ask", { key = mod .. " + A", description = "ask claude" })
shell("dashboard", { key = mod .. " + I", description = "dashboard" })
shell("dashboard", { key = mod .. " + D", description = "dashboard" })
shell("toggleDnd", { key = mod .. " + SHIFT + N", description = "toggle do not disturb" })
shell("clearNotifications", { key = mod .. " + CTRL + SHIFT + N", description = "clear notifications" })
shell("reloadConfig", { key = mod .. " + SHIFT + R", description = "reload shell config" })
+4 -8
View File
@@ -1,4 +1,4 @@
-- Workspaces, including the two scratchpads.
-- Workspaces, including the scratchpad.
local mod = "SUPER"
@@ -13,10 +13,6 @@ end
hl.bind(mod .. " + mouse_down", hl.dsp.focus({ workspace = "e+1" }))
hl.bind(mod .. " + mouse_up", hl.dsp.focus({ workspace = "e-1" }))
-- Scratchpads: S holds anything virtual, D holds chat.
local special = { S = "virtual", D = "discord" }
for key, name in pairs(special) do
hl.bind(mod .. " + " .. key, hl.dsp.workspace.toggle_special(name))
hl.bind(mod .. " + SHIFT + " .. key, hl.dsp.window.move({ workspace = "special:" .. name }))
end
-- Scratchpad: S holds anything virtual. Chat opens wherever it is launched.
hl.bind(mod .. " + S", hl.dsp.workspace.toggle_special("virtual"))
hl.bind(mod .. " + SHIFT + S", hl.dsp.window.move({ workspace = "special:virtual" }))
-1
View File
@@ -54,7 +54,6 @@ hl.window_rule({ match = { class = GAMESCOPE }, workspace = "1" })
-- Special workspaces
hl.window_rule({ match = { class = "^(Spotify|spotify)$" }, workspace = "special:virtual" })
hl.window_rule({ match = { class = "^(discord|vesktop)$" }, workspace = "special:discord" })
-- ==========================================
-- STEAM & GAMING
+18 -13
View File
@@ -3,7 +3,7 @@
A NieR:Automata flavoured Quickshell desktop for Hyprland, kept dark and lit
like its wallpaper: a lone figure at a porthole, the void outside, one planet's
light. The planet white for anything live, the hull red for anything wrong,
grey-green for everything else. Hairlines, square markers, corner ticks,
grey-green for everything else. Hairlines, small dots, soft rounded corners,
letter-spaced capitals, and selection shown by inverting the row. The bar, the
rail and a thin border are one hull around the desktop, and the desktop is the
porthole cut out of it.
@@ -91,7 +91,7 @@ left a thin strip of opening between itself and the rail.
## Dashboard
`dashboard/Dashboard.qml` is a drawer that slides down out of the underside of
the bar — clock click, `SUPER + I`, or `qs ipc call shell dashboard`. It is
the bar — clock click, `SUPER + D`, or `qs ipc call shell dashboard`. It is
painted in the hull colour and joins the bar through two concave fillets, so it
reads as more of the hull rather than as a floating card (caelestia's idea).
Four columns divided by hairlines: operator and time, the month, the system
@@ -262,10 +262,9 @@ brings the marker up to full light, but never inverts. Destructive-active is
the same slab in red. The `treatment*` tokens in `Theme.qml` encode all of
this; use them rather than picking colours per widget.
**Markers, not slashes.** The current row, a button under the pointer and the
end of a header rule carry a small square (`Theme.marker`). Popouts are framed
by corner ticks (`Theme.tick`) in their tone colour; the border itself is
structure and stays neutral.
**Dots, not slashes.** The current row, a button under the pointer, the end of
a header rule and a notification's urgency carry a small dot (`Theme.marker`).
Borders are structure and stay neutral.
**Flicker, not print.** Display text (`SplitText`) is upright, tracked by
`Theme.tracking`, on a one-pixel soft drop. The two ghosts either side of it
@@ -332,16 +331,22 @@ inside the ship and the windows sit in the porthole. The bar and the rail draw
no surface of their own and ignore exclusive zones; Frame reserves all four
zones itself, so every piece is placed from the screen edge.
**Rectangles, everywhere else.** NieR panels are plain boxes. `Theme.skew` and
`Theme.cut` are both `0`, so `P5Panel`, `Skew` and `Geom` all collapse to
rectangles; the knobs are kept so a shape can be brought back on purpose. The
porthole's curve is the only one on screen, which is what lets it read.
**Soft, everywhere else.** The porthole is the shape the desktop is built
around, and every smaller surface is a gentler echo of it. `Theme.skew` and
`Theme.cut` are `0`; `P5Panel` and `Skew` draw `Geom.roundedRect` with
`Theme.radiusS` (pills, chips, meter tracks), `radiusM` (rows, buttons) or
`radiusL`. `radiusL` is `frameRadius - padS`: anything inset by `padS` inside
one of the frame's curves — a hovered notification in the drawer's corner —
gets a corner concentric with it, so the gap stays even and nothing pokes past
the curve. Free-standing panels (launcher, ask) take `frameRadius` itself.
Toggles, transport buttons, workspace pips and today's date are pills or
discs; album art is rounded via `ClippingRectangle`.
**Motion glides.** No overshoot anywhere: things ease in on `OutCubic` or
`OutExpo` and settle. Nothing scales up or nudges sideways on hover either;
hover brightens and marks, the way NieR's menus do. Meters are thin segment
rows, album art sits square in a hairline frame, and the bar's player shows a
five-hairline signal meter.
hover brightens and marks, the way NieR's menus do. Meters are one continuous
rounded line that glides to its level, and the bar's player shows a
five-line signal meter.
Each surface is **one continuous slab**, with modules divided by hairline rules
rather than by gaps. A row of separate floating cards reads as clutter; that is
+8 -5
View File
@@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Shapes
import QtQuick.Window
import Quickshell
import Quickshell.Widgets
import "root:/config"
import "root:/components"
import "root:/services"
@@ -41,12 +42,13 @@ BarPill {
anchors.left: parent.left
spacing: Theme.padS
// Album art in a hairline frame.
Rectangle {
// Album art, rounded, in a hairline frame.
ClippingRectangle {
id: artFrame
anchors.verticalCenter: parent.verticalCenter
width: 24
height: 24
radius: Theme.radiusS
color: Theme.surface
border.width: 1
border.color: Theme.overlay
@@ -111,9 +113,9 @@ BarPill {
}
}
// Signal meter: five hairline bars, NieR's audio readout rather than a
// Signal meter: five thin rounded bars, NieR's audio readout rather than a
// chunky equaliser. It moves only while audio is playing and settles
// into a row of square dots when paused — the channel is open, there
// into a row of dots when paused — the channel is open, there
// is just nothing on it.
//
// Sampled from a timer rather than tweened by an infinite
@@ -181,7 +183,8 @@ BarPill {
Rectangle {
required property int index
width: 1
width: 2
radius: 1
height: Media.playing ? eq.level(index) : 2
anchors.verticalCenter: parent.verticalCenter
color: Media.playing ? Theme.primary : Theme.muted
+1
View File
@@ -135,6 +135,7 @@ Item {
anchors.leftMargin: root.wipeInset
anchors.verticalCenter: parent.verticalCenter
width: 2
radius: 1
height: root.hovered ? Theme.marker * 2 : 0
color: Theme.glow
+3 -1
View File
@@ -4,7 +4,7 @@ import Quickshell.Hyprland
import "root:/config"
import "root:/components"
// Workspace indicator: leaning ticks that stretch open when focused. Occupied
// Workspace indicator: soft pills that stretch open when focused. Occupied
// workspaces fill in, urgent ones snap to the alarm colour.
Item {
id: root
@@ -82,6 +82,7 @@ Item {
Skew {
id: tick
anchors.fill: parent
radius: height / 2
// Focused is a solid accent block. Urgent is a solid alarm
// block — it used to be the accent too, which made an
@@ -132,6 +133,7 @@ Item {
Rectangle {
visible: pip.info !== undefined && pip.info.fullscreen && !pip.focused
width: 4; height: 4
radius: 2
color: Theme.accent
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.bottom
+1
View File
@@ -18,4 +18,5 @@ P5Panel {
slashColor: tone
slashWidth: 2
padding: Theme.padS
radius: Theme.radiusM
}
+23 -3
View File
@@ -3,9 +3,10 @@ pragma Singleton
import QtQuick
import Quickshell
// Polygon maths for panel shapes. Under the YoRHa theme nothing leans and
// nothing is chopped (Theme.skew and Theme.cut are 0), so these collapse to
// plain rectangles; they are kept so a shape can be brought back on purpose.
// Shape maths for panels. Under the YoRHa theme nothing leans and nothing is
// chopped (Theme.skew and Theme.cut are 0); surfaces are rounded rectangles
// (roundedRect). The polygon helpers are kept so a shape can be brought back
// on purpose.
// Originally the Persona 5 panel language: everything leans, and corners
// get chopped rather than rounded.
Singleton {
@@ -89,6 +90,25 @@ Singleton {
return root.closed(out);
}
// A polygon as an SVG path string, for PathSvg.
function svg(pts: var): string {
if (pts.length === 0) return "";
let d = `M ${pts[0].x} ${pts[0].y}`;
for (let i = 1; i < pts.length; i++) d += ` L ${pts[i].x} ${pts[i].y}`;
return d + " Z";
}
// A w x h rectangle with every corner rounded by `r`, clamped so a short
// piece becomes a pill rather than folding over itself.
function roundedRect(w: real, h: real, r: real): string {
const k = Math.max(0, Math.min(r, w / 2, h / 2));
if (k <= 0) return root.svg([Qt.point(0, 0), Qt.point(w, 0), Qt.point(w, h), Qt.point(0, h)]);
return `M ${k} 0 H ${w - k} A ${k} ${k} 0 0 1 ${w} ${k}`
+ ` V ${h - k} A ${k} ${k} 0 0 1 ${w - k} ${h}`
+ ` H ${k} A ${k} ${k} 0 0 1 0 ${h - k}`
+ ` V ${k} A ${k} ${k} 0 0 1 ${k} 0 Z`;
}
function closed(pts: var): var {
if (pts.length === 0) return pts;
const out = pts.slice();
+3 -1
View File
@@ -7,7 +7,7 @@ import "root:/config"
// came out as a faint milky film. This is the one row they share now.
//
// Rest is bare. Hover lifts the row onto the surface tone. The current item —
// connected, in use — carries the NieR square marker at its leading edge and
// connected, in use — carries a dot at its leading edge and
// an accent glyph, and its label goes to full weight.
Item {
id: root
@@ -30,6 +30,7 @@ Item {
Rectangle {
anchors.fill: parent
radius: Theme.radiusM
color: root.hovered ? Theme.treatmentHoverFill : "transparent"
Behavior on color {
@@ -43,6 +44,7 @@ Item {
anchors.leftMargin: 2
width: root.current ? Theme.marker : 0
height: width
radius: width / 2
color: Theme.accent
Behavior on width {
+24 -29
View File
@@ -2,8 +2,12 @@ import QtQuick
import "root:/config"
import "root:/components"
// A segmented load meter — upright ticks that light up left to right. Reads as
// a gauge at a glance and keeps the panel language consistent.
// A load meter: a soft rounded track with the level filling it from the left.
// It used to be a row of separate segments; one continuous line reads calmer,
// and a level that glides reads as a quantity rather than as a count.
//
// `segments`, `segmentWidth` and `spacing` are accepted and ignored, so the
// call sites that still size a segmented meter do not have to be chased down.
Item {
id: root
@@ -12,42 +16,33 @@ Item {
property real segmentWidth: 4
property real spacing: 3
property color activeColor: Theme.heat(value)
property color idleColor: Theme.alpha(Theme.outline, 0.55)
property color idleColor: Theme.alpha(Theme.outline, 0.35)
property real lean: Theme.skew
readonly property int litCount: Math.round(Math.max(0, Math.min(100, value)) / 100 * segments)
implicitWidth: segments * segmentWidth + (segments - 1) * spacing
implicitHeight: 14
implicitHeight: 4
Row {
readonly property real fraction: Math.max(0, Math.min(100, root.value)) / 100
Rectangle {
anchors.fill: parent
spacing: root.spacing
radius: height / 2
color: root.idleColor
}
Repeater {
model: root.segments
Item {
required property int index
width: root.segmentWidth
height: root.height
Skew {
width: root.segmentWidth
height: root.height
lean: root.lean
color: parent.index < root.litCount ? root.activeColor : root.idleColor
// Peak segments glow, so a pegged CPU is visible peripherally.
opacity: parent.index < root.litCount
? (parent.index >= root.segments - 2 ? 1.0 : 0.9)
: 1.0
Rectangle {
height: parent.height
// Never narrower than its own height, so a near-zero level is a dot
// rather than a sliver.
width: root.fraction > 0 ? Math.max(height, parent.width * root.fraction) : 0
radius: height / 2
color: root.activeColor
Behavior on width {
NumberAnimation { duration: Theme.durSlow; easing.type: Easing.OutCubic }
}
Behavior on color {
ColorAnimation { duration: Theme.durBase }
}
}
}
}
}
}
+21 -11
View File
@@ -1,5 +1,6 @@
import QtQuick
import Quickshell
import Quickshell.Widgets
import Quickshell.Services.Notifications
import "root:/config"
import "root:/components"
@@ -7,14 +8,14 @@ import "root:/services"
// One notification, used both in the history list and in the toast drawer.
//
// Laid out like an entry in NieR's message log rather than as a card: a square
// marker and the sender's name running into a hairline, the summary, the body,
// and hairline buttons for any actions. There is no panel of its own — both
// places it appears are already hull surfaces — so rest is bare, hover lifts
// the row onto the surface tone, and entries are divided by the hairline in
// their own header.
// Laid out like an entry in NieR's message log rather than as a card: a dot
// and the sender's name running into a hairline, the summary, the body, and
// pill buttons for any actions. There is no panel of its own — both places it
// appears are already hull surfaces — so rest is bare, hover lifts the entry
// onto a soft rounded wash, and entries are divided by the hairline in their
// own header.
//
// Urgency is the marker: the light for normal, grey for low, red for critical.
// Urgency is the dot: the light for normal, grey for low, red for critical.
// A critical entry also takes the red into its sender line, and nothing else.
Item {
id: root
@@ -38,8 +39,14 @@ Item {
implicitHeight: layout.implicitHeight + Theme.padM * 2
// Hover wash. Inset by padS and rounded by radiusL, which is the frame's
// radius less that inset: an entry in the bottom corner of the drawer gets
// a corner concentric with the drawer's own, instead of a square one that
// ran out past the drawer's curve.
Rectangle {
anchors.fill: parent
anchors.margins: Theme.padS / 2
radius: Theme.radiusL
color: root.hovered ? Theme.treatmentHoverFill : "transparent"
Behavior on color {
@@ -66,6 +73,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
width: Theme.marker
height: Theme.marker
radius: width / 2
color: root.tone
}
@@ -162,12 +170,13 @@ Item {
renderType: Text.NativeRendering
}
// Inline image, when the sender supplied one, in a hairline frame.
Rectangle {
// Inline image, when the sender supplied one, rounded in a hairline frame.
ClippingRectangle {
x: Theme.marker + Theme.padS
visible: inline.source != "" && inline.status === Image.Ready
width: inline.width + 2
height: inline.height + 2
radius: Theme.radiusM
color: "transparent"
border.width: 1
border.color: Theme.overlay
@@ -192,8 +201,7 @@ Item {
Repeater {
model: root.notif?.actions ?? []
// A hairline button with a marker, the P5Button pattern at a
// smaller size. Hover lifts and lights it; it never inverts.
// A hairline pill. Hover lifts and lights it; it never inverts.
Item {
id: actionChip
required property var modelData
@@ -203,6 +211,7 @@ Item {
Rectangle {
anchors.fill: parent
radius: height / 2
color: actionHover.hovered ? Theme.treatmentHoverFill : "transparent"
border.width: 1
border.color: actionHover.hovered ? Theme.treatmentHoverMark : Theme.overlay
@@ -221,6 +230,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
width: 4
height: 4
radius: 2
color: actionLabel.color
opacity: actionHover.hovered ? 1 : 0.4
}
+1
View File
@@ -90,6 +90,7 @@ FocusScope {
anchors.verticalCenter: parent.verticalCenter
width: Theme.marker
height: Theme.marker
radius: width / 2
color: label.color
opacity: root.highlighted ? 1.0 : 0.35
+19 -11
View File
@@ -5,9 +5,8 @@ import "root:/config"
import "root:/components"
// The base surface for everything in this shell. Under the YoRHa theme it is a
// plain rectangle with a hairline border, an optional dot wash, an optional
// accent bar down its leading edge, and optional corner ticks — the brackets
// NieR frames its panels with.
// rounded rectangle with a hairline border, an optional dot wash, an optional
// accent bar down its leading edge, and optional corner ticks.
//
// The lean and chop knobs still exist and still work, so a caller can bring a
// shape back on purpose, but Theme.skew and Theme.cut are both zero.
@@ -34,6 +33,10 @@ Item {
property real chop: Theme.cut
property var chopCorners: [1, 3]
// Corner radius. Used whenever the panel neither leans nor is chopped,
// which under the YoRHa theme is always.
property real radius: Theme.radiusM
// Accent bar down the leading edge.
property bool slash: false
property color slashColor: Theme.accent
@@ -67,6 +70,11 @@ Item {
readonly property real leanInset:
(vertical ? width : height) * Math.abs(lean)
// The outline every layer below is drawn from.
readonly property string outline: root.lean === 0 && root.chop <= 0
? Geom.roundedRect(root.width, root.height, root.radius)
: Geom.svg(Geom.chamfer(root.polygon, root.chop, root.chopCorners).slice(0, -1))
readonly property var polygon: vertical
? (leanLeft ? Geom.parallelogramVL(width, height, lean)
: Geom.parallelogramV(width, height, lean))
@@ -99,8 +107,8 @@ Item {
strokeColor: "transparent"
joinStyle: ShapePath.MiterJoin
PathPolyline {
path: Geom.chamfer(root.polygon, root.chop, root.chopCorners)
PathSvg {
path: root.outline
}
}
}
@@ -123,8 +131,8 @@ Item {
strokeColor: "transparent"
joinStyle: ShapePath.MiterJoin
PathPolyline {
path: Geom.chamfer(root.polygon, root.chop, root.chopCorners)
PathSvg {
path: root.outline
}
}
}
@@ -148,8 +156,8 @@ Item {
joinStyle: ShapePath.MiterJoin
capStyle: ShapePath.FlatCap
PathPolyline {
path: Geom.chamfer(root.polygon, root.chop, root.chopCorners)
PathSvg {
path: root.outline
}
}
@@ -161,8 +169,8 @@ Item {
joinStyle: ShapePath.MiterJoin
capStyle: ShapePath.FlatCap
PathPolyline {
path: Geom.chamfer(root.polygon, root.chop, root.chopCorners)
PathSvg {
path: root.outline
}
}
}
+2 -2
View File
@@ -2,8 +2,7 @@ import QtQuick
import "root:/config"
import "root:/components"
// Hairline slider with a square handle, the NieR settings-menu slider. Drag or
// click anywhere on the rail.
// Hairline slider with a round handle. Drag or click anywhere on the rail.
Item {
id: root
@@ -68,6 +67,7 @@ Item {
Skew {
id: handle
width: height
radius: height / 2
height: root.activeFocus || hover.hovered || drag.active ? 12 : 10
color: root.enabled ? Theme.text : Theme.treatmentDisabledText
anchors.verticalCenter: parent.verticalCenter
+12 -4
View File
@@ -3,7 +3,8 @@ import QtQuick.Shapes
import "root:/config"
import "root:/components"
// A leaning block — the small-scale counterpart to P5Panel.
// A small block — the small-scale counterpart to P5Panel. Upright and rounded
// under the YoRHa theme; it still leans if given a lean.
//
// Every tick, rule, meter segment and slider rail in this shell leans at
// Theme.skew. Shearing a plain Rectangle with a Matrix4x4 does that, but Qt
@@ -31,6 +32,11 @@ Shape {
// rail slab.
property bool vertical: false
// Corner radius for an upright piece, clamped to a pill. Small by default,
// so a meter segment or a hover wash reads soft rather than as a block;
// a hairline stays a hairline.
property real radius: Theme.radiusS
// NOTE ON SIZING. The lean shifts one edge by `lean * height` (or by
// `lean * width` when vertical), and the piece that actually gets painted is
// what is left: a Skew declared 1px wide and 20px tall does not draw a 1px
@@ -55,13 +61,15 @@ Shape {
joinStyle: ShapePath.MiterJoin
capStyle: ShapePath.FlatCap
PathPolyline {
PathSvg {
path: {
const w = root.width, h = root.height, l = root.lean;
if (l === 0)
return Geom.roundedRect(w, h, root.radius);
if (root.vertical)
return Geom.closed(root.leanLeft ? Geom.parallelogramVL(w, h, l)
return Geom.svg(root.leanLeft ? Geom.parallelogramVL(w, h, l)
: Geom.parallelogramV(w, h, l));
return Geom.closed(root.leanLeft ? Geom.parallelogramL(w, h, l)
return Geom.svg(root.leanLeft ? Geom.parallelogramL(w, h, l)
: Geom.parallelogram(w, h, l));
}
}
+17 -5
View File
@@ -190,9 +190,8 @@ Singleton {
readonly property int frame: 8
readonly property int frameRadius: 18
// Nothing leans and nothing is chopped. NieR panels are plain rectangles;
// their character comes from hairlines, square markers and corner ticks.
// Both knobs are kept so the shape code still has one place to ask.
// Nothing leans and nothing is chopped. Both knobs are kept so the shape
// code still has one place to ask.
readonly property real skew: 0
readonly property int cut: 0
readonly property int stroke: 1
@@ -202,8 +201,21 @@ Singleton {
readonly property real dropOffset: 0
readonly property real keylineWidth: 0
// The square bullet that marks the current row, and the length of the
// corner ticks that frame a panel.
// Corners. Everything is soft — the porthole is the shape the whole
// desktop is built around, and every smaller surface is a gentler echo of
// it rather than a hard block.
//
// radiusS pills and small chips: buttons, tags, meter tracks
// radiusM rows and panels inside a surface
// radiusL anything that sits a padS inside the frame's own curve:
// frameRadius - padS, so its corner is concentric with the
// corner it sits in and the gap between them stays even
readonly property int radiusS: 6
readonly property int radiusM: 10
readonly property int radiusL: frameRadius - padS
// The dot that marks the current row, and the length of the corner
// ticks a panel can still ask for.
readonly property int marker: 6
readonly property int tick: 8
+9 -4
View File
@@ -1,6 +1,7 @@
import QtQuick
import QtQuick.Shapes
import Quickshell
import Quickshell.Widgets
import Quickshell.Io
import Quickshell.Wayland
import Quickshell.Hyprland
@@ -241,7 +242,7 @@ PanelWindow {
Rule { height: root.columnHeight }
// The month, Monday first. Today is the NieR cursor: an inverted square.
// The month, Monday first. Today is the NieR cursor: an inverted disc.
Item {
id: month
implicitWidth: 238
@@ -311,7 +312,8 @@ PanelWindow {
Rectangle {
anchors.centerIn: parent
width: 22
height: 20
height: 22
radius: 11
visible: parent.modelData.today
color: Theme.treatmentSelectedFill
}
@@ -418,10 +420,11 @@ PanelWindow {
anchors.bottom: parent.bottom
visible: Media.hasPlayer
Rectangle {
ClippingRectangle {
id: artFrame
width: 96
height: 96
radius: Theme.radiusL
color: Theme.surface
border.width: 1
border.color: Theme.overlay
@@ -506,6 +509,7 @@ PanelWindow {
x: parent.width * Media.progress - width / 2
width: Theme.marker
height: Theme.marker
radius: width / 2
color: Theme.accent
}
}
@@ -596,7 +600,7 @@ PanelWindow {
}
}
// A square hairline button. Hover lifts it; nothing here inverts, since
// A round hairline button. Hover lifts it; nothing here inverts, since
// inversion is reserved for the keyboard's cursor.
component Transport: Item {
id: tb
@@ -609,6 +613,7 @@ PanelWindow {
Rectangle {
anchors.fill: parent
radius: width / 2
color: tbHover.hovered ? Theme.treatmentHoverFill : "transparent"
border.width: 1
border.color: tbHover.hovered ? Theme.treatmentHoverMark : Theme.overlay
+1
View File
@@ -28,6 +28,7 @@ Item {
anchors.fill: parent
anchors.leftMargin: -Theme.padS
anchors.rightMargin: -Theme.padS
radius: Theme.radiusM
color: root.selected ? Theme.treatmentSelectedFill : "transparent"
opacity: root.selected ? 1 : 0
+2 -1
View File
@@ -130,7 +130,8 @@ Popout {
Skew {
anchors.centerIn: parent
width: 26
height: 24
height: 26
radius: 13
visible: cell.modelData.today
color: Theme.accent
}
+6 -2
View File
@@ -1,6 +1,7 @@
import QtQuick
import QtQuick.Shapes
import Quickshell
import Quickshell.Widgets
import "root:/config"
import "root:/components"
import "root:/services"
@@ -32,14 +33,15 @@ Popout {
subtitle: Media.identity
}
// Cover art in a hairline frame.
Rectangle {
// Cover art, rounded, in a hairline frame.
ClippingRectangle {
id: artFrame
anchors.top: header.bottom
anchors.topMargin: Theme.padM
anchors.left: parent.left
width: 108
height: 108
radius: Theme.radiusL
color: Theme.surface
border.width: 1
border.color: Theme.overlay
@@ -216,6 +218,7 @@ Popout {
Skew {
anchors.fill: parent
radius: height / 2
color: !chip.enabled
? Theme.treatmentDisabledFill
: (chip.activeFocus
@@ -287,6 +290,7 @@ Popout {
Skew {
anchors.fill: parent
radius: width / 2
color: {
if (!tb.enabled) return "transparent";
if (tb.activeFocus) return Theme.treatmentFocusFill;
+2 -1
View File
@@ -3,7 +3,7 @@ import "root:/config"
import "root:/components"
// Title bar for a popout, in the NieR header pattern: glyph, tracked heading,
// right-aligned status text, and a hairline rule that ends in a square.
// right-aligned status text, and a hairline rule that ends in a dot.
Item {
id: root
@@ -62,6 +62,7 @@ Item {
anchors.right: parent.right
width: Theme.marker
height: Theme.marker
radius: width / 2
color: Theme.accent
}
}
+5 -3
View File
@@ -17,14 +17,16 @@ P5Panel {
// Zero, not a transparent fill: P5Panel re-applies this opacity to the
// fill colour, which turned "transparent" into 97% black.
fillOpacity: attached ? 0 : 0.97
// The frame is structure: a neutral hairline. The tone goes into the
// corner ticks, which is where NieR puts the one bright mark on a panel.
// The frame is structure: a neutral hairline. A free-standing panel takes
// the frame's own corner radius, so it reads as a piece of the hull set
// down somewhere else rather than as a hard card.
border: Theme.surfaceAlt
borderWidth: attached ? 0 : Theme.stroke
halftone: textured
halftoneColor: tone
halftoneOpacity: 0.06
ticks: !attached
ticks: false
radius: Theme.frameRadius
tickColor: tone
padding: Theme.padM
}
+1
View File
@@ -106,6 +106,7 @@ Column {
anchors.fill: parent
anchors.leftMargin: Theme.padS
anchors.rightMargin: Theme.padS
radius: Theme.radiusM
color: row.hovered ? Theme.accent : "transparent"
Behavior on color {