Seconds per clock, and type that scales with the bar height

Seconds move from one bar-wide switch to a per-clock setting. A clock's own
`showSeconds` wins, the top-level one is the default for clocks with no
opinion, and the centre clock gets `local.showSeconds` since it has no entry in
`clocks[]`. An explicit false on a clock beats a true default, so the check is
for the property's presence rather than its truthiness.

The tick rate follows what is actually displayed: `anyShowsSeconds()` decides
between a per-second and a per-minute SystemClock, so a bar showing no seconds
does not wake the shell sixty times as often to redraw an identical minute.

`barSize` is now editable from the popup, and everything drawn on the bar is
sized against the theme's own bar height rather than pinned to the theme's
12px type. A taller bar carries proportionally larger text, gaps and rule; at
the theme's own height the scale is exactly 1, so nothing moves. Heights are
clamped to 12-120 rather than rejected, so a value the editor can produce can
never be one the config layer silently discards.

Fixes a latent bug this surfaced: updateRow() rebuilt a draft row from a fixed
pair of fields, so editing a clock's label would have thrown away its own
seconds setting. It now copies every key the row had.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MhxtL7WzL5XmuTd8GHbcTY
This commit is contained in:
2026-09-04 18:02:36 +02:00
co-authored by Claude Opus 5
parent 602a6db274
commit b3123ecb3b
6 changed files with 249 additions and 29 deletions
+67
View File
@@ -182,4 +182,71 @@ test("an empty config renders an empty bar, not a crash", function () {
assert.deepStrictEqual(M.buildBar(null, null, NOW, null).center.time, "15:24")
})
test("seconds are per clock, with a config-wide default", function () {
var cfg = {
showSeconds: false,
clocks: [
{ label: "LA", timezone: "America/Los_Angeles", showSeconds: true },
{ label: "NYC", timezone: "America/New_York" }
]
}
var bar = M.buildBar(cfg, OFFSETS, NOW, SAST)
var byLabel = {}
bar.left.forEach(function (c) { byLabel[c.label] = c })
assert.strictEqual(byLabel.LA.time, "08:24:00", "opted in")
assert.strictEqual(byLabel.NYC.time, "11:24", "inherits the default")
assert.strictEqual(bar.center.time, "17:24", "centre inherits the default")
})
test("an explicit false on a clock beats a true default", function () {
var cfg = {
showSeconds: true,
clocks: [
{ label: "LA", timezone: "America/Los_Angeles", showSeconds: false },
{ label: "NYC", timezone: "America/New_York" }
]
}
var bar = M.buildBar(cfg, OFFSETS, NOW, SAST)
var byLabel = {}
bar.left.forEach(function (c) { byLabel[c.label] = c })
assert.strictEqual(byLabel.LA.time, "08:24", "opted out")
assert.strictEqual(byLabel.NYC.time, "11:24:00")
assert.strictEqual(bar.center.time, "17:24:00")
})
test("the centre clock carries its own seconds override", function () {
var cfg = {
showSeconds: false,
local: { showSeconds: true },
clocks: [{ label: "LA", timezone: "America/Los_Angeles" }]
}
var bar = M.buildBar(cfg, OFFSETS, NOW, SAST)
assert.strictEqual(bar.center.time, "17:24:00")
assert.strictEqual(bar.left[0].time, "08:24", "clocks are unaffected by it")
})
test("anyShowsSeconds drives the tick rate", function () {
assert.strictEqual(M.anyShowsSeconds({ clocks: [{ label: "A", timezone: "X" }] }), false)
assert.strictEqual(M.anyShowsSeconds({ showSeconds: true, clocks: [] }), true, "the default alone counts")
assert.strictEqual(M.anyShowsSeconds({ local: { showSeconds: true }, clocks: [] }), true, "the centre alone counts")
assert.strictEqual(M.anyShowsSeconds({
clocks: [{ label: "A", timezone: "X" }, { label: "B", timezone: "Y", showSeconds: true }]
}), true, "one clock is enough")
assert.strictEqual(M.anyShowsSeconds({
showSeconds: true,
local: { showSeconds: false },
clocks: [{ label: "A", timezone: "X", showSeconds: false }]
}), false, "everything opted out")
assert.strictEqual(M.anyShowsSeconds(null), false)
})
test("an unresolved clock keeps the width of the format it asked for", function () {
var bar = M.buildBar({ clocks: [
{ label: "A", timezone: "Not/AZone" },
{ label: "B", timezone: "Not/AZone", showSeconds: true }
] }, {}, NOW, SAST)
assert.strictEqual(bar.right[0].time, "--:--")
assert.strictEqual(bar.right[1].time, "--:--:--")
})
console.log(passed + " passed" + (process.exitCode ? ", some FAILED" : ""))