nosignal-shell/modules/bar/components/Clock.qml
28allday b1e2bb3bc6 feat(bar): horizontal top bar — Phase A geometry (NoSignal layout)
Convert the bar from a vertical left-edge strip to a horizontal top bar. The
shell had no orientation abstraction, so this flips the geometry across the bar
and the drawer/region/interaction layer:

- Bar.qml: ColumnLayout -> RowLayout; hit-testing (checkPopout/handleWheel),
  scroll halves and popout-center anchoring all keyed off x instead of y;
  first/last padding -> left/right margins.
- BarWrapper.qml: the bar's "thickness" is now its height (clampedHeight/
  contentHeight/implicitHeight); content anchors left/right/top.
- drawers: Exclusions (exclusive zone moved left->top), Panels (content inset
  topMargin = bar height), Regions + ContentWindow (panel->window coordinate
  mapping and the thick border flip left->top), Interactions (bar-region check
  y<barHeight, panel Y-origin uses bar height, scroll passes x, bar drag-reveal
  is vertical).
- widgets: Clock (Row, HH:MM with a colon), StatusIcons (Row), Workspaces +
  Workspace (Row), Tray (Row, expand chevron at the right) — each sizes to the
  bar height instead of width.

Verified live in the dev VM: top bar renders with centered-clock entries, the
exclusion zone keeps windows below the bar, and the dashboard drops down
correctly. Popout fly-outs still anchor sideways (Phase B).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 23:26:55 +01:00

113 lines
3.3 KiB
QML

pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import Caelestia.Config
import qs.components
import qs.services
StyledRect {
id: root
readonly property color colour: Colours.palette.m3tertiary
readonly property int padding: Config.bar.clock.background ? Tokens.padding.medium : Tokens.padding.extraSmall
readonly property var font: Tokens.font.body.builders.small.scale(1.1)
implicitHeight: Tokens.sizes.bar.innerWidth
implicitWidth: layout.implicitWidth + root.padding * 2
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, Config.bar.clock.background ? Colours.tPalette.m3surfaceContainer.a : 0)
radius: Tokens.rounding.full
RowLayout {
id: layout
anchors.centerIn: parent
spacing: Tokens.spacing.small
Loader {
Layout.alignment: Qt.AlignVCenter
asynchronous: true
active: Config.bar.clock.showIcon
visible: active
sourceComponent: MaterialIcon {
text: "calendar_month"
color: root.colour
}
}
StyledText {
Layout.alignment: Qt.AlignVCenter
visible: Config.bar.clock.showDate
horizontalAlignment: StyledText.AlignHCenter
text: Time.format("ddd d")
font: Tokens.font.body.small
color: root.colour
}
Rectangle {
Layout.fillHeight: true
Layout.topMargin: root.padding
Layout.bottomMargin: root.padding
visible: Config.bar.clock.showDate
implicitWidth: 1
color: Colours.palette.m3outlineVariant
}
StyledText {
Layout.alignment: Qt.AlignVCenter
text: Time.hourStr
font: {
const scale = text === "11" ? 1.15 : Math.min(1.05, Math.max(hourMetrics.width, minMetrics.width) / hourMetrics.width);
return root.font.width(scale * 100).letterSpacing(scale).build();
}
color: root.colour
TextMetrics {
id: hourMetrics
font: root.font.build()
text: Time.hourStr
}
}
StyledText {
Layout.alignment: Qt.AlignVCenter
text: ":"
font: root.font.build()
color: root.colour
}
StyledText {
Layout.alignment: Qt.AlignVCenter
text: Time.minuteStr
font: {
const scale = text === "11" ? 1.15 : Math.min(1.05, Math.max(hourMetrics.width, minMetrics.width) / minMetrics.width);
return root.font.width(scale * 100).letterSpacing(scale).build();
}
color: root.colour
TextMetrics {
id: minMetrics
font: root.font.build()
text: Time.minuteStr
}
}
Loader {
Layout.alignment: Qt.AlignVCenter
asynchronous: true
active: GlobalConfig.services.useTwelveHourClock
visible: active
sourceComponent: StyledText {
text: Time.amPmStr.toLowerCase()
font: Tokens.font.body.builders.small.scale(0.9).build()
color: root.colour
}
}
}
}