@roxyapi/ui 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -2
- package/LICENSE +21 -0
- package/README.md +505 -0
- package/THEMING.md +24 -7
- package/dist/cdn/components/biorhythm-chart.js +15 -22
- package/dist/cdn/components/biorhythm-chart.js.map +3 -3
- package/dist/cdn/components/compatibility-card.js +36 -34
- package/dist/cdn/components/compatibility-card.js.map +4 -4
- package/dist/cdn/components/dasha-timeline.js +35 -39
- package/dist/cdn/components/dasha-timeline.js.map +4 -4
- package/dist/cdn/components/data.js +6 -6
- package/dist/cdn/components/data.js.map +3 -3
- package/dist/cdn/components/dosha-card.js +13 -13
- package/dist/cdn/components/dosha-card.js.map +2 -2
- package/dist/cdn/components/endpoint-form.js +47 -28
- package/dist/cdn/components/endpoint-form.js.map +3 -3
- package/dist/cdn/components/guna-milan.js +18 -18
- package/dist/cdn/components/guna-milan.js.map +4 -4
- package/dist/cdn/components/hexagram.js +26 -26
- package/dist/cdn/components/hexagram.js.map +3 -3
- package/dist/cdn/components/horoscope-card.js +38 -38
- package/dist/cdn/components/horoscope-card.js.map +3 -3
- package/dist/cdn/components/kp-planets-table.js +10 -10
- package/dist/cdn/components/kp-planets-table.js.map +4 -4
- package/dist/cdn/components/location-search.js +6 -6
- package/dist/cdn/components/location-search.js.map +3 -3
- package/dist/cdn/components/moon-phase.js +21 -21
- package/dist/cdn/components/moon-phase.js.map +4 -4
- package/dist/cdn/components/natal-chart.js +61 -19
- package/dist/cdn/components/natal-chart.js.map +4 -4
- package/dist/cdn/components/numerology-card.js +40 -31
- package/dist/cdn/components/numerology-card.js.map +3 -3
- package/dist/cdn/components/panchang-table.js +25 -25
- package/dist/cdn/components/panchang-table.js.map +4 -4
- package/dist/cdn/components/synastry-chart.js +129 -39
- package/dist/cdn/components/synastry-chart.js.map +4 -4
- package/dist/cdn/components/tarot-card.js +49 -20
- package/dist/cdn/components/tarot-card.js.map +3 -3
- package/dist/cdn/components/tarot-spread.js +43 -27
- package/dist/cdn/components/tarot-spread.js.map +3 -3
- package/dist/cdn/components/vedic-kundli.js +23 -9
- package/dist/cdn/components/vedic-kundli.js.map +3 -3
- package/dist/cdn/roxy-ui.js +560 -350
- package/dist/cdn/roxy-ui.js.map +4 -4
- package/dist/components/biorhythm-chart.d.ts +2 -46
- package/dist/components/biorhythm-chart.d.ts.map +1 -1
- package/dist/components/biorhythm-chart.js +24 -23
- package/dist/components/biorhythm-chart.js.map +2 -2
- package/dist/components/compatibility-card.d.ts +2 -27
- package/dist/components/compatibility-card.d.ts.map +1 -1
- package/dist/components/compatibility-card.js +50 -29
- package/dist/components/compatibility-card.js.map +3 -3
- package/dist/components/dasha-timeline.d.ts +2 -31
- package/dist/components/dasha-timeline.d.ts.map +1 -1
- package/dist/components/dasha-timeline.js +32 -30
- package/dist/components/dasha-timeline.js.map +3 -3
- package/dist/components/data.d.ts +6 -0
- package/dist/components/data.d.ts.map +1 -1
- package/dist/components/data.js +9 -1
- package/dist/components/data.js.map +2 -2
- package/dist/components/dosha-card.d.ts +2 -16
- package/dist/components/dosha-card.d.ts.map +1 -1
- package/dist/components/dosha-card.js +12 -13
- package/dist/components/dosha-card.js.map +2 -2
- package/dist/components/endpoint-form.d.ts +2 -0
- package/dist/components/endpoint-form.d.ts.map +1 -1
- package/dist/components/endpoint-form.js +66 -8
- package/dist/components/endpoint-form.js.map +2 -2
- package/dist/components/guna-milan.d.ts +2 -20
- package/dist/components/guna-milan.d.ts.map +1 -1
- package/dist/components/guna-milan.js +22 -12
- package/dist/components/guna-milan.js.map +3 -3
- package/dist/components/hexagram.d.ts +3 -27
- package/dist/components/hexagram.d.ts.map +1 -1
- package/dist/components/hexagram.js +31 -15
- package/dist/components/hexagram.js.map +2 -2
- package/dist/components/horoscope-card.d.ts +2 -20
- package/dist/components/horoscope-card.d.ts.map +1 -1
- package/dist/components/horoscope-card.js +24 -15
- package/dist/components/horoscope-card.js.map +2 -2
- package/dist/components/kp-planets-table.d.ts +2 -21
- package/dist/components/kp-planets-table.d.ts.map +1 -1
- package/dist/components/kp-planets-table.js +10 -4
- package/dist/components/kp-planets-table.js.map +3 -3
- package/dist/components/location-search.d.ts +3 -11
- package/dist/components/location-search.d.ts.map +1 -1
- package/dist/components/location-search.js +45 -5
- package/dist/components/location-search.js.map +2 -2
- package/dist/components/moon-phase.d.ts +4 -21
- package/dist/components/moon-phase.d.ts.map +1 -1
- package/dist/components/moon-phase.js +17 -4
- package/dist/components/moon-phase.js.map +3 -3
- package/dist/components/natal-chart.d.ts +7 -43
- package/dist/components/natal-chart.d.ts.map +1 -1
- package/dist/components/natal-chart.js +130 -70
- package/dist/components/natal-chart.js.map +3 -3
- package/dist/components/numerology-card.d.ts +5 -37
- package/dist/components/numerology-card.d.ts.map +1 -1
- package/dist/components/numerology-card.js +54 -28
- package/dist/components/numerology-card.js.map +2 -2
- package/dist/components/panchang-table.d.ts +3 -62
- package/dist/components/panchang-table.d.ts.map +1 -1
- package/dist/components/panchang-table.js +62 -32
- package/dist/components/panchang-table.js.map +3 -3
- package/dist/components/synastry-chart.d.ts +9 -28
- package/dist/components/synastry-chart.d.ts.map +1 -1
- package/dist/components/synastry-chart.js +178 -38
- package/dist/components/synastry-chart.js.map +3 -3
- package/dist/components/tarot-card.d.ts +5 -29
- package/dist/components/tarot-card.d.ts.map +1 -1
- package/dist/components/tarot-card.js +59 -20
- package/dist/components/tarot-card.js.map +2 -2
- package/dist/components/tarot-spread.d.ts +2 -24
- package/dist/components/tarot-spread.d.ts.map +1 -1
- package/dist/components/tarot-spread.js +39 -13
- package/dist/components/tarot-spread.js.map +2 -2
- package/dist/components/vedic-kundli.d.ts +3 -23
- package/dist/components/vedic-kundli.d.ts.map +1 -1
- package/dist/components/vedic-kundli.js +25 -13
- package/dist/components/vedic-kundli.js.map +2 -2
- package/dist/index.cjs +1149 -358
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1149 -358
- package/dist/index.js.map +4 -4
- package/dist/manifest.d.ts +49 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.json +1 -1
- package/dist/styles/tokens.css +47 -1
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/types.gen.d.ts +27811 -0
- package/dist/types/types.gen.d.ts.map +1 -0
- package/dist/utils/debounce.d.ts +9 -1
- package/dist/utils/debounce.d.ts.map +1 -1
- package/dist/utils/format.d.ts +15 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +9 -1
- package/src/components/biorhythm-chart.ts +39 -84
- package/src/components/compatibility-card.ts +85 -52
- package/src/components/dasha-timeline.ts +55 -73
- package/src/components/data.ts +20 -1
- package/src/components/dosha-card.ts +18 -31
- package/src/components/endpoint-form.ts +79 -11
- package/src/components/guna-milan.ts +16 -34
- package/src/components/hexagram.ts +53 -43
- package/src/components/horoscope-card.ts +51 -39
- package/src/components/kp-planets-table.ts +8 -27
- package/src/components/location-search.ts +45 -20
- package/src/components/moon-phase.ts +28 -25
- package/src/components/natal-chart.ts +129 -84
- package/src/components/numerology-card.ts +87 -79
- package/src/components/panchang-table.ts +40 -78
- package/src/components/synastry-chart.ts +220 -78
- package/src/components/tarot-card.ts +76 -62
- package/src/components/tarot-spread.ts +72 -45
- package/src/components/vedic-kundli.ts +42 -51
- package/src/index.ts +14 -24
- package/src/manifest.ts +366 -0
- package/src/styles/tokens.css +47 -1
- package/src/tokens/index.ts +5 -0
- package/src/types/types.gen.ts +1 -1
- package/src/utils/debounce.ts +23 -4
- package/src/utils/format.ts +57 -0
- package/src/version.ts +2 -0
package/dist/index.js
CHANGED
|
@@ -122,25 +122,28 @@ var RoxyBiorhythmChart = class extends LitElement {
|
|
|
122
122
|
const d = this.data;
|
|
123
123
|
if (!d)
|
|
124
124
|
return html`<div class="roxy-empty" role="status">No biorhythm data</div>`;
|
|
125
|
-
if (this.mode === "critical-days" && d
|
|
125
|
+
if (this.mode === "critical-days" && "criticalDays" in d) {
|
|
126
126
|
return this.renderCritical(d);
|
|
127
127
|
}
|
|
128
|
-
if (this.mode === "forecast" && d
|
|
128
|
+
if (this.mode === "forecast" && "days" in d) {
|
|
129
129
|
return this.renderForecast(d);
|
|
130
130
|
}
|
|
131
131
|
return this.renderDaily(d);
|
|
132
132
|
}
|
|
133
133
|
renderDaily(d) {
|
|
134
|
-
const
|
|
135
|
-
const entries = Object.entries(
|
|
134
|
+
const raw = d.quickRead ?? {};
|
|
135
|
+
const entries = Object.entries(raw).map(([cycle, value]) => {
|
|
136
|
+
const v = typeof value === "number" ? value : 0;
|
|
137
|
+
const normalized = Math.abs(v) > 1 ? v / 100 : v;
|
|
138
|
+
return [cycle, normalized];
|
|
139
|
+
});
|
|
136
140
|
return html`<section class="wrap" aria-label="Daily biorhythm">
|
|
137
141
|
<header class="head">
|
|
138
142
|
<h2 class="title">Biorhythm</h2>
|
|
139
143
|
${typeof d.energyRating === "number" ? html`<span class="energy">Energy ${d.energyRating}/10</span>` : nothing}
|
|
140
144
|
</header>
|
|
141
145
|
<div class="bars" role="list">
|
|
142
|
-
${entries.map(([cycle,
|
|
143
|
-
const v = typeof value === "number" ? value : 0;
|
|
146
|
+
${entries.map(([cycle, v]) => {
|
|
144
147
|
const pct = (v + 1) / 2 * 100;
|
|
145
148
|
const color = CYCLE_COLOR[cycle] ?? "var(--roxy-accent, #f59e0b)";
|
|
146
149
|
return html`<div class="bar" role="listitem">
|
|
@@ -151,15 +154,12 @@ var RoxyBiorhythmChart = class extends LitElement {
|
|
|
151
154
|
style="width: ${pct}%; background: ${color}"
|
|
152
155
|
></span>
|
|
153
156
|
</span>
|
|
154
|
-
<span class="value">${(v * 100)
|
|
157
|
+
<span class="value">${Math.round(v * 100)}%</span>
|
|
155
158
|
</div>`;
|
|
156
159
|
})}
|
|
157
160
|
</div>
|
|
158
|
-
${d.
|
|
161
|
+
${d.dailyMessage ? html`<p class="advice">${d.dailyMessage}</p>` : nothing}
|
|
159
162
|
${d.advice ? html`<p class="advice">${d.advice}</p>` : nothing}
|
|
160
|
-
${d.criticalAlerts?.length ? html`<div>
|
|
161
|
-
${d.criticalAlerts.map((a) => html`<p class="alert">${a}</p>`)}
|
|
162
|
-
</div>` : nothing}
|
|
163
163
|
</section>`;
|
|
164
164
|
}
|
|
165
165
|
renderForecast(d) {
|
|
@@ -169,13 +169,16 @@ var RoxyBiorhythmChart = class extends LitElement {
|
|
|
169
169
|
const w = 600;
|
|
170
170
|
const h = 160;
|
|
171
171
|
const xStep = w / Math.max(days.length - 1, 1);
|
|
172
|
-
const
|
|
172
|
+
const cycleKeys = [
|
|
173
|
+
"physical",
|
|
174
|
+
"emotional",
|
|
175
|
+
"intellectual",
|
|
176
|
+
"intuitive"
|
|
177
|
+
];
|
|
173
178
|
return html`<section class="wrap" aria-label="Biorhythm forecast">
|
|
174
179
|
<header class="head">
|
|
175
180
|
<h2 class="title">Forecast</h2>
|
|
176
|
-
<span class="energy"
|
|
177
|
-
>${d.startDate ?? ""} - ${d.endDate ?? ""}</span
|
|
178
|
-
>
|
|
181
|
+
<span class="energy">${d.startDate} - ${d.endDate}</span>
|
|
179
182
|
</header>
|
|
180
183
|
<svg
|
|
181
184
|
viewBox="0 0 ${w} ${h}"
|
|
@@ -191,11 +194,11 @@ var RoxyBiorhythmChart = class extends LitElement {
|
|
|
191
194
|
stroke="var(--roxy-border, #e4e4e7)"
|
|
192
195
|
stroke-width="1"
|
|
193
196
|
/>
|
|
194
|
-
${
|
|
197
|
+
${cycleKeys.map((cycle) => {
|
|
195
198
|
const points = days.map((day, i) => {
|
|
196
|
-
const v = day
|
|
199
|
+
const v = day[cycle] ?? 0;
|
|
197
200
|
const x = i * xStep;
|
|
198
|
-
const y = h / 2 - v * (h / 2 - 8);
|
|
201
|
+
const y = h / 2 - v / 100 * (h / 2 - 8);
|
|
199
202
|
return `${x.toFixed(2)},${y.toFixed(2)}`;
|
|
200
203
|
}).join(" ");
|
|
201
204
|
const color = CYCLE_COLOR[cycle] ?? "#475569";
|
|
@@ -209,14 +212,12 @@ var RoxyBiorhythmChart = class extends LitElement {
|
|
|
209
212
|
return html`<section class="wrap" aria-label="Critical days">
|
|
210
213
|
<header class="head">
|
|
211
214
|
<h2 class="title">Critical days</h2>
|
|
212
|
-
<span class="energy"
|
|
213
|
-
>${d.totalCriticalDays ?? d.criticalDays?.length ?? 0} total</span
|
|
214
|
-
>
|
|
215
|
+
<span class="energy">${d.totalCriticalDays} total</span>
|
|
215
216
|
</header>
|
|
216
217
|
<div>
|
|
217
|
-
${
|
|
218
|
+
${d.criticalDays.map(
|
|
218
219
|
(day) => html`<span class="crit"
|
|
219
|
-
>${day.date} · ${day.cycle
|
|
220
|
+
>${day.date} · ${day.cycle} ${day.severity}</span
|
|
220
221
|
>`
|
|
221
222
|
)}
|
|
222
223
|
</div>
|
|
@@ -316,6 +317,50 @@ RoxyBiorhythmChart = __decorateClass([
|
|
|
316
317
|
// packages/ui/src/components/compatibility-card.ts
|
|
317
318
|
import { css as css3, html as html2, LitElement as LitElement2, nothing as nothing2 } from "lit";
|
|
318
319
|
import { customElement as customElement2, property as property2 } from "lit/decorators.js";
|
|
320
|
+
|
|
321
|
+
// packages/ui/src/utils/format.ts
|
|
322
|
+
function formatTime(input) {
|
|
323
|
+
if (typeof input !== "string" || input.length === 0) return "";
|
|
324
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(input)) return "";
|
|
325
|
+
const bareTime = /^\d{2}:\d{2}(:\d{2})?$/.test(input);
|
|
326
|
+
const iso = bareTime ? `1970-01-01T${input}` : input;
|
|
327
|
+
const d = new Date(iso);
|
|
328
|
+
if (Number.isNaN(d.getTime())) return input;
|
|
329
|
+
return d.toLocaleTimeString(void 0, {
|
|
330
|
+
hour: "numeric",
|
|
331
|
+
minute: "2-digit",
|
|
332
|
+
hour12: true
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
function formatDate(input) {
|
|
336
|
+
if (typeof input !== "string" || input.length === 0) return "";
|
|
337
|
+
const d = new Date(
|
|
338
|
+
/^\d{4}-\d{2}-\d{2}$/.test(input) ? `${input}T00:00:00` : input
|
|
339
|
+
);
|
|
340
|
+
if (Number.isNaN(d.getTime())) return input;
|
|
341
|
+
return d.toLocaleDateString(void 0, {
|
|
342
|
+
month: "short",
|
|
343
|
+
day: "numeric",
|
|
344
|
+
year: "numeric"
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
function formatTimeRange(t) {
|
|
348
|
+
if (!t) return "";
|
|
349
|
+
const start = formatTime(t.start);
|
|
350
|
+
const end = formatTime(t.end);
|
|
351
|
+
if (start && end) return `${start} - ${end}`;
|
|
352
|
+
return start || end || "";
|
|
353
|
+
}
|
|
354
|
+
function formatNumber(value, dp = 1) {
|
|
355
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return "";
|
|
356
|
+
return value.toFixed(dp).replace(/\.?0+$/, "");
|
|
357
|
+
}
|
|
358
|
+
function formatPercent(value, dp = 1) {
|
|
359
|
+
const n = formatNumber(value, dp);
|
|
360
|
+
return n ? `${n}%` : "";
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// packages/ui/src/components/compatibility-card.ts
|
|
319
364
|
var RoxyCompatibilityCard = class extends LitElement2 {
|
|
320
365
|
constructor() {
|
|
321
366
|
super(...arguments);
|
|
@@ -325,22 +370,29 @@ var RoxyCompatibilityCard = class extends LitElement2 {
|
|
|
325
370
|
getBreakdown() {
|
|
326
371
|
const d = this.data;
|
|
327
372
|
if (!d) return {};
|
|
328
|
-
if (d
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
return inferred;
|
|
373
|
+
if ("categories" in d && d.categories) {
|
|
374
|
+
const out = {};
|
|
375
|
+
for (const [k, v] of Object.entries(d.categories)) {
|
|
376
|
+
if (typeof v === "number" && Number.isFinite(v)) out[k] = v;
|
|
377
|
+
}
|
|
378
|
+
return out;
|
|
379
|
+
}
|
|
380
|
+
return {};
|
|
337
381
|
}
|
|
338
382
|
render() {
|
|
339
383
|
const d = this.data;
|
|
340
384
|
if (!d)
|
|
341
385
|
return html2`<div class="roxy-empty" role="status">No compatibility data</div>`;
|
|
342
|
-
const score = d.overallScore
|
|
386
|
+
const score = d.overallScore;
|
|
343
387
|
const breakdown = this.getBreakdown();
|
|
388
|
+
const rating = "rating" in d ? d.rating : void 0;
|
|
389
|
+
const archetype = "archetype" in d ? d.archetype : void 0;
|
|
390
|
+
const advice = "advice" in d ? d.advice : void 0;
|
|
391
|
+
const summary = "summary" in d ? d.summary : void 0;
|
|
392
|
+
const interpretation = "interpretation" in d ? d.interpretation : void 0;
|
|
393
|
+
const strengths = "strengths" in d ? d.strengths : void 0;
|
|
394
|
+
const challenges = "challenges" in d ? d.challenges : void 0;
|
|
395
|
+
const keyAspects = "keyAspects" in d ? d.keyAspects : void 0;
|
|
344
396
|
return html2`<article
|
|
345
397
|
class="card"
|
|
346
398
|
aria-label=${`Compatibility (${this.mode})`}
|
|
@@ -348,8 +400,8 @@ var RoxyCompatibilityCard = class extends LitElement2 {
|
|
|
348
400
|
<div class="head">
|
|
349
401
|
<h2>${this.mode} compatibility</h2>
|
|
350
402
|
<div>
|
|
351
|
-
${typeof score === "number" ? html2`<div class="score">${score}</div>` : nothing2}
|
|
352
|
-
${
|
|
403
|
+
${typeof score === "number" ? html2`<div class="score">${formatNumber(score, 0)}</div>` : nothing2}
|
|
404
|
+
${rating ? html2`<div class="rating">${rating}</div>` : nothing2}
|
|
353
405
|
</div>
|
|
354
406
|
</div>
|
|
355
407
|
|
|
@@ -360,35 +412,37 @@ var RoxyCompatibilityCard = class extends LitElement2 {
|
|
|
360
412
|
<span class="bar"
|
|
361
413
|
><span style="width: ${Math.max(0, Math.min(100, v))}%"></span
|
|
362
414
|
></span>
|
|
363
|
-
<span>${v}</span>
|
|
415
|
+
<span>${formatNumber(v, 0)}</span>
|
|
364
416
|
</div>`
|
|
365
417
|
)}
|
|
366
418
|
</div>` : nothing2}
|
|
367
|
-
${
|
|
368
|
-
<span class="archetype">${
|
|
419
|
+
${archetype ? html2`<p>
|
|
420
|
+
<span class="archetype">${archetype.label}</span>
|
|
421
|
+
${archetype.description ? html2` · ${archetype.description}` : nothing2}
|
|
369
422
|
</p>` : nothing2}
|
|
370
|
-
${
|
|
371
|
-
${
|
|
372
|
-
${
|
|
373
|
-
|
|
423
|
+
${summary ? html2`<p>${summary}</p>` : nothing2}
|
|
424
|
+
${interpretation && !summary ? html2`<p>${interpretation}</p>` : nothing2}
|
|
425
|
+
${advice ? html2`<p>${advice}</p>` : nothing2}
|
|
426
|
+
${(strengths?.length ?? 0) > 0 || (challenges?.length ?? 0) > 0 ? html2`<div class="lists">
|
|
427
|
+
${strengths?.length ? html2`<div>
|
|
374
428
|
<h3>Strengths</h3>
|
|
375
429
|
<ul>
|
|
376
|
-
${
|
|
430
|
+
${strengths.map((s) => html2`<li>${s}</li>`)}
|
|
377
431
|
</ul>
|
|
378
432
|
</div>` : nothing2}
|
|
379
|
-
${
|
|
433
|
+
${challenges?.length ? html2`<div>
|
|
380
434
|
<h3>Challenges</h3>
|
|
381
435
|
<ul>
|
|
382
|
-
${
|
|
383
|
-
</ul>
|
|
384
|
-
</div>` : nothing2}
|
|
385
|
-
${d.keyAspects?.length ? html2`<div>
|
|
386
|
-
<h3>Key aspects</h3>
|
|
387
|
-
<ul>
|
|
388
|
-
${d.keyAspects.map((s) => html2`<li>${s}</li>`)}
|
|
436
|
+
${challenges.map((s) => html2`<li>${s}</li>`)}
|
|
389
437
|
</ul>
|
|
390
438
|
</div>` : nothing2}
|
|
391
439
|
</div>` : nothing2}
|
|
440
|
+
${keyAspects?.length ? html2`<div>
|
|
441
|
+
<h3 style="margin: 0 0 0.25rem; font-size: var(--roxy-text-xs); color: var(--roxy-muted); text-transform: uppercase; letter-spacing: 0.06em;">Key aspects</h3>
|
|
442
|
+
<ul style="margin: 0; padding-left: 1rem; font-size: var(--roxy-text-sm);">
|
|
443
|
+
${keyAspects.slice(0, 6).map((a) => html2`<li>${formatAspect(a)}</li>`)}
|
|
444
|
+
</ul>
|
|
445
|
+
</div>` : nothing2}
|
|
392
446
|
</article>`;
|
|
393
447
|
}
|
|
394
448
|
};
|
|
@@ -458,7 +512,7 @@ RoxyCompatibilityCard.styles = [
|
|
|
458
512
|
}
|
|
459
513
|
|
|
460
514
|
.archetype {
|
|
461
|
-
color: var(--roxy-
|
|
515
|
+
color: var(--roxy-accent-fg, #b45309);
|
|
462
516
|
font-weight: var(--roxy-weight-bold, 600);
|
|
463
517
|
}
|
|
464
518
|
|
|
@@ -489,6 +543,12 @@ __decorateClass([
|
|
|
489
543
|
RoxyCompatibilityCard = __decorateClass([
|
|
490
544
|
customElement2("roxy-compatibility-card")
|
|
491
545
|
], RoxyCompatibilityCard);
|
|
546
|
+
function formatAspect(a) {
|
|
547
|
+
const aspect = a.type.toLowerCase().replace(/_/g, "-");
|
|
548
|
+
const orb = typeof a.orb === "number" ? ` (orb ${formatNumber(a.orb, 1)}\xB0)` : "";
|
|
549
|
+
const head = [a.planet1, aspect, a.planet2].filter(Boolean).join(" ");
|
|
550
|
+
return a.description ? `${head}${orb} \xB7 ${a.description}` : `${head}${orb}`;
|
|
551
|
+
}
|
|
492
552
|
|
|
493
553
|
// packages/ui/src/components/dasha-timeline.ts
|
|
494
554
|
import { css as css4, html as html3, LitElement as LitElement3, nothing as nothing3 } from "lit";
|
|
@@ -504,16 +564,16 @@ var RoxyDashaTimeline = class extends LitElement3 {
|
|
|
504
564
|
if (!d)
|
|
505
565
|
return html3`<div class="roxy-empty" role="status">No dasha data</div>`;
|
|
506
566
|
const periods = this.collectPeriods(d);
|
|
507
|
-
const maxYears = periods.length ? Math.max(...periods.map((p) => p.durationYears
|
|
567
|
+
const maxYears = periods.length ? Math.max(...periods.map((p) => p.durationYears)) : 0;
|
|
508
568
|
return html3`<div class="wrap" aria-label="Dasha timeline">
|
|
509
569
|
<header class="head">
|
|
510
570
|
<h2 class="title">
|
|
511
571
|
${this.period === "major" ? "Vimshottari Mahadasha" : this.period === "sub" ? "Antardasha" : "Active dashas"}
|
|
512
572
|
</h2>
|
|
513
|
-
${
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
573
|
+
${"nakshatraName" in d && d.nakshatraName ? html3`<div class="nakshatra">
|
|
574
|
+
Moon nakshatra: ${d.nakshatraName}
|
|
575
|
+
${"nakshatraLord" in d && d.nakshatraLord ? html3`(lord ${d.nakshatraLord})` : nothing3}
|
|
576
|
+
</div>` : nothing3}
|
|
517
577
|
</header>
|
|
518
578
|
|
|
519
579
|
${this.period === "current" ? this.renderCurrent(d) : nothing3}
|
|
@@ -523,39 +583,35 @@ var RoxyDashaTimeline = class extends LitElement3 {
|
|
|
523
583
|
</div>`;
|
|
524
584
|
}
|
|
525
585
|
renderCurrent(d) {
|
|
586
|
+
if (!("mahadasha" in d)) return nothing3;
|
|
526
587
|
return html3`<div class="current">
|
|
527
|
-
${d.mahadasha ? html3`<div>
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
${d.antardasha ? html3`<div>
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
${d.pratyantardasha ? html3`<div>
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
${typeof d.remainingInPratyantardasha === "number" ? html3`<small
|
|
543
|
-
>${d.remainingInPratyantardasha.toFixed(2)} years left</small
|
|
544
|
-
>` : nothing3}
|
|
545
|
-
</div>` : nothing3}
|
|
588
|
+
${"mahadasha" in d && d.mahadasha ? html3`<div>
|
|
589
|
+
<span>Mahadasha</span>
|
|
590
|
+
<strong>${d.mahadasha.planet}</strong>
|
|
591
|
+
${"remainingInMahadasha" in d && d.remainingInMahadasha ? html3`<small>${formatNumber(d.remainingInMahadasha.years + d.remainingInMahadasha.months / 12, 1)} years left</small>` : nothing3}
|
|
592
|
+
</div>` : nothing3}
|
|
593
|
+
${"antardasha" in d && d.antardasha ? html3`<div>
|
|
594
|
+
<span>Antardasha</span>
|
|
595
|
+
<strong>${d.antardasha.planet}</strong>
|
|
596
|
+
${"remainingInAntardasha" in d && d.remainingInAntardasha ? html3`<small>${formatNumber(d.remainingInAntardasha.years + d.remainingInAntardasha.months / 12, 1)} years left</small>` : nothing3}
|
|
597
|
+
</div>` : nothing3}
|
|
598
|
+
${"pratyantardasha" in d && d.pratyantardasha ? html3`<div>
|
|
599
|
+
<span>Pratyantardasha</span>
|
|
600
|
+
<strong>${d.pratyantardasha.planet}</strong>
|
|
601
|
+
${"remainingInPratyantardasha" in d && d.remainingInPratyantardasha ? html3`<small>${formatNumber(d.remainingInPratyantardasha.years + d.remainingInPratyantardasha.months / 12, 1)} years left</small>` : nothing3}
|
|
602
|
+
</div>` : nothing3}
|
|
546
603
|
</div>`;
|
|
547
604
|
}
|
|
548
605
|
collectPeriods(d) {
|
|
549
|
-
if (
|
|
550
|
-
if (
|
|
551
|
-
return
|
|
606
|
+
if ("mahadashas" in d && d.mahadashas?.length) return d.mahadashas;
|
|
607
|
+
if ("antardashas" in d && d.antardashas?.length) return d.antardashas;
|
|
608
|
+
return [];
|
|
552
609
|
}
|
|
553
610
|
renderBar(p, max) {
|
|
554
|
-
const
|
|
555
|
-
const years = p.durationYears ?? p.years ?? 0;
|
|
611
|
+
const years = p.durationYears;
|
|
556
612
|
const width = max > 0 ? years / max * 100 : 0;
|
|
557
613
|
return html3`<div class="bar" role="listitem">
|
|
558
|
-
<span>${
|
|
614
|
+
<span>${p.planet}</span>
|
|
559
615
|
<span class="bar-track"><span style="width: ${width}%"></span></span>
|
|
560
616
|
<span class="dates">
|
|
561
617
|
${p.startDate ? formatYear(p.startDate) : ""}
|
|
@@ -663,15 +719,20 @@ import { customElement as customElement4, property as property4 } from "lit/deco
|
|
|
663
719
|
var TITLE_KEYS = ["title", "name", "label", "heading", "overview", "summary"];
|
|
664
720
|
var IMAGE_KEYS = ["imageUrl", "image", "icon", "symbol"];
|
|
665
721
|
var SKIP_KEYS = ["imageUrl", "image"];
|
|
722
|
+
var MAX_DEPTH = 6;
|
|
666
723
|
var RoxyData = class extends LitElement4 {
|
|
667
724
|
constructor() {
|
|
668
725
|
super(...arguments);
|
|
669
726
|
this.data = null;
|
|
727
|
+
this.depth = 0;
|
|
670
728
|
}
|
|
671
729
|
render() {
|
|
672
730
|
if (this.data == null) {
|
|
673
731
|
return html4`<div class="roxy-empty" role="status">No data</div>`;
|
|
674
732
|
}
|
|
733
|
+
if (this.depth >= MAX_DEPTH) {
|
|
734
|
+
return html4`<div class="roxy-empty" role="status">…</div>`;
|
|
735
|
+
}
|
|
675
736
|
return html4`<div
|
|
676
737
|
class="roxy-card"
|
|
677
738
|
aria-label="Generic data display"
|
|
@@ -768,7 +829,7 @@ var RoxyData = class extends LitElement4 {
|
|
|
768
829
|
</ul>`;
|
|
769
830
|
}
|
|
770
831
|
}
|
|
771
|
-
return html4`<roxy-data .data=${value}></roxy-data>`;
|
|
832
|
+
return html4`<roxy-data .data=${value} .depth=${this.depth + 1}></roxy-data>`;
|
|
772
833
|
}
|
|
773
834
|
formatPrimitive(value) {
|
|
774
835
|
if (value === null || value === void 0) return "";
|
|
@@ -890,6 +951,9 @@ RoxyData.styles = [
|
|
|
890
951
|
__decorateClass([
|
|
891
952
|
property4({ attribute: false })
|
|
892
953
|
], RoxyData.prototype, "data", 2);
|
|
954
|
+
__decorateClass([
|
|
955
|
+
property4({ attribute: false })
|
|
956
|
+
], RoxyData.prototype, "depth", 2);
|
|
893
957
|
RoxyData = __decorateClass([
|
|
894
958
|
customElement4("roxy-data")
|
|
895
959
|
], RoxyData);
|
|
@@ -935,25 +999,24 @@ var RoxyDoshaCard = class extends LitElement5 {
|
|
|
935
999
|
</div>
|
|
936
1000
|
</header>
|
|
937
1001
|
${d.description ? html5`<p class="description">${d.description}</p>` : nothing5}
|
|
938
|
-
${this.renderEffects(d
|
|
1002
|
+
${this.renderEffects(d)}
|
|
939
1003
|
${d.remedies && d.remedies.length > 0 ? html5`<div>
|
|
940
1004
|
<h3>Remedies</h3>
|
|
941
1005
|
<ul>
|
|
942
1006
|
${d.remedies.map((r) => html5`<li>${r}</li>`)}
|
|
943
1007
|
</ul>
|
|
944
1008
|
</div>` : nothing5}
|
|
945
|
-
${d.exceptions && d.exceptions.length > 0 ? html5`<div>
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
1009
|
+
${"exceptions" in d && d.exceptions && d.exceptions.length > 0 ? html5`<div>
|
|
1010
|
+
<h3>Exceptions</h3>
|
|
1011
|
+
<ul>
|
|
1012
|
+
${d.exceptions.map((r) => html5`<li>${r}</li>`)}
|
|
1013
|
+
</ul>
|
|
1014
|
+
</div>` : nothing5}
|
|
951
1015
|
</article>`;
|
|
952
1016
|
}
|
|
953
|
-
renderEffects(
|
|
954
|
-
if (!
|
|
955
|
-
|
|
956
|
-
const entries = Object.entries(e).filter(
|
|
1017
|
+
renderEffects(d) {
|
|
1018
|
+
if (!d.effects) return nothing5;
|
|
1019
|
+
const entries = Object.entries(d.effects).filter(
|
|
957
1020
|
([, v]) => typeof v === "string" && v.length > 0
|
|
958
1021
|
);
|
|
959
1022
|
if (entries.length === 0) return nothing5;
|
|
@@ -1005,11 +1068,11 @@ RoxyDoshaCard.styles = [
|
|
|
1005
1068
|
}
|
|
1006
1069
|
.badge.absent {
|
|
1007
1070
|
background: color-mix(in srgb, var(--roxy-success, #16a34a) 16%, transparent);
|
|
1008
|
-
color: var(--roxy-success, #
|
|
1071
|
+
color: var(--roxy-success-fg, #166534);
|
|
1009
1072
|
}
|
|
1010
1073
|
.badge.present {
|
|
1011
1074
|
background: color-mix(in srgb, var(--roxy-danger, #dc2626) 16%, transparent);
|
|
1012
|
-
color: var(--roxy-danger, #
|
|
1075
|
+
color: var(--roxy-danger-fg, #991b1b);
|
|
1013
1076
|
}
|
|
1014
1077
|
.severity {
|
|
1015
1078
|
display: flex;
|
|
@@ -1073,6 +1136,21 @@ RoxyDoshaCard = __decorateClass([
|
|
|
1073
1136
|
// packages/ui/src/components/endpoint-form.ts
|
|
1074
1137
|
import { css as css7, html as html6, LitElement as LitElement6, nothing as nothing6 } from "lit";
|
|
1075
1138
|
import { customElement as customElement6, property as property6, state } from "lit/decorators.js";
|
|
1139
|
+
var specCache = /* @__PURE__ */ new Map();
|
|
1140
|
+
async function loadSpec(url) {
|
|
1141
|
+
let pending = specCache.get(url);
|
|
1142
|
+
if (!pending) {
|
|
1143
|
+
pending = fetch(url).then(async (res) => {
|
|
1144
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1145
|
+
return await res.json();
|
|
1146
|
+
}).catch((err) => {
|
|
1147
|
+
specCache.delete(url);
|
|
1148
|
+
throw err;
|
|
1149
|
+
});
|
|
1150
|
+
specCache.set(url, pending);
|
|
1151
|
+
}
|
|
1152
|
+
return pending;
|
|
1153
|
+
}
|
|
1076
1154
|
var RoxyEndpointForm = class extends LitElement6 {
|
|
1077
1155
|
constructor() {
|
|
1078
1156
|
super(...arguments);
|
|
@@ -1084,6 +1162,12 @@ var RoxyEndpointForm = class extends LitElement6 {
|
|
|
1084
1162
|
this.values = {};
|
|
1085
1163
|
this.hasLocation = false;
|
|
1086
1164
|
this.loaded = false;
|
|
1165
|
+
this.specError = null;
|
|
1166
|
+
this.retryLoadSchema = () => {
|
|
1167
|
+
this.loaded = false;
|
|
1168
|
+
this.specError = null;
|
|
1169
|
+
void this.loadSchema();
|
|
1170
|
+
};
|
|
1087
1171
|
this.onLocation = (e) => {
|
|
1088
1172
|
const detail = e.detail;
|
|
1089
1173
|
if (detail) {
|
|
@@ -1124,13 +1208,16 @@ var RoxyEndpointForm = class extends LitElement6 {
|
|
|
1124
1208
|
void this.loadSchema();
|
|
1125
1209
|
}
|
|
1126
1210
|
async loadSchema() {
|
|
1211
|
+
this.specError = null;
|
|
1127
1212
|
try {
|
|
1128
|
-
const
|
|
1129
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
1130
|
-
const spec = await res.json();
|
|
1213
|
+
const spec = await loadSpec(this.specUrl);
|
|
1131
1214
|
const path = `/${this.endpoint.replace(/^\//, "")}`;
|
|
1132
1215
|
const op = spec.paths?.[path]?.[this.method.toLowerCase()];
|
|
1133
|
-
if (!op)
|
|
1216
|
+
if (!op) {
|
|
1217
|
+
throw new Error(
|
|
1218
|
+
`Endpoint ${this.method} ${path} not found in OpenAPI spec`
|
|
1219
|
+
);
|
|
1220
|
+
}
|
|
1134
1221
|
const schemas = spec.components?.schemas ?? {};
|
|
1135
1222
|
const fields = [];
|
|
1136
1223
|
let bodySchema;
|
|
@@ -1175,8 +1262,17 @@ var RoxyEndpointForm = class extends LitElement6 {
|
|
|
1175
1262
|
}
|
|
1176
1263
|
this.values = init;
|
|
1177
1264
|
this.loaded = true;
|
|
1178
|
-
} catch (
|
|
1265
|
+
} catch (err) {
|
|
1266
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1267
|
+
this.specError = message;
|
|
1179
1268
|
this.loaded = true;
|
|
1269
|
+
this.dispatchEvent(
|
|
1270
|
+
new CustomEvent("roxy-spec-error", {
|
|
1271
|
+
detail: { url: this.specUrl, message },
|
|
1272
|
+
bubbles: true,
|
|
1273
|
+
composed: true
|
|
1274
|
+
})
|
|
1275
|
+
);
|
|
1180
1276
|
}
|
|
1181
1277
|
}
|
|
1182
1278
|
resolve(schema, all) {
|
|
@@ -1202,6 +1298,12 @@ var RoxyEndpointForm = class extends LitElement6 {
|
|
|
1202
1298
|
if (!this.loaded) {
|
|
1203
1299
|
return html6`<form><div class="roxy-skeleton" style="height: 8rem"></div></form>`;
|
|
1204
1300
|
}
|
|
1301
|
+
if (this.specError) {
|
|
1302
|
+
return html6`<div class="spec-error" role="alert">
|
|
1303
|
+
Schema load failed: ${this.specError}
|
|
1304
|
+
<button type="button" class="submit" @click=${this.retryLoadSchema}>Retry</button>
|
|
1305
|
+
</div>`;
|
|
1306
|
+
}
|
|
1205
1307
|
const renderField = (f) => {
|
|
1206
1308
|
if (this.hasLocation && (f.name === "latitude" || f.name === "longitude" || f.name === "timezone")) {
|
|
1207
1309
|
return nothing6;
|
|
@@ -1299,22 +1401,27 @@ RoxyEndpointForm.styles = [
|
|
|
1299
1401
|
.fields {
|
|
1300
1402
|
display: grid;
|
|
1301
1403
|
grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
|
|
1404
|
+
align-items: start;
|
|
1302
1405
|
gap: var(--roxy-space-md, 1rem);
|
|
1303
1406
|
}
|
|
1304
1407
|
.field {
|
|
1305
|
-
display:
|
|
1408
|
+
display: flex;
|
|
1409
|
+
flex-direction: column;
|
|
1306
1410
|
gap: var(--roxy-space-xs, 0.25rem);
|
|
1411
|
+
min-width: 0;
|
|
1307
1412
|
}
|
|
1308
1413
|
label {
|
|
1309
1414
|
font-size: var(--roxy-text-sm, 0.875rem);
|
|
1310
1415
|
color: var(--roxy-secondary, #475569);
|
|
1311
1416
|
}
|
|
1312
1417
|
label .req {
|
|
1313
|
-
color: var(--roxy-danger, #
|
|
1418
|
+
color: var(--roxy-danger-fg, #991b1b);
|
|
1314
1419
|
margin-left: 4px;
|
|
1315
1420
|
}
|
|
1316
1421
|
input,
|
|
1317
1422
|
select {
|
|
1423
|
+
width: 100%;
|
|
1424
|
+
box-sizing: border-box;
|
|
1318
1425
|
padding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);
|
|
1319
1426
|
font-size: var(--roxy-text-base, 1rem);
|
|
1320
1427
|
font-family: inherit;
|
|
@@ -1349,7 +1456,7 @@ RoxyEndpointForm.styles = [
|
|
|
1349
1456
|
button.submit {
|
|
1350
1457
|
justify-self: start;
|
|
1351
1458
|
background: var(--roxy-accent-fg, #b45309);
|
|
1352
|
-
color: #fff;
|
|
1459
|
+
color: var(--roxy-bg, #fff);
|
|
1353
1460
|
border: 0;
|
|
1354
1461
|
border-radius: var(--roxy-radius-md, 8px);
|
|
1355
1462
|
padding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-lg, 1.5rem);
|
|
@@ -1367,6 +1474,17 @@ RoxyEndpointForm.styles = [
|
|
|
1367
1474
|
outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
|
|
1368
1475
|
outline-offset: 2px;
|
|
1369
1476
|
}
|
|
1477
|
+
.spec-error {
|
|
1478
|
+
display: grid;
|
|
1479
|
+
gap: var(--roxy-space-md, 1rem);
|
|
1480
|
+
justify-items: start;
|
|
1481
|
+
background: var(--roxy-bg, #fff);
|
|
1482
|
+
border: 1px solid var(--roxy-danger, #dc2626);
|
|
1483
|
+
border-radius: var(--roxy-radius-md, 8px);
|
|
1484
|
+
padding: var(--roxy-space-lg, 1.5rem);
|
|
1485
|
+
color: var(--roxy-danger-fg, #991b1b);
|
|
1486
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
1487
|
+
}
|
|
1370
1488
|
`
|
|
1371
1489
|
];
|
|
1372
1490
|
__decorateClass([
|
|
@@ -1393,6 +1511,9 @@ __decorateClass([
|
|
|
1393
1511
|
__decorateClass([
|
|
1394
1512
|
state()
|
|
1395
1513
|
], RoxyEndpointForm.prototype, "loaded", 2);
|
|
1514
|
+
__decorateClass([
|
|
1515
|
+
state()
|
|
1516
|
+
], RoxyEndpointForm.prototype, "specError", 2);
|
|
1396
1517
|
RoxyEndpointForm = __decorateClass([
|
|
1397
1518
|
customElement6("roxy-endpoint-form")
|
|
1398
1519
|
], RoxyEndpointForm);
|
|
@@ -1412,18 +1533,16 @@ var RoxyGunaMilan = class extends LitElement7 {
|
|
|
1412
1533
|
const d = this.data;
|
|
1413
1534
|
if (!d)
|
|
1414
1535
|
return html7`<div class="roxy-empty" role="status">No Guna Milan data</div>`;
|
|
1415
|
-
const total = d.total ?? d.totalScore ?? 0;
|
|
1416
|
-
const max = d.maxScore ?? 36;
|
|
1417
1536
|
const breakdown = (d.breakdown ?? []).filter(
|
|
1418
|
-
(b) => b
|
|
1537
|
+
(b) => b?.category !== void 0
|
|
1419
1538
|
);
|
|
1420
1539
|
return html7`<article class="card" aria-label="Guna Milan score">
|
|
1421
1540
|
<div class="score-bar">
|
|
1422
1541
|
<div>
|
|
1423
|
-
<span class="total">${total}</span>
|
|
1424
|
-
<span class="over"> / ${
|
|
1542
|
+
<span class="total">${formatNumber(d.total, 1)}</span>
|
|
1543
|
+
<span class="over"> / ${d.maxScore}</span>
|
|
1425
1544
|
${typeof d.percentage === "number" ? html7`<small style="margin-left: 0.5rem; color: var(--roxy-muted)">
|
|
1426
|
-
${d.percentage}
|
|
1545
|
+
${formatPercent(d.percentage, 1)}
|
|
1427
1546
|
</small>` : nothing7}
|
|
1428
1547
|
</div>
|
|
1429
1548
|
${d.recommendation ? html7`<span class="recommendation">${d.recommendation}</span>` : nothing7}
|
|
@@ -1440,23 +1559,25 @@ var RoxyGunaMilan = class extends LitElement7 {
|
|
|
1440
1559
|
<tbody>
|
|
1441
1560
|
${breakdown.map((b) => {
|
|
1442
1561
|
const score = b.score ?? 0;
|
|
1443
|
-
const maxScore = b.
|
|
1562
|
+
const maxScore = b.maxScore ?? defaultMax(b.category);
|
|
1444
1563
|
const pct = maxScore ? score / maxScore * 100 : 0;
|
|
1445
1564
|
return html7`<tr>
|
|
1446
|
-
<td>${b.
|
|
1565
|
+
<td>${b.category}</td>
|
|
1447
1566
|
<td class="bar-cell">
|
|
1448
1567
|
<div class="mini-bar">
|
|
1449
1568
|
<span style="width: ${pct}%"></span>
|
|
1450
1569
|
</div>
|
|
1451
1570
|
</td>
|
|
1452
|
-
<td class="score">${score} / ${maxScore}</td>
|
|
1571
|
+
<td class="score">${formatNumber(score, 1)} / ${maxScore}</td>
|
|
1453
1572
|
</tr>`;
|
|
1454
1573
|
})}
|
|
1455
1574
|
</tbody>
|
|
1456
1575
|
</table>` : nothing7}
|
|
1457
1576
|
${(d.doshas?.length ?? 0) > 0 || (d.doshaCancellations?.length ?? 0) > 0 ? html7`<div class="tags">
|
|
1458
1577
|
${d.doshas?.map((x) => html7`<span class="dosha">${x}</span>`)}
|
|
1459
|
-
${d.doshaCancellations?.map(
|
|
1578
|
+
${d.doshaCancellations?.map(
|
|
1579
|
+
(x) => html7`<span class="cancel" title=${x.reason}>${x.dosha} cancelled</span>`
|
|
1580
|
+
)}
|
|
1460
1581
|
</div>` : nothing7}
|
|
1461
1582
|
</article>`;
|
|
1462
1583
|
}
|
|
@@ -1550,11 +1671,11 @@ RoxyGunaMilan.styles = [
|
|
|
1550
1671
|
}
|
|
1551
1672
|
.tags .dosha {
|
|
1552
1673
|
background: color-mix(in srgb, var(--roxy-danger, #dc2626) 16%, transparent);
|
|
1553
|
-
color: var(--roxy-danger, #
|
|
1674
|
+
color: var(--roxy-danger-fg, #991b1b);
|
|
1554
1675
|
}
|
|
1555
1676
|
.tags .cancel {
|
|
1556
1677
|
background: color-mix(in srgb, var(--roxy-success, #16a34a) 18%, transparent);
|
|
1557
|
-
color: var(--roxy-success, #
|
|
1678
|
+
color: var(--roxy-success-fg, #166534);
|
|
1558
1679
|
}
|
|
1559
1680
|
`
|
|
1560
1681
|
];
|
|
@@ -1610,7 +1731,12 @@ var PLANET_GLYPH = {
|
|
|
1610
1731
|
Ascendant: "Asc",
|
|
1611
1732
|
Lagna: "La",
|
|
1612
1733
|
NorthNode: "\u260A",
|
|
1613
|
-
SouthNode: "\u260B"
|
|
1734
|
+
SouthNode: "\u260B",
|
|
1735
|
+
"North node": "\u260A",
|
|
1736
|
+
"South node": "\u260B",
|
|
1737
|
+
Chiron: "\u26B7",
|
|
1738
|
+
Lilith: "\u26B8",
|
|
1739
|
+
"Black moon lilith": "\u26B8"
|
|
1614
1740
|
};
|
|
1615
1741
|
var PLANET_ABBR = {
|
|
1616
1742
|
Sun: "Su",
|
|
@@ -1692,23 +1818,40 @@ var RoxyHexagram = class extends LitElement8 {
|
|
|
1692
1818
|
this.data = null;
|
|
1693
1819
|
this.mode = "lookup";
|
|
1694
1820
|
}
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
if (
|
|
1821
|
+
resolveHexagram() {
|
|
1822
|
+
const d = this.data;
|
|
1823
|
+
if (!d) return null;
|
|
1824
|
+
if ("hexagram" in d && d.hexagram) {
|
|
1825
|
+
if ("lines" in d) {
|
|
1826
|
+
const cast = d;
|
|
1827
|
+
return {
|
|
1828
|
+
hex: cast.hexagram,
|
|
1829
|
+
lines: cast.lines,
|
|
1830
|
+
changingLinePositions: cast.changingLinePositions,
|
|
1831
|
+
resultingHexagram: cast.resultingHexagram
|
|
1832
|
+
};
|
|
1833
|
+
}
|
|
1834
|
+
const daily = d;
|
|
1698
1835
|
return {
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
changingLinePositions: this.data.changingLinePositions
|
|
1836
|
+
hex: daily.hexagram,
|
|
1837
|
+
dailyMessage: daily.dailyMessage
|
|
1702
1838
|
};
|
|
1703
1839
|
}
|
|
1704
|
-
return
|
|
1840
|
+
return { hex: d };
|
|
1705
1841
|
}
|
|
1706
1842
|
render() {
|
|
1707
|
-
const
|
|
1708
|
-
if (!
|
|
1843
|
+
const resolved = this.resolveHexagram();
|
|
1844
|
+
if (!resolved)
|
|
1709
1845
|
return html8`<div class="roxy-empty" role="status">No hexagram data</div>`;
|
|
1710
|
-
const
|
|
1711
|
-
|
|
1846
|
+
const {
|
|
1847
|
+
hex: h,
|
|
1848
|
+
lines: castLines,
|
|
1849
|
+
changingLinePositions,
|
|
1850
|
+
dailyMessage,
|
|
1851
|
+
resultingHexagram
|
|
1852
|
+
} = resolved;
|
|
1853
|
+
const lines = castLines ?? this.derivedLines(h);
|
|
1854
|
+
const changing = new Set(changingLinePositions ?? []);
|
|
1712
1855
|
return html8`<article class="card" aria-label="I Ching hexagram">
|
|
1713
1856
|
<div class="glyphs">
|
|
1714
1857
|
${h.symbol ? html8`<div class="symbol">${h.symbol}</div>` : nothing8}
|
|
@@ -1748,19 +1891,18 @@ var RoxyHexagram = class extends LitElement8 {
|
|
|
1748
1891
|
</div>
|
|
1749
1892
|
${h.judgment ? html8`<p class="judgment">${h.judgment}</p>` : nothing8}
|
|
1750
1893
|
${h.image ? html8`<p class="image">${h.image}</p>` : nothing8}
|
|
1751
|
-
${
|
|
1894
|
+
${dailyMessage ? html8`<p class="message">${dailyMessage}</p>` : nothing8}
|
|
1752
1895
|
${h.interpretation?.general ? html8`<p>${h.interpretation.general}</p>` : nothing8}
|
|
1753
1896
|
${changing.size > 0 ? html8`<div class="changing">
|
|
1754
1897
|
Changing lines: ${Array.from(changing).sort((a, b) => a - b).join(", ")}.
|
|
1755
|
-
${
|
|
1756
|
-
${
|
|
1898
|
+
${resultingHexagram?.english ? html8` Becomes hexagram ${resultingHexagram.number}
|
|
1899
|
+
${resultingHexagram.english}.` : nothing8}
|
|
1757
1900
|
</div>` : nothing8}
|
|
1758
1901
|
</div>
|
|
1759
1902
|
</article>`;
|
|
1760
1903
|
}
|
|
1761
1904
|
/** When the API only ships symbol+number with no line array, render six solid yang. */
|
|
1762
1905
|
derivedLines(h) {
|
|
1763
|
-
if (!h.symbol) return Array.from({ length: 6 }, () => 7);
|
|
1764
1906
|
const cp = h.symbol.codePointAt(0) ?? 0;
|
|
1765
1907
|
if (cp >= 19904 && cp <= 19967) {
|
|
1766
1908
|
const offset = cp - 19904;
|
|
@@ -1910,8 +2052,8 @@ var RoxyHoroscopeCard = class extends LitElement9 {
|
|
|
1910
2052
|
return html9`<div class="roxy-empty" role="status">No horoscope data</div>`;
|
|
1911
2053
|
const sign = d.sign ?? "";
|
|
1912
2054
|
const glyph = sign ? SIGN_GLYPH[capitalize(sign)] ?? "" : "";
|
|
1913
|
-
const energy = typeof d.energyRating === "number" ? d.energyRating : null;
|
|
1914
|
-
const dateLabel = d.date
|
|
2055
|
+
const energy = "energyRating" in d && typeof d.energyRating === "number" ? d.energyRating : null;
|
|
2056
|
+
const dateLabel = "date" in d && d.date || "week" in d && d.week || "month" in d && d.month || "";
|
|
1915
2057
|
return html9`<article
|
|
1916
2058
|
class="card"
|
|
1917
2059
|
aria-label=${`${this.period} horoscope for ${sign}`}
|
|
@@ -1949,31 +2091,40 @@ var RoxyHoroscopeCard = class extends LitElement9 {
|
|
|
1949
2091
|
<h3>Finance</h3>
|
|
1950
2092
|
<p>${d.finance}</p>
|
|
1951
2093
|
</div>` : nothing9}
|
|
1952
|
-
${d.advice ? html9`<div class="section">
|
|
2094
|
+
${"advice" in d && d.advice ? html9`<div class="section">
|
|
1953
2095
|
<h3>Advice</h3>
|
|
1954
2096
|
<p>${d.advice}</p>
|
|
1955
2097
|
</div>` : nothing9}
|
|
1956
2098
|
</div>
|
|
1957
2099
|
|
|
1958
|
-
${
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
2100
|
+
${(() => {
|
|
2101
|
+
const luckyNumber = "luckyNumber" in d && d.luckyNumber !== void 0 ? d.luckyNumber : void 0;
|
|
2102
|
+
const luckyColor = "luckyColor" in d && d.luckyColor ? d.luckyColor : "";
|
|
2103
|
+
const luckyNumbers = "luckyNumbers" in d && d.luckyNumbers ? d.luckyNumbers : [];
|
|
2104
|
+
const luckyDays = "luckyDays" in d && d.luckyDays ? d.luckyDays : [];
|
|
2105
|
+
const compatibleSigns = d.compatibleSigns ?? [];
|
|
2106
|
+
if (luckyNumber === void 0 && !luckyColor && luckyNumbers.length === 0 && luckyDays.length === 0 && compatibleSigns.length === 0)
|
|
2107
|
+
return nothing9;
|
|
2108
|
+
return html9`<div class="lucky">
|
|
2109
|
+
${luckyNumber !== void 0 ? html9`<span>Lucky number <strong>${luckyNumber}</strong></span>` : nothing9}
|
|
2110
|
+
${luckyColor ? html9`<span>Lucky color <strong>${luckyColor}</strong></span>` : nothing9}
|
|
2111
|
+
${luckyNumbers.length ? html9`<span
|
|
1962
2112
|
>Lucky numbers
|
|
1963
|
-
<strong>${
|
|
2113
|
+
<strong>${luckyNumbers.join(", ")}</strong></span
|
|
1964
2114
|
>` : nothing9}
|
|
1965
|
-
${
|
|
1966
|
-
>Lucky days <strong>${
|
|
2115
|
+
${luckyDays.length ? html9`<span
|
|
2116
|
+
>Lucky days <strong>${luckyDays.join(", ")}</strong></span
|
|
1967
2117
|
>` : nothing9}
|
|
1968
|
-
${
|
|
2118
|
+
${compatibleSigns.length ? html9`<span class="compat-wrap">
|
|
1969
2119
|
Best with
|
|
1970
2120
|
<span class="compat"
|
|
1971
|
-
>${
|
|
1972
|
-
|
|
1973
|
-
|
|
2121
|
+
>${compatibleSigns.map(
|
|
2122
|
+
(s) => html9`<span>${s}</span>`
|
|
2123
|
+
)}</span
|
|
1974
2124
|
>
|
|
1975
2125
|
</span>` : nothing9}
|
|
1976
|
-
</div
|
|
2126
|
+
</div>`;
|
|
2127
|
+
})()}
|
|
1977
2128
|
</article>`;
|
|
1978
2129
|
}
|
|
1979
2130
|
};
|
|
@@ -2128,7 +2279,7 @@ var RoxyKpPlanetsTable = class extends LitElement10 {
|
|
|
2128
2279
|
>
|
|
2129
2280
|
<header class="head">
|
|
2130
2281
|
<h2 class="title">KP planets</h2>
|
|
2131
|
-
${this.data.ayanamsa ? html10`<span class="ayanamsa">Ayanamsa: ${this.data.ayanamsa}
|
|
2282
|
+
${typeof this.data.ayanamsa === "number" ? html10`<span class="ayanamsa">Ayanamsa: ${formatNumber(this.data.ayanamsa, 2)}°</span>` : nothing10}
|
|
2132
2283
|
</header>
|
|
2133
2284
|
<table role="table">
|
|
2134
2285
|
<thead>
|
|
@@ -2147,13 +2298,13 @@ var RoxyKpPlanetsTable = class extends LitElement10 {
|
|
|
2147
2298
|
${planets.map(
|
|
2148
2299
|
(p) => html10`<tr>
|
|
2149
2300
|
<td class="planet">
|
|
2150
|
-
${p.planet
|
|
2301
|
+
${p.planet}
|
|
2151
2302
|
${p.retrograde ? html10`<span class="retro">R</span>` : nothing10}
|
|
2152
2303
|
</td>
|
|
2153
2304
|
<td>${p.sign ?? ""}</td>
|
|
2154
2305
|
<td>${p.signLord ?? ""}</td>
|
|
2155
2306
|
<td>${p.nakshatra ?? ""}</td>
|
|
2156
|
-
<td>${p.
|
|
2307
|
+
<td>${p.nakshatraLord ?? ""}</td>
|
|
2157
2308
|
<td>${p.subLord ?? ""}</td>
|
|
2158
2309
|
<td>${p.subSubLord ?? ""}</td>
|
|
2159
2310
|
<td>${p.kpNumber ?? ""}</td>
|
|
@@ -2221,7 +2372,7 @@ RoxyKpPlanetsTable.styles = [
|
|
|
2221
2372
|
color: var(--roxy-fg, #0a0a0a);
|
|
2222
2373
|
}
|
|
2223
2374
|
.retro {
|
|
2224
|
-
color: var(--roxy-warning, #
|
|
2375
|
+
color: var(--roxy-warning-fg, #9a3412);
|
|
2225
2376
|
font-size: var(--roxy-text-xs, 0.75rem);
|
|
2226
2377
|
margin-left: 4px;
|
|
2227
2378
|
}
|
|
@@ -2241,10 +2392,20 @@ import { customElement as customElement11, property as property11, state as stat
|
|
|
2241
2392
|
// packages/ui/src/utils/debounce.ts
|
|
2242
2393
|
function debounce(fn, wait) {
|
|
2243
2394
|
let timer;
|
|
2244
|
-
|
|
2395
|
+
const debounced = ((...args) => {
|
|
2245
2396
|
if (timer) clearTimeout(timer);
|
|
2246
|
-
timer = setTimeout(() =>
|
|
2397
|
+
timer = setTimeout(() => {
|
|
2398
|
+
timer = void 0;
|
|
2399
|
+
fn(...args);
|
|
2400
|
+
}, wait);
|
|
2247
2401
|
});
|
|
2402
|
+
debounced.cancel = () => {
|
|
2403
|
+
if (timer) {
|
|
2404
|
+
clearTimeout(timer);
|
|
2405
|
+
timer = void 0;
|
|
2406
|
+
}
|
|
2407
|
+
};
|
|
2408
|
+
return debounced;
|
|
2248
2409
|
}
|
|
2249
2410
|
|
|
2250
2411
|
// packages/ui/src/components/location-search.ts
|
|
@@ -2259,6 +2420,7 @@ var RoxyLocationSearch = class extends LitElement11 {
|
|
|
2259
2420
|
this.isOpen = false;
|
|
2260
2421
|
this.isLoading = false;
|
|
2261
2422
|
this.highlight = -1;
|
|
2423
|
+
this.secretKeyWarned = false;
|
|
2262
2424
|
this.debouncedFetch = debounce((q) => {
|
|
2263
2425
|
void this.fetchResults(q);
|
|
2264
2426
|
}, 300);
|
|
@@ -2310,8 +2472,32 @@ var RoxyLocationSearch = class extends LitElement11 {
|
|
|
2310
2472
|
if (this.clickOutsideHandler) {
|
|
2311
2473
|
document.removeEventListener("mousedown", this.clickOutsideHandler);
|
|
2312
2474
|
}
|
|
2475
|
+
this.debouncedFetch.cancel();
|
|
2476
|
+
if (this.abortController) {
|
|
2477
|
+
this.abortController.abort();
|
|
2478
|
+
this.abortController = void 0;
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
warnIfSecretKey() {
|
|
2482
|
+
if (this.secretKeyWarned) return;
|
|
2483
|
+
if (!this.apiKey) return;
|
|
2484
|
+
if (this.apiKey.startsWith("pk_")) return;
|
|
2485
|
+
this.secretKeyWarned = true;
|
|
2486
|
+
const message = "Possible secret key in client-side <roxy-location-search>; use a `pk_` publishable key with origin allowlist instead.";
|
|
2487
|
+
console.warn(message);
|
|
2488
|
+
this.dispatchEvent(
|
|
2489
|
+
new CustomEvent("roxy-validation-error", {
|
|
2490
|
+
detail: { reason: "possible-secret-key", message },
|
|
2491
|
+
bubbles: true,
|
|
2492
|
+
composed: true
|
|
2493
|
+
})
|
|
2494
|
+
);
|
|
2313
2495
|
}
|
|
2314
2496
|
async fetchResults(q) {
|
|
2497
|
+
this.warnIfSecretKey();
|
|
2498
|
+
if (this.abortController) this.abortController.abort();
|
|
2499
|
+
const controller = new AbortController();
|
|
2500
|
+
this.abortController = controller;
|
|
2315
2501
|
this.isLoading = true;
|
|
2316
2502
|
try {
|
|
2317
2503
|
const url = new URL(this.endpoint);
|
|
@@ -2322,17 +2508,22 @@ var RoxyLocationSearch = class extends LitElement11 {
|
|
|
2322
2508
|
};
|
|
2323
2509
|
if (this.apiKey) headers["X-API-Key"] = this.apiKey;
|
|
2324
2510
|
if (this.publishableKey) headers["X-API-Key"] = this.publishableKey;
|
|
2325
|
-
const res = await fetch(url, { headers });
|
|
2511
|
+
const res = await fetch(url, { headers, signal: controller.signal });
|
|
2326
2512
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
2327
2513
|
const json = await res.json();
|
|
2514
|
+
if (controller.signal.aborted) return;
|
|
2328
2515
|
this.results = json.cities ?? [];
|
|
2329
2516
|
this.isOpen = this.results.length > 0;
|
|
2330
2517
|
this.highlight = this.results.length > 0 ? 0 : -1;
|
|
2331
|
-
} catch (
|
|
2518
|
+
} catch (err) {
|
|
2519
|
+
if (err?.name === "AbortError") return;
|
|
2332
2520
|
this.results = [];
|
|
2333
2521
|
this.isOpen = false;
|
|
2334
2522
|
} finally {
|
|
2335
|
-
this.
|
|
2523
|
+
if (this.abortController === controller) {
|
|
2524
|
+
this.abortController = void 0;
|
|
2525
|
+
}
|
|
2526
|
+
if (!controller.signal.aborted) this.isLoading = false;
|
|
2336
2527
|
}
|
|
2337
2528
|
}
|
|
2338
2529
|
select(city) {
|
|
@@ -2548,18 +2739,21 @@ var RoxyMoonPhase = class extends LitElement12 {
|
|
|
2548
2739
|
const d = this.data;
|
|
2549
2740
|
if (!d)
|
|
2550
2741
|
return html12`<div class="roxy-empty" role="status">No moon phase data</div>`;
|
|
2551
|
-
const list = d.phases
|
|
2742
|
+
const list = "phases" in d ? d.phases : "calendar" in d ? d.calendar : [];
|
|
2552
2743
|
if (this.mode !== "current" && list.length > 0) {
|
|
2744
|
+
const month = "month" in d ? d.month : void 0;
|
|
2745
|
+
const year = "year" in d ? d.year : void 0;
|
|
2553
2746
|
return html12`<article
|
|
2554
2747
|
class="card"
|
|
2555
2748
|
aria-label="Moon phase calendar"
|
|
2556
2749
|
>
|
|
2557
|
-
<h2 class="label">${
|
|
2750
|
+
<h2 class="label">${month ?? "Moon phases"} ${year ?? ""}</h2>
|
|
2558
2751
|
<div class="list" role="list">
|
|
2559
2752
|
${list.map((phase) => this.renderListItem(phase))}
|
|
2560
2753
|
</div>
|
|
2561
2754
|
</article>`;
|
|
2562
2755
|
}
|
|
2756
|
+
if (!("phase" in d)) return nothing12;
|
|
2563
2757
|
return this.renderSingle(d);
|
|
2564
2758
|
}
|
|
2565
2759
|
renderSingle(d) {
|
|
@@ -2575,11 +2769,11 @@ var RoxyMoonPhase = class extends LitElement12 {
|
|
|
2575
2769
|
<div class="stats">
|
|
2576
2770
|
${typeof d.illumination === "number" ? html12`<div>
|
|
2577
2771
|
<span>Illumination</span>
|
|
2578
|
-
<strong>${(d.illumination
|
|
2772
|
+
<strong>${formatIllumination(d.illumination)}</strong>
|
|
2579
2773
|
</div>` : nothing12}
|
|
2580
2774
|
${typeof d.age === "number" ? html12`<div>
|
|
2581
2775
|
<span>Age</span>
|
|
2582
|
-
<strong>${d.age
|
|
2776
|
+
<strong>${formatNumber(d.age, 1)} days</strong>
|
|
2583
2777
|
</div>` : nothing12}
|
|
2584
2778
|
${d.sign ? html12`<div>
|
|
2585
2779
|
<span>Sign</span>
|
|
@@ -2704,6 +2898,10 @@ function phaseEmoji(phase) {
|
|
|
2704
2898
|
if (!phase) return "\u{1F319}";
|
|
2705
2899
|
return MOON_PHASE_EMOJI[phase.toLowerCase()] ?? "\u{1F319}";
|
|
2706
2900
|
}
|
|
2901
|
+
function formatIllumination(v) {
|
|
2902
|
+
const pct = v <= 1 ? v * 100 : v;
|
|
2903
|
+
return `${Math.round(pct)}%`;
|
|
2904
|
+
}
|
|
2707
2905
|
|
|
2708
2906
|
// packages/ui/src/components/natal-chart.ts
|
|
2709
2907
|
import { css as css14, html as html13, LitElement as LitElement13, nothing as nothing13, svg as svg3 } from "lit";
|
|
@@ -2719,12 +2917,14 @@ function polarToCartesian(cx, cy, radius, angleDeg) {
|
|
|
2719
2917
|
}
|
|
2720
2918
|
|
|
2721
2919
|
// packages/ui/src/components/natal-chart.ts
|
|
2722
|
-
var SIZE =
|
|
2920
|
+
var SIZE = 384;
|
|
2723
2921
|
var CENTER = SIZE / 2;
|
|
2724
2922
|
var OUTER_R = 150;
|
|
2725
2923
|
var SIGN_R = 134;
|
|
2726
2924
|
var HOUSE_R = 110;
|
|
2727
2925
|
var PLANET_R = 88;
|
|
2926
|
+
var ANGLE_TICK_R = 162;
|
|
2927
|
+
var ANGLE_LABEL_R = 176;
|
|
2728
2928
|
var RoxyNatalChart = class extends LitElement13 {
|
|
2729
2929
|
constructor() {
|
|
2730
2930
|
super(...arguments);
|
|
@@ -2732,10 +2932,17 @@ var RoxyNatalChart = class extends LitElement13 {
|
|
|
2732
2932
|
this.houseSystem = "placidus";
|
|
2733
2933
|
}
|
|
2734
2934
|
getPlanets() {
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
return
|
|
2935
|
+
return this.data?.planets ?? [];
|
|
2936
|
+
}
|
|
2937
|
+
getAscendant() {
|
|
2938
|
+
return this.data?.ascendant?.longitude ?? 0;
|
|
2939
|
+
}
|
|
2940
|
+
getMidheaven() {
|
|
2941
|
+
const m = this.data?.midheaven?.longitude;
|
|
2942
|
+
return typeof m === "number" ? m : null;
|
|
2943
|
+
}
|
|
2944
|
+
toAngle(lon) {
|
|
2945
|
+
return 180 + this.getAscendant() - lon;
|
|
2739
2946
|
}
|
|
2740
2947
|
render() {
|
|
2741
2948
|
if (!this.data)
|
|
@@ -2746,11 +2953,7 @@ var RoxyNatalChart = class extends LitElement13 {
|
|
|
2746
2953
|
<header>
|
|
2747
2954
|
<h2 class="title">Natal chart</h2>
|
|
2748
2955
|
${this.data.birthDetails ? html13`<div class="meta">
|
|
2749
|
-
${[
|
|
2750
|
-
this.data.birthDetails.date,
|
|
2751
|
-
this.data.birthDetails.time,
|
|
2752
|
-
this.data.birthDetails.location
|
|
2753
|
-
].filter(Boolean).join(" \xB7 ")}
|
|
2956
|
+
${[this.data.birthDetails.date, this.data.birthDetails.time].filter(Boolean).join(" \xB7 ")}
|
|
2754
2957
|
</div>` : nothing13}
|
|
2755
2958
|
</header>
|
|
2756
2959
|
<svg
|
|
@@ -2786,17 +2989,38 @@ var RoxyNatalChart = class extends LitElement13 {
|
|
|
2786
2989
|
/>
|
|
2787
2990
|
${this.renderSpokes()} ${this.renderSigns()} ${this.renderHouseNumbers()}
|
|
2788
2991
|
${this.renderAspects(planets, aspects)} ${this.renderPlanets(planets)}
|
|
2992
|
+
${this.renderAngles()}
|
|
2789
2993
|
</svg>
|
|
2790
2994
|
<div class="legend">
|
|
2791
2995
|
<span>${planets.length} planets</span>
|
|
2792
2996
|
<span>${aspects.length} aspects</span>
|
|
2793
|
-
<span
|
|
2997
|
+
<span><span class="legend-swatch" style="background: var(--roxy-success)"></span>harmonious</span>
|
|
2998
|
+
<span><span class="legend-swatch" style="background: var(--roxy-danger)"></span>challenging</span>
|
|
2794
2999
|
</div>
|
|
2795
3000
|
</div>`;
|
|
2796
3001
|
}
|
|
3002
|
+
renderAngles() {
|
|
3003
|
+
const asc = this.getAscendant();
|
|
3004
|
+
const mc = this.getMidheaven();
|
|
3005
|
+
const items = [this.renderAngleMark(asc, "ASC")];
|
|
3006
|
+
if (mc !== null) items.push(this.renderAngleMark(mc, "MC"));
|
|
3007
|
+
return items;
|
|
3008
|
+
}
|
|
3009
|
+
renderAngleMark(longitude, label) {
|
|
3010
|
+
const angle = this.toAngle(longitude);
|
|
3011
|
+
const tickInner = polarToCartesian(CENTER, CENTER, OUTER_R, angle);
|
|
3012
|
+
const tickOuter = polarToCartesian(CENTER, CENTER, ANGLE_TICK_R, angle);
|
|
3013
|
+
const labelPos = polarToCartesian(CENTER, CENTER, ANGLE_LABEL_R, angle);
|
|
3014
|
+
return svg3`
|
|
3015
|
+
<g>
|
|
3016
|
+
<line class="angle-tick" x1=${tickInner.x} y1=${tickInner.y} x2=${tickOuter.x} y2=${tickOuter.y} />
|
|
3017
|
+
<text class="angle-marker" x=${labelPos.x} y=${labelPos.y} text-anchor="middle" dominant-baseline="central">${label}</text>
|
|
3018
|
+
</g>
|
|
3019
|
+
`;
|
|
3020
|
+
}
|
|
2797
3021
|
renderSpokes() {
|
|
2798
3022
|
return Array.from({ length: 12 }, (_, i) => {
|
|
2799
|
-
const angle = i * 30
|
|
3023
|
+
const angle = this.toAngle(i * 30);
|
|
2800
3024
|
const start = polarToCartesian(CENTER, CENTER, HOUSE_R, angle);
|
|
2801
3025
|
const end = polarToCartesian(CENTER, CENTER, OUTER_R, angle);
|
|
2802
3026
|
return svg3`<line class="wheel-line" x1=${start.x} y1=${start.y} x2=${end.x} y2=${end.y} stroke-width="0.8" />`;
|
|
@@ -2818,45 +3042,58 @@ var RoxyNatalChart = class extends LitElement13 {
|
|
|
2818
3042
|
"Pisces"
|
|
2819
3043
|
];
|
|
2820
3044
|
return order.map((sign, i) => {
|
|
2821
|
-
const angle = i * 30 + 15
|
|
3045
|
+
const angle = this.toAngle(i * 30 + 15);
|
|
2822
3046
|
const pos = polarToCartesian(CENTER, CENTER, SIGN_R, angle);
|
|
2823
3047
|
return svg3`<text class="sign-glyph" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central">${SIGN_GLYPH[sign]}</text>`;
|
|
2824
3048
|
});
|
|
2825
3049
|
}
|
|
2826
3050
|
renderHouseNumbers() {
|
|
3051
|
+
const ascSignIndex = Math.floor(this.getAscendant() / 30);
|
|
2827
3052
|
return Array.from({ length: 12 }, (_, i) => {
|
|
2828
|
-
const angle = i * 30 + 15
|
|
3053
|
+
const angle = this.toAngle(i * 30 + 15);
|
|
2829
3054
|
const pos = polarToCartesian(CENTER, CENTER, HOUSE_R - 12, angle);
|
|
2830
|
-
|
|
3055
|
+
const houseNum = (i - ascSignIndex + 12) % 12 + 1;
|
|
3056
|
+
return svg3`<text class="house-num" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central">${houseNum}</text>`;
|
|
2831
3057
|
});
|
|
2832
3058
|
}
|
|
2833
3059
|
renderPlanets(planets) {
|
|
2834
3060
|
return planets.map((p) => {
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
const angle = lon - 90;
|
|
3061
|
+
if (!Number.isFinite(p.longitude)) return nothing13;
|
|
3062
|
+
const angle = this.toAngle(p.longitude);
|
|
2838
3063
|
const pos = polarToCartesian(CENTER, CENTER, PLANET_R, angle);
|
|
2839
|
-
const
|
|
2840
|
-
const
|
|
2841
|
-
const
|
|
2842
|
-
return svg3`<text class="planet-glyph" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central"><title>${name}${retro}</title>${
|
|
3064
|
+
const glyph = PLANET_GLYPH[capitalize2(p.name)] ?? p.name.slice(0, 2);
|
|
3065
|
+
const retro = p.isRetrograde ? " R" : "";
|
|
3066
|
+
const display = retro ? `${glyph}\u1D3F` : glyph;
|
|
3067
|
+
return svg3`<text class="planet-glyph" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central"><title>${p.name}${retro}</title>${display}</text>`;
|
|
2843
3068
|
});
|
|
2844
3069
|
}
|
|
2845
3070
|
renderAspects(planets, aspects) {
|
|
2846
3071
|
const planetMap = /* @__PURE__ */ new Map();
|
|
2847
3072
|
for (const p of planets) {
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
if (name) planetMap.set(name, lon);
|
|
3073
|
+
if (typeof p.longitude !== "number") continue;
|
|
3074
|
+
const name = capitalize2(p.name);
|
|
3075
|
+
if (name) planetMap.set(name, p.longitude);
|
|
2852
3076
|
}
|
|
2853
3077
|
return aspects.map((a) => {
|
|
2854
|
-
const l1 = planetMap.get(capitalize2(a.planet1
|
|
2855
|
-
const l2 = planetMap.get(capitalize2(a.planet2
|
|
3078
|
+
const l1 = planetMap.get(capitalize2(a.planet1));
|
|
3079
|
+
const l2 = planetMap.get(capitalize2(a.planet2));
|
|
2856
3080
|
if (l1 === void 0 || l2 === void 0) return nothing13;
|
|
2857
|
-
const p1 = polarToCartesian(
|
|
2858
|
-
|
|
2859
|
-
|
|
3081
|
+
const p1 = polarToCartesian(
|
|
3082
|
+
CENTER,
|
|
3083
|
+
CENTER,
|
|
3084
|
+
PLANET_R - 18,
|
|
3085
|
+
this.toAngle(l1)
|
|
3086
|
+
);
|
|
3087
|
+
const p2 = polarToCartesian(
|
|
3088
|
+
CENTER,
|
|
3089
|
+
CENTER,
|
|
3090
|
+
PLANET_R - 18,
|
|
3091
|
+
this.toAngle(l2)
|
|
3092
|
+
);
|
|
3093
|
+
const aspectName = normalizeAspect(a);
|
|
3094
|
+
const aspectClass = ASPECT_CLASS[aspectName] ?? "aspect-other";
|
|
3095
|
+
const orbLabel = formatNumber(a.orb, 1);
|
|
3096
|
+
return svg3`<line class=${`aspect ${aspectClass}`} x1=${p1.x} y1=${p1.y} x2=${p2.x} y2=${p2.y}><title>${a.planet1} ${aspectName || ""} ${a.planet2}${orbLabel ? ` (orb ${orbLabel}\xB0)` : ""}</title></line>`;
|
|
2860
3097
|
});
|
|
2861
3098
|
}
|
|
2862
3099
|
};
|
|
@@ -2914,9 +3151,36 @@ RoxyNatalChart.styles = [
|
|
|
2914
3151
|
}
|
|
2915
3152
|
|
|
2916
3153
|
.aspect {
|
|
2917
|
-
stroke:
|
|
2918
|
-
stroke-width: 0.6;
|
|
3154
|
+
stroke-width: 0.8;
|
|
2919
3155
|
fill: none;
|
|
3156
|
+
opacity: 0.55;
|
|
3157
|
+
}
|
|
3158
|
+
.aspect-trine,
|
|
3159
|
+
.aspect-sextile {
|
|
3160
|
+
stroke: var(--roxy-success, #16a34a);
|
|
3161
|
+
}
|
|
3162
|
+
.aspect-square,
|
|
3163
|
+
.aspect-opposition {
|
|
3164
|
+
stroke: var(--roxy-danger, #dc2626);
|
|
3165
|
+
}
|
|
3166
|
+
.aspect-conjunction {
|
|
3167
|
+
stroke: var(--roxy-accent-fg, #b45309);
|
|
3168
|
+
}
|
|
3169
|
+
.aspect-other {
|
|
3170
|
+
stroke: var(--roxy-muted, #71717a);
|
|
3171
|
+
opacity: 0.4;
|
|
3172
|
+
}
|
|
3173
|
+
|
|
3174
|
+
.angle-marker {
|
|
3175
|
+
fill: var(--roxy-accent-fg, #b45309);
|
|
3176
|
+
font-size: 10px;
|
|
3177
|
+
font-weight: 700;
|
|
3178
|
+
font-family: var(--roxy-font-sans);
|
|
3179
|
+
letter-spacing: 0.04em;
|
|
3180
|
+
}
|
|
3181
|
+
.angle-tick {
|
|
3182
|
+
stroke: var(--roxy-accent-fg, #b45309);
|
|
3183
|
+
stroke-width: 1.5;
|
|
2920
3184
|
}
|
|
2921
3185
|
|
|
2922
3186
|
.legend {
|
|
@@ -2926,6 +3190,14 @@ RoxyNatalChart.styles = [
|
|
|
2926
3190
|
flex-wrap: wrap;
|
|
2927
3191
|
gap: var(--roxy-space-md, 1rem);
|
|
2928
3192
|
}
|
|
3193
|
+
.legend-swatch {
|
|
3194
|
+
display: inline-block;
|
|
3195
|
+
width: 8px;
|
|
3196
|
+
height: 8px;
|
|
3197
|
+
border-radius: 50%;
|
|
3198
|
+
margin-right: 4px;
|
|
3199
|
+
vertical-align: middle;
|
|
3200
|
+
}
|
|
2929
3201
|
`
|
|
2930
3202
|
];
|
|
2931
3203
|
__decorateClass([
|
|
@@ -2941,6 +3213,16 @@ function capitalize2(s) {
|
|
|
2941
3213
|
if (!s) return "";
|
|
2942
3214
|
return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
|
|
2943
3215
|
}
|
|
3216
|
+
var ASPECT_CLASS = {
|
|
3217
|
+
conjunction: "aspect-conjunction",
|
|
3218
|
+
sextile: "aspect-sextile",
|
|
3219
|
+
square: "aspect-square",
|
|
3220
|
+
trine: "aspect-trine",
|
|
3221
|
+
opposition: "aspect-opposition"
|
|
3222
|
+
};
|
|
3223
|
+
function normalizeAspect(a) {
|
|
3224
|
+
return (a.type ?? "").toLowerCase().replace(/_/g, "-");
|
|
3225
|
+
}
|
|
2944
3226
|
|
|
2945
3227
|
// packages/ui/src/components/numerology-card.ts
|
|
2946
3228
|
import { css as css15, html as html14, LitElement as LitElement14, nothing as nothing14 } from "lit";
|
|
@@ -2956,42 +3238,63 @@ var RoxyNumerologyCard = class extends LitElement14 {
|
|
|
2956
3238
|
if (!d)
|
|
2957
3239
|
return html14`<div class="roxy-empty" role="status">No numerology data</div>`;
|
|
2958
3240
|
const headerLabel = LABELS[this.type] ?? this.type;
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
3241
|
+
if ("coreNumbers" in d) return this.renderChart(d, headerLabel);
|
|
3242
|
+
if ("personalYear" in d) return this.renderPersonalYear(d, headerLabel);
|
|
3243
|
+
return this.renderNumberCard(
|
|
3244
|
+
d,
|
|
3245
|
+
headerLabel
|
|
3246
|
+
);
|
|
3247
|
+
}
|
|
3248
|
+
renderNumberCard(d, headerLabel) {
|
|
3249
|
+
const keywords = d.meaning?.keywords ?? [];
|
|
3250
|
+
return html14`<article class="card" aria-label=${headerLabel}>
|
|
2967
3251
|
<div class="hero">
|
|
2968
|
-
${typeof number === "number" ? html14`<div class="numeral">${number}</div>` : nothing14}
|
|
3252
|
+
${typeof d.number === "number" ? html14`<div class="numeral">${d.number}</div>` : nothing14}
|
|
2969
3253
|
<div>
|
|
2970
3254
|
<p class="label">${headerLabel}</p>
|
|
2971
|
-
${d.title ? html14`<h2 class="title">${d.title}</h2>` :
|
|
2972
|
-
${d.type === "master" ? "Master number" : "Single digit"}
|
|
2973
|
-
</h2>` : nothing14}
|
|
3255
|
+
${d.meaning?.title ? html14`<h2 class="title">${d.meaning.title}</h2>` : nothing14}
|
|
2974
3256
|
</div>
|
|
2975
3257
|
</div>
|
|
2976
|
-
${d.
|
|
2977
|
-
${d.meaning ? html14`<p class="meaning">${d.meaning}</p>` : nothing14}
|
|
2978
|
-
${d.advice ? html14`<p>${d.advice}</p>` : nothing14}
|
|
3258
|
+
${d.meaning?.description ? html14`<p class="meaning">${d.meaning.description}</p>` : nothing14}
|
|
2979
3259
|
${d.calculation ? html14`<pre class="calc">${d.calculation}</pre>` : nothing14}
|
|
2980
|
-
${
|
|
2981
|
-
${
|
|
2982
|
-
</div>` : nothing14}
|
|
2983
|
-
${cores.length > 0 ? html14`<div class="cores">
|
|
2984
|
-
${cores.map(([k, v]) => {
|
|
2985
|
-
const value = typeof v === "number" ? v : v.number;
|
|
2986
|
-
return html14`<div class="item">
|
|
2987
|
-
<span>${humanize2(k)}</span>
|
|
2988
|
-
<strong>${value ?? ""}</strong>
|
|
2989
|
-
</div>`;
|
|
2990
|
-
})}
|
|
3260
|
+
${keywords.length > 0 ? html14`<div class="chips">
|
|
3261
|
+
${keywords.map((k) => html14`<span>${k}</span>`)}
|
|
2991
3262
|
</div>` : nothing14}
|
|
2992
3263
|
${d.hasKarmicDebt && d.karmicDebtNumber ? html14`<div class="karmic">
|
|
2993
3264
|
Karmic debt ${d.karmicDebtNumber}.
|
|
2994
|
-
${d.karmicDebtMeaning
|
|
3265
|
+
${karmicDebtText(d.karmicDebtMeaning)}
|
|
3266
|
+
</div>` : nothing14}
|
|
3267
|
+
</article>`;
|
|
3268
|
+
}
|
|
3269
|
+
renderPersonalYear(d, headerLabel) {
|
|
3270
|
+
return html14`<article class="card" aria-label=${headerLabel}>
|
|
3271
|
+
<div class="hero">
|
|
3272
|
+
${typeof d.personalYear === "number" ? html14`<div class="numeral">${d.personalYear}</div>` : nothing14}
|
|
3273
|
+
<div>
|
|
3274
|
+
<p class="label">${headerLabel}</p>
|
|
3275
|
+
${d.theme ? html14`<h2 class="title">${d.theme}</h2>` : nothing14}
|
|
3276
|
+
</div>
|
|
3277
|
+
</div>
|
|
3278
|
+
${d.forecast ? html14`<p class="meaning">${d.forecast}</p>` : nothing14}
|
|
3279
|
+
${d.advice ? html14`<p>${d.advice}</p>` : nothing14}
|
|
3280
|
+
</article>`;
|
|
3281
|
+
}
|
|
3282
|
+
renderChart(d, headerLabel) {
|
|
3283
|
+
const cores = Object.entries(d.coreNumbers).filter(
|
|
3284
|
+
([, v]) => v !== null && v !== void 0
|
|
3285
|
+
);
|
|
3286
|
+
return html14`<article class="card" aria-label=${headerLabel}>
|
|
3287
|
+
<div>
|
|
3288
|
+
<p class="label">${headerLabel}</p>
|
|
3289
|
+
${d.profile?.name ? html14`<h2 class="title">${d.profile.name}</h2>` : nothing14}
|
|
3290
|
+
</div>
|
|
3291
|
+
${cores.length > 0 ? html14`<div class="cores">
|
|
3292
|
+
${cores.map(
|
|
3293
|
+
([k, v]) => html14`<div class="item">
|
|
3294
|
+
<span>${humanize2(k)}</span>
|
|
3295
|
+
<strong>${v.number ?? ""}</strong>
|
|
3296
|
+
</div>`
|
|
3297
|
+
)}
|
|
2995
3298
|
</div>` : nothing14}
|
|
2996
3299
|
</article>`;
|
|
2997
3300
|
}
|
|
@@ -3046,7 +3349,8 @@ RoxyNumerologyCard.styles = [
|
|
|
3046
3349
|
background: color-mix(in srgb, var(--roxy-border, #e4e4e7) 30%, transparent);
|
|
3047
3350
|
padding: var(--roxy-space-sm, 0.5rem);
|
|
3048
3351
|
border-radius: var(--roxy-radius-sm, 4px);
|
|
3049
|
-
|
|
3352
|
+
white-space: pre-wrap;
|
|
3353
|
+
overflow-wrap: anywhere;
|
|
3050
3354
|
}
|
|
3051
3355
|
|
|
3052
3356
|
.chips {
|
|
@@ -3110,6 +3414,10 @@ var LABELS = {
|
|
|
3110
3414
|
"personal-year": "Personal Year",
|
|
3111
3415
|
chart: "Numerology chart"
|
|
3112
3416
|
};
|
|
3417
|
+
function karmicDebtText(value) {
|
|
3418
|
+
if (!value) return "";
|
|
3419
|
+
return [value.description, value.challenge, value.resolution].filter(Boolean).join(" ");
|
|
3420
|
+
}
|
|
3113
3421
|
function humanize2(s) {
|
|
3114
3422
|
return s.replace(/[_-]+/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^\w/, (c) => c.toUpperCase());
|
|
3115
3423
|
}
|
|
@@ -3127,31 +3435,32 @@ var RoxyPanchangTable = class extends LitElement15 {
|
|
|
3127
3435
|
const d = this.data;
|
|
3128
3436
|
if (!d)
|
|
3129
3437
|
return html15`<div class="roxy-empty" role="status">No panchang data</div>`;
|
|
3438
|
+
const detailed = "sunrise" in d ? d : null;
|
|
3130
3439
|
const fivefold = [
|
|
3131
3440
|
["Tithi", this.formatPart(d.tithi)],
|
|
3132
3441
|
["Nakshatra", this.formatPart(d.nakshatra)],
|
|
3133
3442
|
["Yoga", this.formatPart(d.yoga)],
|
|
3134
|
-
["Karana", this.formatPart(d.karana)]
|
|
3135
|
-
["Vara", d.vara ?? ""]
|
|
3136
|
-
];
|
|
3137
|
-
const muhurtas = [
|
|
3138
|
-
["Brahma Muhurta", d.brahmaMuhurta],
|
|
3139
|
-
["Abhijit Muhurta", d.abhijitMuhurta],
|
|
3140
|
-
["Vijaya Muhurta", d.vijayaMuhurta],
|
|
3141
|
-
["Godhuli Muhurta", d.godhuliMuhurta],
|
|
3142
|
-
["Nishita Muhurta", d.nishitaMuhurta],
|
|
3143
|
-
["Pratah Sandhya", d.pratahSandhya],
|
|
3144
|
-
["Sayahna Sandhya", d.sayahnaSandhya]
|
|
3145
|
-
];
|
|
3146
|
-
const inauspicious = [
|
|
3147
|
-
["Rahu Kaal", d.rahuKaal],
|
|
3148
|
-
["Yamaganda", d.yamaganda],
|
|
3149
|
-
["Gulika", d.gulika]
|
|
3443
|
+
["Karana", this.formatPart(d.karana)]
|
|
3150
3444
|
];
|
|
3445
|
+
if (detailed) fivefold.push(["Vara", this.formatPart(detailed.vara)]);
|
|
3446
|
+
const muhurtas = detailed ? [
|
|
3447
|
+
["Brahma Muhurta", detailed.brahmaMuhurta],
|
|
3448
|
+
["Abhijit Muhurta", detailed.abhijitMuhurta],
|
|
3449
|
+
["Vijaya Muhurta", detailed.vijayaMuhurta],
|
|
3450
|
+
["Godhuli Muhurta", detailed.godhuliMuhurta],
|
|
3451
|
+
["Nishita Muhurta", detailed.nishitaMuhurta],
|
|
3452
|
+
["Pratah Sandhya", detailed.pratahSandhya],
|
|
3453
|
+
["Sayahna Sandhya", detailed.sayahnaSandhya]
|
|
3454
|
+
] : [];
|
|
3455
|
+
const inauspicious = detailed ? [
|
|
3456
|
+
["Rahu Kaal", detailed.rahuKaal],
|
|
3457
|
+
["Yamaganda", detailed.yamaganda],
|
|
3458
|
+
["Gulika", detailed.gulika]
|
|
3459
|
+
] : [];
|
|
3151
3460
|
return html15`<div class="wrap" aria-label="Panchang">
|
|
3152
3461
|
<header class="head">
|
|
3153
3462
|
<h2 class="title">Panchang</h2>
|
|
3154
|
-
<span class="date">${
|
|
3463
|
+
<span class="date">${detailed ? formatDate(detailed.date) : ""}</span>
|
|
3155
3464
|
</header>
|
|
3156
3465
|
<table>
|
|
3157
3466
|
<tbody>
|
|
@@ -3161,21 +3470,21 @@ var RoxyPanchangTable = class extends LitElement15 {
|
|
|
3161
3470
|
<td>${v}</td>
|
|
3162
3471
|
</tr>`
|
|
3163
3472
|
)}
|
|
3164
|
-
${
|
|
3473
|
+
${detailed?.sunrise ? html15`<tr>
|
|
3165
3474
|
<th>Sunrise</th>
|
|
3166
|
-
<td>${
|
|
3475
|
+
<td>${formatTime(detailed.sunrise)}</td>
|
|
3167
3476
|
</tr>` : nothing15}
|
|
3168
|
-
${
|
|
3477
|
+
${detailed?.sunset ? html15`<tr>
|
|
3169
3478
|
<th>Sunset</th>
|
|
3170
|
-
<td>${
|
|
3479
|
+
<td>${formatTime(detailed.sunset)}</td>
|
|
3171
3480
|
</tr>` : nothing15}
|
|
3172
|
-
${
|
|
3481
|
+
${detailed?.moonrise ? html15`<tr>
|
|
3173
3482
|
<th>Moonrise</th>
|
|
3174
|
-
<td>${
|
|
3483
|
+
<td>${formatTime(detailed.moonrise)}</td>
|
|
3175
3484
|
</tr>` : nothing15}
|
|
3176
|
-
${
|
|
3485
|
+
${detailed?.moonset ? html15`<tr>
|
|
3177
3486
|
<th>Moonset</th>
|
|
3178
|
-
<td>${
|
|
3487
|
+
<td>${formatTime(detailed.moonset)}</td>
|
|
3179
3488
|
</tr>` : nothing15}
|
|
3180
3489
|
</tbody>
|
|
3181
3490
|
</table>
|
|
@@ -3186,7 +3495,7 @@ var RoxyPanchangTable = class extends LitElement15 {
|
|
|
3186
3495
|
${muhurtas.filter(([, v]) => !!v).map(
|
|
3187
3496
|
([k, v]) => html15`<tr>
|
|
3188
3497
|
<th>${k}</th>
|
|
3189
|
-
<td>${
|
|
3498
|
+
<td>${formatTimeRange(v)}</td>
|
|
3190
3499
|
</tr>`
|
|
3191
3500
|
)}
|
|
3192
3501
|
</tbody>
|
|
@@ -3197,7 +3506,7 @@ var RoxyPanchangTable = class extends LitElement15 {
|
|
|
3197
3506
|
${inauspicious.filter(([, v]) => !!v).map(
|
|
3198
3507
|
([k, v]) => html15`<tr>
|
|
3199
3508
|
<th>${k}</th>
|
|
3200
|
-
<td>${
|
|
3509
|
+
<td>${formatTimeRange(v)}</td>
|
|
3201
3510
|
</tr>`
|
|
3202
3511
|
)}
|
|
3203
3512
|
</tbody>
|
|
@@ -3291,11 +3600,6 @@ __decorateClass([
|
|
|
3291
3600
|
RoxyPanchangTable = __decorateClass([
|
|
3292
3601
|
customElement15("roxy-panchang-table")
|
|
3293
3602
|
], RoxyPanchangTable);
|
|
3294
|
-
function formatRange(t) {
|
|
3295
|
-
if (!t) return "";
|
|
3296
|
-
if (t.start && t.end) return `${t.start} - ${t.end}`;
|
|
3297
|
-
return t.start ?? t.end ?? "";
|
|
3298
|
-
}
|
|
3299
3603
|
|
|
3300
3604
|
// packages/ui/src/components/synastry-chart.ts
|
|
3301
3605
|
import { css as css17, html as html16, LitElement as LitElement16, nothing as nothing16, svg as svg4 } from "lit";
|
|
@@ -3314,23 +3618,58 @@ var RoxySynastryChart = class extends LitElement16 {
|
|
|
3314
3618
|
render() {
|
|
3315
3619
|
if (!this.data)
|
|
3316
3620
|
return html16`<div class="roxy-empty" role="status">No synastry data</div>`;
|
|
3317
|
-
const {
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
const
|
|
3325
|
-
const
|
|
3621
|
+
const { person1, person2, compatibilityScore, analysis } = this.data;
|
|
3622
|
+
const interAspects = this.data.interAspects ?? [];
|
|
3623
|
+
const p1Planets = person1?.planets ?? [];
|
|
3624
|
+
const p2Planets = person2?.planets ?? [];
|
|
3625
|
+
const score = typeof compatibilityScore === "number" ? Math.round(compatibilityScore) : void 0;
|
|
3626
|
+
const summaryText = analysis?.overall;
|
|
3627
|
+
const strengths = analysis?.strengths ?? [];
|
|
3628
|
+
const challenges = analysis?.challenges ?? [];
|
|
3629
|
+
const hasPlanets = p1Planets.length > 0 && p2Planets.length > 0;
|
|
3630
|
+
if (!hasPlanets) {
|
|
3631
|
+
return html16`<div
|
|
3632
|
+
class="wrap"
|
|
3633
|
+
aria-label="Synastry compatibility chart"
|
|
3634
|
+
>
|
|
3635
|
+
<div class="head">
|
|
3636
|
+
<h2 class="title">Synastry</h2>
|
|
3637
|
+
${typeof score === "number" ? html16`<span class="score" aria-label=${`Score ${score} of 100`}
|
|
3638
|
+
>${score} / 100</span
|
|
3639
|
+
>` : nothing16}
|
|
3640
|
+
</div>
|
|
3641
|
+
<div class="missing-planets" role="status">
|
|
3642
|
+
Synastry response missing planet positions. Pass
|
|
3643
|
+
<code>data</code> with <code>person1.planets</code> and
|
|
3644
|
+
<code>person2.planets</code> arrays from the natal-chart endpoint, or
|
|
3645
|
+
use the <code><roxy-data></code> fallback.
|
|
3646
|
+
</div>
|
|
3647
|
+
${summaryText ? html16`<p class="summary">${summaryText}</p>` : nothing16}
|
|
3648
|
+
${interAspects.length > 0 ? this.renderAspects(interAspects) : nothing16}
|
|
3649
|
+
${strengths.length > 0 || challenges.length > 0 ? html16`<div class="lists">
|
|
3650
|
+
${strengths.length ? html16`<div>
|
|
3651
|
+
<h3>Strengths</h3>
|
|
3652
|
+
<ul>
|
|
3653
|
+
${strengths.map((s) => html16`<li>${s}</li>`)}
|
|
3654
|
+
</ul>
|
|
3655
|
+
</div>` : nothing16}
|
|
3656
|
+
${challenges.length ? html16`<div>
|
|
3657
|
+
<h3>Challenges</h3>
|
|
3658
|
+
<ul>
|
|
3659
|
+
${challenges.map((s) => html16`<li>${s}</li>`)}
|
|
3660
|
+
</ul>
|
|
3661
|
+
</div>` : nothing16}
|
|
3662
|
+
</div>` : nothing16}
|
|
3663
|
+
</div>`;
|
|
3664
|
+
}
|
|
3326
3665
|
return html16`<div
|
|
3327
3666
|
class="wrap"
|
|
3328
3667
|
aria-label="Synastry compatibility chart"
|
|
3329
3668
|
>
|
|
3330
3669
|
<div class="head">
|
|
3331
3670
|
<h2 class="title">Synastry</h2>
|
|
3332
|
-
${typeof
|
|
3333
|
-
>${
|
|
3671
|
+
${typeof score === "number" ? html16`<span class="score" aria-label=${`Score ${score} of 100`}
|
|
3672
|
+
>${score} / 100</span
|
|
3334
3673
|
>` : nothing16}
|
|
3335
3674
|
</div>
|
|
3336
3675
|
<svg
|
|
@@ -3361,34 +3700,39 @@ var RoxySynastryChart = class extends LitElement16 {
|
|
|
3361
3700
|
stroke-width="0.6"
|
|
3362
3701
|
/>
|
|
3363
3702
|
${this.renderSpokes()} ${this.renderSigns()}
|
|
3703
|
+
${this.renderInterAspectLines(p1Planets, p2Planets, interAspects)}
|
|
3364
3704
|
${this.renderRing(p1Planets, P1_R, "p1")} ${this.renderRing(p2Planets, P2_R, "p2")}
|
|
3365
3705
|
</svg>
|
|
3366
|
-
|
|
3706
|
+
<div class="legend-row">
|
|
3707
|
+
<span><span class="swatch" style="background: var(--roxy-accent)"></span>Person 1</span>
|
|
3708
|
+
<span><span class="swatch" style="background: var(--roxy-info)"></span>Person 2</span>
|
|
3709
|
+
<span><span class="swatch" style="background: var(--roxy-success)"></span>harmonious</span>
|
|
3710
|
+
<span><span class="swatch" style="background: var(--roxy-danger)"></span>challenging</span>
|
|
3711
|
+
</div>
|
|
3712
|
+
${summaryText ? html16`<p class="summary">${summaryText}</p>` : nothing16}
|
|
3367
3713
|
${interAspects.length > 0 ? this.renderAspects(interAspects) : nothing16}
|
|
3368
|
-
${
|
|
3369
|
-
${
|
|
3714
|
+
${strengths.length > 0 || challenges.length > 0 ? html16`<div class="lists">
|
|
3715
|
+
${strengths.length ? html16`<div>
|
|
3370
3716
|
<h3>Strengths</h3>
|
|
3371
3717
|
<ul>
|
|
3372
|
-
${
|
|
3718
|
+
${strengths.map((s) => html16`<li>${s}</li>`)}
|
|
3373
3719
|
</ul>
|
|
3374
3720
|
</div>` : nothing16}
|
|
3375
|
-
${
|
|
3721
|
+
${challenges.length ? html16`<div>
|
|
3376
3722
|
<h3>Challenges</h3>
|
|
3377
3723
|
<ul>
|
|
3378
|
-
${
|
|
3724
|
+
${challenges.map((s) => html16`<li>${s}</li>`)}
|
|
3379
3725
|
</ul>
|
|
3380
3726
|
</div>` : nothing16}
|
|
3381
3727
|
</div>` : nothing16}
|
|
3382
3728
|
</div>`;
|
|
3383
3729
|
}
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
if (Array.isArray(p)) return p;
|
|
3387
|
-
return Object.entries(p).map(([name, e]) => ({ ...e, name }));
|
|
3730
|
+
toAngle(longitude) {
|
|
3731
|
+
return 180 - longitude;
|
|
3388
3732
|
}
|
|
3389
3733
|
renderSpokes() {
|
|
3390
3734
|
return Array.from({ length: 12 }, (_, i) => {
|
|
3391
|
-
const angle = i * 30
|
|
3735
|
+
const angle = this.toAngle(i * 30);
|
|
3392
3736
|
const start = polarToCartesian(CENTER2, CENTER2, P2_R - 14, angle);
|
|
3393
3737
|
const end = polarToCartesian(CENTER2, CENTER2, OUTER_R2, angle);
|
|
3394
3738
|
return svg4`<line class="wheel-line" x1=${start.x} y1=${start.y} x2=${end.x} y2=${end.y} stroke-width="0.6" />`;
|
|
@@ -3410,19 +3754,43 @@ var RoxySynastryChart = class extends LitElement16 {
|
|
|
3410
3754
|
"Pisces"
|
|
3411
3755
|
];
|
|
3412
3756
|
return order.map((s, i) => {
|
|
3413
|
-
const angle = i * 30 + 15
|
|
3757
|
+
const angle = this.toAngle(i * 30 + 15);
|
|
3414
3758
|
const pos = polarToCartesian(CENTER2, CENTER2, SIGN_R2, angle);
|
|
3415
3759
|
return svg4`<text class="sign" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central">${SIGN_GLYPH[s]}</text>`;
|
|
3416
3760
|
});
|
|
3417
3761
|
}
|
|
3418
3762
|
renderRing(planets, radius, cls) {
|
|
3419
3763
|
return planets.map((p) => {
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3764
|
+
if (!Number.isFinite(p.longitude)) return nothing16;
|
|
3765
|
+
const pos = polarToCartesian(
|
|
3766
|
+
CENTER2,
|
|
3767
|
+
CENTER2,
|
|
3768
|
+
radius,
|
|
3769
|
+
this.toAngle(p.longitude)
|
|
3770
|
+
);
|
|
3771
|
+
const glyph = PLANET_GLYPH[capitalize3(p.name)] ?? p.name.slice(0, 2);
|
|
3772
|
+
return svg4`<text class=${cls} x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central"><title>${p.name}</title>${glyph}</text>`;
|
|
3773
|
+
});
|
|
3774
|
+
}
|
|
3775
|
+
renderInterAspectLines(p1, p2, aspects) {
|
|
3776
|
+
const longitudeOf = (list, name) => {
|
|
3777
|
+
const target = capitalize3(name);
|
|
3778
|
+
for (const p of list) {
|
|
3779
|
+
if (capitalize3(p.name) !== target) continue;
|
|
3780
|
+
if (typeof p.longitude === "number") return p.longitude;
|
|
3781
|
+
}
|
|
3782
|
+
return void 0;
|
|
3783
|
+
};
|
|
3784
|
+
return aspects.map((a) => {
|
|
3785
|
+
const l1 = longitudeOf(p1, a.planet1);
|
|
3786
|
+
const l2 = longitudeOf(p2, a.planet2);
|
|
3787
|
+
if (l1 === void 0 || l2 === void 0) return nothing16;
|
|
3788
|
+
const out = polarToCartesian(CENTER2, CENTER2, P1_R - 12, this.toAngle(l1));
|
|
3789
|
+
const inn = polarToCartesian(CENTER2, CENTER2, P2_R + 8, this.toAngle(l2));
|
|
3790
|
+
const aspectName = normalizeAspect2(a);
|
|
3791
|
+
const cls = ASPECT_CLASS2[aspectName] ?? "aspect-other";
|
|
3792
|
+
const orbLabel = formatNumber(a.orb, 1);
|
|
3793
|
+
return svg4`<line class=${`aspect ${cls}`} x1=${out.x} y1=${out.y} x2=${inn.x} y2=${inn.y}><title>${a.planet1} ${aspectName} ${a.planet2}${orbLabel ? ` (orb ${orbLabel}\xB0)` : ""}</title></line>`;
|
|
3426
3794
|
});
|
|
3427
3795
|
}
|
|
3428
3796
|
renderAspects(aspects) {
|
|
@@ -3437,15 +3805,13 @@ var RoxySynastryChart = class extends LitElement16 {
|
|
|
3437
3805
|
</tr>
|
|
3438
3806
|
</thead>
|
|
3439
3807
|
<tbody>
|
|
3440
|
-
${aspects.slice(0,
|
|
3808
|
+
${aspects.slice(0, 12).map(
|
|
3441
3809
|
(a) => html16`<tr>
|
|
3442
|
-
<td>${a.planet1
|
|
3443
|
-
<td>${a.planet2
|
|
3444
|
-
<td>${a
|
|
3445
|
-
<td class="orb">
|
|
3446
|
-
|
|
3447
|
-
</td>
|
|
3448
|
-
<td>${a.strength ?? ""}</td>
|
|
3810
|
+
<td>${a.planet1}</td>
|
|
3811
|
+
<td>${a.planet2}</td>
|
|
3812
|
+
<td>${normalizeAspect2(a) || ""}</td>
|
|
3813
|
+
<td class="orb">${formatNumber(a.orb, 1)}</td>
|
|
3814
|
+
<td>${formatStrength(a.strength)}</td>
|
|
3449
3815
|
</tr>`
|
|
3450
3816
|
)}
|
|
3451
3817
|
</tbody>
|
|
@@ -3506,6 +3872,42 @@ RoxySynastryChart.styles = [
|
|
|
3506
3872
|
font-weight: 600;
|
|
3507
3873
|
font-size: 13px;
|
|
3508
3874
|
}
|
|
3875
|
+
.aspect {
|
|
3876
|
+
stroke-width: 0.8;
|
|
3877
|
+
fill: none;
|
|
3878
|
+
opacity: 0.5;
|
|
3879
|
+
}
|
|
3880
|
+
.aspect-trine,
|
|
3881
|
+
.aspect-sextile {
|
|
3882
|
+
stroke: var(--roxy-success, #16a34a);
|
|
3883
|
+
}
|
|
3884
|
+
.aspect-square,
|
|
3885
|
+
.aspect-opposition {
|
|
3886
|
+
stroke: var(--roxy-danger, #dc2626);
|
|
3887
|
+
}
|
|
3888
|
+
.aspect-conjunction {
|
|
3889
|
+
stroke: var(--roxy-accent-fg, #b45309);
|
|
3890
|
+
}
|
|
3891
|
+
.aspect-other {
|
|
3892
|
+
stroke: var(--roxy-muted, #71717a);
|
|
3893
|
+
opacity: 0.35;
|
|
3894
|
+
}
|
|
3895
|
+
.legend-row {
|
|
3896
|
+
display: flex;
|
|
3897
|
+
flex-wrap: wrap;
|
|
3898
|
+
gap: var(--roxy-space-md, 1rem);
|
|
3899
|
+
font-size: var(--roxy-text-xs, 0.75rem);
|
|
3900
|
+
color: var(--roxy-muted, #71717a);
|
|
3901
|
+
margin-top: calc(var(--roxy-space-xs, 0.25rem) * -1);
|
|
3902
|
+
}
|
|
3903
|
+
.legend-row .swatch {
|
|
3904
|
+
display: inline-block;
|
|
3905
|
+
width: 8px;
|
|
3906
|
+
height: 8px;
|
|
3907
|
+
border-radius: 50%;
|
|
3908
|
+
margin-right: 4px;
|
|
3909
|
+
vertical-align: middle;
|
|
3910
|
+
}
|
|
3509
3911
|
|
|
3510
3912
|
.summary {
|
|
3511
3913
|
margin: 0;
|
|
@@ -3553,6 +3955,23 @@ RoxySynastryChart.styles = [
|
|
|
3553
3955
|
padding-left: var(--roxy-space-md, 1rem);
|
|
3554
3956
|
font-size: var(--roxy-text-sm, 0.875rem);
|
|
3555
3957
|
}
|
|
3958
|
+
|
|
3959
|
+
.missing-planets {
|
|
3960
|
+
background: color-mix(in srgb, var(--roxy-accent, #f59e0b) 8%, transparent);
|
|
3961
|
+
border: 1px solid var(--roxy-border, #e4e4e7);
|
|
3962
|
+
border-radius: var(--roxy-radius-md, 8px);
|
|
3963
|
+
padding: var(--roxy-space-md, 1rem);
|
|
3964
|
+
color: var(--roxy-fg, #0a0a0a);
|
|
3965
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
3966
|
+
line-height: 1.5;
|
|
3967
|
+
}
|
|
3968
|
+
.missing-planets code {
|
|
3969
|
+
font-family: var(--roxy-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
|
|
3970
|
+
font-size: 0.95em;
|
|
3971
|
+
background: color-mix(in srgb, var(--roxy-fg, #0a0a0a) 6%, transparent);
|
|
3972
|
+
padding: 0 4px;
|
|
3973
|
+
border-radius: 4px;
|
|
3974
|
+
}
|
|
3556
3975
|
`
|
|
3557
3976
|
];
|
|
3558
3977
|
__decorateClass([
|
|
@@ -3565,6 +3984,20 @@ function capitalize3(s) {
|
|
|
3565
3984
|
if (!s) return "";
|
|
3566
3985
|
return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
|
|
3567
3986
|
}
|
|
3987
|
+
var ASPECT_CLASS2 = {
|
|
3988
|
+
conjunction: "aspect-conjunction",
|
|
3989
|
+
sextile: "aspect-sextile",
|
|
3990
|
+
square: "aspect-square",
|
|
3991
|
+
trine: "aspect-trine",
|
|
3992
|
+
opposition: "aspect-opposition"
|
|
3993
|
+
};
|
|
3994
|
+
function normalizeAspect2(a) {
|
|
3995
|
+
return (a.type ?? "").toLowerCase().replace(/_/g, "-");
|
|
3996
|
+
}
|
|
3997
|
+
function formatStrength(s) {
|
|
3998
|
+
if (typeof s === "number") return Math.round(s).toString();
|
|
3999
|
+
return "";
|
|
4000
|
+
}
|
|
3568
4001
|
|
|
3569
4002
|
// packages/ui/src/components/tarot-card.ts
|
|
3570
4003
|
import { css as css18, html as html17, LitElement as LitElement17, nothing as nothing17 } from "lit";
|
|
@@ -3578,18 +4011,17 @@ var RoxyTarotCard = class extends LitElement17 {
|
|
|
3578
4011
|
this.flipped = !this.flipped;
|
|
3579
4012
|
};
|
|
3580
4013
|
}
|
|
3581
|
-
getCard() {
|
|
3582
|
-
if (!this.data) return null;
|
|
3583
|
-
if ("card" in this.data && this.data.card) return this.data.card;
|
|
3584
|
-
return this.data;
|
|
3585
|
-
}
|
|
3586
4014
|
render() {
|
|
3587
|
-
const
|
|
3588
|
-
if (!
|
|
4015
|
+
const d = this.data;
|
|
4016
|
+
if (!d)
|
|
3589
4017
|
return html17`<div class="roxy-empty" role="status">No tarot data</div>`;
|
|
4018
|
+
if ("card" in d) return this.renderDailyCard(d);
|
|
4019
|
+
return this.renderFullCard(d);
|
|
4020
|
+
}
|
|
4021
|
+
renderDailyCard(d) {
|
|
4022
|
+
const card = d.card;
|
|
3590
4023
|
const isReversed = this.flipped !== Boolean(card.reversed);
|
|
3591
|
-
const
|
|
3592
|
-
const dailyMessage = this.data && "dailyMessage" in this.data ? this.data.dailyMessage : void 0;
|
|
4024
|
+
const keywords = card.keywords ?? [];
|
|
3593
4025
|
return html17`<article class="card" aria-label=${card.name ?? "Tarot card"}>
|
|
3594
4026
|
<div class="image-wrap">
|
|
3595
4027
|
${card.imageUrl ? html17`<img
|
|
@@ -3614,15 +4046,60 @@ var RoxyTarotCard = class extends LitElement17 {
|
|
|
3614
4046
|
<div>
|
|
3615
4047
|
<div class="meta">
|
|
3616
4048
|
${card.arcana ? html17`${card.arcana} arcana` : nothing17}
|
|
3617
|
-
${card.number !== void 0 && card.number !== null ? html17` · ${card.number}` : nothing17}
|
|
3618
4049
|
${isReversed ? html17` · reversed` : nothing17}
|
|
3619
|
-
${card.position ? html17`<span class="position">${card.position}</span>` : nothing17}
|
|
3620
4050
|
</div>
|
|
3621
4051
|
<h2 class="title">${card.name ?? "Tarot card"}</h2>
|
|
3622
|
-
${dailyMessage ? html17`<p class="message">${dailyMessage}</p>` : nothing17}
|
|
3623
|
-
${meaning ? html17`<p>${meaning}</p>` : nothing17}
|
|
3624
|
-
${
|
|
3625
|
-
${
|
|
4052
|
+
${d.dailyMessage ? html17`<p class="message">${d.dailyMessage}</p>` : nothing17}
|
|
4053
|
+
${card.meaning ? html17`<p>${card.meaning}</p>` : nothing17}
|
|
4054
|
+
${keywords.length > 0 ? html17`<div class="chips">
|
|
4055
|
+
${keywords.map((k) => html17`<span>${k}</span>`)}
|
|
4056
|
+
</div>` : nothing17}
|
|
4057
|
+
<button
|
|
4058
|
+
class="flip"
|
|
4059
|
+
type="button"
|
|
4060
|
+
@click=${this.toggleFlip}
|
|
4061
|
+
aria-pressed=${this.flipped ? "true" : "false"}
|
|
4062
|
+
>
|
|
4063
|
+
Flip card
|
|
4064
|
+
</button>
|
|
4065
|
+
</div>
|
|
4066
|
+
</article>`;
|
|
4067
|
+
}
|
|
4068
|
+
renderFullCard(d) {
|
|
4069
|
+
const isReversed = this.flipped;
|
|
4070
|
+
const orientedMeaning = isReversed ? d.reversed : d.upright;
|
|
4071
|
+
const keywords = isReversed ? d.keywords?.reversed ?? [] : d.keywords?.upright ?? [];
|
|
4072
|
+
return html17`<article class="card" aria-label=${d.name ?? "Tarot card"}>
|
|
4073
|
+
<div class="image-wrap">
|
|
4074
|
+
${d.imageUrl ? html17`<img
|
|
4075
|
+
class=${`image ${isReversed ? "reversed" : ""}`}
|
|
4076
|
+
src=${d.imageUrl}
|
|
4077
|
+
alt=${d.name ?? "Tarot card"}
|
|
4078
|
+
tabindex="0"
|
|
4079
|
+
@click=${this.toggleFlip}
|
|
4080
|
+
@keydown=${(e) => {
|
|
4081
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
4082
|
+
e.preventDefault();
|
|
4083
|
+
this.toggleFlip();
|
|
4084
|
+
}
|
|
4085
|
+
}}
|
|
4086
|
+
/>` : html17`<div
|
|
4087
|
+
class=${`image ${isReversed ? "reversed" : ""}`}
|
|
4088
|
+
style="aspect-ratio: 0.6; display: flex; align-items: center; justify-content: center; color: var(--roxy-muted)"
|
|
4089
|
+
>
|
|
4090
|
+
${d.name ?? "?"}
|
|
4091
|
+
</div>`}
|
|
4092
|
+
</div>
|
|
4093
|
+
<div>
|
|
4094
|
+
<div class="meta">
|
|
4095
|
+
${d.arcana ? html17`${d.arcana} arcana` : nothing17}
|
|
4096
|
+
${d.number !== void 0 && d.number !== null ? html17` · ${d.number}` : nothing17}
|
|
4097
|
+
${isReversed ? html17` · reversed` : nothing17}
|
|
4098
|
+
</div>
|
|
4099
|
+
<h2 class="title">${d.name ?? "Tarot card"}</h2>
|
|
4100
|
+
${orientedMeaning?.description ? html17`<p>${orientedMeaning.description}</p>` : nothing17}
|
|
4101
|
+
${keywords.length > 0 ? html17`<div class="chips">
|
|
4102
|
+
${keywords.map((k) => html17`<span>${k}</span>`)}
|
|
3626
4103
|
</div>` : nothing17}
|
|
3627
4104
|
<button
|
|
3628
4105
|
class="flip"
|
|
@@ -3692,11 +4169,6 @@ RoxyTarotCard.styles = [
|
|
|
3692
4169
|
letter-spacing: 0.06em;
|
|
3693
4170
|
margin-bottom: var(--roxy-space-sm, 0.5rem);
|
|
3694
4171
|
}
|
|
3695
|
-
.position {
|
|
3696
|
-
color: var(--roxy-info, #0284c7);
|
|
3697
|
-
margin-left: var(--roxy-space-xs, 0.25rem);
|
|
3698
|
-
text-transform: capitalize;
|
|
3699
|
-
}
|
|
3700
4172
|
|
|
3701
4173
|
.message {
|
|
3702
4174
|
color: var(--roxy-fg, #0a0a0a);
|
|
@@ -3758,22 +4230,30 @@ var RoxyTarotSpread = class extends LitElement18 {
|
|
|
3758
4230
|
const d = this.data;
|
|
3759
4231
|
if (!d)
|
|
3760
4232
|
return html18`<div class="roxy-empty" role="status">No tarot spread</div>`;
|
|
3761
|
-
const
|
|
3762
|
-
const
|
|
3763
|
-
const
|
|
4233
|
+
const isYesNo = "answer" in d;
|
|
4234
|
+
const isDrawn = "cards" in d && !("spread" in d);
|
|
4235
|
+
const positions = isDrawn ? [] : "positions" in d ? d.positions ?? [] : [];
|
|
4236
|
+
const cards = isDrawn && "cards" in d ? d.cards : [];
|
|
4237
|
+
const answer = isYesNo ? d.answer : void 0;
|
|
4238
|
+
const strength = isYesNo ? d.strength : void 0;
|
|
4239
|
+
const spreadLabel = "spread" in d ? d.spread : this.spread.replace(/-/g, " ");
|
|
4240
|
+
const question = "question" in d ? d.question : void 0;
|
|
4241
|
+
const summary = "summary" in d ? d.summary : void 0;
|
|
4242
|
+
const yesNoInterp = isYesNo ? d.interpretation : void 0;
|
|
4243
|
+
const answerClass = answer ? answer.toLowerCase().replace(/[^a-z]/g, "") : "";
|
|
3764
4244
|
return html18`<article class="wrap" aria-label="Tarot spread">
|
|
3765
4245
|
<header class="head">
|
|
3766
|
-
<h2 class="title">${
|
|
3767
|
-
${
|
|
4246
|
+
<h2 class="title">${spreadLabel}</h2>
|
|
4247
|
+
${question ? html18`<span class="question">"${question}"</span>` : nothing18}
|
|
3768
4248
|
</header>
|
|
3769
4249
|
${isYesNo ? html18`<div>
|
|
3770
|
-
<span class=${`answer ${answerClass}`}>${
|
|
3771
|
-
${
|
|
4250
|
+
<span class=${`answer ${answerClass}`}>${answer}</span>
|
|
4251
|
+
${strength ? html18`<small> · ${strength}</small>` : nothing18}
|
|
3772
4252
|
</div>` : nothing18}
|
|
3773
4253
|
${positions.length > 0 ? html18`<div class="grid">
|
|
3774
4254
|
${positions.map(
|
|
3775
4255
|
(p) => html18`<div class="card">
|
|
3776
|
-
<p class="label">${p.
|
|
4256
|
+
<p class="label">${p.name ?? ""}</p>
|
|
3777
4257
|
<div class="image">
|
|
3778
4258
|
${p.card?.imageUrl ? html18`<img
|
|
3779
4259
|
src=${p.card.imageUrl}
|
|
@@ -3789,8 +4269,26 @@ var RoxyTarotSpread = class extends LitElement18 {
|
|
|
3789
4269
|
</div>`
|
|
3790
4270
|
)}
|
|
3791
4271
|
</div>` : nothing18}
|
|
3792
|
-
${
|
|
3793
|
-
|
|
4272
|
+
${cards.length > 0 ? html18`<div class="grid">
|
|
4273
|
+
${cards.map(
|
|
4274
|
+
(c) => html18`<div class="card">
|
|
4275
|
+
<div class="image">
|
|
4276
|
+
${c.imageUrl ? html18`<img
|
|
4277
|
+
src=${c.imageUrl}
|
|
4278
|
+
alt=${c.name ?? "tarot card"}
|
|
4279
|
+
class=${c.reversed ? "reversed" : ""}
|
|
4280
|
+
/>` : html18`${c.name ?? "?"}`}
|
|
4281
|
+
</div>
|
|
4282
|
+
<p class="name">
|
|
4283
|
+
${c.name ?? ""}
|
|
4284
|
+
${c.reversed ? html18`<small>(reversed)</small>` : nothing18}
|
|
4285
|
+
</p>
|
|
4286
|
+
${c.meaning ? html18`<p class="interp">${c.meaning}</p>` : nothing18}
|
|
4287
|
+
</div>`
|
|
4288
|
+
)}
|
|
4289
|
+
</div>` : nothing18}
|
|
4290
|
+
${summary ? html18`<p class="reading">${summary}</p>` : nothing18}
|
|
4291
|
+
${yesNoInterp ? html18`<p class="reading">${yesNoInterp}</p>` : nothing18}
|
|
3794
4292
|
</article>`;
|
|
3795
4293
|
}
|
|
3796
4294
|
};
|
|
@@ -3832,15 +4330,15 @@ RoxyTarotSpread.styles = [
|
|
|
3832
4330
|
}
|
|
3833
4331
|
.answer.yes {
|
|
3834
4332
|
background: color-mix(in srgb, var(--roxy-success, #16a34a) 16%, transparent);
|
|
3835
|
-
color: var(--roxy-success, #
|
|
4333
|
+
color: var(--roxy-success-fg, #166534);
|
|
3836
4334
|
}
|
|
3837
4335
|
.answer.no {
|
|
3838
4336
|
background: color-mix(in srgb, var(--roxy-danger, #dc2626) 16%, transparent);
|
|
3839
|
-
color: var(--roxy-danger, #
|
|
4337
|
+
color: var(--roxy-danger-fg, #991b1b);
|
|
3840
4338
|
}
|
|
3841
4339
|
.answer.maybe {
|
|
3842
4340
|
background: color-mix(in srgb, var(--roxy-warning, #ea580c) 16%, transparent);
|
|
3843
|
-
color: var(--roxy-warning, #
|
|
4341
|
+
color: var(--roxy-warning-fg, #9a3412);
|
|
3844
4342
|
}
|
|
3845
4343
|
|
|
3846
4344
|
.grid {
|
|
@@ -3981,21 +4479,12 @@ var RoxyVedicKundli = class extends LitElement19 {
|
|
|
3981
4479
|
}
|
|
3982
4480
|
buildHouses() {
|
|
3983
4481
|
if (!this.data) return [];
|
|
4482
|
+
const data = this.data;
|
|
3984
4483
|
const houses = [];
|
|
3985
|
-
if (Array.isArray(this.data.houses)) {
|
|
3986
|
-
for (const h of this.data.houses) {
|
|
3987
|
-
houses.push({
|
|
3988
|
-
house: h.house ?? h.number ?? houses.length + 1,
|
|
3989
|
-
sign: h.sign ?? "",
|
|
3990
|
-
planets: h.planets ?? []
|
|
3991
|
-
});
|
|
3992
|
-
}
|
|
3993
|
-
if (houses.length > 0) return houses;
|
|
3994
|
-
}
|
|
3995
4484
|
for (let i = 0; i < 12; i++) {
|
|
3996
4485
|
const key = RASHI_KEYS[i];
|
|
3997
|
-
const bucket =
|
|
3998
|
-
const planets = (bucket?.signs ?? []).map((p) => p.
|
|
4486
|
+
const bucket = data[key];
|
|
4487
|
+
const planets = (bucket?.signs ?? []).map((p) => p.graha).filter(Boolean);
|
|
3999
4488
|
houses.push({
|
|
4000
4489
|
house: i + 1,
|
|
4001
4490
|
sign: RASHI_TO_SIGN[key] ?? "",
|
|
@@ -4035,19 +4524,28 @@ var RoxyVedicKundli = class extends LitElement19 {
|
|
|
4035
4524
|
</svg>
|
|
4036
4525
|
</div>`;
|
|
4037
4526
|
}
|
|
4527
|
+
isLagna(h) {
|
|
4528
|
+
const ascSign = this.data?.meta?.Lagna?.rashi;
|
|
4529
|
+
if (!ascSign) return false;
|
|
4530
|
+
return ascSign.toLowerCase() === h.sign.toLowerCase();
|
|
4531
|
+
}
|
|
4038
4532
|
renderHouseGroup(h) {
|
|
4039
4533
|
const center = SOUTH_HOUSE_CENTERS[h.house];
|
|
4040
4534
|
const signPos = SOUTH_SIGN_POSITIONS[h.house];
|
|
4041
4535
|
if (!center || !signPos) return nothing19;
|
|
4042
4536
|
const signAbbr = SIGN_ABBR[h.sign] ?? "";
|
|
4043
4537
|
const planets = h.planets ?? [];
|
|
4538
|
+
const isLagna = this.isLagna(h);
|
|
4044
4539
|
return svg5`
|
|
4045
4540
|
<g>
|
|
4541
|
+
${isLagna ? svg5`<rect class="lagna-bg" x=${center.x - 30} y=${center.y - 28} width="60" height="56" rx="6" />` : nothing19}
|
|
4046
4542
|
${signAbbr ? svg5`<text class="sign-text" x=${signPos.x} y=${signPos.y} text-anchor="middle" dominant-baseline="central">${signAbbr}</text>` : nothing19}
|
|
4543
|
+
${isLagna ? svg5`<text class="lagna-marker" x=${center.x} y=${center.y - 18} text-anchor="middle" dominant-baseline="central">LAGNA</text>` : nothing19}
|
|
4047
4544
|
${planets.map((planet, j) => {
|
|
4048
4545
|
const abbr = PLANET_ABBR[capitalize4(planet)] ?? planet.slice(0, 2);
|
|
4049
4546
|
const lineHeight = 13;
|
|
4050
|
-
const
|
|
4547
|
+
const baseY = isLagna ? center.y + 8 : center.y;
|
|
4548
|
+
const startY = baseY - (planets.length - 1) * lineHeight / 2;
|
|
4051
4549
|
const yPos = startY + j * lineHeight;
|
|
4052
4550
|
return svg5`<text class="planet-text" x=${center.x} y=${yPos} text-anchor="middle" dominant-baseline="central">${abbr}</text>`;
|
|
4053
4551
|
})}
|
|
@@ -4089,6 +4587,18 @@ RoxyVedicKundli.styles = [
|
|
|
4089
4587
|
font-weight: 600;
|
|
4090
4588
|
font-family: var(--roxy-font-sans);
|
|
4091
4589
|
}
|
|
4590
|
+
.lagna-marker {
|
|
4591
|
+
fill: var(--roxy-accent-fg, #b45309);
|
|
4592
|
+
font-size: 8px;
|
|
4593
|
+
font-weight: 700;
|
|
4594
|
+
font-family: var(--roxy-font-sans);
|
|
4595
|
+
letter-spacing: 0.05em;
|
|
4596
|
+
}
|
|
4597
|
+
.lagna-bg {
|
|
4598
|
+
fill: color-mix(in srgb, var(--roxy-accent, #f59e0b) 12%, transparent);
|
|
4599
|
+
stroke: color-mix(in srgb, var(--roxy-accent, #f59e0b) 45%, transparent);
|
|
4600
|
+
stroke-width: 0.8;
|
|
4601
|
+
}
|
|
4092
4602
|
`
|
|
4093
4603
|
];
|
|
4094
4604
|
__decorateClass([
|
|
@@ -4105,30 +4615,311 @@ function capitalize4(s) {
|
|
|
4105
4615
|
return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
|
|
4106
4616
|
}
|
|
4107
4617
|
|
|
4108
|
-
// packages/ui/src/
|
|
4109
|
-
var
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4618
|
+
// packages/ui/src/manifest.ts
|
|
4619
|
+
var ROXY_COMPONENTS = [
|
|
4620
|
+
{
|
|
4621
|
+
pascal: "RoxyNatalChart",
|
|
4622
|
+
tag: "roxy-natal-chart",
|
|
4623
|
+
slug: "natal-chart",
|
|
4624
|
+
domain: "astrology",
|
|
4625
|
+
heading: "Natal chart",
|
|
4626
|
+
endpoints: ["astrology.generateNatalChart"],
|
|
4627
|
+
description: "Western natal chart wheel for /astrology/natal-chart responses",
|
|
4628
|
+
docsLabel: "Western",
|
|
4629
|
+
endpointLabel: "POST /astrology/natal-chart",
|
|
4630
|
+
docsSummary: "Natal chart wheel with planet glyphs and aspect lines",
|
|
4631
|
+
topic: "Astrology"
|
|
4632
|
+
},
|
|
4633
|
+
{
|
|
4634
|
+
pascal: "RoxyHoroscopeCard",
|
|
4635
|
+
tag: "roxy-horoscope-card",
|
|
4636
|
+
slug: "horoscope-card",
|
|
4637
|
+
domain: "astrology",
|
|
4638
|
+
heading: "Daily horoscope",
|
|
4639
|
+
endpoints: [
|
|
4640
|
+
"astrology.getDailyHoroscope",
|
|
4641
|
+
"astrology.getWeeklyHoroscope",
|
|
4642
|
+
"astrology.getMonthlyHoroscope"
|
|
4643
|
+
],
|
|
4644
|
+
description: "Daily, weekly, or monthly horoscope card for /astrology/horoscope/...",
|
|
4645
|
+
docsLabel: "Western",
|
|
4646
|
+
endpointLabel: "GET /astrology/horoscope/{sign}/{daily,weekly,monthly}",
|
|
4647
|
+
docsSummary: "Daily, weekly, or monthly horoscope card",
|
|
4648
|
+
topic: "Astrology"
|
|
4649
|
+
},
|
|
4650
|
+
{
|
|
4651
|
+
pascal: "RoxySynastryChart",
|
|
4652
|
+
tag: "roxy-synastry-chart",
|
|
4653
|
+
slug: "synastry-chart",
|
|
4654
|
+
domain: "astrology",
|
|
4655
|
+
heading: "Synastry",
|
|
4656
|
+
endpoints: ["astrology.calculateSynastry"],
|
|
4657
|
+
description: "Dual-wheel synastry chart with inter-aspects table",
|
|
4658
|
+
docsLabel: "Western",
|
|
4659
|
+
endpointLabel: "POST /astrology/synastry",
|
|
4660
|
+
docsSummary: "Dual-wheel synastry with inter-aspects table",
|
|
4661
|
+
topic: "Astrology"
|
|
4662
|
+
},
|
|
4663
|
+
{
|
|
4664
|
+
pascal: "RoxyCompatibilityCard",
|
|
4665
|
+
tag: "roxy-compatibility-card",
|
|
4666
|
+
slug: "compatibility-card",
|
|
4667
|
+
domain: "astrology",
|
|
4668
|
+
heading: "Compatibility score",
|
|
4669
|
+
endpoints: [
|
|
4670
|
+
"astrology.calculateCompatibility",
|
|
4671
|
+
"numerology.calculateNumCompatibility",
|
|
4672
|
+
"biorhythm.calculateBioCompatibility"
|
|
4673
|
+
],
|
|
4674
|
+
description: "Cross-domain compatibility score card",
|
|
4675
|
+
docsLabel: "Cross",
|
|
4676
|
+
endpointLabel: "POST /astrology/compatibility-score, /numerology/compatibility, /biorhythm/compatibility",
|
|
4677
|
+
docsSummary: "Score card with category breakdown",
|
|
4678
|
+
topic: "Astrology"
|
|
4679
|
+
},
|
|
4680
|
+
{
|
|
4681
|
+
pascal: "RoxyMoonPhase",
|
|
4682
|
+
tag: "roxy-moon-phase",
|
|
4683
|
+
slug: "moon-phase",
|
|
4684
|
+
domain: "astrology",
|
|
4685
|
+
heading: "Moon phase",
|
|
4686
|
+
endpoints: [
|
|
4687
|
+
"astrology.getCurrentMoonPhase",
|
|
4688
|
+
"astrology.getUpcomingMoonPhases",
|
|
4689
|
+
"astrology.getMoonCalendar"
|
|
4690
|
+
],
|
|
4691
|
+
description: "Moon phase card and calendar",
|
|
4692
|
+
docsLabel: "Western",
|
|
4693
|
+
endpointLabel: "GET /astrology/moon-phase/{current,upcoming,calendar/...}",
|
|
4694
|
+
docsSummary: "Moon phase card and calendar",
|
|
4695
|
+
topic: "Astrology"
|
|
4696
|
+
},
|
|
4697
|
+
{
|
|
4698
|
+
pascal: "RoxyVedicKundli",
|
|
4699
|
+
tag: "roxy-vedic-kundli",
|
|
4700
|
+
slug: "vedic-kundli",
|
|
4701
|
+
domain: "vedic",
|
|
4702
|
+
heading: "Vedic kundli",
|
|
4703
|
+
endpoints: ["vedicAstrology.generateBirthChart"],
|
|
4704
|
+
description: "South or North Indian Vedic kundli for /vedic-astrology/birth-chart",
|
|
4705
|
+
docsLabel: "Vedic",
|
|
4706
|
+
endpointLabel: "POST /vedic-astrology/birth-chart",
|
|
4707
|
+
docsSummary: "South or North Indian kundli",
|
|
4708
|
+
topic: "Vedic"
|
|
4709
|
+
},
|
|
4710
|
+
{
|
|
4711
|
+
pascal: "RoxyPanchangTable",
|
|
4712
|
+
tag: "roxy-panchang-table",
|
|
4713
|
+
slug: "panchang-table",
|
|
4714
|
+
domain: "vedic",
|
|
4715
|
+
heading: "Panchang",
|
|
4716
|
+
endpoints: [
|
|
4717
|
+
"vedicAstrology.getBasicPanchang",
|
|
4718
|
+
"vedicAstrology.getDetailedPanchang"
|
|
4719
|
+
],
|
|
4720
|
+
description: "Panchang muhurta table with auspicious and inauspicious periods",
|
|
4721
|
+
docsLabel: "Vedic",
|
|
4722
|
+
endpointLabel: "POST /vedic-astrology/panchang/{basic,detailed}",
|
|
4723
|
+
docsSummary: "15+ muhurtas in detailed mode",
|
|
4724
|
+
topic: "Vedic"
|
|
4725
|
+
},
|
|
4726
|
+
{
|
|
4727
|
+
pascal: "RoxyDashaTimeline",
|
|
4728
|
+
tag: "roxy-dasha-timeline",
|
|
4729
|
+
slug: "dasha-timeline",
|
|
4730
|
+
domain: "vedic",
|
|
4731
|
+
heading: "Vimshottari dasha",
|
|
4732
|
+
endpoints: [
|
|
4733
|
+
"vedicAstrology.getCurrentDasha",
|
|
4734
|
+
"vedicAstrology.getMajorDashas",
|
|
4735
|
+
"vedicAstrology.getSubDashas"
|
|
4736
|
+
],
|
|
4737
|
+
description: "Vimshottari dasha timeline with active mahadasha highlighted",
|
|
4738
|
+
docsLabel: "Vedic",
|
|
4739
|
+
endpointLabel: "POST /vedic-astrology/dasha/{current,major,sub/...}",
|
|
4740
|
+
docsSummary: "Vimshottari mahadasha + antardasha + pratyantardasha",
|
|
4741
|
+
topic: "Vedic"
|
|
4742
|
+
},
|
|
4743
|
+
{
|
|
4744
|
+
pascal: "RoxyDoshaCard",
|
|
4745
|
+
tag: "roxy-dosha-card",
|
|
4746
|
+
slug: "dosha-card",
|
|
4747
|
+
domain: "vedic",
|
|
4748
|
+
heading: "Manglik dosha",
|
|
4749
|
+
endpoints: [
|
|
4750
|
+
"vedicAstrology.checkManglikDosha",
|
|
4751
|
+
"vedicAstrology.checkKalsarpaDosha",
|
|
4752
|
+
"vedicAstrology.checkSadhesati"
|
|
4753
|
+
],
|
|
4754
|
+
description: "Manglik, Kaal Sarp, or Sade Sati presence card",
|
|
4755
|
+
docsLabel: "Vedic",
|
|
4756
|
+
endpointLabel: "POST /vedic-astrology/dosha/{manglik,kalsarpa,sadhesati}",
|
|
4757
|
+
docsSummary: "Presence, severity, remedies, scoped effects",
|
|
4758
|
+
topic: "Vedic"
|
|
4759
|
+
},
|
|
4760
|
+
{
|
|
4761
|
+
pascal: "RoxyGunaMilan",
|
|
4762
|
+
tag: "roxy-guna-milan",
|
|
4763
|
+
slug: "guna-milan",
|
|
4764
|
+
domain: "vedic",
|
|
4765
|
+
heading: "Guna milan",
|
|
4766
|
+
endpoints: ["vedicAstrology.calculateGunMilan"],
|
|
4767
|
+
description: "36-point Ashtakoota matrimonial compatibility breakdown",
|
|
4768
|
+
docsLabel: "Vedic",
|
|
4769
|
+
endpointLabel: "POST /vedic-astrology/compatibility",
|
|
4770
|
+
docsSummary: "36-point Ashtakoota with eight sub-scores",
|
|
4771
|
+
topic: "Vedic"
|
|
4772
|
+
},
|
|
4773
|
+
{
|
|
4774
|
+
pascal: "RoxyKpPlanetsTable",
|
|
4775
|
+
tag: "roxy-kp-planets-table",
|
|
4776
|
+
slug: "kp-planets-table",
|
|
4777
|
+
domain: "vedic",
|
|
4778
|
+
heading: "KP planets",
|
|
4779
|
+
endpoints: ["vedicAstrology.getKpPlanets"],
|
|
4780
|
+
description: "KP planets table with sub-lord and sub-sub-lord columns",
|
|
4781
|
+
docsLabel: "Vedic (KP)",
|
|
4782
|
+
endpointLabel: "POST /vedic-astrology/kp/planets",
|
|
4783
|
+
docsSummary: "Sub-lord and sub-sub-lord columns",
|
|
4784
|
+
topic: "Vedic"
|
|
4785
|
+
},
|
|
4786
|
+
{
|
|
4787
|
+
pascal: "RoxyNumerologyCard",
|
|
4788
|
+
tag: "roxy-numerology-card",
|
|
4789
|
+
slug: "numerology-card",
|
|
4790
|
+
domain: "numerology",
|
|
4791
|
+
heading: "Life path number",
|
|
4792
|
+
endpoints: [
|
|
4793
|
+
"numerology.calculateLifePath",
|
|
4794
|
+
"numerology.calculateExpression",
|
|
4795
|
+
"numerology.calculatePersonalYear",
|
|
4796
|
+
"numerology.generateNumerologyChart"
|
|
4797
|
+
],
|
|
4798
|
+
description: "Numerology card for life path, expression, personal year, or full chart",
|
|
4799
|
+
docsLabel: "Numerology",
|
|
4800
|
+
endpointLabel: "POST /numerology/{life-path,expression,personal-year,chart}",
|
|
4801
|
+
docsSummary: "Life path, expression, personal year, full chart",
|
|
4802
|
+
topic: "Numerology"
|
|
4803
|
+
},
|
|
4804
|
+
{
|
|
4805
|
+
pascal: "RoxyTarotCard",
|
|
4806
|
+
tag: "roxy-tarot-card",
|
|
4807
|
+
slug: "tarot-card",
|
|
4808
|
+
domain: "tarot",
|
|
4809
|
+
heading: "Daily tarot card",
|
|
4810
|
+
endpoints: ["tarot.getCard", "tarot.getDailyCard"],
|
|
4811
|
+
description: "Single tarot card with upright/reversed flip animation",
|
|
4812
|
+
docsLabel: "Tarot",
|
|
4813
|
+
endpointLabel: "GET /tarot/cards/{id}, POST /tarot/daily",
|
|
4814
|
+
docsSummary: "Single card with upright and reversed flip",
|
|
4815
|
+
topic: "Tarot"
|
|
4816
|
+
},
|
|
4817
|
+
{
|
|
4818
|
+
pascal: "RoxyTarotSpread",
|
|
4819
|
+
tag: "roxy-tarot-spread",
|
|
4820
|
+
slug: "tarot-spread",
|
|
4821
|
+
domain: "tarot",
|
|
4822
|
+
heading: "Three-card spread",
|
|
4823
|
+
endpoints: [
|
|
4824
|
+
"tarot.castThreeCard",
|
|
4825
|
+
"tarot.castCelticCross",
|
|
4826
|
+
"tarot.castLoveSpread",
|
|
4827
|
+
"tarot.castYesNo",
|
|
4828
|
+
"tarot.drawCards"
|
|
4829
|
+
],
|
|
4830
|
+
description: "Tarot spread renderer for three-card, Celtic Cross, love, or yes/no",
|
|
4831
|
+
docsLabel: "Tarot",
|
|
4832
|
+
endpointLabel: "POST /tarot/spreads/{three-card,celtic-cross,love}, /tarot/yes-no, /tarot/draw",
|
|
4833
|
+
docsSummary: "Spreads with positions and reading",
|
|
4834
|
+
topic: "Tarot"
|
|
4835
|
+
},
|
|
4836
|
+
{
|
|
4837
|
+
pascal: "RoxyBiorhythmChart",
|
|
4838
|
+
tag: "roxy-biorhythm-chart",
|
|
4839
|
+
slug: "biorhythm-chart",
|
|
4840
|
+
domain: "biorhythm",
|
|
4841
|
+
heading: "Daily biorhythm",
|
|
4842
|
+
endpoints: [
|
|
4843
|
+
"biorhythm.getDailyBiorhythm",
|
|
4844
|
+
"biorhythm.getForecast",
|
|
4845
|
+
"biorhythm.getCriticalDays"
|
|
4846
|
+
],
|
|
4847
|
+
description: "Daily biorhythm bars or multi-day forecast cycle lines",
|
|
4848
|
+
docsLabel: "Biorhythm",
|
|
4849
|
+
endpointLabel: "POST /biorhythm/{daily,forecast,critical-days}",
|
|
4850
|
+
docsSummary: "Daily bars, forecast cycle lines, critical days",
|
|
4851
|
+
topic: "Biorhythm"
|
|
4852
|
+
},
|
|
4853
|
+
{
|
|
4854
|
+
pascal: "RoxyHexagram",
|
|
4855
|
+
tag: "roxy-hexagram",
|
|
4856
|
+
slug: "hexagram",
|
|
4857
|
+
domain: "iching",
|
|
4858
|
+
heading: "I Ching hexagram",
|
|
4859
|
+
endpoints: [
|
|
4860
|
+
"iching.getHexagram",
|
|
4861
|
+
"iching.castReading",
|
|
4862
|
+
"iching.getDailyHexagram",
|
|
4863
|
+
"iching.castDailyReading",
|
|
4864
|
+
"iching.getRandomHexagram"
|
|
4865
|
+
],
|
|
4866
|
+
description: "I Ching hexagram with trigram glyphs, judgment, image, and changing lines",
|
|
4867
|
+
docsLabel: "I Ching",
|
|
4868
|
+
endpointLabel: "GET /iching/hexagrams/{number}, /iching/cast, POST /iching/daily, /iching/daily/cast",
|
|
4869
|
+
docsSummary: "Hexagram with trigrams, judgment, image, changing lines",
|
|
4870
|
+
topic: "I Ching"
|
|
4871
|
+
},
|
|
4872
|
+
{
|
|
4873
|
+
pascal: "RoxyEndpointForm",
|
|
4874
|
+
tag: "roxy-endpoint-form",
|
|
4875
|
+
slug: "endpoint-form",
|
|
4876
|
+
domain: "utility",
|
|
4877
|
+
heading: "Schema-driven form",
|
|
4878
|
+
endpoints: [],
|
|
4879
|
+
description: "Schema-driven form that emits roxy-submit with a validated payload",
|
|
4880
|
+
docsLabel: "Helper",
|
|
4881
|
+
endpointLabel: "Any endpoint via x-roxy-ui hints",
|
|
4882
|
+
docsSummary: "Schema-driven form, emits roxy-submit",
|
|
4883
|
+
topic: "Helpers",
|
|
4884
|
+
selfFetching: true
|
|
4885
|
+
},
|
|
4886
|
+
{
|
|
4887
|
+
pascal: "RoxyLocationSearch",
|
|
4888
|
+
tag: "roxy-location-search",
|
|
4889
|
+
slug: "location-search",
|
|
4890
|
+
domain: "utility",
|
|
4891
|
+
heading: "City search",
|
|
4892
|
+
endpoints: ["location.searchCities"],
|
|
4893
|
+
description: "City search input with debounced /location/search calls",
|
|
4894
|
+
docsLabel: "Helper",
|
|
4895
|
+
endpointLabel: "GET /location/search",
|
|
4896
|
+
docsSummary: "Debounced city search input, emits roxy-location-select",
|
|
4897
|
+
topic: "Helpers",
|
|
4898
|
+
selfFetching: true
|
|
4899
|
+
},
|
|
4900
|
+
{
|
|
4901
|
+
pascal: "RoxyData",
|
|
4902
|
+
tag: "roxy-data",
|
|
4903
|
+
slug: "data",
|
|
4904
|
+
domain: "utility",
|
|
4905
|
+
heading: "Generic renderer",
|
|
4906
|
+
endpoints: [],
|
|
4907
|
+
description: "Generic fallback renderer for any OpenAPI response shape",
|
|
4908
|
+
docsLabel: "Helper",
|
|
4909
|
+
endpointLabel: "Any response shape",
|
|
4910
|
+
docsSummary: "Generic fallback renderer for unknown shapes",
|
|
4911
|
+
topic: "Helpers",
|
|
4912
|
+
selfFetching: true
|
|
4913
|
+
}
|
|
4130
4914
|
];
|
|
4915
|
+
|
|
4916
|
+
// packages/ui/src/version.ts
|
|
4917
|
+
var ROXY_UI_VERSION = "0.1.3";
|
|
4918
|
+
|
|
4919
|
+
// packages/ui/src/index.ts
|
|
4920
|
+
var ROXY_UI_COMPONENTS = ROXY_COMPONENTS.map((c) => c.slug);
|
|
4131
4921
|
export {
|
|
4922
|
+
ROXY_COMPONENTS,
|
|
4132
4923
|
ROXY_UI_COMPONENTS,
|
|
4133
4924
|
ROXY_UI_VERSION,
|
|
4134
4925
|
RoxyBiorhythmChart,
|