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:
+30
-3
@@ -84,6 +84,29 @@ function isWorkingHours(wall, hours) {
|
||||
return hour >= start || hour < end
|
||||
}
|
||||
|
||||
// Seconds are decided per clock, falling back to the config-wide default.
|
||||
// An explicit `false` on a clock has to beat a `true` default, so the check is
|
||||
// for the property's presence, not its truthiness.
|
||||
function showsSeconds(entry, fallback) {
|
||||
if (entry && typeof entry.showSeconds === "boolean") return entry.showSeconds
|
||||
return fallback === true
|
||||
}
|
||||
|
||||
// Whether anything on the bar is showing seconds, which is what decides
|
||||
// between a per-second and a per-minute tick. Ticking every second when
|
||||
// nothing displays them wakes the whole shell sixty times as often for no
|
||||
// visible change.
|
||||
function anyShowsSeconds(config) {
|
||||
var cfg = config || {}
|
||||
var fallback = cfg.showSeconds === true
|
||||
if (showsSeconds(cfg.local, fallback)) return true
|
||||
var entries = Array.isArray(cfg.clocks) ? cfg.clocks : []
|
||||
for (var i = 0; i < entries.length; i++) {
|
||||
if (showsSeconds(entries[i], fallback)) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function isValidLabel(label) {
|
||||
return typeof label === "string" && label.replace(/^\s+|\s+$/g, "").length > 0
|
||||
}
|
||||
@@ -93,6 +116,7 @@ function isValidLabel(label) {
|
||||
// show the label struck through instead of quietly lying about the time.
|
||||
function buildClock(entry, offsets, utcMs, localOffset, options) {
|
||||
var opts = options || {}
|
||||
var withSeconds = showsSeconds(entry, opts.showSeconds)
|
||||
var timezone = String(entry && entry.timezone ? entry.timezone : "")
|
||||
var label = isValidLabel(entry && entry.label) ? String(entry.label).replace(/^\s+|\s+$/g, "") : timezone
|
||||
var offset = parseOffset(offsets ? offsets[timezone] : null)
|
||||
@@ -100,7 +124,8 @@ function buildClock(entry, offsets, utcMs, localOffset, options) {
|
||||
if (offset === null) {
|
||||
return {
|
||||
label: label, timezone: timezone, known: false,
|
||||
time: "--:--", marker: "", delta: 0, relativeMinutes: 0, working: false
|
||||
time: withSeconds ? "--:--:--" : "--:--",
|
||||
marker: "", delta: 0, relativeMinutes: 0, working: false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +137,7 @@ function buildClock(entry, offsets, utcMs, localOffset, options) {
|
||||
label: label,
|
||||
timezone: timezone,
|
||||
known: true,
|
||||
time: formatTime(wall, opts.showSeconds === true),
|
||||
time: formatTime(wall, withSeconds),
|
||||
marker: dayMarker(delta),
|
||||
delta: delta,
|
||||
relativeMinutes: offset - localOffset,
|
||||
@@ -165,7 +190,7 @@ function buildBar(config, offsets, utcMs, localOffsetRaw) {
|
||||
// of the trailing group where they are visible but never mis-ordered.
|
||||
right: right.concat(unknown),
|
||||
center: {
|
||||
time: formatTime(localWall, options.showSeconds),
|
||||
time: formatTime(localWall, showsSeconds(cfg.local, options.showSeconds)),
|
||||
date: localWall.getUTCFullYear() + "-" + pad2(localWall.getUTCMonth() + 1) + "-" + pad2(localWall.getUTCDate()),
|
||||
offsetMinutes: localOffset
|
||||
}
|
||||
@@ -211,6 +236,8 @@ if (typeof module !== "undefined" && module.exports) {
|
||||
dayDelta: dayDelta,
|
||||
dayMarker: dayMarker,
|
||||
isWorkingHours: isWorkingHours,
|
||||
showsSeconds: showsSeconds,
|
||||
anyShowsSeconds: anyShowsSeconds,
|
||||
buildClock: buildClock,
|
||||
buildBar: buildBar,
|
||||
zonesToProbe: zonesToProbe,
|
||||
|
||||
+26
-13
@@ -33,15 +33,28 @@ Item {
|
||||
// stay the same weight when the theme or font size changes.
|
||||
readonly property int barSize: config && config.barSize > 0 ? config.barSize : Style.bar.sizeHorizontal
|
||||
|
||||
// Everything drawn on the bar is sized against the theme's own bar height,
|
||||
// so a taller bar carries proportionally larger type and gaps rather than
|
||||
// the theme's 26px-sized text marooned in the middle of it. At the default
|
||||
// height this is exactly 1, which leaves the theme's own tokens untouched.
|
||||
readonly property real barScale: Style.bar.sizeHorizontal > 0
|
||||
? barSize / Style.bar.sizeHorizontal
|
||||
: 1
|
||||
|
||||
function scaled(px) { return Math.max(1, Math.round(px * root.barScale)) }
|
||||
|
||||
readonly property int timeFontSize: scaled(Style.font.body)
|
||||
readonly property int labelFontSize: scaled(Style.font.caption)
|
||||
|
||||
readonly property color background: Color.bar.background
|
||||
readonly property color foreground: Color.bar.text
|
||||
readonly property color muted: Color.muted
|
||||
readonly property color accent: Color.accent
|
||||
readonly property color urgent: Color.urgent
|
||||
|
||||
readonly property int edgePadding: Style.space(12)
|
||||
readonly property int clockGap: Style.space(16)
|
||||
readonly property int labelGap: Style.space(6)
|
||||
readonly property int edgePadding: scaled(Style.space(12))
|
||||
readonly property int clockGap: scaled(Style.space(16))
|
||||
readonly property int labelGap: scaled(Style.space(6))
|
||||
|
||||
Config { id: configFile }
|
||||
|
||||
@@ -50,12 +63,12 @@ Item {
|
||||
zones: Model.zonesToProbe(root.config)
|
||||
}
|
||||
|
||||
// Minute precision is all the display needs; seconds are opt-in because
|
||||
// ticking every second wakes the whole shell sixty times as often for a
|
||||
// readout nobody reads that closely.
|
||||
// Seconds are opt-in per clock, so the tick only drops to per-second when
|
||||
// something on the bar is actually displaying them — otherwise this wakes
|
||||
// the whole shell sixty times as often to redraw an identical minute.
|
||||
SystemClock {
|
||||
id: clock
|
||||
precision: root.config && root.config.showSeconds ? SystemClock.Seconds : SystemClock.Minutes
|
||||
precision: Model.anyShowsSeconds(root.config) ? SystemClock.Seconds : SystemClock.Minutes
|
||||
onDateChanged: {
|
||||
root.nowMs = date.getTime()
|
||||
// Offsets only move at a transition, and transitions land on the hour.
|
||||
@@ -117,7 +130,7 @@ Item {
|
||||
// step down the scale — present for identification, not competing with
|
||||
// the time for the glance.
|
||||
font.family: Style.font.family
|
||||
font.pixelSize: Style.font.caption
|
||||
font.pixelSize: root.labelFontSize
|
||||
// Held back from the time it captions, but only once: a dimmed clock is
|
||||
// already carrying the muted tint, and compounding the two put its label
|
||||
// under the legibility floor.
|
||||
@@ -129,7 +142,7 @@ Item {
|
||||
text: entry.clock.time
|
||||
color: entry.tint
|
||||
font.family: Style.font.family
|
||||
font.pixelSize: Style.font.body
|
||||
font.pixelSize: root.timeFontSize
|
||||
}
|
||||
|
||||
Text {
|
||||
@@ -142,7 +155,7 @@ Item {
|
||||
text: entry.clock.marker
|
||||
color: entry.tint
|
||||
font.family: Style.font.family
|
||||
font.pixelSize: Style.font.caption
|
||||
font.pixelSize: root.labelFontSize
|
||||
opacity: 0.7
|
||||
}
|
||||
}
|
||||
@@ -184,7 +197,7 @@ Item {
|
||||
// that cannot be overlapped by a long list of clocks.
|
||||
Rectangle {
|
||||
anchors { top: parent.top; left: parent.left; right: parent.right }
|
||||
height: configFile.parseError !== "" ? 2 : 1
|
||||
height: configFile.parseError !== "" ? root.scaled(2) : Math.max(1, root.scaled(1))
|
||||
color: configFile.parseError !== "" ? root.urgent : root.foreground
|
||||
opacity: configFile.parseError !== "" ? 0.9 : 0.12
|
||||
}
|
||||
@@ -215,7 +228,7 @@ Item {
|
||||
text: root.bar.center.time
|
||||
color: root.accent
|
||||
font.family: Style.font.family
|
||||
font.pixelSize: Style.font.body
|
||||
font.pixelSize: root.timeFontSize
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
@@ -228,7 +241,7 @@ Item {
|
||||
text: "config error"
|
||||
color: root.urgent
|
||||
font.family: Style.font.family
|
||||
font.pixelSize: Style.font.caption
|
||||
font.pixelSize: root.labelFontSize
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+17
-2
@@ -38,7 +38,10 @@ QtObject {
|
||||
],
|
||||
workingHours: { start: 8, end: 18, workdays: [1, 2, 3, 4, 5] },
|
||||
dimOutsideWorkingHours: true,
|
||||
// The bar-wide default for seconds. Any clock, and the centre clock via
|
||||
// `local`, may override it.
|
||||
showSeconds: false,
|
||||
local: { showSeconds: false },
|
||||
barSize: 0
|
||||
}
|
||||
}
|
||||
@@ -58,7 +61,12 @@ QtObject {
|
||||
var tz = String(entry.timezone || "").replace(/^\s+|\s+$/g, "")
|
||||
if (!tz) continue
|
||||
var label = String(entry.label === undefined || entry.label === null ? "" : entry.label).replace(/^\s+|\s+$/g, "")
|
||||
clocks.push({ label: label || tz, timezone: tz })
|
||||
var clock = { label: label || tz, timezone: tz }
|
||||
// Carried through only when the clock actually sets it, so a clock
|
||||
// with no opinion keeps inheriting the bar-wide default rather than
|
||||
// being frozen to whatever it happened to be when this was written.
|
||||
if (typeof entry.showSeconds === "boolean") clock.showSeconds = entry.showSeconds
|
||||
clocks.push(clock)
|
||||
}
|
||||
out.clocks = clocks
|
||||
}
|
||||
@@ -81,8 +89,15 @@ QtObject {
|
||||
|
||||
if (typeof raw.dimOutsideWorkingHours === "boolean") out.dimOutsideWorkingHours = raw.dimOutsideWorkingHours
|
||||
if (typeof raw.showSeconds === "boolean") out.showSeconds = raw.showSeconds
|
||||
if (raw.local && typeof raw.local === "object" && typeof raw.local.showSeconds === "boolean")
|
||||
out.local.showSeconds = raw.local.showSeconds
|
||||
|
||||
// 0 means "follow the theme". The ceiling is a guard against a typo
|
||||
// turning the bar into a full-screen panel with no way back to the
|
||||
// editor that would undo it.
|
||||
var size = Number(raw.barSize)
|
||||
if (isFinite(size) && size >= 0 && size <= 200) out.barSize = size
|
||||
if (isFinite(size) && size > 0) out.barSize = Math.min(120, Math.max(12, Math.round(size)))
|
||||
else if (isFinite(size)) out.barSize = 0
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
+93
-7
@@ -24,6 +24,9 @@ Item {
|
||||
property int workStart: 8
|
||||
property int workEnd: 18
|
||||
property bool dimOutside: true
|
||||
property bool defaultSeconds: false
|
||||
property bool localSeconds: false
|
||||
property int barSize: 0
|
||||
|
||||
readonly property color background: Color.popups.background
|
||||
readonly property color foreground: Color.popups.text
|
||||
@@ -56,24 +59,38 @@ Item {
|
||||
var cfg = root.configFile ? root.configFile.config : null
|
||||
var clocks = cfg && Array.isArray(cfg.clocks) ? cfg.clocks : []
|
||||
var copy = []
|
||||
for (var i = 0; i < clocks.length; i++)
|
||||
copy.push({ label: String(clocks[i].label || ""), timezone: String(clocks[i].timezone || "") })
|
||||
for (var i = 0; i < clocks.length; i++) {
|
||||
var row = { label: String(clocks[i].label || ""), timezone: String(clocks[i].timezone || "") }
|
||||
if (typeof clocks[i].showSeconds === "boolean") row.showSeconds = clocks[i].showSeconds
|
||||
copy.push(row)
|
||||
}
|
||||
root.draft = copy
|
||||
if (cfg && cfg.workingHours) {
|
||||
root.workStart = Number(cfg.workingHours.start)
|
||||
root.workEnd = Number(cfg.workingHours.end)
|
||||
}
|
||||
root.dimOutside = cfg ? cfg.dimOutsideWorkingHours !== false : true
|
||||
root.defaultSeconds = cfg ? cfg.showSeconds === true : false
|
||||
root.localSeconds = Model.showsSeconds(cfg ? cfg.local : null, root.defaultSeconds)
|
||||
root.barSize = cfg && cfg.barSize > 0 ? cfg.barSize : 0
|
||||
}
|
||||
|
||||
// What a row's toggle shows: its own setting when it has one, otherwise the
|
||||
// bar-wide default it is inheriting.
|
||||
function rowShowsSeconds(row) { return Model.showsSeconds(row, root.defaultSeconds) }
|
||||
|
||||
// QML only re-renders a var array when the reference changes, so every
|
||||
// mutation rebuilds it rather than editing in place.
|
||||
function replaceDraft(next) { root.draft = next }
|
||||
|
||||
// Copies every key the row already had. Rebuilding it from a fixed pair of
|
||||
// fields silently dropped anything else on it — editing a label would have
|
||||
// thrown away that clock's own seconds setting.
|
||||
function updateRow(index, key, value) {
|
||||
var next = root.draft.slice()
|
||||
if (!next[index]) return
|
||||
var row = { label: next[index].label, timezone: next[index].timezone }
|
||||
var row = {}
|
||||
for (var k in next[index]) row[k] = next[index][k]
|
||||
row[key] = value
|
||||
next[index] = row
|
||||
replaceDraft(next)
|
||||
@@ -99,7 +116,11 @@ Item {
|
||||
var tz = String(root.draft[i].timezone || "").replace(/^\s+|\s+$/g, "")
|
||||
if (!tz) continue
|
||||
var label = String(root.draft[i].label || "").replace(/^\s+|\s+$/g, "")
|
||||
out.push({ label: label || tz.split("/").pop().replace(/_/g, " "), timezone: tz })
|
||||
var row = { label: label || tz.split("/").pop().replace(/_/g, " "), timezone: tz }
|
||||
// Only clocks the user actually set keep an explicit flag; the rest go
|
||||
// on inheriting the bar-wide default.
|
||||
if (typeof root.draft[i].showSeconds === "boolean") row.showSeconds = root.draft[i].showSeconds
|
||||
out.push(row)
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -116,8 +137,9 @@ Item {
|
||||
workdays: cfg && cfg.workingHours ? cfg.workingHours.workdays : [1, 2, 3, 4, 5]
|
||||
},
|
||||
dimOutsideWorkingHours: root.dimOutside,
|
||||
showSeconds: cfg ? cfg.showSeconds === true : false,
|
||||
barSize: cfg ? cfg.barSize : 0
|
||||
showSeconds: root.defaultSeconds,
|
||||
local: { showSeconds: root.localSeconds },
|
||||
barSize: root.barSize
|
||||
})
|
||||
close()
|
||||
}
|
||||
@@ -211,7 +233,7 @@ Item {
|
||||
spacing: Style.space(8)
|
||||
|
||||
TextField {
|
||||
Layout.preferredWidth: Style.space(74)
|
||||
Layout.preferredWidth: Style.space(66)
|
||||
text: row.modelData.label
|
||||
placeholderText: "Label"
|
||||
foreground: root.foreground
|
||||
@@ -245,6 +267,18 @@ Item {
|
||||
font.pixelSize: Style.font.caption
|
||||
}
|
||||
|
||||
Button {
|
||||
text: "SS"
|
||||
bordered: true
|
||||
selected: root.rowShowsSeconds(row.modelData)
|
||||
tooltipText: root.rowShowsSeconds(row.modelData)
|
||||
? "Showing seconds — click for HH:MM"
|
||||
: "Show seconds on this clock"
|
||||
foreground: root.foreground
|
||||
accent: root.accent
|
||||
onClicked: root.updateRow(row.index, "showSeconds", !root.rowShowsSeconds(row.modelData))
|
||||
}
|
||||
|
||||
Button {
|
||||
iconText: ""
|
||||
tooltipText: "Remove this clock"
|
||||
@@ -346,6 +380,58 @@ Item {
|
||||
|
||||
PanelSeparator { Layout.fillWidth: true }
|
||||
|
||||
PanelSectionHeader {
|
||||
Layout.fillWidth: true
|
||||
text: "Bar"
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.space(8)
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: "Seconds on your local clock"
|
||||
color: root.foreground
|
||||
elide: Text.ElideRight
|
||||
font.family: Style.font.family
|
||||
font.pixelSize: Style.font.body
|
||||
}
|
||||
|
||||
ToggleSwitch {
|
||||
checked: root.localSeconds
|
||||
foreground: root.foreground
|
||||
accent: root.accent
|
||||
onToggled: root.localSeconds = !root.localSeconds
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.space(8)
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: "Bar height — 0 follows the theme. Text scales with it."
|
||||
color: root.muted
|
||||
elide: Text.ElideRight
|
||||
font.family: Style.font.family
|
||||
font.pixelSize: Style.font.caption
|
||||
}
|
||||
|
||||
NumberField {
|
||||
Layout.preferredWidth: Style.spacing.numberFieldWidth
|
||||
value: root.barSize
|
||||
from: 0
|
||||
to: 120
|
||||
foreground: root.foreground
|
||||
accent: root.accent
|
||||
onModified: function (v) { root.barSize = v }
|
||||
}
|
||||
}
|
||||
|
||||
PanelSeparator { Layout.fillWidth: true }
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.space(8)
|
||||
|
||||
@@ -21,8 +21,12 @@ tiles windows above it exactly as it does for the top bar.
|
||||
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.
|
||||
Omarchy theme; it follows a theme switch with no restart. Set your own bar
|
||||
height and the type and spacing scale with it.
|
||||
|
||||
## Install
|
||||
|
||||
@@ -65,11 +69,12 @@ shows that zone's current offset so you can see the effect before saving.
|
||||
{ "label": "NYC", "timezone": "America/New_York" },
|
||||
{ "label": "SG", "timezone": "Asia/Singapore" },
|
||||
{ "label": "AUS", "timezone": "Australia/Sydney" },
|
||||
{ "label": "NZ", "timezone": "Pacific/Auckland" }
|
||||
{ "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
|
||||
}
|
||||
```
|
||||
@@ -78,11 +83,18 @@ shows that zone's current offset so you can see the effect before saving.
|
||||
|---|---|
|
||||
| `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` | `HH:MM:SS` and a per-second tick, instead of `HH:MM`. |
|
||||
| `barSize` | Bar height in px. `0` follows the theme's bar height. |
|
||||
| `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.
|
||||
|
||||
@@ -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" : ""))
|
||||
|
||||
Reference in New Issue
Block a user