Skip to content

Commit 161b4f2

Browse files
committed
feat(ephemeris-table): name the sign glyphs the table prints
1 parent 8d347d8 commit 161b4f2

11 files changed

Lines changed: 215 additions & 2 deletions

File tree

packages/ui/components-catalog.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@
568568
"error",
569569
"form",
570570
"header",
571+
"legend",
571572
"loading",
572573
"section",
573574
"table"

packages/ui/src/components/ephemeris-table.ts

Lines changed: 105 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { css, html, nothing } from 'lit';
22
import { customElement, property } from 'lit/decorators.js';
3-
import { planetGlyph, signGlyph } from '../tokens/index.js';
3+
import { planetGlyph, SIGNS_ORDER, signGlyph } from '../tokens/index.js';
44
import type {
55
GetMonthlyEphemerisResponse,
66
GetMonthlyTropicalEphemerisResponse,
@@ -75,11 +75,21 @@ interface DayRow {
7575
cells: Array<Position | undefined>;
7676
}
7777

78+
/** One line of the sign key: the glyph the table prints and the name it stands for. */
79+
interface SignKeyEntry {
80+
/** Canonical English sign, the glyph lookup key. */
81+
sign: string;
82+
/** The sign name a reader sees, in the response language. */
83+
label: string;
84+
glyph: string;
85+
}
86+
7887
interface ViewModel {
7988
year: number;
8089
month: number;
8190
bodies: BodyTrack[];
8291
rows: DayRow[];
92+
signs: SignKeyEntry[];
8393
}
8494

8595
/**
@@ -224,6 +234,29 @@ export class RoxyEphemerisTable extends RoxyDataElement<EphemerisResponse> {
224234
letter-spacing: 0.06em;
225235
color: var(--roxy-muted, #71717a);
226236
}
237+
/* Wraps rather than scrolls: it is a reference a reader scans, and a
238+
* key hidden behind a horizontal scrollbar helps nobody. */
239+
.signkey {
240+
display: flex;
241+
flex-wrap: wrap;
242+
gap: 1px 0;
243+
margin: 0;
244+
padding: 0;
245+
list-style: none;
246+
}
247+
.signkey-item {
248+
display: inline-flex;
249+
align-items: baseline;
250+
gap: 0.3rem;
251+
padding: 2px 10px 2px 0;
252+
font-size: var(--roxy-text-xs, 0.75rem);
253+
color: var(--roxy-muted, #71717a);
254+
white-space: nowrap;
255+
}
256+
.signkey-glyph {
257+
font-size: var(--roxy-text-sm, 0.875rem);
258+
color: var(--roxy-fg, #0a0a0a);
259+
}
227260
.tracks {
228261
display: grid;
229262
grid-template-columns: minmax(0, 1fr);
@@ -402,6 +435,7 @@ export class RoxyEphemerisTable extends RoxyDataElement<EphemerisResponse> {
402435
><span class="basis">${SAMPLE_INSTANT}</span>
403436
</p>
404437
</header>
438+
${this.renderSignKey(vm.signs)}
405439
<section part="section changes">
406440
<h3>${this.t('Sign changes and retrograde periods')}</h3>
407441
<div class="tracks" role="list">
@@ -424,6 +458,34 @@ export class RoxyEphemerisTable extends RoxyDataElement<EphemerisResponse> {
424458
</div>`;
425459
}
426460

461+
/**
462+
* The glyph-to-name key, above the table it explains.
463+
*
464+
* @remarks
465+
* Every position in this component prints its sign as a glyph, which is how a
466+
* printed ephemeris prints one and is unreadable to somebody still learning
467+
* them. The name rides on each cell's `title`, and a title is a hover: it does
468+
* not exist on touch and it cannot be read down a column. A key that names all
469+
* of them once is the form the page actually needed.
470+
*
471+
* `part="section legend"` rather than a name of its own, because a page hiding
472+
* legends should hide this one too and the vocabulary is shared across every
473+
* component.
474+
*/
475+
private renderSignKey(signs: SignKeyEntry[]) {
476+
if (signs.length === 0) return nothing;
477+
return html`<section part="section legend">
478+
<h3>${this.t('Signs in this month')}</h3>
479+
<ul class="signkey" role="list">
480+
${signs.map(
481+
(s) => html`<li class="signkey-item">
482+
<span class="signkey-glyph" aria-hidden="true">${s.glyph}</span>${s.label}
483+
</li>`,
484+
)}
485+
</ul>
486+
</section>`;
487+
}
488+
427489
/** One body across the month: where it started, where it ended, and every change in between. */
428490
private renderTrack(b: BodyTrack) {
429491
const glyph = planetGlyph(b.name);
@@ -617,7 +679,48 @@ export class RoxyEphemerisTable extends RoxyDataElement<EphemerisResponse> {
617679
const byName = new Map(day.positions.map((p) => [p.planet, p]));
618680
return { date: day.date, cells: bodies.map((b) => byName.get(b.name)) };
619681
});
620-
return { year: data.year, month: data.month, bodies, rows };
682+
return {
683+
year: data.year,
684+
month: data.month,
685+
bodies,
686+
rows,
687+
signs: this.toSignKey(data),
688+
};
689+
}
690+
691+
/**
692+
* The signs this month's table actually prints, in zodiacal order.
693+
*
694+
* @remarks
695+
* Read from the response rather than from the twelve-sign constant, so the key
696+
* explains the glyphs ON THIS PAGE and nothing else. In practice the Moon
697+
* crosses every sign in a month, so a full month lists all twelve anyway; a
698+
* partial range lists only what it contains, which is the point.
699+
*
700+
* The label is the API's own localized sign name, taken the same way every
701+
* other sign name in this component is taken. Translating it here instead
702+
* would put a second vocabulary on the page and let the key disagree with the
703+
* cells it explains.
704+
*
705+
* Ordered by {@link SIGNS_ORDER} because first-seen order is the order the
706+
* bodies happen to sit in on the first of the month, which is meaningless to a
707+
* reader learning the glyphs.
708+
*/
709+
private toSignKey(data: EphemerisResponse): SignKeyEntry[] {
710+
const labels = new Map<string, string>();
711+
for (const day of data.days) {
712+
for (const p of day.positions) {
713+
const key = String(p.sign ?? '').toLowerCase();
714+
if (key && !labels.has(key)) labels.set(key, display(p, 'sign'));
715+
}
716+
}
717+
const out: SignKeyEntry[] = [];
718+
for (const sign of SIGNS_ORDER) {
719+
const label = labels.get(sign.toLowerCase());
720+
const glyph = signGlyph(sign);
721+
if (label && glyph) out.push({ sign, label, glyph });
722+
}
723+
return out;
621724
}
622725
}
623726

packages/ui/src/i18n/chrome-strings.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ export const CHROME_STRINGS = [
143143
// only word it adds is the verb.
144144
'Ephemeris',
145145
'No ephemeris data',
146+
'Signs in this month',
146147
'Sign changes and retrograde periods',
147148
'Daily positions',
148149
'Date',

packages/ui/src/locales/de.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ export const de: Record<ChromeString, string> = {
178178

179179
Ephemeris: 'Ephemeriden',
180180
'No ephemeris data': 'Keine Ephemeridendaten',
181+
'Signs in this month': 'Zeichen in diesem Monat',
181182
'Sign changes and retrograde periods': 'Zeichenwechsel und Rückläufigkeiten',
182183
'Daily positions': 'Tägliche Planetenstände',
183184
Date: 'Datum',

packages/ui/src/locales/es.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ export const es: Record<ChromeString, string> = {
191191

192192
Ephemeris: 'Efemérides',
193193
'No ephemeris data': 'Sin datos de efemérides',
194+
'Signs in this month': 'Signos de este mes',
194195
'Sign changes and retrograde periods':
195196
'Cambios de signo y períodos retrógrados',
196197
'Daily positions': 'Posiciones diarias',

packages/ui/src/locales/fr.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ export const fr: Record<ChromeString, string> = {
177177

178178
Ephemeris: 'Éphémérides',
179179
'No ephemeris data': 'Aucune donnée disponible',
180+
'Signs in this month': 'Signes de ce mois',
180181
'Sign changes and retrograde periods':
181182
'Changements de signe et rétrogradations',
182183
'Daily positions': 'Positions planétaires au quotidien',

packages/ui/src/locales/hi.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ export const hi: Record<ChromeString, string> = {
193193

194194
Ephemeris: 'ग्रह स्थिति',
195195
'No ephemeris data': 'ग्रह स्थिति का कोई डेटा नहीं है',
196+
'Signs in this month': 'इस माह की राशियाँ',
196197
'Sign changes and retrograde periods': 'राशि परिवर्तन और वक्री अवधि',
197198
'Daily positions': 'दैनिक ग्रह स्थिति',
198199
Date: 'दिनांक',

packages/ui/src/locales/pt.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ export const pt: Record<ChromeString, string> = {
171171

172172
Ephemeris: 'Efemérides',
173173
'No ephemeris data': 'Sem dados de efemérides',
174+
'Signs in this month': 'Signos deste mês',
174175
'Sign changes and retrograde periods': 'Mudanças de signo e retrogradações',
175176
'Daily positions': 'Posições diárias dos planetas',
176177
Date: 'Data',

packages/ui/src/locales/ru.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ export const ru: Record<ChromeString, string> = {
173173

174174
Ephemeris: 'Эфемериды',
175175
'No ephemeris data': 'Нет данных эфемерид',
176+
'Signs in this month': 'Знаки в этом месяце',
176177
'Sign changes and retrograde periods': 'Вход в знаки и ретроградные периоды',
177178
'Daily positions': 'Положения планет по дням',
178179
Date: 'Дата',

packages/ui/src/locales/tr.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ export const tr: Record<ChromeString, string> = {
178178

179179
Ephemeris: 'Efemeris',
180180
'No ephemeris data': 'Efemeris verisi yok',
181+
'Signs in this month': 'Bu ayki burçlar',
181182
'Sign changes and retrograde periods': 'Burç değişimleri ve retro dönemleri',
182183
'Daily positions': 'Gezegen konumları',
183184
Date: 'Tarih',

0 commit comments

Comments
 (0)