@roxyapi/ui 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +321 -14
- package/THEMING.md +24 -7
- package/dist/cdn/components/biorhythm-chart.js +15 -22
- package/dist/cdn/components/biorhythm-chart.js.map +3 -3
- package/dist/cdn/components/compatibility-card.js +36 -34
- package/dist/cdn/components/compatibility-card.js.map +4 -4
- package/dist/cdn/components/dasha-timeline.js +35 -39
- package/dist/cdn/components/dasha-timeline.js.map +4 -4
- package/dist/cdn/components/data.js +6 -6
- package/dist/cdn/components/data.js.map +3 -3
- package/dist/cdn/components/dosha-card.js +13 -13
- package/dist/cdn/components/dosha-card.js.map +2 -2
- package/dist/cdn/components/endpoint-form.js +47 -28
- package/dist/cdn/components/endpoint-form.js.map +3 -3
- package/dist/cdn/components/guna-milan.js +18 -18
- package/dist/cdn/components/guna-milan.js.map +4 -4
- package/dist/cdn/components/hexagram.js +26 -26
- package/dist/cdn/components/hexagram.js.map +3 -3
- package/dist/cdn/components/horoscope-card.js +38 -38
- package/dist/cdn/components/horoscope-card.js.map +3 -3
- package/dist/cdn/components/kp-planets-table.js +10 -10
- package/dist/cdn/components/kp-planets-table.js.map +4 -4
- package/dist/cdn/components/location-search.js +6 -6
- package/dist/cdn/components/location-search.js.map +3 -3
- package/dist/cdn/components/moon-phase.js +21 -21
- package/dist/cdn/components/moon-phase.js.map +4 -4
- package/dist/cdn/components/natal-chart.js +61 -19
- package/dist/cdn/components/natal-chart.js.map +4 -4
- package/dist/cdn/components/numerology-card.js +40 -31
- package/dist/cdn/components/numerology-card.js.map +3 -3
- package/dist/cdn/components/panchang-table.js +25 -25
- package/dist/cdn/components/panchang-table.js.map +4 -4
- package/dist/cdn/components/synastry-chart.js +129 -39
- package/dist/cdn/components/synastry-chart.js.map +4 -4
- package/dist/cdn/components/tarot-card.js +49 -20
- package/dist/cdn/components/tarot-card.js.map +3 -3
- package/dist/cdn/components/tarot-spread.js +43 -27
- package/dist/cdn/components/tarot-spread.js.map +3 -3
- package/dist/cdn/components/vedic-kundli.js +23 -9
- package/dist/cdn/components/vedic-kundli.js.map +3 -3
- package/dist/cdn/roxy-ui.js +560 -350
- package/dist/cdn/roxy-ui.js.map +4 -4
- package/dist/components/biorhythm-chart.d.ts +2 -46
- package/dist/components/biorhythm-chart.d.ts.map +1 -1
- package/dist/components/biorhythm-chart.js +24 -23
- package/dist/components/biorhythm-chart.js.map +2 -2
- package/dist/components/compatibility-card.d.ts +2 -27
- package/dist/components/compatibility-card.d.ts.map +1 -1
- package/dist/components/compatibility-card.js +50 -29
- package/dist/components/compatibility-card.js.map +3 -3
- package/dist/components/dasha-timeline.d.ts +2 -31
- package/dist/components/dasha-timeline.d.ts.map +1 -1
- package/dist/components/dasha-timeline.js +32 -30
- package/dist/components/dasha-timeline.js.map +3 -3
- package/dist/components/data.d.ts +6 -0
- package/dist/components/data.d.ts.map +1 -1
- package/dist/components/data.js +9 -1
- package/dist/components/data.js.map +2 -2
- package/dist/components/dosha-card.d.ts +2 -16
- package/dist/components/dosha-card.d.ts.map +1 -1
- package/dist/components/dosha-card.js +12 -13
- package/dist/components/dosha-card.js.map +2 -2
- package/dist/components/endpoint-form.d.ts +2 -0
- package/dist/components/endpoint-form.d.ts.map +1 -1
- package/dist/components/endpoint-form.js +66 -8
- package/dist/components/endpoint-form.js.map +2 -2
- package/dist/components/guna-milan.d.ts +2 -20
- package/dist/components/guna-milan.d.ts.map +1 -1
- package/dist/components/guna-milan.js +22 -12
- package/dist/components/guna-milan.js.map +3 -3
- package/dist/components/hexagram.d.ts +3 -27
- package/dist/components/hexagram.d.ts.map +1 -1
- package/dist/components/hexagram.js +31 -15
- package/dist/components/hexagram.js.map +2 -2
- package/dist/components/horoscope-card.d.ts +2 -20
- package/dist/components/horoscope-card.d.ts.map +1 -1
- package/dist/components/horoscope-card.js +24 -15
- package/dist/components/horoscope-card.js.map +2 -2
- package/dist/components/kp-planets-table.d.ts +2 -21
- package/dist/components/kp-planets-table.d.ts.map +1 -1
- package/dist/components/kp-planets-table.js +10 -4
- package/dist/components/kp-planets-table.js.map +3 -3
- package/dist/components/location-search.d.ts +3 -11
- package/dist/components/location-search.d.ts.map +1 -1
- package/dist/components/location-search.js +45 -5
- package/dist/components/location-search.js.map +2 -2
- package/dist/components/moon-phase.d.ts +4 -21
- package/dist/components/moon-phase.d.ts.map +1 -1
- package/dist/components/moon-phase.js +17 -4
- package/dist/components/moon-phase.js.map +3 -3
- package/dist/components/natal-chart.d.ts +7 -43
- package/dist/components/natal-chart.d.ts.map +1 -1
- package/dist/components/natal-chart.js +130 -70
- package/dist/components/natal-chart.js.map +3 -3
- package/dist/components/numerology-card.d.ts +5 -37
- package/dist/components/numerology-card.d.ts.map +1 -1
- package/dist/components/numerology-card.js +54 -28
- package/dist/components/numerology-card.js.map +2 -2
- package/dist/components/panchang-table.d.ts +3 -62
- package/dist/components/panchang-table.d.ts.map +1 -1
- package/dist/components/panchang-table.js +62 -32
- package/dist/components/panchang-table.js.map +3 -3
- package/dist/components/synastry-chart.d.ts +9 -28
- package/dist/components/synastry-chart.d.ts.map +1 -1
- package/dist/components/synastry-chart.js +178 -38
- package/dist/components/synastry-chart.js.map +3 -3
- package/dist/components/tarot-card.d.ts +5 -29
- package/dist/components/tarot-card.d.ts.map +1 -1
- package/dist/components/tarot-card.js +59 -20
- package/dist/components/tarot-card.js.map +2 -2
- package/dist/components/tarot-spread.d.ts +2 -24
- package/dist/components/tarot-spread.d.ts.map +1 -1
- package/dist/components/tarot-spread.js +39 -13
- package/dist/components/tarot-spread.js.map +2 -2
- package/dist/components/vedic-kundli.d.ts +3 -23
- package/dist/components/vedic-kundli.d.ts.map +1 -1
- package/dist/components/vedic-kundli.js +25 -13
- package/dist/components/vedic-kundli.js.map +2 -2
- package/dist/index.cjs +1149 -358
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1149 -358
- package/dist/index.js.map +4 -4
- package/dist/manifest.d.ts +49 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.json +1 -1
- package/dist/styles/tokens.css +47 -1
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/types.gen.d.ts +27811 -0
- package/dist/types/types.gen.d.ts.map +1 -0
- package/dist/utils/debounce.d.ts +9 -1
- package/dist/utils/debounce.d.ts.map +1 -1
- package/dist/utils/format.d.ts +15 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +7 -1
- package/src/components/biorhythm-chart.ts +39 -84
- package/src/components/compatibility-card.ts +85 -52
- package/src/components/dasha-timeline.ts +55 -73
- package/src/components/data.ts +20 -1
- package/src/components/dosha-card.ts +18 -31
- package/src/components/endpoint-form.ts +79 -11
- package/src/components/guna-milan.ts +16 -34
- package/src/components/hexagram.ts +53 -43
- package/src/components/horoscope-card.ts +51 -39
- package/src/components/kp-planets-table.ts +8 -27
- package/src/components/location-search.ts +45 -20
- package/src/components/moon-phase.ts +28 -25
- package/src/components/natal-chart.ts +129 -84
- package/src/components/numerology-card.ts +87 -79
- package/src/components/panchang-table.ts +40 -78
- package/src/components/synastry-chart.ts +220 -78
- package/src/components/tarot-card.ts +76 -62
- package/src/components/tarot-spread.ts +72 -45
- package/src/components/vedic-kundli.ts +42 -51
- package/src/index.ts +14 -24
- package/src/manifest.ts +366 -0
- package/src/styles/tokens.css +47 -1
- package/src/tokens/index.ts +5 -0
- package/src/types/types.gen.ts +1 -1
- package/src/utils/debounce.ts +23 -4
- package/src/utils/format.ts +57 -0
- package/src/version.ts +2 -0
|
@@ -1,28 +1,17 @@
|
|
|
1
1
|
import { css, html, LitElement, nothing } from 'lit';
|
|
2
2
|
import { customElement, property } from 'lit/decorators.js';
|
|
3
3
|
import { SIGN_GLYPH } from '../tokens/index.js';
|
|
4
|
+
import type {
|
|
5
|
+
GetDailyHoroscopeResponse,
|
|
6
|
+
GetMonthlyHoroscopeResponse,
|
|
7
|
+
GetWeeklyHoroscopeResponse,
|
|
8
|
+
} from '../types/index.js';
|
|
4
9
|
import { baseStyles } from '../utils/base-styles.js';
|
|
5
10
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
love?: string;
|
|
11
|
-
career?: string;
|
|
12
|
-
health?: string;
|
|
13
|
-
finance?: string;
|
|
14
|
-
advice?: string;
|
|
15
|
-
luckyNumber?: number | string;
|
|
16
|
-
luckyColor?: string;
|
|
17
|
-
compatibleSigns?: string[];
|
|
18
|
-
moonSign?: string;
|
|
19
|
-
moonPhase?: string;
|
|
20
|
-
energyRating?: number;
|
|
21
|
-
week?: string;
|
|
22
|
-
month?: string;
|
|
23
|
-
luckyDays?: string[];
|
|
24
|
-
luckyNumbers?: number[];
|
|
25
|
-
}
|
|
11
|
+
type HoroscopeData =
|
|
12
|
+
| GetDailyHoroscopeResponse
|
|
13
|
+
| GetWeeklyHoroscopeResponse
|
|
14
|
+
| GetMonthlyHoroscopeResponse;
|
|
26
15
|
|
|
27
16
|
/**
|
|
28
17
|
* Daily, weekly, or monthly horoscope card. Pass `data` from
|
|
@@ -163,8 +152,15 @@ export class RoxyHoroscopeCard extends LitElement {
|
|
|
163
152
|
|
|
164
153
|
const sign = d.sign ?? '';
|
|
165
154
|
const glyph = sign ? (SIGN_GLYPH[capitalize(sign)] ?? '') : '';
|
|
166
|
-
const energy =
|
|
167
|
-
|
|
155
|
+
const energy =
|
|
156
|
+
'energyRating' in d && typeof d.energyRating === 'number'
|
|
157
|
+
? d.energyRating
|
|
158
|
+
: null;
|
|
159
|
+
const dateLabel =
|
|
160
|
+
('date' in d && d.date) ||
|
|
161
|
+
('week' in d && d.week) ||
|
|
162
|
+
('month' in d && d.month) ||
|
|
163
|
+
'';
|
|
168
164
|
|
|
169
165
|
return html`<article
|
|
170
166
|
class="card"
|
|
@@ -224,7 +220,7 @@ export class RoxyHoroscopeCard extends LitElement {
|
|
|
224
220
|
: nothing
|
|
225
221
|
}
|
|
226
222
|
${
|
|
227
|
-
d.advice
|
|
223
|
+
'advice' in d && d.advice
|
|
228
224
|
? html`<div class="section">
|
|
229
225
|
<h3>Advice</h3>
|
|
230
226
|
<p>${d.advice}</p>
|
|
@@ -233,49 +229,65 @@ export class RoxyHoroscopeCard extends LitElement {
|
|
|
233
229
|
}
|
|
234
230
|
</div>
|
|
235
231
|
|
|
236
|
-
${
|
|
237
|
-
|
|
238
|
-
|
|
232
|
+
${(() => {
|
|
233
|
+
const luckyNumber =
|
|
234
|
+
'luckyNumber' in d && d.luckyNumber !== undefined
|
|
235
|
+
? d.luckyNumber
|
|
236
|
+
: undefined;
|
|
237
|
+
const luckyColor =
|
|
238
|
+
'luckyColor' in d && d.luckyColor ? d.luckyColor : '';
|
|
239
|
+
const luckyNumbers =
|
|
240
|
+
'luckyNumbers' in d && d.luckyNumbers ? d.luckyNumbers : [];
|
|
241
|
+
const luckyDays = 'luckyDays' in d && d.luckyDays ? d.luckyDays : [];
|
|
242
|
+
const compatibleSigns = d.compatibleSigns ?? [];
|
|
243
|
+
if (
|
|
244
|
+
luckyNumber === undefined &&
|
|
245
|
+
!luckyColor &&
|
|
246
|
+
luckyNumbers.length === 0 &&
|
|
247
|
+
luckyDays.length === 0 &&
|
|
248
|
+
compatibleSigns.length === 0
|
|
249
|
+
)
|
|
250
|
+
return nothing;
|
|
251
|
+
return html`<div class="lucky">
|
|
239
252
|
${
|
|
240
|
-
|
|
241
|
-
? html`<span>Lucky number <strong>${
|
|
253
|
+
luckyNumber !== undefined
|
|
254
|
+
? html`<span>Lucky number <strong>${luckyNumber}</strong></span>`
|
|
242
255
|
: nothing
|
|
243
256
|
}
|
|
244
257
|
${
|
|
245
|
-
|
|
246
|
-
? html`<span>Lucky color <strong>${
|
|
258
|
+
luckyColor
|
|
259
|
+
? html`<span>Lucky color <strong>${luckyColor}</strong></span>`
|
|
247
260
|
: nothing
|
|
248
261
|
}
|
|
249
262
|
${
|
|
250
|
-
|
|
263
|
+
luckyNumbers.length
|
|
251
264
|
? html`<span
|
|
252
265
|
>Lucky numbers
|
|
253
|
-
<strong>${
|
|
266
|
+
<strong>${luckyNumbers.join(', ')}</strong></span
|
|
254
267
|
>`
|
|
255
268
|
: nothing
|
|
256
269
|
}
|
|
257
270
|
${
|
|
258
|
-
|
|
271
|
+
luckyDays.length
|
|
259
272
|
? html`<span
|
|
260
|
-
>Lucky days <strong>${
|
|
273
|
+
>Lucky days <strong>${luckyDays.join(', ')}</strong></span
|
|
261
274
|
>`
|
|
262
275
|
: nothing
|
|
263
276
|
}
|
|
264
277
|
${
|
|
265
|
-
|
|
278
|
+
compatibleSigns.length
|
|
266
279
|
? html`<span class="compat-wrap">
|
|
267
280
|
Best with
|
|
268
281
|
<span class="compat"
|
|
269
|
-
>${
|
|
282
|
+
>${compatibleSigns.map(
|
|
270
283
|
(s) => html`<span>${s}</span>`,
|
|
271
284
|
)}</span
|
|
272
285
|
>
|
|
273
286
|
</span>`
|
|
274
287
|
: nothing
|
|
275
288
|
}
|
|
276
|
-
</div
|
|
277
|
-
|
|
278
|
-
}
|
|
289
|
+
</div>`;
|
|
290
|
+
})()}
|
|
279
291
|
</article>`;
|
|
280
292
|
}
|
|
281
293
|
}
|
|
@@ -1,27 +1,8 @@
|
|
|
1
1
|
import { css, html, LitElement, nothing } from 'lit';
|
|
2
2
|
import { customElement, property } from 'lit/decorators.js';
|
|
3
|
+
import type { KpPlanetsResponse } from '../types/index.js';
|
|
3
4
|
import { baseStyles } from '../utils/base-styles.js';
|
|
4
|
-
|
|
5
|
-
interface KpPlanet {
|
|
6
|
-
planet?: string;
|
|
7
|
-
name?: string;
|
|
8
|
-
sign?: string;
|
|
9
|
-
signLord?: string;
|
|
10
|
-
nakshatra?: string;
|
|
11
|
-
nakshatraLord?: string;
|
|
12
|
-
pada?: number;
|
|
13
|
-
starLord?: string;
|
|
14
|
-
subLord?: string;
|
|
15
|
-
subSubLord?: string;
|
|
16
|
-
kpNumber?: number;
|
|
17
|
-
retrograde?: boolean;
|
|
18
|
-
longitude?: number;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface KpData {
|
|
22
|
-
ayanamsa?: number | string;
|
|
23
|
-
planets?: KpPlanet[];
|
|
24
|
-
}
|
|
5
|
+
import { formatNumber } from '../utils/format.js';
|
|
25
6
|
|
|
26
7
|
/**
|
|
27
8
|
* KP planets table with sub-lord and sub-sub-lord columns. Renders
|
|
@@ -86,7 +67,7 @@ export class RoxyKpPlanetsTable extends LitElement {
|
|
|
86
67
|
color: var(--roxy-fg, #0a0a0a);
|
|
87
68
|
}
|
|
88
69
|
.retro {
|
|
89
|
-
color: var(--roxy-warning, #
|
|
70
|
+
color: var(--roxy-warning-fg, #9a3412);
|
|
90
71
|
font-size: var(--roxy-text-xs, 0.75rem);
|
|
91
72
|
margin-left: 4px;
|
|
92
73
|
}
|
|
@@ -94,7 +75,7 @@ export class RoxyKpPlanetsTable extends LitElement {
|
|
|
94
75
|
];
|
|
95
76
|
|
|
96
77
|
@property({ attribute: false })
|
|
97
|
-
data:
|
|
78
|
+
data: KpPlanetsResponse | null = null;
|
|
98
79
|
|
|
99
80
|
render() {
|
|
100
81
|
if (!this.data)
|
|
@@ -109,8 +90,8 @@ export class RoxyKpPlanetsTable extends LitElement {
|
|
|
109
90
|
<header class="head">
|
|
110
91
|
<h2 class="title">KP planets</h2>
|
|
111
92
|
${
|
|
112
|
-
this.data.ayanamsa
|
|
113
|
-
? html`<span class="ayanamsa">Ayanamsa: ${this.data.ayanamsa}
|
|
93
|
+
typeof this.data.ayanamsa === 'number'
|
|
94
|
+
? html`<span class="ayanamsa">Ayanamsa: ${formatNumber(this.data.ayanamsa, 2)}°</span>`
|
|
114
95
|
: nothing
|
|
115
96
|
}
|
|
116
97
|
</header>
|
|
@@ -131,13 +112,13 @@ export class RoxyKpPlanetsTable extends LitElement {
|
|
|
131
112
|
${planets.map(
|
|
132
113
|
(p) => html`<tr>
|
|
133
114
|
<td class="planet">
|
|
134
|
-
${p.planet
|
|
115
|
+
${p.planet}
|
|
135
116
|
${p.retrograde ? html`<span class="retro">R</span>` : nothing}
|
|
136
117
|
</td>
|
|
137
118
|
<td>${p.sign ?? ''}</td>
|
|
138
119
|
<td>${p.signLord ?? ''}</td>
|
|
139
120
|
<td>${p.nakshatra ?? ''}</td>
|
|
140
|
-
<td>${p.
|
|
121
|
+
<td>${p.nakshatraLord ?? ''}</td>
|
|
141
122
|
<td>${p.subLord ?? ''}</td>
|
|
142
123
|
<td>${p.subSubLord ?? ''}</td>
|
|
143
124
|
<td>${p.kpNumber ?? ''}</td>
|
|
@@ -1,24 +1,10 @@
|
|
|
1
1
|
import { css, html, LitElement, nothing } from 'lit';
|
|
2
2
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
3
|
+
import type { SearchCitiesResponse } from '../types/index.js';
|
|
3
4
|
import { baseStyles } from '../utils/base-styles.js';
|
|
4
5
|
import { debounce } from '../utils/debounce.js';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
city: string;
|
|
8
|
-
province?: string;
|
|
9
|
-
country: string;
|
|
10
|
-
iso2?: string;
|
|
11
|
-
latitude: number;
|
|
12
|
-
longitude: number;
|
|
13
|
-
timezone: string;
|
|
14
|
-
utcOffset: number;
|
|
15
|
-
population?: number;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface CitySearchResponse {
|
|
19
|
-
total?: number;
|
|
20
|
-
cities?: CityResult[];
|
|
21
|
-
}
|
|
7
|
+
type CityResult = SearchCitiesResponse['cities'][number];
|
|
22
8
|
|
|
23
9
|
/**
|
|
24
10
|
* Stateful location search input. Calls /location/search and emits
|
|
@@ -175,6 +161,8 @@ export class RoxyLocationSearch extends LitElement {
|
|
|
175
161
|
private highlight = -1;
|
|
176
162
|
|
|
177
163
|
private clickOutsideHandler?: (e: MouseEvent) => void;
|
|
164
|
+
private abortController?: AbortController;
|
|
165
|
+
private secretKeyWarned = false;
|
|
178
166
|
private debouncedFetch = debounce((q: string) => {
|
|
179
167
|
void this.fetchResults(q);
|
|
180
168
|
}, 300);
|
|
@@ -194,9 +182,41 @@ export class RoxyLocationSearch extends LitElement {
|
|
|
194
182
|
if (this.clickOutsideHandler) {
|
|
195
183
|
document.removeEventListener('mousedown', this.clickOutsideHandler);
|
|
196
184
|
}
|
|
185
|
+
this.debouncedFetch.cancel();
|
|
186
|
+
if (this.abortController) {
|
|
187
|
+
this.abortController.abort();
|
|
188
|
+
this.abortController = undefined;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
private warnIfSecretKey() {
|
|
193
|
+
if (this.secretKeyWarned) return;
|
|
194
|
+
if (!this.apiKey) return;
|
|
195
|
+
// Browser-safe publishable keys carry the `pk_` prefix and a server-side
|
|
196
|
+
// origin allowlist. Anything else (a raw secret key, UUID-style token)
|
|
197
|
+
// must not ship to the browser.
|
|
198
|
+
if (this.apiKey.startsWith('pk_')) return;
|
|
199
|
+
this.secretKeyWarned = true;
|
|
200
|
+
const message =
|
|
201
|
+
'Possible secret key in client-side <roxy-location-search>; use a `pk_` publishable key with origin allowlist instead.';
|
|
202
|
+
// eslint-disable-next-line no-console
|
|
203
|
+
console.warn(message);
|
|
204
|
+
this.dispatchEvent(
|
|
205
|
+
new CustomEvent('roxy-validation-error', {
|
|
206
|
+
detail: { reason: 'possible-secret-key', message },
|
|
207
|
+
bubbles: true,
|
|
208
|
+
composed: true,
|
|
209
|
+
}),
|
|
210
|
+
);
|
|
197
211
|
}
|
|
198
212
|
|
|
199
213
|
private async fetchResults(q: string) {
|
|
214
|
+
this.warnIfSecretKey();
|
|
215
|
+
// Abort any in-flight request so a stale response cannot overwrite a
|
|
216
|
+
// fresher one (debounced typing) or land after disconnect.
|
|
217
|
+
if (this.abortController) this.abortController.abort();
|
|
218
|
+
const controller = new AbortController();
|
|
219
|
+
this.abortController = controller;
|
|
200
220
|
this.isLoading = true;
|
|
201
221
|
try {
|
|
202
222
|
const url = new URL(this.endpoint);
|
|
@@ -207,17 +227,22 @@ export class RoxyLocationSearch extends LitElement {
|
|
|
207
227
|
};
|
|
208
228
|
if (this.apiKey) headers['X-API-Key'] = this.apiKey;
|
|
209
229
|
if (this.publishableKey) headers['X-API-Key'] = this.publishableKey;
|
|
210
|
-
const res = await fetch(url, { headers });
|
|
230
|
+
const res = await fetch(url, { headers, signal: controller.signal });
|
|
211
231
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
212
|
-
const json = (await res.json()) as
|
|
232
|
+
const json = (await res.json()) as SearchCitiesResponse;
|
|
233
|
+
if (controller.signal.aborted) return;
|
|
213
234
|
this.results = json.cities ?? [];
|
|
214
235
|
this.isOpen = this.results.length > 0;
|
|
215
236
|
this.highlight = this.results.length > 0 ? 0 : -1;
|
|
216
|
-
} catch (
|
|
237
|
+
} catch (err) {
|
|
238
|
+
if ((err as { name?: string })?.name === 'AbortError') return;
|
|
217
239
|
this.results = [];
|
|
218
240
|
this.isOpen = false;
|
|
219
241
|
} finally {
|
|
220
|
-
this.
|
|
242
|
+
if (this.abortController === controller) {
|
|
243
|
+
this.abortController = undefined;
|
|
244
|
+
}
|
|
245
|
+
if (!controller.signal.aborted) this.isLoading = false;
|
|
221
246
|
}
|
|
222
247
|
}
|
|
223
248
|
|
|
@@ -1,27 +1,21 @@
|
|
|
1
1
|
import { css, html, LitElement, nothing } from 'lit';
|
|
2
2
|
import { customElement, property } from 'lit/decorators.js';
|
|
3
3
|
import { MOON_PHASE_EMOJI } from '../tokens/index.js';
|
|
4
|
+
import type {
|
|
5
|
+
GetCurrentMoonPhaseResponse,
|
|
6
|
+
GetMoonCalendarResponse,
|
|
7
|
+
GetUpcomingMoonPhasesResponse,
|
|
8
|
+
} from '../types/index.js';
|
|
4
9
|
import { baseStyles } from '../utils/base-styles.js';
|
|
10
|
+
import { formatNumber } from '../utils/format.js';
|
|
5
11
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
distance?: number;
|
|
14
|
-
meaning?: {
|
|
15
|
-
name?: string;
|
|
16
|
-
symbol?: string;
|
|
17
|
-
description?: string;
|
|
18
|
-
keywords?: string[];
|
|
19
|
-
};
|
|
20
|
-
month?: string;
|
|
21
|
-
year?: number;
|
|
22
|
-
phases?: Array<MoonPhaseData>;
|
|
23
|
-
upcoming?: Array<MoonPhaseData>;
|
|
24
|
-
}
|
|
12
|
+
type MoonPhaseData =
|
|
13
|
+
| GetCurrentMoonPhaseResponse
|
|
14
|
+
| GetUpcomingMoonPhasesResponse
|
|
15
|
+
| GetMoonCalendarResponse;
|
|
16
|
+
type MoonListEntry =
|
|
17
|
+
| GetUpcomingMoonPhasesResponse['phases'][number]
|
|
18
|
+
| GetMoonCalendarResponse['calendar'][number];
|
|
25
19
|
|
|
26
20
|
/**
|
|
27
21
|
* Moon phase card. Renders /astrology/moon-phase/{current,upcoming,calendar/...}.
|
|
@@ -125,22 +119,26 @@ export class RoxyMoonPhase extends LitElement {
|
|
|
125
119
|
const d = this.data;
|
|
126
120
|
if (!d)
|
|
127
121
|
return html`<div class="roxy-empty" role="status">No moon phase data</div>`;
|
|
128
|
-
const list
|
|
122
|
+
const list: MoonListEntry[] =
|
|
123
|
+
'phases' in d ? d.phases : 'calendar' in d ? d.calendar : [];
|
|
129
124
|
if (this.mode !== 'current' && list.length > 0) {
|
|
125
|
+
const month = 'month' in d ? d.month : undefined;
|
|
126
|
+
const year = 'year' in d ? d.year : undefined;
|
|
130
127
|
return html`<article
|
|
131
128
|
class="card"
|
|
132
129
|
aria-label="Moon phase calendar"
|
|
133
130
|
>
|
|
134
|
-
<h2 class="label">${
|
|
131
|
+
<h2 class="label">${month ?? 'Moon phases'} ${year ?? ''}</h2>
|
|
135
132
|
<div class="list" role="list">
|
|
136
133
|
${list.map((phase) => this.renderListItem(phase))}
|
|
137
134
|
</div>
|
|
138
135
|
</article>`;
|
|
139
136
|
}
|
|
137
|
+
if (!('phase' in d)) return nothing;
|
|
140
138
|
return this.renderSingle(d);
|
|
141
139
|
}
|
|
142
140
|
|
|
143
|
-
private renderSingle(d:
|
|
141
|
+
private renderSingle(d: GetCurrentMoonPhaseResponse) {
|
|
144
142
|
const emoji = phaseEmoji(d.phase);
|
|
145
143
|
return html`<article class="card" aria-label="Current moon phase">
|
|
146
144
|
<div class="hero">
|
|
@@ -155,7 +153,7 @@ export class RoxyMoonPhase extends LitElement {
|
|
|
155
153
|
typeof d.illumination === 'number'
|
|
156
154
|
? html`<div>
|
|
157
155
|
<span>Illumination</span>
|
|
158
|
-
<strong>${(d.illumination
|
|
156
|
+
<strong>${formatIllumination(d.illumination)}</strong>
|
|
159
157
|
</div>`
|
|
160
158
|
: nothing
|
|
161
159
|
}
|
|
@@ -163,7 +161,7 @@ export class RoxyMoonPhase extends LitElement {
|
|
|
163
161
|
typeof d.age === 'number'
|
|
164
162
|
? html`<div>
|
|
165
163
|
<span>Age</span>
|
|
166
|
-
<strong>${d.age
|
|
164
|
+
<strong>${formatNumber(d.age, 1)} days</strong>
|
|
167
165
|
</div>`
|
|
168
166
|
: nothing
|
|
169
167
|
}
|
|
@@ -199,7 +197,7 @@ export class RoxyMoonPhase extends LitElement {
|
|
|
199
197
|
</article>`;
|
|
200
198
|
}
|
|
201
199
|
|
|
202
|
-
private renderListItem(p:
|
|
200
|
+
private renderListItem(p: MoonListEntry) {
|
|
203
201
|
const emoji = phaseEmoji(p.phase);
|
|
204
202
|
return html`<div class="list-item" role="listitem">
|
|
205
203
|
<span aria-hidden="true">${emoji}</span>
|
|
@@ -214,6 +212,11 @@ function phaseEmoji(phase: string | undefined): string {
|
|
|
214
212
|
return MOON_PHASE_EMOJI[phase.toLowerCase()] ?? '🌙';
|
|
215
213
|
}
|
|
216
214
|
|
|
215
|
+
function formatIllumination(v: number): string {
|
|
216
|
+
const pct = v <= 1 ? v * 100 : v;
|
|
217
|
+
return `${Math.round(pct)}%`;
|
|
218
|
+
}
|
|
219
|
+
|
|
217
220
|
declare global {
|
|
218
221
|
interface HTMLElementTagNameMap {
|
|
219
222
|
'roxy-moon-phase': RoxyMoonPhase;
|