The install snippet carried a placeholder, which was all it could carry before the repo had a public home. It has one now. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MhxtL7WzL5XmuTd8GHbcTY
151 lines
6.2 KiB
Markdown
151 lines
6.2 KiB
Markdown
# Clock bar
|
||
|
||
A second bar along the bottom edge of every screen, carrying world clocks laid
|
||
out as **one timeline**: furthest behind your local time at the far left,
|
||
furthest ahead at the far right, your own time dead centre.
|
||
|
||
```
|
||
LA 08:24 NYC 11:24 LDN 16:24 17:24 SG 23:24 TOK 00:24 +1 AUS 01:24 +1 NZ 03:24 +1
|
||
```
|
||
|
||
An Omarchy 4 shell plugin (Quickshell). It reserves its own space, so Hyprland
|
||
tiles windows above it exactly as it does for the top bar.
|
||
|
||
## What it does
|
||
|
||
- **Timeline layout.** Side and position are derived from each zone's live UTC
|
||
offset, not from config order. Reading left to right always moves forward in
|
||
time, and a DST shift re-sorts the bar on its own.
|
||
- **24-hour times**, with `+1` / `-1` against clocks on a different date to you.
|
||
- **Labels** to the left of each time. The centre clock is your local time and
|
||
carries no label.
|
||
- **Dimmed outside working hours**, evaluated in each clock's *own* timezone
|
||
(weekends included), so a glance tells you who is actually around.
|
||
- **Seconds per clock.** Any clock can show `HH:MM:SS` on its own, including
|
||
your local one. The bar only drops to a per-second tick when something is
|
||
actually displaying seconds.
|
||
- **Themed.** Colours, fonts, spacing and bar height all come from the active
|
||
Omarchy theme; it follows a theme switch with no restart. Set your own bar
|
||
height and the type and spacing scale with it.
|
||
|
||
## Install
|
||
|
||
On any Omarchy 4 machine:
|
||
|
||
```bash
|
||
omarchy plugin add https://git.nerdnation.co.za/NerdNation/OmarchyClockBar.git --enable --yes
|
||
```
|
||
|
||
The plugin lands in `~/.config/omarchy/plugins/nerdnation.clockbar/`, and
|
||
`~/.config/omarchy/clockbar.json` is seeded on first run.
|
||
|
||
To update it later, and to remove it:
|
||
|
||
```bash
|
||
omarchy plugin update nerdnation.clockbar
|
||
omarchy plugin remove nerdnation.clockbar
|
||
```
|
||
|
||
> Plugins run as unsandboxed QML inside `omarchy-shell`, so `omarchy plugin add`
|
||
> clones disabled by default and wants you to read the code first. `--enable`
|
||
> skips that.
|
||
|
||
## Configuring it
|
||
|
||
Two routes, one source of truth — both read and write
|
||
`~/.config/omarchy/clockbar.json`, and the bar reloads from the file either way.
|
||
|
||
**Click the bar.** Opens an editor with a searchable timezone picker: add,
|
||
rename, retime and remove clocks, and set the working-hours window. Each row
|
||
shows that zone's current offset so you can see the effect before saving.
|
||
|
||
**Edit the file.** It hot-reloads on save, no restart:
|
||
|
||
```json
|
||
{
|
||
"version": 1,
|
||
"clocks": [
|
||
{ "label": "LA", "timezone": "America/Los_Angeles" },
|
||
{ "label": "NYC", "timezone": "America/New_York" },
|
||
{ "label": "SG", "timezone": "Asia/Singapore" },
|
||
{ "label": "AUS", "timezone": "Australia/Sydney" },
|
||
{ "label": "NZ", "timezone": "Pacific/Auckland", "showSeconds": true }
|
||
],
|
||
"workingHours": { "start": 8, "end": 18, "workdays": [1, 2, 3, 4, 5] },
|
||
"dimOutsideWorkingHours": true,
|
||
"showSeconds": false,
|
||
"local": { "showSeconds": false },
|
||
"barSize": 0
|
||
}
|
||
```
|
||
|
||
| Key | Meaning |
|
||
|---|---|
|
||
| `clocks[].label` | Shown left of the time. Defaults to the last part of the zone name. |
|
||
| `clocks[].timezone` | Any IANA zone (`timedatectl list-timezones`). |
|
||
| `clocks[].showSeconds` | Seconds on this clock. Omit it to inherit the bar-wide default below. |
|
||
| `workingHours.start` / `.end` | Hours, 0–24, in each clock's own zone. A window that wraps midnight (`22`–`6`) is understood. |
|
||
| `workingHours.workdays` | Days counted as working. `0` = Sunday. |
|
||
| `dimOutsideWorkingHours` | Mute clocks outside that window. |
|
||
| `showSeconds` | The bar-wide default for seconds, for clocks that do not set their own. |
|
||
| `local.showSeconds` | Seconds on your local clock, which has no entry in `clocks[]`. |
|
||
| `barSize` | Bar height in px. `0` follows the theme's. Otherwise 12–120; text and spacing scale with it. |
|
||
|
||
Seconds resolve per clock: a clock's own `showSeconds` wins, otherwise the
|
||
bar-wide default applies. An explicit `false` on a clock beats a `true`
|
||
default. The bar ticks once a minute unless something on it is showing
|
||
seconds — nothing pays for a per-second redraw it does not use.
|
||
|
||
There is no `left` / `right` setting: which side a clock lands on is a fact
|
||
about its offset, not a preference.
|
||
|
||
**When something is wrong**, the bar says so rather than lying. A zone tzdata
|
||
cannot resolve renders as `LABEL --:--` in the theme's urgent colour instead of
|
||
silently falling back to UTC. A `clockbar.json` that will not parse turns the
|
||
bar's top hairline red and puts `config error` beside your local time, while
|
||
the last good config keeps ticking — and the broken file is never overwritten.
|
||
|
||
## IPC
|
||
|
||
```bash
|
||
omarchy-shell nerdnation.clockbar edit # open the editor
|
||
omarchy-shell nerdnation.clockbar toggle
|
||
omarchy-shell nerdnation.clockbar refresh # re-probe timezone offsets
|
||
omarchy-shell nerdnation.clockbar reload # re-read clockbar.json
|
||
```
|
||
|
||
Bind the editor to a key in `~/.config/hypr/bindings.lua` if you want one.
|
||
|
||
## How it works, and why
|
||
|
||
Qt's QML engine ships **no `Intl`**, so there is no way to render an IANA
|
||
timezone from inside QML — the usual `Intl.DateTimeFormat({ timeZone })` route
|
||
does not exist. Rather than bundle a copy of the tz database, the plugin asks
|
||
the system's own tzdata for each zone's current UTC offset (`TZ=<zone> date +%z`)
|
||
and then does the arithmetic itself. That keeps it correct across DST changes
|
||
and tzdata updates without knowing any of the rules.
|
||
|
||
The probe is one short-lived shell, and its answer stays valid until a
|
||
transition, so it runs on a slow timer — every ten minutes, on each hour
|
||
boundary (where transitions land), and whenever the config changes. In between,
|
||
the clocks advance by arithmetic on the minute tick.
|
||
|
||
`ClockModel.js` holds all of that logic and touches no QML types, so it runs
|
||
unchanged under node:
|
||
|
||
```bash
|
||
node tests/model.test.js
|
||
```
|
||
|
||
## Layout
|
||
|
||
| File | Role |
|
||
|---|---|
|
||
| `manifest.json` | Plugin manifest — `kind: panel`, `keepLoaded` |
|
||
| `Clockbar.qml` | Entry point: the bottom layer-shell surface, one per screen |
|
||
| `Editor.qml` | The click-to-edit popup |
|
||
| `Config.qml` | `clockbar.json` — read, watch, write |
|
||
| `Zones.qml` | Timezone offset probe and the zone list for the picker |
|
||
| `ClockModel.js` | Ordering, formatting, day offsets, working hours (pure JS) |
|
||
| `tests/model.test.js` | Unit tests for the above |
|