* Move Elsewhen into Omarchy as omarchy.elsewhen The world clock ships in the shell tree instead of its own package. A migration renames existing bar entries with their settings and removes the retired package. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Remove Elsewhen's shelved Earth row, overlap band and sky tint Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Tidy Elsewhen's models, data helper and docs, and drop currency Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Restructure Elsewhen's panel and globe on the shared shell components Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Show Elsewhen's bar globe upright Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Use the shared city search for Elsewhen's globe jump bar Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Keep legacy Elsewhen entries single and retry offline geocodes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Fetch Elsewhen's weather with curl instead of a Python helper Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
69 lines
3.6 KiB
Bash
69 lines
3.6 KiB
Bash
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
|
|
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
|
|
|
|
run_node_test <<'JS'
|
|
const { layout } = requireFromRoot('shell/plugins/panels/elsewhen/Arc.js')
|
|
|
|
const near = (a, b, eps) => Math.abs(a - b) <= (eps === undefined ? 0.01 : eps)
|
|
const mono = (count, width) => new Array(count).fill(width === undefined ? 6 : width)
|
|
const RISE = 6
|
|
|
|
// ---- a flat line
|
|
|
|
const flat = layout(mono(10), 0, true)
|
|
assert(flat.height === 0 && flat.width === 60, 'elsewhen lays a flat line out full width with no height')
|
|
assertEqual(flat.chars.map(c => c.x).join(), '0,6,12,18,24,30,36,42,48,54', 'elsewhen lays a flat line out end to end')
|
|
assert(flat.chars.every(c => c.rotation === 0), 'elsewhen turns nothing on a flat line')
|
|
assertEqual(layout([], 6, true).chars.length, 0, 'elsewhen lays out empty text')
|
|
assertEqual(layout(mono(4), -3, true).height, 0, 'elsewhen treats a negative rise as flat')
|
|
|
|
// ---- the rise
|
|
|
|
for (const count of [20, 30, 50, 90]) {
|
|
const r = layout(mono(count), RISE, true)
|
|
const ys = r.chars.map(c => c.y)
|
|
const dip = Math.max(...ys) - (ys[0] + ys[ys.length - 1]) / 2
|
|
assert(near(r.height, RISE, 0.05), `elsewhen bends ${count} characters by the rise`, r.height)
|
|
// The end glyphs sit half a character in from the ends of the arc.
|
|
assert(dip > RISE * 0.85 && dip <= RISE, `elsewhen dips ${count} glyphs by about the rise`, dip)
|
|
}
|
|
|
|
// ---- shape
|
|
|
|
const smile = layout(mono(30), RISE, true)
|
|
const frown = layout(mono(30), RISE, false)
|
|
const last = smile.chars.length - 1
|
|
assert(smile.chars[15].y > smile.chars[0].y && frown.chars[15].y < frown.chars[0].y, 'elsewhen dips a smile and raises a frown')
|
|
assert(smile.chars.every((c, i) => near(c.y, smile.height - frown.chars[i].y) && near(c.rotation, -frown.chars[i].rotation) && near(c.x, frown.chars[i].x)), 'elsewhen mirrors a smile and a frown')
|
|
assert(smile.chars.every((c, i) => near(c.y, smile.chars[last - i].y) && near(c.rotation, -smile.chars[last - i].rotation)), 'elsewhen bends symmetrically')
|
|
assert(smile.chars.every((c, i) => i === 0 || c.x > smile.chars[i - 1].x) && near(smile.chars[0].x, 0), 'elsewhen advances from the left edge')
|
|
// Qt turns clockwise for a positive angle.
|
|
assert(smile.chars[0].rotation > 0 && smile.chars[last].rotation < 0, 'elsewhen leans into each end')
|
|
assert(near(smile.chars[14].rotation, -smile.chars[15].rotation), 'elsewhen levels the middle')
|
|
|
|
const offTangent = []
|
|
for (let i = 1; i < smile.chars.length; i++) {
|
|
const dy = smile.chars[i].y - smile.chars[i - 1].y
|
|
const dx = smile.chars[i].x - smile.chars[i - 1].x
|
|
const turn = (smile.chars[i].rotation + smile.chars[i - 1].rotation) / 2
|
|
if (!near(Math.atan2(dy, dx) * 180 / Math.PI, turn, 0.1)) offTangent.push(i)
|
|
}
|
|
assertDeepEqual(offTangent, [], 'elsewhen turns each character along the arc')
|
|
|
|
// ---- proportional text and reserved width
|
|
|
|
const prop = layout([4, 4, 4, 16, 16, 16].concat(mono(24)), RISE, true)
|
|
assert(near(prop.chars[1].x - prop.chars[0].x, 4, 0.1) && near(prop.chars[4].x - prop.chars[3].x, 16, 0.1), 'elsewhen keeps proportional advances')
|
|
|
|
const wide = layout(mono(40), 20, true)
|
|
assert(wide.chars.every(c => c.x >= -0.001 && c.x + 6 <= wide.width + 0.001), 'elsewhen reserves width for every box')
|
|
assert(wide.width < 240 && wide.width > 230, 'elsewhen narrows the arc only a little', wide.width)
|
|
|
|
const absurd = layout(mono(10), 1000, true)
|
|
assert(isFinite(absurd.height) && absurd.height <= 15.01, 'elsewhen clamps an absurd rise', absurd.height)
|
|
assert(absurd.chars.length === 10 && absurd.chars.every(c => isFinite(c.x) && isFinite(c.y) && isFinite(c.rotation)), 'elsewhen still lays out every character under an absurd rise')
|
|
JS
|