Make Shell a category, the bar legible, and the dock a real dock
Desktop & Dock becomes Shell — Bar, Dock, Control Center, Tiling, Workspaces — the home for everything Quickshell draws. The settings- management cluster moves to System as Sync & Backup, Appearance's Shell tab dissolves, and 24-hour time finally lives on Date & Time, which always owned it. The bar gets what it never had: a way to survive the wallpaper. A second neutral text family (follow theme, or forced light or dark), a one-layer shadow under every glyph, and a gradient scrim for wallpapers nothing else survives — all off by default, pixel-identical until asked. Widgets earn toggles (weather, media, clipboard, calendar countdown), the vitals cluster stops leaving a dead pill behind, and Control Center's sections learn to step aside. The dock graduates from MVP: a context menu with window rows, pin, unpin, quit and new-window; scroll an icon to cycle its windows; drag to reorder on the dock itself; hover previews with one-shot captures; and "Add App to Dock" in the launcher. Three real bugs died en route — menus that slid away with the autohide, a readonly-property crash on every menu open, and a drag that drifted half a slot per icon on side docks. The pinned-apps editor in Settings becomes a drag strip. 166 contracts; the full suite is green except two live display and switcher tests that cannot run behind a locked session — re-verified on unlock. Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
This commit is contained in:
@@ -36,7 +36,7 @@ Pill {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: PrivacyState.activeKinds.length > 1
|
||||
text: String(PrivacyState.activeKinds.length)
|
||||
color: Theme.fg
|
||||
color: Theme.barFg
|
||||
font.family: Theme.fontFamily
|
||||
font.features: Theme.tabularFigures
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
|
||||
@@ -27,8 +27,8 @@ Pill {
|
||||
|
||||
visible: Settings.showAgentUsage && AgentUsage.available
|
||||
|
||||
onActivated: ShellState.openSettings("appearance")
|
||||
onSecondaryActivated: ShellState.openSettings("appearance")
|
||||
onActivated: ShellState.openSettings("bar")
|
||||
onSecondaryActivated: ShellState.openSettings("bar")
|
||||
|
||||
Row {
|
||||
spacing: 4
|
||||
@@ -39,7 +39,7 @@ Pill {
|
||||
color: {
|
||||
if (AgentUsage.headline >= 90) return Theme.danger;
|
||||
if (AgentUsage.headline >= 75) return Theme.warn;
|
||||
return Theme.fgDim;
|
||||
return Theme.barFgDim;
|
||||
}
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: Theme.fontSize
|
||||
@@ -48,7 +48,7 @@ Pill {
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: AgentUsage.headline + "%"
|
||||
color: Theme.fg
|
||||
color: Theme.barFg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.features: Theme.tabularFigures
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import qs.config
|
||||
import qs.modules.clipboard
|
||||
import qs.modules.focus
|
||||
@@ -62,13 +63,46 @@ PanelWindow {
|
||||
item: barContent
|
||||
}
|
||||
|
||||
// A scrim for wallpapers the bar cannot win against on tone alone. Drawn
|
||||
// behind the content rows, fading out downward so the bar still has no
|
||||
// hard edge of its own — the point is to darken what is under the text,
|
||||
// not to give the bar a surface. Static: a gradient that never changes
|
||||
// costs one paint, and this one has nothing to animate.
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
visible: Settings.barBackdrop
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.0
|
||||
color: Theme.alpha("#0c0e18", 0.55)
|
||||
}
|
||||
GradientStop {
|
||||
position: 1.0
|
||||
color: "transparent"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: barContent
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
// One shadow for the whole bar rather than one per widget: the content
|
||||
// is flattened into a single layer and the halo is drawn under it, so
|
||||
// every glyph and label picks it up and nothing has to opt in. Off by
|
||||
// default — it only earns its layer on a busy wallpaper.
|
||||
layer.enabled: Settings.barTextShadow
|
||||
layer.effect: MultiEffect {
|
||||
shadowEnabled: true
|
||||
shadowColor: "#0a0c14"
|
||||
shadowBlur: 0.6
|
||||
shadowVerticalOffset: 1
|
||||
}
|
||||
|
||||
// ── Left ────────────────────────────────────────────────────────────
|
||||
Row {
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.itemSpacing
|
||||
|
||||
@@ -10,7 +10,7 @@ import qs.widgets
|
||||
Pill {
|
||||
id: root
|
||||
|
||||
visible: CalendarAgenda.capsuleVisible
|
||||
visible: Settings.showCalendarCountdown && CalendarAgenda.capsuleVisible
|
||||
opacity: visible ? 1 : 0
|
||||
horizontalPadding: 8
|
||||
onActivated: ShellState.openDateMenu("agenda")
|
||||
@@ -47,7 +47,7 @@ Pill {
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: CalendarAgenda.capsuleText
|
||||
color: Theme.fg
|
||||
color: Theme.barFg
|
||||
font.family: Theme.fontFamily
|
||||
font.features: Theme.tabularFigures
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
|
||||
@@ -39,7 +39,7 @@ Pill {
|
||||
// figures the whole clock shifts sideways on every digit change.
|
||||
font.features: Theme.tabularFigures
|
||||
font.pixelSize: Theme.fontSize
|
||||
color: Theme.fg
|
||||
color: Theme.barFg
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ Pill {
|
||||
return artist ? artist + " — " + title : title;
|
||||
}
|
||||
|
||||
visible: root.player !== null
|
||||
visible: Settings.showMediaWidget && root.player !== null
|
||||
horizontalPadding: 8
|
||||
|
||||
onActivated: if (root.player?.canTogglePlaying)
|
||||
@@ -63,7 +63,7 @@ Pill {
|
||||
text: root.label
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
color: Theme.fg
|
||||
color: Theme.barFg
|
||||
|
||||
// Titles are unbounded; the bar is not. Elide rather than let one
|
||||
// podcast episode push the tray off the edge.
|
||||
|
||||
@@ -77,10 +77,10 @@ Pill {
|
||||
|
||||
color: {
|
||||
if (root.wiredDevice)
|
||||
return Theme.fg;
|
||||
return Theme.barFg;
|
||||
if (!root.wifiNetwork)
|
||||
return Theme.fgMuted;
|
||||
return Networking.connectivity === NetworkConnectivity.Full ? Theme.fg : Theme.warn;
|
||||
return Theme.barFgMuted;
|
||||
return Networking.connectivity === NetworkConnectivity.Full ? Theme.barFg : Theme.warn;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ Pill {
|
||||
visible: KeyboardLayout.multiple
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: KeyboardLayout.shortLabel
|
||||
color: Theme.fg
|
||||
color: Theme.barFg
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
@@ -117,7 +117,7 @@ Pill {
|
||||
return "\u{F0580}"; // md-volume_medium
|
||||
return "\u{F057E}"; // md-volume_high
|
||||
}
|
||||
color: root.muted ? Theme.fgMuted : Theme.fg
|
||||
color: root.muted ? Theme.barFgMuted : Theme.barFg
|
||||
}
|
||||
|
||||
StatusGlyph {
|
||||
@@ -125,7 +125,7 @@ Pill {
|
||||
// simply absent rather than shown crossed out.
|
||||
visible: root.bluetoothOn
|
||||
glyph: root.bluetoothConnected ? "\u{F00B1}" : "\u{F00AF}" // md-bluetooth_connect / md-bluetooth
|
||||
color: root.bluetoothConnected ? Theme.accent : Theme.fg
|
||||
color: root.bluetoothConnected ? Theme.accent : Theme.barFg
|
||||
}
|
||||
|
||||
StatusGlyph {
|
||||
@@ -151,7 +151,7 @@ Pill {
|
||||
if (Battery.critical) return Theme.danger;
|
||||
if (Battery.low) return Theme.warn;
|
||||
if (Battery.charging) return Theme.ok;
|
||||
return Theme.fg;
|
||||
return Theme.barFg;
|
||||
}
|
||||
|
||||
StatusGlyph {
|
||||
|
||||
@@ -16,7 +16,7 @@ Text {
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
width: 18
|
||||
color: Theme.fg
|
||||
color: Theme.barFg
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
|
||||
@@ -20,7 +20,7 @@ Row {
|
||||
text: root.glyph
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: Theme.fontSize
|
||||
color: Theme.fgDim
|
||||
color: Theme.barFgDim
|
||||
}
|
||||
|
||||
Text {
|
||||
@@ -41,7 +41,7 @@ Row {
|
||||
return Theme.danger;
|
||||
if (root.value >= root.warnAt)
|
||||
return Theme.warn;
|
||||
return Theme.fg;
|
||||
return Theme.barFg;
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
|
||||
@@ -15,7 +15,12 @@ Pill {
|
||||
|
||||
// Right-click opens the settings that govern this widget. Which readouts
|
||||
// appear in the bar, and how often they update.
|
||||
onSecondaryActivated: ShellState.openSettings("appearance")
|
||||
onSecondaryActivated: ShellState.openSettings("bar")
|
||||
|
||||
// Turning off all three readouts should remove the pill, not leave an empty
|
||||
// one behind: an invisible child still occupies its Row, so without this the
|
||||
// padding stays and the bar keeps a gap that reports nothing.
|
||||
visible: Settings.showCpu || Settings.showMemory || (Settings.showGpu && Vitals.gpuAvailable)
|
||||
|
||||
interactive: false
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ Pill {
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: VideoWallpaper.paused ? "\u{F040A}" : "\u{F03E4}" // play / pause
|
||||
color: VideoWallpaper.paused ? Theme.fgDim : Theme.warn
|
||||
color: VideoWallpaper.paused ? Theme.barFgDim : Theme.warn
|
||||
font.family: Theme.fontMono
|
||||
font.pixelSize: 13
|
||||
}
|
||||
@@ -33,7 +33,7 @@ Pill {
|
||||
? (VideoWallpaper.gamePaused ? "Paused for game"
|
||||
: (VideoWallpaper.batteryPaused ? "Paused on battery" : "Paused"))
|
||||
: "Wallpaper"
|
||||
color: Theme.fgDim
|
||||
color: Theme.barFgDim
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ Pill {
|
||||
onSecondaryActivated: ShellState.openSettings("home")
|
||||
|
||||
interactive: false
|
||||
visible: Weather.available
|
||||
visible: Settings.showWeatherWidget && Weather.available
|
||||
|
||||
Text {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -29,6 +29,6 @@ Pill {
|
||||
text: Math.round(Weather.temperature) + Weather.unitSuffix
|
||||
font.family: Theme.fontFamily
|
||||
font.pixelSize: Theme.fontSize
|
||||
color: Theme.fg
|
||||
color: Theme.barFg
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ Item {
|
||||
color: {
|
||||
if (slot.modelData.urgent)
|
||||
return Theme.urgent;
|
||||
return slot.isOccupied ? Theme.fg : Theme.alpha(Theme.fg, 0.3);
|
||||
return slot.isOccupied ? Theme.barFg : Theme.alpha(Theme.barFg, 0.3);
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
|
||||
Reference in New Issue
Block a user