@roxyapi/ui 0.1.2 → 0.2.0
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/AGENTS.md +6 -0
- package/README.md +327 -14
- package/THEMING.md +24 -7
- package/dist/cdn/components/ashtakavarga-grid.js +349 -0
- package/dist/cdn/components/ashtakavarga-grid.js.map +7 -0
- package/dist/cdn/components/biorhythm-chart.js +15 -22
- package/dist/cdn/components/biorhythm-chart.js.map +3 -3
- package/dist/cdn/components/choghadiya-grid.js +239 -0
- package/dist/cdn/components/choghadiya-grid.js.map +7 -0
- 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 +9 -9
- package/dist/cdn/components/data.js.map +4 -4
- package/dist/cdn/components/divisional-chart.js +279 -0
- package/dist/cdn/components/divisional-chart.js.map +7 -0
- package/dist/cdn/components/dosha-card.js +49 -49
- package/dist/cdn/components/dosha-card.js.map +3 -3
- package/dist/cdn/components/endpoint-form.js +47 -28
- package/dist/cdn/components/endpoint-form.js.map +4 -4
- package/dist/cdn/components/guna-milan.js +66 -24
- 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 +47 -40
- package/dist/cdn/components/horoscope-card.js.map +4 -4
- 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 +18 -18
- package/dist/cdn/components/moon-phase.js.map +4 -4
- package/dist/cdn/components/natal-chart.js +240 -24
- 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 +4 -4
- package/dist/cdn/components/panchang-table.js +30 -30
- package/dist/cdn/components/panchang-table.js.map +4 -4
- package/dist/cdn/components/shadbala-table.js +312 -0
- package/dist/cdn/components/shadbala-table.js.map +7 -0
- 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/transits-table.js +391 -0
- package/dist/cdn/components/transits-table.js.map +7 -0
- package/dist/cdn/components/vedic-kundli.js +63 -27
- package/dist/cdn/components/vedic-kundli.js.map +4 -4
- package/dist/cdn/components/yoga-list.js +334 -0
- package/dist/cdn/components/yoga-list.js.map +7 -0
- package/dist/cdn/roxy-ui.js +2104 -544
- package/dist/cdn/roxy-ui.js.map +4 -4
- package/dist/components/ashtakavarga-grid.d.ts +26 -0
- package/dist/components/ashtakavarga-grid.d.ts.map +1 -0
- package/dist/components/ashtakavarga-grid.js +457 -0
- package/dist/components/ashtakavarga-grid.js.map +7 -0
- 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/choghadiya-grid.d.ts +19 -0
- package/dist/components/choghadiya-grid.d.ts.map +1 -0
- package/dist/components/choghadiya-grid.js +304 -0
- package/dist/components/choghadiya-grid.js.map +7 -0
- 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 +11 -7
- package/dist/components/data.d.ts.map +1 -1
- package/dist/components/data.js +16 -6
- package/dist/components/data.js.map +3 -3
- package/dist/components/divisional-chart.d.ts +20 -0
- package/dist/components/divisional-chart.d.ts.map +1 -0
- package/dist/components/divisional-chart.js +471 -0
- package/dist/components/divisional-chart.js.map +7 -0
- 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 +45 -43
- 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 +71 -11
- package/dist/components/endpoint-form.js.map +3 -3
- 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 +79 -20
- package/dist/components/guna-milan.js.map +4 -4
- package/dist/components/hexagram.d.ts +3 -27
- package/dist/components/hexagram.d.ts.map +1 -1
- package/dist/components/hexagram.js +48 -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 +54 -18
- package/dist/components/horoscope-card.js.map +3 -3
- 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 +5 -14
- 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 +34 -4
- package/dist/components/moon-phase.js.map +3 -3
- package/dist/components/natal-chart.d.ts +9 -43
- package/dist/components/natal-chart.d.ts.map +1 -1
- package/dist/components/natal-chart.js +346 -79
- 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 +58 -30
- package/dist/components/numerology-card.js.map +3 -3
- 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/shadbala-table.d.ts +18 -0
- package/dist/components/shadbala-table.d.ts.map +1 -0
- package/dist/components/shadbala-table.js +400 -0
- package/dist/components/shadbala-table.js.map +7 -0
- 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 +201 -56
- 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/transits-table.d.ts +21 -0
- package/dist/components/transits-table.d.ts.map +1 -0
- package/dist/components/transits-table.js +515 -0
- package/dist/components/transits-table.js.map +7 -0
- package/dist/components/vedic-kundli.d.ts +5 -28
- package/dist/components/vedic-kundli.d.ts.map +1 -1
- package/dist/components/vedic-kundli.js +147 -83
- package/dist/components/vedic-kundli.js.map +3 -3
- package/dist/components/yoga-list.d.ts +29 -0
- package/dist/components/yoga-list.d.ts.map +1 -0
- package/dist/components/yoga-list.js +389 -0
- package/dist/components/yoga-list.js.map +7 -0
- package/dist/index.cjs +3693 -1180
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3709 -1196
- package/dist/index.js.map +4 -4
- package/dist/manifest.d.ts +43 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.json +7 -2
- package/dist/styles/tokens.css +73 -1
- package/dist/tokens/index.d.ts +6 -0
- 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 +29 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/kundli-render.d.ts +63 -0
- package/dist/utils/kundli-render.d.ts.map +1 -0
- package/dist/utils/string.d.ts +14 -0
- package/dist/utils/string.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/ashtakavarga-grid.ts +354 -0
- package/src/components/biorhythm-chart.ts +39 -84
- package/src/components/choghadiya-grid.ts +185 -0
- package/src/components/compatibility-card.ts +85 -52
- package/src/components/dasha-timeline.ts +55 -73
- package/src/components/data.ts +28 -16
- package/src/components/divisional-chart.ts +214 -0
- package/src/components/dosha-card.ts +72 -68
- package/src/components/endpoint-form.ts +80 -18
- package/src/components/guna-milan.ts +87 -47
- package/src/components/hexagram.ts +53 -43
- package/src/components/horoscope-card.ts +59 -43
- package/src/components/kp-planets-table.ts +8 -27
- package/src/components/location-search.ts +47 -23
- package/src/components/moon-phase.ts +28 -25
- package/src/components/natal-chart.ts +364 -110
- package/src/components/numerology-card.ts +86 -84
- package/src/components/panchang-table.ts +40 -78
- package/src/components/shadbala-table.ts +286 -0
- package/src/components/synastry-chart.ts +213 -97
- package/src/components/tarot-card.ts +76 -62
- package/src/components/tarot-spread.ts +72 -45
- package/src/components/transits-table.ts +350 -0
- package/src/components/vedic-kundli.ts +59 -173
- package/src/components/yoga-list.ts +328 -0
- package/src/index.ts +18 -26
- package/src/manifest.ts +340 -0
- package/src/styles/tokens.css +73 -1
- package/src/tokens/index.ts +14 -0
- package/src/types/types.gen.ts +3 -3
- package/src/utils/debounce.ts +23 -4
- package/src/utils/format.ts +75 -0
- package/src/utils/kundli-render.ts +197 -0
- package/src/utils/string.ts +23 -0
- package/src/version.ts +2 -0
- package/dist/utils/motion.d.ts +0 -13
- package/dist/utils/motion.d.ts.map +0 -1
- package/src/utils/motion.ts +0 -18
|
@@ -28,6 +28,23 @@ var SIGN_GLYPH = {
|
|
|
28
28
|
Aquarius: "\u2652",
|
|
29
29
|
Pisces: "\u2653"
|
|
30
30
|
};
|
|
31
|
+
var SIGNS_ORDER = [
|
|
32
|
+
"Aries",
|
|
33
|
+
"Taurus",
|
|
34
|
+
"Gemini",
|
|
35
|
+
"Cancer",
|
|
36
|
+
"Leo",
|
|
37
|
+
"Virgo",
|
|
38
|
+
"Libra",
|
|
39
|
+
"Scorpio",
|
|
40
|
+
"Sagittarius",
|
|
41
|
+
"Capricorn",
|
|
42
|
+
"Aquarius",
|
|
43
|
+
"Pisces"
|
|
44
|
+
];
|
|
45
|
+
var RASHI_KEYS = SIGNS_ORDER.map(
|
|
46
|
+
(s) => s.toLowerCase()
|
|
47
|
+
);
|
|
31
48
|
|
|
32
49
|
// packages/ui/src/utils/base-styles.ts
|
|
33
50
|
import { css } from "lit";
|
|
@@ -115,6 +132,12 @@ var baseStyles = css`
|
|
|
115
132
|
}
|
|
116
133
|
`;
|
|
117
134
|
|
|
135
|
+
// packages/ui/src/utils/string.ts
|
|
136
|
+
function capitalize(s) {
|
|
137
|
+
if (!s) return "";
|
|
138
|
+
return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
|
|
139
|
+
}
|
|
140
|
+
|
|
118
141
|
// packages/ui/src/components/horoscope-card.ts
|
|
119
142
|
var RoxyHoroscopeCard = class extends LitElement {
|
|
120
143
|
constructor() {
|
|
@@ -128,8 +151,8 @@ var RoxyHoroscopeCard = class extends LitElement {
|
|
|
128
151
|
return html`<div class="roxy-empty" role="status">No horoscope data</div>`;
|
|
129
152
|
const sign = d.sign ?? "";
|
|
130
153
|
const glyph = sign ? SIGN_GLYPH[capitalize(sign)] ?? "" : "";
|
|
131
|
-
const energy = typeof d.energyRating === "number" ? d.energyRating : null;
|
|
132
|
-
const dateLabel = d.date
|
|
154
|
+
const energy = "energyRating" in d && typeof d.energyRating === "number" ? d.energyRating : null;
|
|
155
|
+
const dateLabel = "date" in d && d.date || "week" in d && d.week || "month" in d && d.month || "";
|
|
133
156
|
return html`<article
|
|
134
157
|
class="card"
|
|
135
158
|
aria-label=${`${this.period} horoscope for ${sign}`}
|
|
@@ -167,31 +190,40 @@ var RoxyHoroscopeCard = class extends LitElement {
|
|
|
167
190
|
<h3>Finance</h3>
|
|
168
191
|
<p>${d.finance}</p>
|
|
169
192
|
</div>` : nothing}
|
|
170
|
-
${d.advice ? html`<div class="section">
|
|
193
|
+
${"advice" in d && d.advice ? html`<div class="section">
|
|
171
194
|
<h3>Advice</h3>
|
|
172
195
|
<p>${d.advice}</p>
|
|
173
196
|
</div>` : nothing}
|
|
174
197
|
</div>
|
|
175
198
|
|
|
176
|
-
${
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
199
|
+
${(() => {
|
|
200
|
+
const luckyNumber = "luckyNumber" in d && d.luckyNumber !== void 0 ? d.luckyNumber : void 0;
|
|
201
|
+
const luckyColor = "luckyColor" in d && d.luckyColor ? d.luckyColor : "";
|
|
202
|
+
const luckyNumbers = "luckyNumbers" in d && d.luckyNumbers ? d.luckyNumbers : [];
|
|
203
|
+
const luckyDays = "luckyDays" in d && d.luckyDays ? d.luckyDays : [];
|
|
204
|
+
const compatibleSigns = d.compatibleSigns ?? [];
|
|
205
|
+
if (luckyNumber === void 0 && !luckyColor && luckyNumbers.length === 0 && luckyDays.length === 0 && compatibleSigns.length === 0)
|
|
206
|
+
return nothing;
|
|
207
|
+
return html`<div class="lucky">
|
|
208
|
+
${luckyNumber !== void 0 ? html`<span>Lucky number <strong>${luckyNumber}</strong></span>` : nothing}
|
|
209
|
+
${luckyColor ? html`<span>Lucky color <strong>${luckyColor}</strong></span>` : nothing}
|
|
210
|
+
${luckyNumbers.length ? html`<span
|
|
180
211
|
>Lucky numbers
|
|
181
|
-
<strong>${
|
|
212
|
+
<strong>${luckyNumbers.join(", ")}</strong></span
|
|
182
213
|
>` : nothing}
|
|
183
|
-
${
|
|
184
|
-
>Lucky days <strong>${
|
|
214
|
+
${luckyDays.length ? html`<span
|
|
215
|
+
>Lucky days <strong>${luckyDays.join(", ")}</strong></span
|
|
185
216
|
>` : nothing}
|
|
186
|
-
${
|
|
217
|
+
${compatibleSigns.length ? html`<span class="compat-wrap">
|
|
187
218
|
Best with
|
|
188
219
|
<span class="compat"
|
|
189
|
-
>${
|
|
190
|
-
|
|
191
|
-
|
|
220
|
+
>${compatibleSigns.map(
|
|
221
|
+
(s) => html`<span>${s}</span>`
|
|
222
|
+
)}</span
|
|
192
223
|
>
|
|
193
224
|
</span>` : nothing}
|
|
194
|
-
</div
|
|
225
|
+
</div>`;
|
|
226
|
+
})()}
|
|
195
227
|
</article>`;
|
|
196
228
|
}
|
|
197
229
|
};
|
|
@@ -299,6 +331,13 @@ RoxyHoroscopeCard.styles = [
|
|
|
299
331
|
font-weight: var(--roxy-weight-bold, 600);
|
|
300
332
|
}
|
|
301
333
|
|
|
334
|
+
.compat-wrap {
|
|
335
|
+
width: 100%;
|
|
336
|
+
display: flex;
|
|
337
|
+
align-items: center;
|
|
338
|
+
flex-wrap: wrap;
|
|
339
|
+
gap: var(--roxy-space-xs, 0.25rem);
|
|
340
|
+
}
|
|
302
341
|
.compat {
|
|
303
342
|
display: flex;
|
|
304
343
|
flex-wrap: wrap;
|
|
@@ -323,9 +362,6 @@ __decorateClass([
|
|
|
323
362
|
RoxyHoroscopeCard = __decorateClass([
|
|
324
363
|
customElement("roxy-horoscope-card")
|
|
325
364
|
], RoxyHoroscopeCard);
|
|
326
|
-
function capitalize(s) {
|
|
327
|
-
return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
|
|
328
|
-
}
|
|
329
365
|
export {
|
|
330
366
|
RoxyHoroscopeCard
|
|
331
367
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../src/components/horoscope-card.ts", "../../src/tokens/index.ts", "../../src/utils/base-styles.ts"],
|
|
4
|
-
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { SIGN_GLYPH } from '../tokens/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ninterface HoroscopeData {\n\tsign?: string;\n\tdate?: string;\n\toverview?: string;\n\tlove?: string;\n\tcareer?: string;\n\thealth?: string;\n\tfinance?: string;\n\tadvice?: string;\n\tluckyNumber?: number | string;\n\tluckyColor?: string;\n\tcompatibleSigns?: string[];\n\tmoonSign?: string;\n\tmoonPhase?: string;\n\tenergyRating?: number;\n\tweek?: string;\n\tmonth?: string;\n\tluckyDays?: string[];\n\tluckyNumbers?: number[];\n}\n\n/**\n * Daily, weekly, or monthly horoscope card. Pass `data` from\n * /astrology/horoscope/{sign}/{daily|weekly|monthly}.\n */\n@customElement('roxy-horoscope-card')\nexport class RoxyHoroscopeCard extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.card {\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.head {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.glyph {\n\t\t\t\tfont-size: 2.25rem;\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tline-height: 1;\n\t\t\t}\n\n\t\t\t.title {\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tmargin: 0;\n\t\t\t\tletter-spacing: var(--roxy-tracking-tight);\n\t\t\t\ttext-transform: capitalize;\n\t\t\t}\n\n\t\t\t.date {\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t}\n\n\t\t\t.energy {\n\t\t\t\tmargin-left: auto;\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\t\t\t.energy-bar {\n\t\t\t\tdisplay: inline-block;\n\t\t\t\twidth: 6rem;\n\t\t\t\theight: 6px;\n\t\t\t\tbackground: var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\toverflow: hidden;\n\t\t\t\tmargin-left: 6px;\n\t\t\t\tvertical-align: middle;\n\t\t\t}\n\t\t\t.energy-bar > span {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 100%;\n\t\t\t\tbackground: var(--roxy-accent, #f59e0b);\n\t\t\t\ttransition:\n\t\t\t\t\twidth var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t}\n\n\t\t\t.overview {\n\t\t\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.sections {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.section h3 {\n\t\t\t\tmargin: 0 0 var(--roxy-space-xs, 0.25rem) 0;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t\t.section p {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\n\t\t\t.lucky {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tpadding-top: var(--roxy-space-md, 1rem);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\n\t\t\t.lucky strong {\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\n\t\t\t.compat {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t}\n\t\t\t.compat span {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-accent, #f59e0b) 16%, transparent);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tpadding: 2px 8px;\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\ttext-transform: capitalize;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: HoroscopeData | null = null;\n\n\t@property({ type: String, reflect: true })\n\tperiod: 'daily' | 'weekly' | 'monthly' = 'daily';\n\n\trender() {\n\t\tconst d = this.data;\n\t\tif (!d)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No horoscope data</div>`;\n\n\t\tconst sign = d.sign ?? '';\n\t\tconst glyph = sign ? (SIGN_GLYPH[capitalize(sign)] ?? '') : '';\n\t\tconst energy = typeof d.energyRating === 'number' ? d.energyRating : null;\n\t\tconst dateLabel = d.date ?? d.week ?? d.month ?? '';\n\n\t\treturn html`<article\n\t\t\tclass=\"card\"\n\t\t\taria-label=${`${this.period} horoscope for ${sign}`}\n\t\t>\n\t\t\t<header class=\"head\">\n\t\t\t\t<span class=\"glyph\" aria-hidden=\"true\">${glyph}</span>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 class=\"title\">${sign} ${this.period}</h2>\n\t\t\t\t\t${dateLabel ? html`<div class=\"date\">${dateLabel}</div>` : nothing}\n\t\t\t\t</div>\n\t\t\t\t${\n\t\t\t\t\tenergy !== null\n\t\t\t\t\t\t? html`<span class=\"energy\" aria-label=${`Energy ${energy} of 10`}>\n\t\t\t\t\t\t\tEnergy ${energy}/10\n\t\t\t\t\t\t\t<span class=\"energy-bar\"\n\t\t\t\t\t\t\t\t><span style=\"width: ${(energy / 10) * 100}%\"></span\n\t\t\t\t\t\t\t></span>\n\t\t\t\t\t\t</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</header>\n\n\t\t\t${d.overview ? html`<p class=\"overview\">${d.overview}</p>` : nothing}\n\n\t\t\t<div class=\"sections\">\n\t\t\t\t${\n\t\t\t\t\td.love\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Love</h3>\n\t\t\t\t\t\t\t<p>${d.love}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.career\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Career</h3>\n\t\t\t\t\t\t\t<p>${d.career}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.health\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Health</h3>\n\t\t\t\t\t\t\t<p>${d.health}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.finance\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Finance</h3>\n\t\t\t\t\t\t\t<p>${d.finance}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.advice\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Advice</h3>\n\t\t\t\t\t\t\t<p>${d.advice}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</div>\n\n\t\t\t${\n\t\t\t\td.luckyNumber || d.luckyColor || (d.compatibleSigns?.length ?? 0) > 0\n\t\t\t\t\t? html`<div class=\"lucky\">\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\td.luckyNumber !== undefined\n\t\t\t\t\t\t\t\t? html`<span>Lucky number <strong>${d.luckyNumber}</strong></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\td.luckyColor\n\t\t\t\t\t\t\t\t? html`<span>Lucky color <strong>${d.luckyColor}</strong></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\td.luckyNumbers?.length\n\t\t\t\t\t\t\t\t? html`<span\n\t\t\t\t\t\t\t\t\t>Lucky numbers\n\t\t\t\t\t\t\t\t\t<strong>${d.luckyNumbers.join(', ')}</strong></span\n\t\t\t\t\t\t\t\t>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\td.luckyDays?.length\n\t\t\t\t\t\t\t\t? html`<span\n\t\t\t\t\t\t\t\t\t>Lucky days <strong>${d.luckyDays.join(', ')}</strong></span\n\t\t\t\t\t\t\t\t>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\td.compatibleSigns?.length\n\t\t\t\t\t\t\t\t? html`<span class=\"compat-wrap\">\n\t\t\t\t\t\t\t\t\tBest with\n\t\t\t\t\t\t\t\t\t<span class=\"compat\"\n\t\t\t\t\t\t\t\t\t\t>${d.compatibleSigns.map(\n\t\t\t\t\t\t\t\t\t\t\t(s) => html`<span>${s}</span>`,\n\t\t\t\t\t\t\t\t\t\t)}</span\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t</article>`;\n\t}\n}\n\nfunction capitalize(s: string): string {\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-horoscope-card': RoxyHoroscopeCard;\n\t}\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;AAAA,SAAS,OAAAA,MAAK,MAAM,YAAY,eAAe;AAC/C,SAAS,eAAe,gBAAgB;;;
|
|
3
|
+
"sources": ["../../src/components/horoscope-card.ts", "../../src/tokens/index.ts", "../../src/utils/base-styles.ts", "../../src/utils/string.ts"],
|
|
4
|
+
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { SIGN_GLYPH } from '../tokens/index.js';\nimport type {\n\tGetDailyHoroscopeResponse,\n\tGetMonthlyHoroscopeResponse,\n\tGetWeeklyHoroscopeResponse,\n} from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { capitalize } from '../utils/string.js';\n\ntype HoroscopeData =\n\t| GetDailyHoroscopeResponse\n\t| GetWeeklyHoroscopeResponse\n\t| GetMonthlyHoroscopeResponse;\n\n/**\n * Daily, weekly, or monthly horoscope card. Pass `data` from\n * /astrology/horoscope/{sign}/{daily|weekly|monthly}.\n */\n@customElement('roxy-horoscope-card')\nexport class RoxyHoroscopeCard extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.card {\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.head {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.glyph {\n\t\t\t\tfont-size: 2.25rem;\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tline-height: 1;\n\t\t\t}\n\n\t\t\t.title {\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tmargin: 0;\n\t\t\t\tletter-spacing: var(--roxy-tracking-tight);\n\t\t\t\ttext-transform: capitalize;\n\t\t\t}\n\n\t\t\t.date {\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t}\n\n\t\t\t.energy {\n\t\t\t\tmargin-left: auto;\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\t\t\t.energy-bar {\n\t\t\t\tdisplay: inline-block;\n\t\t\t\twidth: 6rem;\n\t\t\t\theight: 6px;\n\t\t\t\tbackground: var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\toverflow: hidden;\n\t\t\t\tmargin-left: 6px;\n\t\t\t\tvertical-align: middle;\n\t\t\t}\n\t\t\t.energy-bar > span {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 100%;\n\t\t\t\tbackground: var(--roxy-accent, #f59e0b);\n\t\t\t\ttransition:\n\t\t\t\t\twidth var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t}\n\n\t\t\t.overview {\n\t\t\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.sections {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.section h3 {\n\t\t\t\tmargin: 0 0 var(--roxy-space-xs, 0.25rem) 0;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t\t.section p {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\n\t\t\t.lucky {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tpadding-top: var(--roxy-space-md, 1rem);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\n\t\t\t.lucky strong {\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\n\t\t\t.compat-wrap {\n\t\t\t\twidth: 100%;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t}\n\t\t\t.compat {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t}\n\t\t\t.compat span {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-accent, #f59e0b) 16%, transparent);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tpadding: 2px 8px;\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\ttext-transform: capitalize;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: HoroscopeData | null = null;\n\n\t@property({ type: String, reflect: true })\n\tperiod: 'daily' | 'weekly' | 'monthly' = 'daily';\n\n\trender() {\n\t\tconst d = this.data;\n\t\tif (!d)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No horoscope data</div>`;\n\n\t\tconst sign = d.sign ?? '';\n\t\tconst glyph = sign ? (SIGN_GLYPH[capitalize(sign)] ?? '') : '';\n\t\tconst energy =\n\t\t\t'energyRating' in d && typeof d.energyRating === 'number'\n\t\t\t\t? d.energyRating\n\t\t\t\t: null;\n\t\tconst dateLabel =\n\t\t\t('date' in d && d.date) ||\n\t\t\t('week' in d && d.week) ||\n\t\t\t('month' in d && d.month) ||\n\t\t\t'';\n\n\t\treturn html`<article\n\t\t\tclass=\"card\"\n\t\t\taria-label=${`${this.period} horoscope for ${sign}`}\n\t\t>\n\t\t\t<header class=\"head\">\n\t\t\t\t<span class=\"glyph\" aria-hidden=\"true\">${glyph}</span>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 class=\"title\">${sign} ${this.period}</h2>\n\t\t\t\t\t${dateLabel ? html`<div class=\"date\">${dateLabel}</div>` : nothing}\n\t\t\t\t</div>\n\t\t\t\t${\n\t\t\t\t\tenergy !== null\n\t\t\t\t\t\t? html`<span class=\"energy\" aria-label=${`Energy ${energy} of 10`}>\n\t\t\t\t\t\t\tEnergy ${energy}/10\n\t\t\t\t\t\t\t<span class=\"energy-bar\"\n\t\t\t\t\t\t\t\t><span style=\"width: ${(energy / 10) * 100}%\"></span\n\t\t\t\t\t\t\t></span>\n\t\t\t\t\t\t</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</header>\n\n\t\t\t${d.overview ? html`<p class=\"overview\">${d.overview}</p>` : nothing}\n\n\t\t\t<div class=\"sections\">\n\t\t\t\t${\n\t\t\t\t\td.love\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Love</h3>\n\t\t\t\t\t\t\t<p>${d.love}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.career\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Career</h3>\n\t\t\t\t\t\t\t<p>${d.career}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.health\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Health</h3>\n\t\t\t\t\t\t\t<p>${d.health}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.finance\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Finance</h3>\n\t\t\t\t\t\t\t<p>${d.finance}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\t'advice' in d && d.advice\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Advice</h3>\n\t\t\t\t\t\t\t<p>${d.advice}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</div>\n\n\t\t\t${(() => {\n\t\t\t\tconst luckyNumber =\n\t\t\t\t\t'luckyNumber' in d && d.luckyNumber !== undefined\n\t\t\t\t\t\t? d.luckyNumber\n\t\t\t\t\t\t: undefined;\n\t\t\t\tconst luckyColor =\n\t\t\t\t\t'luckyColor' in d && d.luckyColor ? d.luckyColor : '';\n\t\t\t\tconst luckyNumbers =\n\t\t\t\t\t'luckyNumbers' in d && d.luckyNumbers ? d.luckyNumbers : [];\n\t\t\t\tconst luckyDays = 'luckyDays' in d && d.luckyDays ? d.luckyDays : [];\n\t\t\t\tconst compatibleSigns = d.compatibleSigns ?? [];\n\t\t\t\tif (\n\t\t\t\t\tluckyNumber === undefined &&\n\t\t\t\t\t!luckyColor &&\n\t\t\t\t\tluckyNumbers.length === 0 &&\n\t\t\t\t\tluckyDays.length === 0 &&\n\t\t\t\t\tcompatibleSigns.length === 0\n\t\t\t\t)\n\t\t\t\t\treturn nothing;\n\t\t\t\treturn html`<div class=\"lucky\">\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyNumber !== undefined\n\t\t\t\t\t\t\t\t? html`<span>Lucky number <strong>${luckyNumber}</strong></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyColor\n\t\t\t\t\t\t\t\t? html`<span>Lucky color <strong>${luckyColor}</strong></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyNumbers.length\n\t\t\t\t\t\t\t\t? html`<span\n\t\t\t\t\t\t\t\t\t>Lucky numbers\n\t\t\t\t\t\t\t\t\t<strong>${luckyNumbers.join(', ')}</strong></span\n\t\t\t\t\t\t\t\t>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyDays.length\n\t\t\t\t\t\t\t\t? html`<span\n\t\t\t\t\t\t\t\t\t>Lucky days <strong>${luckyDays.join(', ')}</strong></span\n\t\t\t\t\t\t\t\t>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tcompatibleSigns.length\n\t\t\t\t\t\t\t\t? html`<span class=\"compat-wrap\">\n\t\t\t\t\t\t\t\t\tBest with\n\t\t\t\t\t\t\t\t\t<span class=\"compat\"\n\t\t\t\t\t\t\t\t\t\t>${compatibleSigns.map(\n\t\t\t\t\t\t\t\t\t\t\t(s) => html`<span>${s}</span>`,\n\t\t\t\t\t\t\t\t\t\t)}</span\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>`;\n\t\t\t})()}\n\t\t</article>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-horoscope-card': RoxyHoroscopeCard;\n\t}\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n\t'North node': '\u260A',\n\t'South node': '\u260B',\n\tChiron: '\u26B7',\n\tLilith: '\u26B8',\n\t'Black moon lilith': '\u26B8',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/**\n * Lowercase rashi keys in canonical zodiac order. Derived from `SIGNS_ORDER`\n * so the two stay in lockstep. The /vedic-astrology/birth-chart response\n * carries planet buckets keyed by these names.\n */\nexport const RASHI_KEYS = SIGNS_ORDER.map((s) =>\n\ts.toLowerCase(),\n) as readonly Lowercase<(typeof SIGNS_ORDER)[number]>[];\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n", "/**\n * Shared string helpers used across components. Single source of truth so the\n * same formatting rules apply to every key/label/title that surfaces in the\n * shadow tree.\n *\n * - `capitalize`: title-cases the first character, lowercases the rest. Used\n * when matching API-supplied planet/sign names against the glyph maps in\n * `tokens/index.ts`, which use canonical TitleCase keys.\n * - `humanize`: turns an API key (`birth_date`, `birthDate`, `mahadasha-end`)\n * into a label suitable for display (\"Birth date\", \"Mahadasha end\").\n */\n\nexport function capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function humanize(s: string): string {\n\treturn s\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.replace(/([a-z])([A-Z])/g, '$1 $2')\n\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;AAAA,SAAS,OAAAA,MAAK,MAAM,YAAY,eAAe;AAC/C,SAAS,eAAe,gBAAgB;;;AC+CjC,IAAM,aAAqC;AAAA,EACjD,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,OAAO;AAAA,EACP,OAAO;AAAA,EACP,SAAS;AAAA,EACT,aAAa;AAAA,EACb,WAAW;AAAA,EACX,UAAU;AAAA,EACV,QAAQ;AACT;AAiBO,IAAM,cAAc;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAOO,IAAM,aAAa,YAAY;AAAA,EAAI,CAAC,MAC1C,EAAE,YAAY;AACf;;;ACpGA,SAAS,WAAW;AAMb,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACMnB,SAAS,WAAW,GAAmB;AAC7C,MAAI,CAAC,EAAG,QAAO;AACf,SAAO,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,EAAE,MAAM,CAAC,EAAE,YAAY;AAC3D;;;AHMO,IAAM,oBAAN,cAAgC,WAAW;AAAA,EAA3C;AAAA;AAiIN,gBAA6B;AAG7B,kBAAyC;AAAA;AAAA,EAEzC,SAAS;AACR,UAAM,IAAI,KAAK;AACf,QAAI,CAAC;AACJ,aAAO;AAER,UAAM,OAAO,EAAE,QAAQ;AACvB,UAAM,QAAQ,OAAQ,WAAW,WAAW,IAAI,CAAC,KAAK,KAAM;AAC5D,UAAM,SACL,kBAAkB,KAAK,OAAO,EAAE,iBAAiB,WAC9C,EAAE,eACF;AACJ,UAAM,YACJ,UAAU,KAAK,EAAE,QACjB,UAAU,KAAK,EAAE,QACjB,WAAW,KAAK,EAAE,SACnB;AAED,WAAO;AAAA;AAAA,gBAEO,GAAG,KAAK,MAAM,kBAAkB,IAAI,EAAE;AAAA;AAAA;AAAA,6CAGT,KAAK;AAAA;AAAA,yBAEzB,IAAI,IAAI,KAAK,MAAM;AAAA,OACrC,YAAY,yBAAyB,SAAS,WAAW,OAAO;AAAA;AAAA,MAGlE,WAAW,OACR,uCAAuC,UAAU,MAAM,QAAQ;AAAA,gBACvD,MAAM;AAAA;AAAA,+BAEU,SAAS,KAAM,GAAG;AAAA;AAAA,iBAG1C,OACJ;AAAA;AAAA;AAAA,KAGC,EAAE,WAAW,2BAA2B,EAAE,QAAQ,SAAS,OAAO;AAAA;AAAA;AAAA,MAIlE,EAAE,OACC;AAAA;AAAA,YAEI,EAAE,IAAI;AAAA,gBAEV,OACJ;AAAA,MAEC,EAAE,SACC;AAAA;AAAA,YAEI,EAAE,MAAM;AAAA,gBAEZ,OACJ;AAAA,MAEC,EAAE,SACC;AAAA;AAAA,YAEI,EAAE,MAAM;AAAA,gBAEZ,OACJ;AAAA,MAEC,EAAE,UACC;AAAA;AAAA,YAEI,EAAE,OAAO;AAAA,gBAEb,OACJ;AAAA,MAEC,YAAY,KAAK,EAAE,SAChB;AAAA;AAAA,YAEI,EAAE,MAAM;AAAA,gBAEZ,OACJ;AAAA;AAAA;AAAA,MAGE,MAAM;AACR,YAAM,cACL,iBAAiB,KAAK,EAAE,gBAAgB,SACrC,EAAE,cACF;AACJ,YAAM,aACL,gBAAgB,KAAK,EAAE,aAAa,EAAE,aAAa;AACpD,YAAM,eACL,kBAAkB,KAAK,EAAE,eAAe,EAAE,eAAe,CAAC;AAC3D,YAAM,YAAY,eAAe,KAAK,EAAE,YAAY,EAAE,YAAY,CAAC;AACnE,YAAM,kBAAkB,EAAE,mBAAmB,CAAC;AAC9C,UACC,gBAAgB,UAChB,CAAC,cACD,aAAa,WAAW,KACxB,UAAU,WAAW,KACrB,gBAAgB,WAAW;AAE3B,eAAO;AACR,aAAO;AAAA,QAEJ,gBAAgB,SACb,kCAAkC,WAAW,qBAC7C,OACJ;AAAA,QAEC,aACG,iCAAiC,UAAU,qBAC3C,OACJ;AAAA,QAEC,aAAa,SACV;AAAA;AAAA,mBAES,aAAa,KAAK,IAAI,CAAC;AAAA,aAEhC,OACJ;AAAA,QAEC,UAAU,SACP;AAAA,+BACqB,UAAU,KAAK,IAAI,CAAC;AAAA,aAEzC,OACJ;AAAA,QAEC,gBAAgB,SACb;AAAA;AAAA;AAAA,aAGG,gBAAgB;AAAA,QAClB,CAAC,MAAM,aAAa,CAAC;AAAA,MACtB,CAAC;AAAA;AAAA,mBAGD,OACJ;AAAA;AAAA,IAEH,GAAG,CAAC;AAAA;AAAA,EAEN;AACD;AAvRa,kBACL,SAAS;AAAA,EACf;AAAA,EACAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2HD;AAGA;AAAA,EADC,SAAS,EAAE,WAAW,MAAM,CAAC;AAAA,GAhIlB,kBAiIZ;AAGA;AAAA,EADC,SAAS,EAAE,MAAM,QAAQ,SAAS,KAAK,CAAC;AAAA,GAnI7B,kBAoIZ;AApIY,oBAAN;AAAA,EADN,cAAc,qBAAqB;AAAA,GACvB;",
|
|
6
6
|
"names": ["css", "css"]
|
|
7
7
|
}
|
|
@@ -1,30 +1,12 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
|
-
|
|
3
|
-
planet?: string;
|
|
4
|
-
name?: string;
|
|
5
|
-
sign?: string;
|
|
6
|
-
signLord?: string;
|
|
7
|
-
nakshatra?: string;
|
|
8
|
-
nakshatraLord?: string;
|
|
9
|
-
pada?: number;
|
|
10
|
-
starLord?: string;
|
|
11
|
-
subLord?: string;
|
|
12
|
-
subSubLord?: string;
|
|
13
|
-
kpNumber?: number;
|
|
14
|
-
retrograde?: boolean;
|
|
15
|
-
longitude?: number;
|
|
16
|
-
}
|
|
17
|
-
interface KpData {
|
|
18
|
-
ayanamsa?: number | string;
|
|
19
|
-
planets?: KpPlanet[];
|
|
20
|
-
}
|
|
2
|
+
import type { KpPlanetsResponse } from '../types/index.js';
|
|
21
3
|
/**
|
|
22
4
|
* KP planets table with sub-lord and sub-sub-lord columns. Renders
|
|
23
5
|
* /vedic-astrology/kp/planets.
|
|
24
6
|
*/
|
|
25
7
|
export declare class RoxyKpPlanetsTable extends LitElement {
|
|
26
8
|
static styles: import("lit").CSSResult[];
|
|
27
|
-
data:
|
|
9
|
+
data: KpPlanetsResponse | null;
|
|
28
10
|
render(): import("lit").TemplateResult<1>;
|
|
29
11
|
}
|
|
30
12
|
declare global {
|
|
@@ -32,5 +14,4 @@ declare global {
|
|
|
32
14
|
'roxy-kp-planets-table': RoxyKpPlanetsTable;
|
|
33
15
|
}
|
|
34
16
|
}
|
|
35
|
-
export {};
|
|
36
17
|
//# sourceMappingURL=kp-planets-table.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kp-planets-table.d.ts","sourceRoot":"","sources":["../../src/components/kp-planets-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"kp-planets-table.d.ts","sourceRoot":"","sources":["../../src/components/kp-planets-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAErD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAI3D;;;GAGG;AACH,qBACa,kBAAmB,SAAQ,UAAU;IACjD,MAAM,CAAC,MAAM,4BA8DX;IAGF,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAQ;IAEtC,MAAM;CAmDN;AAED,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,uBAAuB,EAAE,kBAAkB,CAAC;KAC5C;CACD"}
|
|
@@ -99,6 +99,12 @@ var baseStyles = css`
|
|
|
99
99
|
}
|
|
100
100
|
`;
|
|
101
101
|
|
|
102
|
+
// packages/ui/src/utils/format.ts
|
|
103
|
+
function formatNumber(value, dp = 1) {
|
|
104
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return "";
|
|
105
|
+
return value.toFixed(dp).replace(/\.?0+$/, "");
|
|
106
|
+
}
|
|
107
|
+
|
|
102
108
|
// packages/ui/src/components/kp-planets-table.ts
|
|
103
109
|
var RoxyKpPlanetsTable = class extends LitElement {
|
|
104
110
|
constructor() {
|
|
@@ -116,7 +122,7 @@ var RoxyKpPlanetsTable = class extends LitElement {
|
|
|
116
122
|
>
|
|
117
123
|
<header class="head">
|
|
118
124
|
<h2 class="title">KP planets</h2>
|
|
119
|
-
${this.data.ayanamsa ? html`<span class="ayanamsa">Ayanamsa: ${this.data.ayanamsa}
|
|
125
|
+
${typeof this.data.ayanamsa === "number" ? html`<span class="ayanamsa">Ayanamsa: ${formatNumber(this.data.ayanamsa, 2)}°</span>` : nothing}
|
|
120
126
|
</header>
|
|
121
127
|
<table role="table">
|
|
122
128
|
<thead>
|
|
@@ -135,13 +141,13 @@ var RoxyKpPlanetsTable = class extends LitElement {
|
|
|
135
141
|
${planets.map(
|
|
136
142
|
(p) => html`<tr>
|
|
137
143
|
<td class="planet">
|
|
138
|
-
${p.planet
|
|
144
|
+
${p.planet}
|
|
139
145
|
${p.retrograde ? html`<span class="retro">R</span>` : nothing}
|
|
140
146
|
</td>
|
|
141
147
|
<td>${p.sign ?? ""}</td>
|
|
142
148
|
<td>${p.signLord ?? ""}</td>
|
|
143
149
|
<td>${p.nakshatra ?? ""}</td>
|
|
144
|
-
<td>${p.
|
|
150
|
+
<td>${p.nakshatraLord ?? ""}</td>
|
|
145
151
|
<td>${p.subLord ?? ""}</td>
|
|
146
152
|
<td>${p.subSubLord ?? ""}</td>
|
|
147
153
|
<td>${p.kpNumber ?? ""}</td>
|
|
@@ -209,7 +215,7 @@ RoxyKpPlanetsTable.styles = [
|
|
|
209
215
|
color: var(--roxy-fg, #0a0a0a);
|
|
210
216
|
}
|
|
211
217
|
.retro {
|
|
212
|
-
color: var(--roxy-warning, #
|
|
218
|
+
color: var(--roxy-warning-fg, #9a3412);
|
|
213
219
|
font-size: var(--roxy-text-xs, 0.75rem);
|
|
214
220
|
margin-left: 4px;
|
|
215
221
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../src/components/kp-planets-table.ts", "../../src/utils/base-styles.ts"],
|
|
4
|
-
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;AAAA,SAAS,OAAAA,MAAK,MAAM,YAAY,eAAe;AAC/C,SAAS,eAAe,gBAAgB;;;ACDxC,SAAS,WAAW;AAMb,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;
|
|
3
|
+
"sources": ["../../src/components/kp-planets-table.ts", "../../src/utils/base-styles.ts", "../../src/utils/format.ts"],
|
|
4
|
+
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { KpPlanetsResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\n/**\n * KP planets table with sub-lord and sub-sub-lord columns. Renders\n * /vedic-astrology/kp/planets.\n */\n@customElement('roxy-kp-planets-table')\nexport class RoxyKpPlanetsTable extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.wrap {\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\toverflow: auto;\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t}\n\t\t\t.head {\n\t\t\t\tpadding: var(--roxy-space-md, 1rem);\n\t\t\t\tborder-bottom: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tdisplay: flex;\n\t\t\t\tjustify-content: space-between;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t\t\t}\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-lg, 1.125rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.ayanamsa {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t\ttable {\n\t\t\t\twidth: 100%;\n\t\t\t\tborder-collapse: collapse;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tmin-width: 560px;\n\t\t\t}\n\t\t\tthead {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-border, #e4e4e7) 20%, transparent);\n\t\t\t}\n\t\t\tth,\n\t\t\ttd {\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\ttext-align: left;\n\t\t\t\twhite-space: nowrap;\n\t\t\t}\n\t\t\tth {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tletter-spacing: 0.04em;\n\t\t\t}\n\t\t\ttbody tr {\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\ttd.planet {\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.retro {\n\t\t\t\tcolor: var(--roxy-warning-fg, #9a3412);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tmargin-left: 4px;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: KpPlanetsResponse | null = null;\n\n\trender() {\n\t\tif (!this.data)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No KP data</div>`;\n\t\tconst planets = this.data.planets ?? [];\n\n\t\treturn html`<div\n\t\t\tclass=\"wrap\"\n\t\t\taria-label=\"KP planets table\"\n\t\t\ttabindex=\"0\"\n\t\t>\n\t\t\t<header class=\"head\">\n\t\t\t\t<h2 class=\"title\">KP planets</h2>\n\t\t\t\t${\n\t\t\t\t\ttypeof this.data.ayanamsa === 'number'\n\t\t\t\t\t\t? html`<span class=\"ayanamsa\">Ayanamsa: ${formatNumber(this.data.ayanamsa, 2)}\u00B0</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</header>\n\t\t\t<table role=\"table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th scope=\"col\">Planet</th>\n\t\t\t\t\t\t<th scope=\"col\">Sign</th>\n\t\t\t\t\t\t<th scope=\"col\">Sign lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Nakshatra</th>\n\t\t\t\t\t\t<th scope=\"col\">Star lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Sub lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Sub sub lord</th>\n\t\t\t\t\t\t<th scope=\"col\">KP no.</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t${planets.map(\n\t\t\t\t\t\t(p) => html`<tr>\n\t\t\t\t\t\t\t<td class=\"planet\">\n\t\t\t\t\t\t\t\t${p.planet}\n\t\t\t\t\t\t\t\t${p.retrograde ? html`<span class=\"retro\">R</span>` : nothing}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>${p.sign ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.signLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.nakshatra ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.nakshatraLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.subLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.subSubLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.kpNumber ?? ''}</td>\n\t\t\t\t\t\t</tr>`,\n\t\t\t\t\t)}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-kp-planets-table': RoxyKpPlanetsTable;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n", "/**\n * Display formatters for ISO timestamps and floats coming back from the API.\n * Every helper returns \"\" for nullish or unparseable input so it falls out of\n * template literals cleanly.\n */\n\nexport function formatTime(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tif (/^\\d{4}-\\d{2}-\\d{2}$/.test(input)) return '';\n\tconst bareTime = /^\\d{2}:\\d{2}(:\\d{2})?$/.test(input);\n\tconst iso = bareTime ? `1970-01-01T${input}` : input;\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleTimeString(undefined, {\n\t\thour: 'numeric',\n\t\tminute: '2-digit',\n\t\thour12: true,\n\t});\n}\n\nexport function formatDate(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tconst d = new Date(\n\t\t/^\\d{4}-\\d{2}-\\d{2}$/.test(input) ? `${input}T00:00:00` : input,\n\t);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleDateString(undefined, {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: 'numeric',\n\t});\n}\n\nexport function formatTimeRange(\n\tt: { start?: string; end?: string } | undefined,\n): string {\n\tif (!t) return '';\n\tconst start = formatTime(t.start);\n\tconst end = formatTime(t.end);\n\tif (start && end) return `${start} - ${end}`;\n\treturn start || end || '';\n}\n\nexport function formatNumber(value: unknown, dp = 1): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\treturn value.toFixed(dp).replace(/\\.?0+$/, '');\n}\n\nexport function formatPercent(value: unknown, dp = 1): string {\n\tconst n = formatNumber(value, dp);\n\treturn n ? `${n}%` : '';\n}\n\n/**\n * CSS class name per aspect type. Used by natal and synastry chart aspect\n * lines so the same color encoding (harmonious vs challenging) applies in\n * both wheels. Keys are lowercase canonical names, values are CSS class\n * suffixes the chart components define in their `:host` styles.\n */\nexport const ASPECT_CLASS: Record<string, string> = {\n\tconjunction: 'aspect-conjunction',\n\tsextile: 'aspect-sextile',\n\tsquare: 'aspect-square',\n\ttrine: 'aspect-trine',\n\topposition: 'aspect-opposition',\n};\n\n/**\n * Normalize an aspect entry's `type` field to a lowercase, hyphen-separated\n * canonical name (`SEMI_SEXTILE` \u2192 `semi-sextile`). Accepts any aspect-shaped\n * object so both natal and synastry inter-aspect entries can share this.\n */\nexport function normalizeAspect(a: { type?: string }): string {\n\treturn (a.type ?? '').toLowerCase().replace(/_/g, '-');\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;AAAA,SAAS,OAAAA,MAAK,MAAM,YAAY,eAAe;AAC/C,SAAS,eAAe,gBAAgB;;;ACDxC,SAAS,WAAW;AAMb,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACqCnB,SAAS,aAAa,OAAgB,KAAK,GAAW;AAC5D,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACjE,SAAO,MAAM,QAAQ,EAAE,EAAE,QAAQ,UAAU,EAAE;AAC9C;;;AFnCO,IAAM,qBAAN,cAAiC,WAAW;AAAA,EAA5C;AAAA;AAkEN,gBAAiC;AAAA;AAAA,EAEjC,SAAS;AACR,QAAI,CAAC,KAAK;AACT,aAAO;AACR,UAAM,UAAU,KAAK,KAAK,WAAW,CAAC;AAEtC,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQJ,OAAO,KAAK,KAAK,aAAa,WAC3B,wCAAwC,aAAa,KAAK,KAAK,UAAU,CAAC,CAAC,aAC3E,OACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAgBG,QAAQ;AAAA,MACT,CAAC,MAAM;AAAA;AAAA,UAEH,EAAE,MAAM;AAAA,UACR,EAAE,aAAa,qCAAqC,OAAO;AAAA;AAAA,aAExD,EAAE,QAAQ,EAAE;AAAA,aACZ,EAAE,YAAY,EAAE;AAAA,aAChB,EAAE,aAAa,EAAE;AAAA,aACjB,EAAE,iBAAiB,EAAE;AAAA,aACrB,EAAE,WAAW,EAAE;AAAA,aACf,EAAE,cAAc,EAAE;AAAA,aAClB,EAAE,YAAY,EAAE;AAAA;AAAA,IAExB,CAAC;AAAA;AAAA;AAAA;AAAA,EAIL;AACD;AAvHa,mBACL,SAAS;AAAA,EACf;AAAA,EACAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4DD;AAGA;AAAA,EADC,SAAS,EAAE,WAAW,MAAM,CAAC;AAAA,GAjElB,mBAkEZ;AAlEY,qBAAN;AAAA,EADN,cAAc,uBAAuB;AAAA,GACzB;",
|
|
6
6
|
"names": ["css", "css"]
|
|
7
7
|
}
|
|
@@ -1,23 +1,11 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
|
-
export interface CityResult {
|
|
3
|
-
city: string;
|
|
4
|
-
province?: string;
|
|
5
|
-
country: string;
|
|
6
|
-
iso2?: string;
|
|
7
|
-
latitude: number;
|
|
8
|
-
longitude: number;
|
|
9
|
-
timezone: string;
|
|
10
|
-
utcOffset: number;
|
|
11
|
-
population?: number;
|
|
12
|
-
}
|
|
13
2
|
/**
|
|
14
3
|
* Stateful location search input. Calls /location/search and emits
|
|
15
4
|
* `roxy-location-select` CustomEvent with the chosen city. Required for any
|
|
16
5
|
* chart endpoint.
|
|
17
6
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* state with Lit reactive properties and using direct fetch to RoxyAPI.
|
|
7
|
+
* Behavior: 300ms input debounce, click-outside dismiss, keyboard navigation
|
|
8
|
+
* with arrow keys / Enter / Escape, AbortController on stale requests.
|
|
21
9
|
*
|
|
22
10
|
* Attributes:
|
|
23
11
|
* api-key optional. Direct call to roxyapi.com when set.
|
|
@@ -39,9 +27,12 @@ export declare class RoxyLocationSearch extends LitElement {
|
|
|
39
27
|
private isLoading;
|
|
40
28
|
private highlight;
|
|
41
29
|
private clickOutsideHandler?;
|
|
30
|
+
private abortController?;
|
|
31
|
+
private secretKeyWarned;
|
|
42
32
|
private debouncedFetch;
|
|
43
33
|
connectedCallback(): void;
|
|
44
34
|
disconnectedCallback(): void;
|
|
35
|
+
private warnIfSecretKey;
|
|
45
36
|
private fetchResults;
|
|
46
37
|
private onInput;
|
|
47
38
|
private select;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"location-search.d.ts","sourceRoot":"","sources":["../../src/components/location-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"location-search.d.ts","sourceRoot":"","sources":["../../src/components/location-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAQrD;;;;;;;;;;;;;;GAcG;AACH,qBACa,kBAAmB,SAAQ,UAAU;IACjD,MAAM,CAAC,MAAM,4BAwGX;IAGF,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,QAAQ,SAAgD;IAGxD,WAAW,SAAiB;IAG5B,YAAY,SAAM;IAGlB,OAAO,CAAC,KAAK,CAAM;IAGnB,OAAO,CAAC,OAAO,CAAoB;IAGnC,OAAO,CAAC,MAAM,CAAS;IAGvB,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,SAAS,CAAM;IAEvB,OAAO,CAAC,mBAAmB,CAAC,CAA0B;IACtD,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,cAAc,CAEd;IAER,iBAAiB,IAAI,IAAI;IAUzB,oBAAoB,IAAI,IAAI;IAY5B,OAAO,CAAC,eAAe;YAqBT,YAAY;IAoC1B,OAAO,CAAC,OAAO,CAUb;IAEF,OAAO,CAAC,MAAM;IAad,OAAO,CAAC,SAAS,CAsBf;IAEF,MAAM;CAwDN;AAED,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,sBAAsB,EAAE,kBAAkB,CAAC;KAC3C;CACD"}
|
|
@@ -102,10 +102,20 @@ var baseStyles = css`
|
|
|
102
102
|
// packages/ui/src/utils/debounce.ts
|
|
103
103
|
function debounce(fn, wait) {
|
|
104
104
|
let timer;
|
|
105
|
-
|
|
105
|
+
const debounced = ((...args) => {
|
|
106
106
|
if (timer) clearTimeout(timer);
|
|
107
|
-
timer = setTimeout(() =>
|
|
107
|
+
timer = setTimeout(() => {
|
|
108
|
+
timer = void 0;
|
|
109
|
+
fn(...args);
|
|
110
|
+
}, wait);
|
|
108
111
|
});
|
|
112
|
+
debounced.cancel = () => {
|
|
113
|
+
if (timer) {
|
|
114
|
+
clearTimeout(timer);
|
|
115
|
+
timer = void 0;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
return debounced;
|
|
109
119
|
}
|
|
110
120
|
|
|
111
121
|
// packages/ui/src/components/location-search.ts
|
|
@@ -120,6 +130,7 @@ var RoxyLocationSearch = class extends LitElement {
|
|
|
120
130
|
this.isOpen = false;
|
|
121
131
|
this.isLoading = false;
|
|
122
132
|
this.highlight = -1;
|
|
133
|
+
this.secretKeyWarned = false;
|
|
123
134
|
this.debouncedFetch = debounce((q) => {
|
|
124
135
|
void this.fetchResults(q);
|
|
125
136
|
}, 300);
|
|
@@ -171,8 +182,32 @@ var RoxyLocationSearch = class extends LitElement {
|
|
|
171
182
|
if (this.clickOutsideHandler) {
|
|
172
183
|
document.removeEventListener("mousedown", this.clickOutsideHandler);
|
|
173
184
|
}
|
|
185
|
+
this.debouncedFetch.cancel();
|
|
186
|
+
if (this.abortController) {
|
|
187
|
+
this.abortController.abort();
|
|
188
|
+
this.abortController = void 0;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
warnIfSecretKey() {
|
|
192
|
+
if (this.secretKeyWarned) return;
|
|
193
|
+
if (!this.apiKey) return;
|
|
194
|
+
if (this.apiKey.startsWith("pk_")) return;
|
|
195
|
+
this.secretKeyWarned = true;
|
|
196
|
+
const message = "Possible secret key in client-side <roxy-location-search>; use a `pk_` publishable key with origin allowlist instead.";
|
|
197
|
+
console.warn(message);
|
|
198
|
+
this.dispatchEvent(
|
|
199
|
+
new CustomEvent("roxy-validation-error", {
|
|
200
|
+
detail: { reason: "possible-secret-key", message },
|
|
201
|
+
bubbles: true,
|
|
202
|
+
composed: true
|
|
203
|
+
})
|
|
204
|
+
);
|
|
174
205
|
}
|
|
175
206
|
async fetchResults(q) {
|
|
207
|
+
this.warnIfSecretKey();
|
|
208
|
+
if (this.abortController) this.abortController.abort();
|
|
209
|
+
const controller = new AbortController();
|
|
210
|
+
this.abortController = controller;
|
|
176
211
|
this.isLoading = true;
|
|
177
212
|
try {
|
|
178
213
|
const url = new URL(this.endpoint);
|
|
@@ -183,17 +218,22 @@ var RoxyLocationSearch = class extends LitElement {
|
|
|
183
218
|
};
|
|
184
219
|
if (this.apiKey) headers["X-API-Key"] = this.apiKey;
|
|
185
220
|
if (this.publishableKey) headers["X-API-Key"] = this.publishableKey;
|
|
186
|
-
const res = await fetch(url, { headers });
|
|
221
|
+
const res = await fetch(url, { headers, signal: controller.signal });
|
|
187
222
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
188
223
|
const json = await res.json();
|
|
224
|
+
if (controller.signal.aborted) return;
|
|
189
225
|
this.results = json.cities ?? [];
|
|
190
226
|
this.isOpen = this.results.length > 0;
|
|
191
227
|
this.highlight = this.results.length > 0 ? 0 : -1;
|
|
192
|
-
} catch (
|
|
228
|
+
} catch (err) {
|
|
229
|
+
if (err?.name === "AbortError") return;
|
|
193
230
|
this.results = [];
|
|
194
231
|
this.isOpen = false;
|
|
195
232
|
} finally {
|
|
196
|
-
this.
|
|
233
|
+
if (this.abortController === controller) {
|
|
234
|
+
this.abortController = void 0;
|
|
235
|
+
}
|
|
236
|
+
if (!controller.signal.aborted) this.isLoading = false;
|
|
197
237
|
}
|
|
198
238
|
}
|
|
199
239
|
select(city) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/location-search.ts", "../../src/utils/base-styles.ts", "../../src/utils/debounce.ts"],
|
|
4
|
-
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { debounce } from '../utils/debounce.js';\n\nexport interface CityResult {\n\tcity: string;\n\tprovince?: string;\n\tcountry: string;\n\tiso2?: string;\n\tlatitude: number;\n\tlongitude: number;\n\ttimezone: string;\n\tutcOffset: number;\n\tpopulation?: number;\n}\n\ninterface CitySearchResponse {\n\ttotal?: number;\n\tcities?: CityResult[];\n}\n\n/**\n * Stateful location search input. Calls /location/search and emits\n * `roxy-location-select` CustomEvent with the chosen city. Required for any\n * chart endpoint.\n *\n * Lifted from jyotish-vedic-astrology-app/src/components/city-search.tsx,\n * keeping the 300ms debounce and click-outside behavior, replacing React\n * state with Lit reactive properties and using direct fetch to RoxyAPI.\n *\n * Attributes:\n * api-key optional. Direct call to roxyapi.com when set.\n * publishable-key optional. Browser-safe pk_* key with allowed_origins.\n * endpoint optional. Override URL (default https://roxyapi.com/api/v2/location/search).\n * placeholder optional. Input placeholder.\n * default-value optional. Pre-filled query.\n */\n@customElement('roxy-location-search')\nexport class RoxyLocationSearch extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t:host {\n\t\t\t\tdisplay: block;\n\t\t\t\tposition: relative;\n\t\t\t}\n\t\t\t.field {\n\t\t\t\tposition: relative;\n\t\t\t}\n\t\t\tinput {\n\t\t\t\twidth: 100%;\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\t\t\tfont-family: inherit;\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\ttransition:\n\t\t\t\t\tborder-color var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t\tbox-sizing: border-box;\n\t\t\t}\n\t\t\tinput:focus {\n\t\t\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\t\t\toutline-offset: 2px;\n\t\t\t\tborder-color: var(--roxy-accent-fg, #b45309);\n\t\t\t}\n\t\t\t.spinner {\n\t\t\t\tposition: absolute;\n\t\t\t\tright: 12px;\n\t\t\t\ttop: 50%;\n\t\t\t\ttransform: translateY(-50%);\n\t\t\t\twidth: 14px;\n\t\t\t\theight: 14px;\n\t\t\t\tborder: 2px solid var(--roxy-muted, #71717a);\n\t\t\t\tborder-top-color: transparent;\n\t\t\t\tborder-radius: 50%;\n\t\t\t\tanimation: roxy-spin 700ms linear infinite;\n\t\t\t}\n\t\t\t@keyframes roxy-spin {\n\t\t\t\tto {\n\t\t\t\t\ttransform: translateY(-50%) rotate(360deg);\n\t\t\t\t}\n\t\t\t}\n\t\t\t@media (prefers-reduced-motion: reduce) {\n\t\t\t\t.spinner {\n\t\t\t\t\tanimation: none;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t.results {\n\t\t\t\tposition: absolute;\n\t\t\t\tz-index: 50;\n\t\t\t\ttop: calc(100% + 4px);\n\t\t\t\tleft: 0;\n\t\t\t\tright: 0;\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tbox-shadow: var(--roxy-shadow-md);\n\t\t\t\tmax-height: 22rem;\n\t\t\t\toverflow-y: auto;\n\t\t\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t}\n\t\t\t.option {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: baseline;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t\t\t\twidth: 100%;\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\tbackground: transparent;\n\t\t\t\tborder: 0;\n\t\t\t\ttext-align: left;\n\t\t\t\tfont-family: inherit;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tcursor: pointer;\n\t\t\t\ttransition: background-color var(--roxy-motion-duration, 200ms);\n\t\t\t}\n\t\t\t.option:hover,\n\t\t\t.option[aria-selected='true'] {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-accent, #f59e0b) 10%, transparent);\n\t\t\t}\n\t\t\t.option .city {\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.option .where {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tflex-grow: 1;\n\t\t\t}\n\t\t\t.option .tz {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t}\n\t\t\t.empty {\n\t\t\t\tpadding: var(--roxy-space-md, 1rem);\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ type: String, attribute: 'api-key' })\n\tapiKey?: string;\n\n\t@property({ type: String, attribute: 'publishable-key' })\n\tpublishableKey?: string;\n\n\t@property({ type: String })\n\tendpoint = 'https://roxyapi.com/api/v2/location/search';\n\n\t@property({ type: String })\n\tplaceholder = 'Search city';\n\n\t@property({ type: String, attribute: 'default-value' })\n\tdefaultValue = '';\n\n\t@state()\n\tprivate query = '';\n\n\t@state()\n\tprivate results: CityResult[] = [];\n\n\t@state()\n\tprivate isOpen = false;\n\n\t@state()\n\tprivate isLoading = false;\n\n\t@state()\n\tprivate highlight = -1;\n\n\tprivate clickOutsideHandler?: (e: MouseEvent) => void;\n\tprivate debouncedFetch = debounce((q: string) => {\n\t\tvoid this.fetchResults(q);\n\t}, 300);\n\n\tconnectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tthis.query = this.defaultValue;\n\t\tthis.clickOutsideHandler = (e: MouseEvent) => {\n\t\t\tconst path = e.composedPath();\n\t\t\tif (!path.includes(this)) this.isOpen = false;\n\t\t};\n\t\tdocument.addEventListener('mousedown', this.clickOutsideHandler);\n\t}\n\n\tdisconnectedCallback(): void {\n\t\tsuper.disconnectedCallback();\n\t\tif (this.clickOutsideHandler) {\n\t\t\tdocument.removeEventListener('mousedown', this.clickOutsideHandler);\n\t\t}\n\t}\n\n\tprivate async fetchResults(q: string) {\n\t\tthis.isLoading = true;\n\t\ttry {\n\t\t\tconst url = new URL(this.endpoint);\n\t\t\turl.searchParams.set('q', q);\n\t\t\turl.searchParams.set('limit', '8');\n\t\t\tconst headers: Record<string, string> = {\n\t\t\t\tAccept: 'application/json',\n\t\t\t};\n\t\t\tif (this.apiKey) headers['X-API-Key'] = this.apiKey;\n\t\t\tif (this.publishableKey) headers['X-API-Key'] = this.publishableKey;\n\t\t\tconst res = await fetch(url, { headers });\n\t\t\tif (!res.ok) throw new Error(`HTTP ${res.status}`);\n\t\t\tconst json = (await res.json()) as CitySearchResponse;\n\t\t\tthis.results = json.cities ?? [];\n\t\t\tthis.isOpen = this.results.length > 0;\n\t\t\tthis.highlight = this.results.length > 0 ? 0 : -1;\n\t\t} catch (_err) {\n\t\t\tthis.results = [];\n\t\t\tthis.isOpen = false;\n\t\t} finally {\n\t\t\tthis.isLoading = false;\n\t\t}\n\t}\n\n\tprivate onInput = (e: Event) => {\n\t\tconst value = (e.target as HTMLInputElement).value;\n\t\tthis.query = value;\n\t\tif (value.length < 2) {\n\t\t\tthis.results = [];\n\t\t\tthis.isOpen = false;\n\t\t\tthis.highlight = -1;\n\t\t\treturn;\n\t\t}\n\t\tthis.debouncedFetch(value);\n\t};\n\n\tprivate select(city: CityResult) {\n\t\tthis.query = `${city.city}${city.province ? `, ${city.province}` : ''}, ${city.country}`;\n\t\tthis.isOpen = false;\n\t\tthis.results = [];\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-location-select', {\n\t\t\t\tdetail: city,\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate onKeyDown = (e: KeyboardEvent) => {\n\t\tif (!this.isOpen || this.results.length === 0) {\n\t\t\tif (e.key === 'ArrowDown' && this.query.length >= 2) {\n\t\t\t\tvoid this.fetchResults(this.query);\n\t\t\t\te.preventDefault();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (e.key === 'ArrowDown') {\n\t\t\te.preventDefault();\n\t\t\tthis.highlight = (this.highlight + 1) % this.results.length;\n\t\t} else if (e.key === 'ArrowUp') {\n\t\t\te.preventDefault();\n\t\t\tthis.highlight =\n\t\t\t\t(this.highlight - 1 + this.results.length) % this.results.length;\n\t\t} else if (e.key === 'Enter') {\n\t\t\te.preventDefault();\n\t\t\tconst target = this.results[this.highlight] ?? this.results[0];\n\t\t\tif (target) this.select(target);\n\t\t} else if (e.key === 'Escape') {\n\t\t\tthis.isOpen = false;\n\t\t}\n\t};\n\n\trender() {\n\t\treturn html`<div class=\"field\">\n\t\t\t<input\n\t\t\t\ttype=\"text\"\n\t\t\t\trole=\"combobox\"\n\t\t\t\taria-expanded=${this.isOpen ? 'true' : 'false'}\n\t\t\t\taria-controls=\"roxy-location-listbox\"\n\t\t\t\taria-autocomplete=\"list\"\n\t\t\t\tautocomplete=\"off\"\n\t\t\t\tplaceholder=${this.placeholder}\n\t\t\t\t.value=${this.query}\n\t\t\t\t@input=${this.onInput}\n\t\t\t\t@keydown=${this.onKeyDown}\n\t\t\t\t@focus=${() => {\n\t\t\t\t\tif (this.results.length > 0) this.isOpen = true;\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t${this.isLoading ? html`<span class=\"spinner\" role=\"status\" aria-label=\"Loading\"></span>` : nothing}\n\t\t\t${\n\t\t\t\tthis.isOpen\n\t\t\t\t\t? html`<ul\n\t\t\t\t\t\tid=\"roxy-location-listbox\"\n\t\t\t\t\t\tclass=\"results\"\n\t\t\t\t\t\trole=\"listbox\"\n\t\t\t\t\t>\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tthis.results.length === 0\n\t\t\t\t\t\t\t\t? html`<li class=\"empty\" role=\"status\">No cities found</li>`\n\t\t\t\t\t\t\t\t: this.results.map(\n\t\t\t\t\t\t\t\t\t\t(city, idx) => html`<li role=\"presentation\">\n\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\tclass=\"option\"\n\t\t\t\t\t\t\t\t\t\t\trole=\"option\"\n\t\t\t\t\t\t\t\t\t\t\taria-selected=${this.highlight === idx ? 'true' : 'false'}\n\t\t\t\t\t\t\t\t\t\t\t@click=${() => this.select(city)}\n\t\t\t\t\t\t\t\t\t\t\t@mouseenter=${() => {\n\t\t\t\t\t\t\t\t\t\t\t\tthis.highlight = idx;\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"city\">${city.city}</span>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"where\"\n\t\t\t\t\t\t\t\t\t\t\t\t>${city.province ? html`${city.province}, ` : ''}${city.country}</span\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"tz\"\n\t\t\t\t\t\t\t\t\t\t\t\t>UTC${city.utcOffset >= 0 ? '+' : ''}${city.utcOffset}</span\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t</li>`,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t</ul>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-location-search': RoxyLocationSearch;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n", "/**\n * Lightweight debounce for input handlers. Used by location search.\n */\nexport function debounce<F extends (...args: never[]) => unknown>(\n\tfn: F,\n\twait: number,\n): F {\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\treturn ((...args: Parameters<F>) => {\n\t\tif (timer) clearTimeout(timer);\n\t\ttimer = setTimeout(() => fn(...args), wait);\n\t}) as F;\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;AAAA,SAAS,OAAAA,MAAK,MAAM,YAAY,eAAe;AAC/C,SAAS,eAAe,UAAU,aAAa;;;ACD/C,SAAS,WAAW;AAMb,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;
|
|
4
|
+
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport type { SearchCitiesResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { debounce } from '../utils/debounce.js';\n\ntype CityResult = SearchCitiesResponse['cities'][number];\n\n/**\n * Stateful location search input. Calls /location/search and emits\n * `roxy-location-select` CustomEvent with the chosen city. Required for any\n * chart endpoint.\n *\n * Behavior: 300ms input debounce, click-outside dismiss, keyboard navigation\n * with arrow keys / Enter / Escape, AbortController on stale requests.\n *\n * Attributes:\n * api-key optional. Direct call to roxyapi.com when set.\n * publishable-key optional. Browser-safe pk_* key with allowed_origins.\n * endpoint optional. Override URL (default https://roxyapi.com/api/v2/location/search).\n * placeholder optional. Input placeholder.\n * default-value optional. Pre-filled query.\n */\n@customElement('roxy-location-search')\nexport class RoxyLocationSearch extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t:host {\n\t\t\t\tdisplay: block;\n\t\t\t\tposition: relative;\n\t\t\t}\n\t\t\t.field {\n\t\t\t\tposition: relative;\n\t\t\t}\n\t\t\tinput {\n\t\t\t\twidth: 100%;\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\t\t\tfont-family: inherit;\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\ttransition:\n\t\t\t\t\tborder-color var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t\tbox-sizing: border-box;\n\t\t\t}\n\t\t\tinput:focus {\n\t\t\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\t\t\toutline-offset: 2px;\n\t\t\t\tborder-color: var(--roxy-accent-fg, #b45309);\n\t\t\t}\n\t\t\t.spinner {\n\t\t\t\tposition: absolute;\n\t\t\t\tright: 12px;\n\t\t\t\ttop: 50%;\n\t\t\t\ttransform: translateY(-50%);\n\t\t\t\twidth: 14px;\n\t\t\t\theight: 14px;\n\t\t\t\tborder: 2px solid var(--roxy-muted, #71717a);\n\t\t\t\tborder-top-color: transparent;\n\t\t\t\tborder-radius: 50%;\n\t\t\t\tanimation: roxy-spin 700ms linear infinite;\n\t\t\t}\n\t\t\t@keyframes roxy-spin {\n\t\t\t\tto {\n\t\t\t\t\ttransform: translateY(-50%) rotate(360deg);\n\t\t\t\t}\n\t\t\t}\n\t\t\t@media (prefers-reduced-motion: reduce) {\n\t\t\t\t.spinner {\n\t\t\t\t\tanimation: none;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t.results {\n\t\t\t\tposition: absolute;\n\t\t\t\tz-index: 50;\n\t\t\t\ttop: calc(100% + 4px);\n\t\t\t\tleft: 0;\n\t\t\t\tright: 0;\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tbox-shadow: var(--roxy-shadow-md);\n\t\t\t\tmax-height: 22rem;\n\t\t\t\toverflow-y: auto;\n\t\t\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t}\n\t\t\t.option {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: baseline;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t\t\t\twidth: 100%;\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\tbackground: transparent;\n\t\t\t\tborder: 0;\n\t\t\t\ttext-align: left;\n\t\t\t\tfont-family: inherit;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tcursor: pointer;\n\t\t\t\ttransition: background-color var(--roxy-motion-duration, 200ms);\n\t\t\t}\n\t\t\t.option:hover,\n\t\t\t.option[aria-selected='true'] {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-accent, #f59e0b) 10%, transparent);\n\t\t\t}\n\t\t\t.option .city {\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.option .where {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tflex-grow: 1;\n\t\t\t}\n\t\t\t.option .tz {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t}\n\t\t\t.empty {\n\t\t\t\tpadding: var(--roxy-space-md, 1rem);\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ type: String, attribute: 'api-key' })\n\tapiKey?: string;\n\n\t@property({ type: String, attribute: 'publishable-key' })\n\tpublishableKey?: string;\n\n\t@property({ type: String })\n\tendpoint = 'https://roxyapi.com/api/v2/location/search';\n\n\t@property({ type: String })\n\tplaceholder = 'Search city';\n\n\t@property({ type: String, attribute: 'default-value' })\n\tdefaultValue = '';\n\n\t@state()\n\tprivate query = '';\n\n\t@state()\n\tprivate results: CityResult[] = [];\n\n\t@state()\n\tprivate isOpen = false;\n\n\t@state()\n\tprivate isLoading = false;\n\n\t@state()\n\tprivate highlight = -1;\n\n\tprivate clickOutsideHandler?: (e: MouseEvent) => void;\n\tprivate abortController?: AbortController;\n\tprivate secretKeyWarned = false;\n\tprivate debouncedFetch = debounce((q: string) => {\n\t\tvoid this.fetchResults(q);\n\t}, 300);\n\n\tconnectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tthis.query = this.defaultValue;\n\t\tthis.clickOutsideHandler = (e: MouseEvent) => {\n\t\t\tconst path = e.composedPath();\n\t\t\tif (!path.includes(this)) this.isOpen = false;\n\t\t};\n\t\tdocument.addEventListener('mousedown', this.clickOutsideHandler);\n\t}\n\n\tdisconnectedCallback(): void {\n\t\tsuper.disconnectedCallback();\n\t\tif (this.clickOutsideHandler) {\n\t\t\tdocument.removeEventListener('mousedown', this.clickOutsideHandler);\n\t\t}\n\t\tthis.debouncedFetch.cancel();\n\t\tif (this.abortController) {\n\t\t\tthis.abortController.abort();\n\t\t\tthis.abortController = undefined;\n\t\t}\n\t}\n\n\tprivate warnIfSecretKey() {\n\t\tif (this.secretKeyWarned) return;\n\t\tif (!this.apiKey) return;\n\t\t// Browser-safe publishable keys carry the `pk_` prefix and a server-side\n\t\t// origin allowlist. Anything else (a raw secret key, UUID-style token)\n\t\t// must not ship to the browser.\n\t\tif (this.apiKey.startsWith('pk_')) return;\n\t\tthis.secretKeyWarned = true;\n\t\tconst message =\n\t\t\t'Possible secret key in client-side <roxy-location-search>; use a `pk_` publishable key with origin allowlist instead.';\n\t\t// eslint-disable-next-line no-console\n\t\tconsole.warn(message);\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-validation-error', {\n\t\t\t\tdetail: { reason: 'possible-secret-key', message },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate async fetchResults(q: string) {\n\t\tthis.warnIfSecretKey();\n\t\t// Abort any in-flight request so a stale response cannot overwrite a\n\t\t// fresher one (debounced typing) or land after disconnect.\n\t\tif (this.abortController) this.abortController.abort();\n\t\tconst controller = new AbortController();\n\t\tthis.abortController = controller;\n\t\tthis.isLoading = true;\n\t\ttry {\n\t\t\tconst url = new URL(this.endpoint);\n\t\t\turl.searchParams.set('q', q);\n\t\t\turl.searchParams.set('limit', '8');\n\t\t\tconst headers: Record<string, string> = {\n\t\t\t\tAccept: 'application/json',\n\t\t\t};\n\t\t\tif (this.apiKey) headers['X-API-Key'] = this.apiKey;\n\t\t\tif (this.publishableKey) headers['X-API-Key'] = this.publishableKey;\n\t\t\tconst res = await fetch(url, { headers, signal: controller.signal });\n\t\t\tif (!res.ok) throw new Error(`HTTP ${res.status}`);\n\t\t\tconst json = (await res.json()) as SearchCitiesResponse;\n\t\t\tif (controller.signal.aborted) return;\n\t\t\tthis.results = json.cities ?? [];\n\t\t\tthis.isOpen = this.results.length > 0;\n\t\t\tthis.highlight = this.results.length > 0 ? 0 : -1;\n\t\t} catch (err) {\n\t\t\tif ((err as { name?: string })?.name === 'AbortError') return;\n\t\t\tthis.results = [];\n\t\t\tthis.isOpen = false;\n\t\t} finally {\n\t\t\tif (this.abortController === controller) {\n\t\t\t\tthis.abortController = undefined;\n\t\t\t}\n\t\t\tif (!controller.signal.aborted) this.isLoading = false;\n\t\t}\n\t}\n\n\tprivate onInput = (e: Event) => {\n\t\tconst value = (e.target as HTMLInputElement).value;\n\t\tthis.query = value;\n\t\tif (value.length < 2) {\n\t\t\tthis.results = [];\n\t\t\tthis.isOpen = false;\n\t\t\tthis.highlight = -1;\n\t\t\treturn;\n\t\t}\n\t\tthis.debouncedFetch(value);\n\t};\n\n\tprivate select(city: CityResult) {\n\t\tthis.query = `${city.city}${city.province ? `, ${city.province}` : ''}, ${city.country}`;\n\t\tthis.isOpen = false;\n\t\tthis.results = [];\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-location-select', {\n\t\t\t\tdetail: city,\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate onKeyDown = (e: KeyboardEvent) => {\n\t\tif (!this.isOpen || this.results.length === 0) {\n\t\t\tif (e.key === 'ArrowDown' && this.query.length >= 2) {\n\t\t\t\tvoid this.fetchResults(this.query);\n\t\t\t\te.preventDefault();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (e.key === 'ArrowDown') {\n\t\t\te.preventDefault();\n\t\t\tthis.highlight = (this.highlight + 1) % this.results.length;\n\t\t} else if (e.key === 'ArrowUp') {\n\t\t\te.preventDefault();\n\t\t\tthis.highlight =\n\t\t\t\t(this.highlight - 1 + this.results.length) % this.results.length;\n\t\t} else if (e.key === 'Enter') {\n\t\t\te.preventDefault();\n\t\t\tconst target = this.results[this.highlight] ?? this.results[0];\n\t\t\tif (target) this.select(target);\n\t\t} else if (e.key === 'Escape') {\n\t\t\tthis.isOpen = false;\n\t\t}\n\t};\n\n\trender() {\n\t\treturn html`<div class=\"field\">\n\t\t\t<input\n\t\t\t\ttype=\"text\"\n\t\t\t\trole=\"combobox\"\n\t\t\t\taria-expanded=${this.isOpen ? 'true' : 'false'}\n\t\t\t\taria-controls=\"roxy-location-listbox\"\n\t\t\t\taria-autocomplete=\"list\"\n\t\t\t\tautocomplete=\"off\"\n\t\t\t\tplaceholder=${this.placeholder}\n\t\t\t\t.value=${this.query}\n\t\t\t\t@input=${this.onInput}\n\t\t\t\t@keydown=${this.onKeyDown}\n\t\t\t\t@focus=${() => {\n\t\t\t\t\tif (this.results.length > 0) this.isOpen = true;\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t${this.isLoading ? html`<span class=\"spinner\" role=\"status\" aria-label=\"Loading\"></span>` : nothing}\n\t\t\t${\n\t\t\t\tthis.isOpen\n\t\t\t\t\t? html`<ul\n\t\t\t\t\t\tid=\"roxy-location-listbox\"\n\t\t\t\t\t\tclass=\"results\"\n\t\t\t\t\t\trole=\"listbox\"\n\t\t\t\t\t>\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tthis.results.length === 0\n\t\t\t\t\t\t\t\t? html`<li class=\"empty\" role=\"status\">No cities found</li>`\n\t\t\t\t\t\t\t\t: this.results.map(\n\t\t\t\t\t\t\t\t\t\t(city, idx) => html`<li role=\"presentation\">\n\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\tclass=\"option\"\n\t\t\t\t\t\t\t\t\t\t\trole=\"option\"\n\t\t\t\t\t\t\t\t\t\t\taria-selected=${this.highlight === idx ? 'true' : 'false'}\n\t\t\t\t\t\t\t\t\t\t\t@click=${() => this.select(city)}\n\t\t\t\t\t\t\t\t\t\t\t@mouseenter=${() => {\n\t\t\t\t\t\t\t\t\t\t\t\tthis.highlight = idx;\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"city\">${city.city}</span>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"where\"\n\t\t\t\t\t\t\t\t\t\t\t\t>${city.province ? html`${city.province}, ` : ''}${city.country}</span\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"tz\"\n\t\t\t\t\t\t\t\t\t\t\t\t>UTC${city.utcOffset >= 0 ? '+' : ''}${city.utcOffset}</span\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t</li>`,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t</ul>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-location-search': RoxyLocationSearch;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n", "/**\n * Lightweight debounce for input handlers. Used by location search.\n *\n * The returned function exposes a `.cancel()` method so callers can clear a\n * pending invocation when the host element disconnects, preventing the timer\n * from firing on a detached node and mutating reactive state after teardown.\n */\nexport interface Debounced<F extends (...args: never[]) => unknown> {\n\t(...args: Parameters<F>): void;\n\tcancel: () => void;\n}\n\nexport function debounce<F extends (...args: never[]) => unknown>(\n\tfn: F,\n\twait: number,\n): Debounced<F> {\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tconst debounced = ((...args: Parameters<F>) => {\n\t\tif (timer) clearTimeout(timer);\n\t\ttimer = setTimeout(() => {\n\t\t\ttimer = undefined;\n\t\t\tfn(...args);\n\t\t}, wait);\n\t}) as Debounced<F>;\n\tdebounced.cancel = () => {\n\t\tif (timer) {\n\t\t\tclearTimeout(timer);\n\t\t\ttimer = undefined;\n\t\t}\n\t};\n\treturn debounced;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["css", "css"]
|
|
7
7
|
}
|