mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-01 12:18:51 +00:00
At dawn, dusk and night the environment shows the moon in the top-left corner of the scene, behind the plan: computed in the card from the home coordinates and the browser clock (short Meeus series + topocentric parallax, within 1.4° / 1.8 pp of JPL Horizons), one designer image under a continuous phase mask with the lit side always on the left (owner 2026-09-29), a feathered terminator, 3°/3 % thresholds and the 2 s fade of the window rays. Everything but a small gate lives in the lazy moon-runtime chunk, with its own 30 s ticker. General settings: "Sun" becomes "Sun and Moon" with one switch, on for new installations (DEFAULT_CONFIG), off for existing ones. The initial View graph sat 728 B under its budget: the gate is paid for by moving fifteen dialog-only strings of General settings into the lazy settings dictionary (#459) and by one build fingerprint literal instead of three, so the graph ends 4 B above dev. Golden: two new moon scenes, and the two General settings help frames show «Sun and Moon»; the WSL artifact test fixture now models scenes whose first capture awaits acceptance. Issue: #661 User-Visible: yes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
54 lines
3.0 KiB
JavaScript
54 lines
3.0 KiB
JavaScript
// #661 AC10: the moon switch in General settings — «Sun and Moon» section,
|
|
// reset to on, save writes `true` or removes the key; its strings exist in all
|
|
// four dictionaries. The dialog is a lazy Lit module (its layout is read as a
|
|
// source contract); reading and writing the key are executed.
|
|
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
import { moonDraftOf, writeMoonSetting } from '../test-build/editors/general-form-state.js';
|
|
|
|
const read = (path) => readFileSync(new URL(`../${path}`, import.meta.url), 'utf8');
|
|
const json = (path) => JSON.parse(read(path));
|
|
|
|
test('#661 AC10: the switch sits in the «Sun and Moon» card under «Sunlight through windows»', () => {
|
|
const dialog = read('src/editors/general-settings-dialog.ts');
|
|
const sun = dialog.slice(dialog.indexOf("id: 'sun',"), dialog.indexOf("id: 'data',"));
|
|
assert.match(sun, /title: t\('gs\.sun_group'\)/);
|
|
const rays = sun.indexOf("id: 'gs-sun-rays'");
|
|
const moon = sun.indexOf("id: 'gs-moon'");
|
|
assert.ok(rays > 0 && moon > rays, 'moon row follows the sun-rays row');
|
|
const row = sun.slice(moon, sun.indexOf('})}', moon));
|
|
assert.match(row, /icon: 'mdi:moon-waning-crescent'/);
|
|
assert.match(row, /title: st\('gs\.moon'\), caption: st\('gs\.moon_hint'\)/);
|
|
assert.match(row, /checked: d\.moon, onChange: \(v\) => set\(\{ moon: v \}\)/);
|
|
const reset = dialog.slice(dialog.indexOf("${t('gs.reset')}") - 600, dialog.indexOf("${t('gs.reset')}"));
|
|
assert.match(reset, /moon: true/, 'reset to defaults switches the moon on (new installations)');
|
|
});
|
|
|
|
test('#661 AC10: opening reads only an explicit true; saving writes true or removes the key', () => {
|
|
assert.equal(moonDraftOf({ moon: true }), true);
|
|
for (const settings of [undefined, null, {}, { moon: false }, { moon: 'true' }, { moon: 1 }]) {
|
|
assert.equal(moonDraftOf(settings), false, JSON.stringify(settings));
|
|
}
|
|
const on = { bg_mode: 'daynight' };
|
|
writeMoonSetting(on, true);
|
|
assert.deepEqual(on, { bg_mode: 'daynight', moon: true });
|
|
const off = { bg_mode: 'daynight', moon: true };
|
|
writeMoonSetting(off, false);
|
|
assert.deepEqual(off, { bg_mode: 'daynight' });
|
|
assert.equal('moon' in off, false, 'false is stored as absence');
|
|
});
|
|
|
|
test('#661 AC10: strings in all four dictionaries, section renamed', () => {
|
|
const group = { en: 'Sun and Moon', ru: 'Солнце и Луна', de: 'Sonne und Mond', fr: 'Soleil et Lune' };
|
|
for (const lang of ['en', 'ru', 'de', 'fr']) {
|
|
assert.equal(json(`src/i18n/${lang}.json`)['gs.sun_group'], group[lang], lang);
|
|
const settings = json(`src/i18n/settings/${lang}.json`);
|
|
for (const key of ['gs.moon', 'gs.moon_hint']) {
|
|
assert.ok(typeof settings[key] === 'string' && settings[key].trim(), `${lang} ${key}`);
|
|
}
|
|
}
|
|
assert.equal(json('src/i18n/settings/ru.json')['gs.moon'], 'Луна на плане в сумерках и ночью');
|
|
assert.equal(json('src/i18n/settings/en.json')['gs.moon'], 'Moon over the plan at dusk and night');
|
|
});
|