Commit Graph
79 Commits
Author SHA1 Message Date
David Heinemeier HanssonandClaude Fable 5 7020a6ea57 Span the power widget's open-panel mark across the percentage block
The widget declared no indicator hint, so the mark fell back to 55% of
the slot — sized for a lone icon, too short once the percentage doubles
the block. Hint the glyph's painted width, the way the clock hints its
label width.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 15:36:34 -05:00
3cb3861fbc Dismiss bar panels when clicking on another monitor (#6487)
* Dismiss bar panels when clicking on another monitor

* Preserve keyboard focus for reopened panels

* Harden cross-monitor panel dismissal

* Wait for panel mapping before releasing focus

---------

Co-authored-by: David Heinemeier Hansson <david@hey.com>
2026-08-01 13:00:24 -05:00
14f1bb6c88 Add a Wi-Fi band toggle to the network panel (#6437)
Pins the active connection to 2.4/5/6GHz, or leaves the choice automatic.
The section only appears on Wi-Fi when the network answers on more than one
band, or while a pin is in force so it stays clearable.

bin/omarchy-network-band reports and sets the band. It sets NetworkManager's
802-11-wireless.band rather than pinning a BSSID: NM 1.44+ accepts a third
band value so 5 and 6GHz can be pinned apart, and a band survives an AP
rotating its BSSIDs while leaving roaming between APs intact. It refuses a
band the network does not answer on, and restores the previous setting if
reassociation fails rather than leaving the machine offline.

Under Automatic the pills collapse and the header reads the live band
("WI-FI BAND: 2.4GHZ"); pinning reveals them and the header goes plain. The
height is animated, and the section stays mounted through the reconnect a
band change causes -- otherwise `kind` briefly stops being "wifi" and the
whole segment would tear down and rebuild.

Two fixes to the same panel fall out of this:

- Every stat row stays mounted and reads "--" until it has data, instead of
  appearing a beat after the panel opens and shoving the rows below down.
- The speed test's Run button is scaled to match the band header's controls
  and joins the keyboard cursor chain.

ToggleSwitch gains a settable trackHeight so a compact placement can render a
genuinely small switch instead of scaling one down onto fractional pixels.
Defaults are unchanged.


Claude-Session: https://claude.ai/code/session_01XcKqYe1n5bnRBuAZwikwsr

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 10:11:23 -04:00
1045975946 Stop section headers rendering clipped at the top of a list
JetBrainsMono Nerd Font draws 10% of the em above the ascent Text
reserves for it (yMax 1120 against ascent 1020), and a patched or
user-chosen family can be worse. In normal flow that sliver costs
nothing; at the top of a clipping list it is sliced off and the header
renders beheaded.

Reserving it in PanelSectionHeader covers every panel at once, rather
than each list working around it in its own geometry.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 12:26:01 -07:00
J. S. Brown 6675f6b711 Fix asymmetric rounded shell borders 2026-07-28 21:28:31 -07:00
David Heinemeier HanssonandClaude Opus 5 4a8091cd41 Give PanelSlider a right-click signal
Sliders only ever accepted the left button. Audio wants right-click as a
secondary action on the track, so emit rightClicked() for it and keep dragging
left-button-only: press and release both ignore anything else, so a right-click
can neither start a drag nor move the value.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 07:55:29 -07:00
4cfb2c2fae Toggle panel heroes with a switch instead of the status icon (#6408)
* Add Tailscale header on/off toggle

* Address Tailscale toggle review feedback

* Hide Tailscale tooltip while busy

* Keep Tailscale labels clear of header toggle

* Extract the switch from Toggle into a reusable ToggleSwitch

Toggle rendered its own track and knob inline, so anything else wanting a
switch had to copy the geometry. Pull it into Ui/ToggleSwitch.qml and let
Toggle compose it, and give PanelHero a trailingControl slot so a hero can
pin a control to its trailing edge without the caller doing the layout.

The switch draws its cursor as a ring outside the track: themes give normal
chrome a stronger border than hover-cursor, which is right for controls that
are borderless at rest but would make a bordered track go fainter under the
cursor.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Keep the panel cursor on the virtual header section

clampCursor resets focusSection whenever it is not in visibleSections, but
"header" is virtual and never appears there. Any refresh of the underlying
model therefore threw the cursor off the hero toggle: muting republishes the
PipeWire snapshot, and toggling the Bluetooth adapter empties and refills the
device lists. moveCursor already special-cases "header"; clampCursor now does
too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Toggle panel heroes with a switch instead of the status icon

The hero icon doubled as the on/off control, which was invisible as an
affordance and made the icon carry two jobs at once. Give Tailscale, Dropbox,
Bluetooth, Audio, and Network a ToggleSwitch on the trailing edge of the hero
and leave the icon to report status. The switch is the header's only cursor
target, so the keyboard reaches it the same way the mouse does.

Dropping the icon's focus ring also drops heroRingPad, which lets each hero
line up with the rows beneath it. Network's link detail moves inline after the
name -- "Ethernet (2.5gbit)" -- since the pill crowded the switch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Make the network hero switch honestly a Wi-Fi switch

The switch reads and writes Networking.wifiEnabled, but its tooltip claimed to
turn "network" on and off whenever Ethernet was the active connection. A click
asserted nothing; a switch asserts state, so on a wired machine with the radio
off it sat there reading "off" beside a perfectly live Ethernet connection.

Say Wi-Fi, and only offer the switch when there is a radio to switch.
headerActionCount follows the same condition so the keyboard cannot reach a
control that is not there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Stop the header cursor claiming an absent switch

The switch hides when the thing it toggles is unavailable -- no Tailscale CLI,
no Dropbox CLI, no Wi-Fi radio -- but "header" stayed reachable, so the cursor
could sit on a target that never rendered. The old clickable icon was always on
screen, so there was always something to highlight.

"header" stays navigable and Enter still no-ops safely; the cursor just stops
claiming a spot that is not there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Wrap the gallery's switch caption

The caption sat unbounded inside the switch row. The gallery has a 560px
minimum width, horizontal scrolling off, and clipping on, so at that size the
end of the line was simply unreachable. Move it below the row and wrap it, the
way every other description in the gallery already does.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: David Heinemeier Hansson <david@hey.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-28 07:44:30 -07:00
David Heinemeier HanssonandClaude Opus 5 6d4fa7acaf Make the open-panel mark find and fit its module
A center-anchored module is mounted twice: the copy that is drawn, and a
zero-size placeholder holding its place in the flow beside the anchor.
findPanelWidget returned whichever registered first, and that order is
not stable across a live bar reconfiguration, so a panel could open
anchored to the invisible copy -- mispositioned, with the drawn slot
never lighting up and switchPanelFrom unable to find it again.

The mark was also always 55% of the slot, which fits an icon but
underlines only a fraction of a text label, and runs the full height of a
multi-line module on a vertical bar. Modules can now say how long the
mark should be along the bar; anything that does not answer keeps the old
proportion.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-26 19:10:06 -07:00
David Heinemeier HanssonandClaude Opus 5 d2e1587ceb Refresh bar widgets on every monitor, not just one
A bar surface is built per monitor, so a widget in the layout is live once
per screen — but an IPC target only ever routes to the handler that
registered first. `omarchy.indicators refresh` therefore reached a single
bar, and since indicators only re-read their state on that signal, the
other screens kept showing a stale reminder count, tmux alert, or DND
state until the next reload. Clock and system-update refreshes had the
same reach.

Let the bar resolve every live instance of a widget id and relay the call
to all of them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-24 14:16:22 -07:00
David Heinemeier Hansson 7a9947a732 Combine the Omarchy menu and the launcher
Now that we can deep search, they don't need to be different
2026-07-23 15:04:22 -07:00
ssuptandGitHub 3481b5614b Fix pointer navigation in Quattro launcher menus (#6343)
Accumulate sub-threshold movement so slow motion with a flat acceleration profile updates selection. Sample pointer state on row entry and carry pointer intent through subordinate menus while preserving predictable keyboard selection.
2026-07-22 15:27:56 -07:00
David Heinemeier HanssonandClaude Opus 4.8 c681396a47 Let PanelSlider draw macOS-style notches
Optional tickCount cuts evenly-spaced marks into the track for stepped
sliders. Defaults to 0, so existing sliders are unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-20 18:08:17 -07:00
David Heinemeier Hansson 6742adce3d Focus weather city input on return 2026-07-18 21:19:14 -07:00
David Heinemeier Hansson 52ecb4eaf7 Equalize bar status icon spacing 2026-07-18 10:51:14 -07:00
David Heinemeier Hansson f8fec7cccf Tighten compact status icon spacing 2026-07-17 16:17:49 -07:00
David Heinemeier Hansson 8211b86ac6 Restore compact status icon spacing 2026-07-17 16:15:01 -07:00
David Heinemeier Hansson 6867f16b78 Restore compact bar indicator sizing 2026-07-17 16:08:33 -07:00
David Heinemeier Hansson 22791803ed Align vertical bar widgets to the icon grid 2026-07-17 16:03:49 -07:00
David Heinemeier Hansson 0c8c4ea26a Align bar icons on a shared baseline 2026-07-17 15:37:01 -07:00
David Heinemeier Hansson 6e3b69b8da Standardize bar icon geometry 2026-07-17 15:20:55 -07:00
David Heinemeier Hansson 472b5cd557 Share pointer movement gate across menus 2026-06-29 11:56:21 -05:00
David Heinemeier Hansson b043a9f90e Fix panel IPC hotkeys 2026-06-24 18:26:02 -04:00
David Heinemeier Hansson 1db2323fd9 Remove legacy bar widgets 2026-06-23 16:22:47 +02:00
David Heinemeier Hansson e8e3b7ef54 Fix weather panel clipping and units 2026-06-22 20:52:02 +02:00
David Heinemeier Hansson 79470dde92 Refine shell panel and lock theming 2026-06-03 22:14:48 +02:00
Ryan Hughes d52b69c49b Fix button hover border layout shift 2026-06-02 22:19:09 -04:00
Ryan Hughes 98ba4a9697 Bring on gradient borders 2026-06-02 11:17:13 -04:00
David Heinemeier Hansson 49ca79081f Extract confirmation dialog 2026-05-29 12:57:43 +02:00
David Heinemeier Hansson 6be9b8b6d9 Fix night light indicator state 2026-05-29 09:42:24 +02:00
David Heinemeier Hansson bc32980cca Replace bar settings with inline config panel 2026-05-27 15:11:36 +02:00
David Heinemeier Hansson d6fa701543 Separate transparent bar foreground from panel text 2026-05-27 14:23:13 +02:00
David Heinemeier Hansson 419cd37e14 Fix transparent bar contrast timing 2026-05-27 12:36:45 +02:00
David Heinemeier Hansson b03a7cc73c Use Tab to switch bar panels 2026-05-27 10:40:32 +02:00
David Heinemeier Hansson 67dd7a2953 Add Tailscale panel connection controls 2026-05-26 22:07:20 +02:00
Ryan Hughes 4f0bdb790b Make built-in widgets plugins 2026-05-23 04:32:20 -04:00
Ryan Hughes e8fc2ef08f Re-implement better scaling with new icon spacing 2026-05-22 13:30:53 -04:00
David Heinemeier Hansson b5079bdbad Revert "Provide better scaling"
This reverts commit 3ea8d9ffb7.
2026-05-22 17:41:30 +02:00
Ryan Hughes 3ea8d9ffb7 Provide better scaling 2026-05-22 11:30:43 -04:00
David Heinemeier Hansson 7b6a03fa08 Refine shell panel transitions and layout 2026-05-22 11:22:42 +02:00
David Heinemeier Hansson 181ce06a5b Tab to move quicker between sections 2026-05-22 08:46:19 +02:00
Ryan Hughes d13854857e Add MultiSelect 2026-05-21 16:35:26 -04:00
David Heinemeier Hansson b54d8e04ae Collapse focus/hover/normal ternaries into Style.controlFill helpers
TextField, NumberField, Dropdown, SearchableDropdown, and Toggle all
painted their background, border color, and border width with the same
three-line ternary ladder (`_focused ? focusFill : _hot ? hoverFill :
normalFill`). Five components × three properties × three branches is a
lot of room for one of them to drift from the others when a new state
ever gets added.

Add controlFill / controlBorder / controlBorderWidth on Style and rewrite
each call site as a single binding. No visual change.
2026-05-20 20:37:04 +02:00
David Heinemeier Hansson 8ed6e302b0 Small cleanups: reuse Util.clamp in OSD; PanelSlider hover via _hot
OSD reimplemented clamp() inline when Util already has one.

PanelSlider's knob-scale binding read `mouseArea.containsMouse` directly
instead of going through a `_hot` like the other interactive controls
(TextField, NumberField, Dropdown). Mirror them so future style work
has a single property to override.
2026-05-20 20:33:27 +02:00
David Heinemeier Hansson c1fca7cbe4 Use Color.foreground / Style.font.family for fallbacks
Five sites hardcoded "#cacccc" or "JetBrainsMono Nerd Font" as the
fallback when no bar context was available. Those magic strings are
the *current* palette defaults — they diverge silently when the theme
changes. Bind to the Color / Style singletons so the fallback tracks
whatever the theme says the foreground / monospace family should be.

Color.qml itself keeps the literal "#cacccc" — that's the seed value
the singleton is bootstrapped with before the theme loads.
2026-05-20 20:29:23 +02:00
David Heinemeier Hansson 73e6127d4e Lift setting() onto the Panel base too
Matches the BarWidget extraction in the previous commit. The weather
panel was the only panel reimplementing the helper inline; future
panels with inline settings get it for free.
2026-05-20 20:27:59 +02:00
David Heinemeier Hansson 16604c67b3 Lift setting / vertical / barSize onto BarWidget
Six widgets (clock, daytime, keyboardLayout, lockKeys, activeWindow,
media) shipped identical copies of `function setting(name, fallback)`.
Eight widgets reimplemented `readonly property bool vertical`, and
three reimplemented `readonly property int barSize`. Move all three
onto the BarWidget base so widgets read the same wiring everyone else
gets for free.

While in here, drop the dead `setting()` declaration on media.qml — it
was defined but never called.
2026-05-20 19:50:10 +02:00
David Heinemeier Hansson 9baf3f7f79 Fix parseModuleJson undefined call in custom command modules
CustomCommandModule.update() in Bar.qml called root.parseModuleJson(raw)
but the function was removed in 3b970068 (the indicator split). Any
custom command module emitting waybar-style JSON would have crashed on
first poll.

Hoist the helper into Util so both call sites — the bar's custom command
module and BarIndicator.extractData — share one definition.
2026-05-20 19:46:47 +02:00
David Heinemeier Hansson cf4729ca2b Extract indicators bar widget 2026-05-20 18:32:00 +02:00
David Heinemeier Hansson 4941fe4bf9 Replace calendar widget with daytime label 2026-05-20 16:59:38 +02:00
David Heinemeier Hansson dc6468cdfa Stabilize indicator activation rendering 2026-05-20 16:03:51 +02:00