@roxyapi/ui 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +6 -0
- package/README.md +327 -14
- package/THEMING.md +24 -7
- package/dist/cdn/components/ashtakavarga-grid.js +349 -0
- package/dist/cdn/components/ashtakavarga-grid.js.map +7 -0
- package/dist/cdn/components/biorhythm-chart.js +15 -22
- package/dist/cdn/components/biorhythm-chart.js.map +3 -3
- package/dist/cdn/components/choghadiya-grid.js +239 -0
- package/dist/cdn/components/choghadiya-grid.js.map +7 -0
- package/dist/cdn/components/compatibility-card.js +36 -34
- package/dist/cdn/components/compatibility-card.js.map +4 -4
- package/dist/cdn/components/dasha-timeline.js +35 -39
- package/dist/cdn/components/dasha-timeline.js.map +4 -4
- package/dist/cdn/components/data.js +9 -9
- package/dist/cdn/components/data.js.map +4 -4
- package/dist/cdn/components/divisional-chart.js +279 -0
- package/dist/cdn/components/divisional-chart.js.map +7 -0
- package/dist/cdn/components/dosha-card.js +49 -49
- package/dist/cdn/components/dosha-card.js.map +3 -3
- package/dist/cdn/components/endpoint-form.js +47 -28
- package/dist/cdn/components/endpoint-form.js.map +4 -4
- package/dist/cdn/components/guna-milan.js +66 -24
- package/dist/cdn/components/guna-milan.js.map +4 -4
- package/dist/cdn/components/hexagram.js +26 -26
- package/dist/cdn/components/hexagram.js.map +3 -3
- package/dist/cdn/components/horoscope-card.js +47 -40
- package/dist/cdn/components/horoscope-card.js.map +4 -4
- package/dist/cdn/components/kp-planets-table.js +10 -10
- package/dist/cdn/components/kp-planets-table.js.map +4 -4
- package/dist/cdn/components/location-search.js +6 -6
- package/dist/cdn/components/location-search.js.map +3 -3
- package/dist/cdn/components/moon-phase.js +18 -18
- package/dist/cdn/components/moon-phase.js.map +4 -4
- package/dist/cdn/components/natal-chart.js +240 -24
- package/dist/cdn/components/natal-chart.js.map +4 -4
- package/dist/cdn/components/numerology-card.js +40 -31
- package/dist/cdn/components/numerology-card.js.map +4 -4
- package/dist/cdn/components/panchang-table.js +30 -30
- package/dist/cdn/components/panchang-table.js.map +4 -4
- package/dist/cdn/components/shadbala-table.js +312 -0
- package/dist/cdn/components/shadbala-table.js.map +7 -0
- package/dist/cdn/components/synastry-chart.js +129 -39
- package/dist/cdn/components/synastry-chart.js.map +4 -4
- package/dist/cdn/components/tarot-card.js +49 -20
- package/dist/cdn/components/tarot-card.js.map +3 -3
- package/dist/cdn/components/tarot-spread.js +43 -27
- package/dist/cdn/components/tarot-spread.js.map +3 -3
- package/dist/cdn/components/transits-table.js +391 -0
- package/dist/cdn/components/transits-table.js.map +7 -0
- package/dist/cdn/components/vedic-kundli.js +63 -27
- package/dist/cdn/components/vedic-kundli.js.map +4 -4
- package/dist/cdn/components/yoga-list.js +334 -0
- package/dist/cdn/components/yoga-list.js.map +7 -0
- package/dist/cdn/roxy-ui.js +2104 -544
- package/dist/cdn/roxy-ui.js.map +4 -4
- package/dist/components/ashtakavarga-grid.d.ts +26 -0
- package/dist/components/ashtakavarga-grid.d.ts.map +1 -0
- package/dist/components/ashtakavarga-grid.js +457 -0
- package/dist/components/ashtakavarga-grid.js.map +7 -0
- package/dist/components/biorhythm-chart.d.ts +2 -46
- package/dist/components/biorhythm-chart.d.ts.map +1 -1
- package/dist/components/biorhythm-chart.js +24 -23
- package/dist/components/biorhythm-chart.js.map +2 -2
- package/dist/components/choghadiya-grid.d.ts +19 -0
- package/dist/components/choghadiya-grid.d.ts.map +1 -0
- package/dist/components/choghadiya-grid.js +304 -0
- package/dist/components/choghadiya-grid.js.map +7 -0
- package/dist/components/compatibility-card.d.ts +2 -27
- package/dist/components/compatibility-card.d.ts.map +1 -1
- package/dist/components/compatibility-card.js +50 -29
- package/dist/components/compatibility-card.js.map +3 -3
- package/dist/components/dasha-timeline.d.ts +2 -31
- package/dist/components/dasha-timeline.d.ts.map +1 -1
- package/dist/components/dasha-timeline.js +32 -30
- package/dist/components/dasha-timeline.js.map +3 -3
- package/dist/components/data.d.ts +11 -7
- package/dist/components/data.d.ts.map +1 -1
- package/dist/components/data.js +16 -6
- package/dist/components/data.js.map +3 -3
- package/dist/components/divisional-chart.d.ts +20 -0
- package/dist/components/divisional-chart.d.ts.map +1 -0
- package/dist/components/divisional-chart.js +471 -0
- package/dist/components/divisional-chart.js.map +7 -0
- package/dist/components/dosha-card.d.ts +2 -16
- package/dist/components/dosha-card.d.ts.map +1 -1
- package/dist/components/dosha-card.js +45 -43
- package/dist/components/dosha-card.js.map +2 -2
- package/dist/components/endpoint-form.d.ts +2 -0
- package/dist/components/endpoint-form.d.ts.map +1 -1
- package/dist/components/endpoint-form.js +71 -11
- package/dist/components/endpoint-form.js.map +3 -3
- package/dist/components/guna-milan.d.ts +2 -20
- package/dist/components/guna-milan.d.ts.map +1 -1
- package/dist/components/guna-milan.js +79 -20
- package/dist/components/guna-milan.js.map +4 -4
- package/dist/components/hexagram.d.ts +3 -27
- package/dist/components/hexagram.d.ts.map +1 -1
- package/dist/components/hexagram.js +48 -15
- package/dist/components/hexagram.js.map +2 -2
- package/dist/components/horoscope-card.d.ts +2 -20
- package/dist/components/horoscope-card.d.ts.map +1 -1
- package/dist/components/horoscope-card.js +54 -18
- package/dist/components/horoscope-card.js.map +3 -3
- package/dist/components/kp-planets-table.d.ts +2 -21
- package/dist/components/kp-planets-table.d.ts.map +1 -1
- package/dist/components/kp-planets-table.js +10 -4
- package/dist/components/kp-planets-table.js.map +3 -3
- package/dist/components/location-search.d.ts +5 -14
- package/dist/components/location-search.d.ts.map +1 -1
- package/dist/components/location-search.js +45 -5
- package/dist/components/location-search.js.map +2 -2
- package/dist/components/moon-phase.d.ts +4 -21
- package/dist/components/moon-phase.d.ts.map +1 -1
- package/dist/components/moon-phase.js +34 -4
- package/dist/components/moon-phase.js.map +3 -3
- package/dist/components/natal-chart.d.ts +9 -43
- package/dist/components/natal-chart.d.ts.map +1 -1
- package/dist/components/natal-chart.js +346 -79
- package/dist/components/natal-chart.js.map +3 -3
- package/dist/components/numerology-card.d.ts +5 -37
- package/dist/components/numerology-card.d.ts.map +1 -1
- package/dist/components/numerology-card.js +58 -30
- package/dist/components/numerology-card.js.map +3 -3
- package/dist/components/panchang-table.d.ts +3 -62
- package/dist/components/panchang-table.d.ts.map +1 -1
- package/dist/components/panchang-table.js +62 -32
- package/dist/components/panchang-table.js.map +3 -3
- package/dist/components/shadbala-table.d.ts +18 -0
- package/dist/components/shadbala-table.d.ts.map +1 -0
- package/dist/components/shadbala-table.js +400 -0
- package/dist/components/shadbala-table.js.map +7 -0
- package/dist/components/synastry-chart.d.ts +9 -28
- package/dist/components/synastry-chart.d.ts.map +1 -1
- package/dist/components/synastry-chart.js +201 -56
- package/dist/components/synastry-chart.js.map +3 -3
- package/dist/components/tarot-card.d.ts +5 -29
- package/dist/components/tarot-card.d.ts.map +1 -1
- package/dist/components/tarot-card.js +59 -20
- package/dist/components/tarot-card.js.map +2 -2
- package/dist/components/tarot-spread.d.ts +2 -24
- package/dist/components/tarot-spread.d.ts.map +1 -1
- package/dist/components/tarot-spread.js +39 -13
- package/dist/components/tarot-spread.js.map +2 -2
- package/dist/components/transits-table.d.ts +21 -0
- package/dist/components/transits-table.d.ts.map +1 -0
- package/dist/components/transits-table.js +515 -0
- package/dist/components/transits-table.js.map +7 -0
- package/dist/components/vedic-kundli.d.ts +5 -28
- package/dist/components/vedic-kundli.d.ts.map +1 -1
- package/dist/components/vedic-kundli.js +147 -83
- package/dist/components/vedic-kundli.js.map +3 -3
- package/dist/components/yoga-list.d.ts +29 -0
- package/dist/components/yoga-list.d.ts.map +1 -0
- package/dist/components/yoga-list.js +389 -0
- package/dist/components/yoga-list.js.map +7 -0
- package/dist/index.cjs +3693 -1180
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3709 -1196
- package/dist/index.js.map +4 -4
- package/dist/manifest.d.ts +43 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.json +7 -2
- package/dist/styles/tokens.css +73 -1
- package/dist/tokens/index.d.ts +6 -0
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/types.gen.d.ts +27811 -0
- package/dist/types/types.gen.d.ts.map +1 -0
- package/dist/utils/debounce.d.ts +9 -1
- package/dist/utils/debounce.d.ts.map +1 -1
- package/dist/utils/format.d.ts +29 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/kundli-render.d.ts +63 -0
- package/dist/utils/kundli-render.d.ts.map +1 -0
- package/dist/utils/string.d.ts +14 -0
- package/dist/utils/string.d.ts.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +7 -1
- package/src/components/ashtakavarga-grid.ts +354 -0
- package/src/components/biorhythm-chart.ts +39 -84
- package/src/components/choghadiya-grid.ts +185 -0
- package/src/components/compatibility-card.ts +85 -52
- package/src/components/dasha-timeline.ts +55 -73
- package/src/components/data.ts +28 -16
- package/src/components/divisional-chart.ts +214 -0
- package/src/components/dosha-card.ts +72 -68
- package/src/components/endpoint-form.ts +80 -18
- package/src/components/guna-milan.ts +87 -47
- package/src/components/hexagram.ts +53 -43
- package/src/components/horoscope-card.ts +59 -43
- package/src/components/kp-planets-table.ts +8 -27
- package/src/components/location-search.ts +47 -23
- package/src/components/moon-phase.ts +28 -25
- package/src/components/natal-chart.ts +364 -110
- package/src/components/numerology-card.ts +86 -84
- package/src/components/panchang-table.ts +40 -78
- package/src/components/shadbala-table.ts +286 -0
- package/src/components/synastry-chart.ts +213 -97
- package/src/components/tarot-card.ts +76 -62
- package/src/components/tarot-spread.ts +72 -45
- package/src/components/transits-table.ts +350 -0
- package/src/components/vedic-kundli.ts +59 -173
- package/src/components/yoga-list.ts +328 -0
- package/src/index.ts +18 -26
- package/src/manifest.ts +340 -0
- package/src/styles/tokens.css +73 -1
- package/src/tokens/index.ts +14 -0
- package/src/types/types.gen.ts +3 -3
- package/src/utils/debounce.ts +23 -4
- package/src/utils/format.ts +75 -0
- package/src/utils/kundli-render.ts +197 -0
- package/src/utils/string.ts +23 -0
- package/src/version.ts +2 -0
- package/dist/utils/motion.d.ts +0 -13
- package/dist/utils/motion.d.ts.map +0 -1
- package/src/utils/motion.ts +0 -18
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { css, html, LitElement, nothing } from 'lit';
|
|
2
2
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
3
3
|
import { baseStyles } from '../utils/base-styles.js';
|
|
4
|
+
import { humanize } from '../utils/string.js';
|
|
4
5
|
|
|
5
6
|
interface OpenApiSchemaRef {
|
|
6
7
|
$ref?: string;
|
|
@@ -31,6 +32,33 @@ interface FieldDef {
|
|
|
31
32
|
default?: unknown;
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
interface OpenApiDoc {
|
|
36
|
+
paths?: Record<string, Record<string, unknown>>;
|
|
37
|
+
components?: { schemas?: Record<string, OpenApiSchema> };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const specCache = new Map<string, Promise<OpenApiDoc>>();
|
|
41
|
+
|
|
42
|
+
async function loadSpec(url: string): Promise<OpenApiDoc> {
|
|
43
|
+
let pending = specCache.get(url);
|
|
44
|
+
if (!pending) {
|
|
45
|
+
pending = fetch(url)
|
|
46
|
+
.then(async (res) => {
|
|
47
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
48
|
+
return (await res.json()) as OpenApiDoc;
|
|
49
|
+
})
|
|
50
|
+
.catch((err) => {
|
|
51
|
+
// Evict the rejected promise BEFORE rethrowing so subsequent
|
|
52
|
+
// callers (the user clicking Retry, a remount) hit the network
|
|
53
|
+
// again instead of replaying the cached failure forever.
|
|
54
|
+
specCache.delete(url);
|
|
55
|
+
throw err;
|
|
56
|
+
});
|
|
57
|
+
specCache.set(url, pending);
|
|
58
|
+
}
|
|
59
|
+
return pending;
|
|
60
|
+
}
|
|
61
|
+
|
|
34
62
|
/**
|
|
35
63
|
* Schema-driven form. Pass `endpoint` (e.g. "vedic-astrology/birth-chart").
|
|
36
64
|
* The form introspects the cached OpenAPI spec, slots a roxy-location-search
|
|
@@ -64,22 +92,27 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
64
92
|
.fields {
|
|
65
93
|
display: grid;
|
|
66
94
|
grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
|
|
95
|
+
align-items: start;
|
|
67
96
|
gap: var(--roxy-space-md, 1rem);
|
|
68
97
|
}
|
|
69
98
|
.field {
|
|
70
|
-
display:
|
|
99
|
+
display: flex;
|
|
100
|
+
flex-direction: column;
|
|
71
101
|
gap: var(--roxy-space-xs, 0.25rem);
|
|
102
|
+
min-width: 0;
|
|
72
103
|
}
|
|
73
104
|
label {
|
|
74
105
|
font-size: var(--roxy-text-sm, 0.875rem);
|
|
75
106
|
color: var(--roxy-secondary, #475569);
|
|
76
107
|
}
|
|
77
108
|
label .req {
|
|
78
|
-
color: var(--roxy-danger, #
|
|
109
|
+
color: var(--roxy-danger-fg, #991b1b);
|
|
79
110
|
margin-left: 4px;
|
|
80
111
|
}
|
|
81
112
|
input,
|
|
82
113
|
select {
|
|
114
|
+
width: 100%;
|
|
115
|
+
box-sizing: border-box;
|
|
83
116
|
padding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);
|
|
84
117
|
font-size: var(--roxy-text-base, 1rem);
|
|
85
118
|
font-family: inherit;
|
|
@@ -114,7 +147,7 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
114
147
|
button.submit {
|
|
115
148
|
justify-self: start;
|
|
116
149
|
background: var(--roxy-accent-fg, #b45309);
|
|
117
|
-
color: #fff;
|
|
150
|
+
color: var(--roxy-bg, #fff);
|
|
118
151
|
border: 0;
|
|
119
152
|
border-radius: var(--roxy-radius-md, 8px);
|
|
120
153
|
padding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-lg, 1.5rem);
|
|
@@ -132,6 +165,17 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
132
165
|
outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
|
|
133
166
|
outline-offset: 2px;
|
|
134
167
|
}
|
|
168
|
+
.spec-error {
|
|
169
|
+
display: grid;
|
|
170
|
+
gap: var(--roxy-space-md, 1rem);
|
|
171
|
+
justify-items: start;
|
|
172
|
+
background: var(--roxy-bg, #fff);
|
|
173
|
+
border: 1px solid var(--roxy-danger, #dc2626);
|
|
174
|
+
border-radius: var(--roxy-radius-md, 8px);
|
|
175
|
+
padding: var(--roxy-space-lg, 1.5rem);
|
|
176
|
+
color: var(--roxy-danger-fg, #991b1b);
|
|
177
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
178
|
+
}
|
|
135
179
|
`,
|
|
136
180
|
];
|
|
137
181
|
|
|
@@ -159,19 +203,18 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
159
203
|
@state()
|
|
160
204
|
private loaded = false;
|
|
161
205
|
|
|
206
|
+
@state()
|
|
207
|
+
private specError: string | null = null;
|
|
208
|
+
|
|
162
209
|
connectedCallback(): void {
|
|
163
210
|
super.connectedCallback();
|
|
164
211
|
void this.loadSchema();
|
|
165
212
|
}
|
|
166
213
|
|
|
167
214
|
private async loadSchema() {
|
|
215
|
+
this.specError = null;
|
|
168
216
|
try {
|
|
169
|
-
const
|
|
170
|
-
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
171
|
-
const spec = (await res.json()) as {
|
|
172
|
-
paths?: Record<string, Record<string, unknown>>;
|
|
173
|
-
components?: { schemas?: Record<string, OpenApiSchema> };
|
|
174
|
-
};
|
|
217
|
+
const spec = await loadSpec(this.specUrl);
|
|
175
218
|
const path = `/${this.endpoint.replace(/^\//, '')}`;
|
|
176
219
|
const op = spec.paths?.[path]?.[this.method.toLowerCase()] as
|
|
177
220
|
| {
|
|
@@ -189,7 +232,11 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
189
232
|
}>;
|
|
190
233
|
}
|
|
191
234
|
| undefined;
|
|
192
|
-
if (!op)
|
|
235
|
+
if (!op) {
|
|
236
|
+
throw new Error(
|
|
237
|
+
`Endpoint ${this.method} ${path} not found in OpenAPI spec`,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
193
240
|
|
|
194
241
|
const schemas = spec.components?.schemas ?? {};
|
|
195
242
|
const fields: FieldDef[] = [];
|
|
@@ -244,11 +291,26 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
244
291
|
}
|
|
245
292
|
this.values = init;
|
|
246
293
|
this.loaded = true;
|
|
247
|
-
} catch (
|
|
294
|
+
} catch (err) {
|
|
295
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
296
|
+
this.specError = message;
|
|
248
297
|
this.loaded = true;
|
|
298
|
+
this.dispatchEvent(
|
|
299
|
+
new CustomEvent('roxy-spec-error', {
|
|
300
|
+
detail: { url: this.specUrl, message },
|
|
301
|
+
bubbles: true,
|
|
302
|
+
composed: true,
|
|
303
|
+
}),
|
|
304
|
+
);
|
|
249
305
|
}
|
|
250
306
|
}
|
|
251
307
|
|
|
308
|
+
private retryLoadSchema = () => {
|
|
309
|
+
this.loaded = false;
|
|
310
|
+
this.specError = null;
|
|
311
|
+
void this.loadSchema();
|
|
312
|
+
};
|
|
313
|
+
|
|
252
314
|
private resolve(
|
|
253
315
|
schema: OpenApiSchema | OpenApiSchemaRef | undefined,
|
|
254
316
|
all: Record<string, OpenApiSchema>,
|
|
@@ -322,6 +384,13 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
322
384
|
return html`<form><div class="roxy-skeleton" style="height: 8rem"></div></form>`;
|
|
323
385
|
}
|
|
324
386
|
|
|
387
|
+
if (this.specError) {
|
|
388
|
+
return html`<div class="spec-error" role="alert">
|
|
389
|
+
Schema load failed: ${this.specError}
|
|
390
|
+
<button type="button" class="submit" @click=${this.retryLoadSchema}>Retry</button>
|
|
391
|
+
</div>`;
|
|
392
|
+
}
|
|
393
|
+
|
|
325
394
|
const renderField = (f: FieldDef) => {
|
|
326
395
|
if (
|
|
327
396
|
this.hasLocation &&
|
|
@@ -419,13 +488,6 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
419
488
|
}
|
|
420
489
|
}
|
|
421
490
|
|
|
422
|
-
function humanize(s: string): string {
|
|
423
|
-
return s
|
|
424
|
-
.replace(/[_-]+/g, ' ')
|
|
425
|
-
.replace(/([a-z])([A-Z])/g, '$1 $2')
|
|
426
|
-
.replace(/^\w/, (c) => c.toUpperCase());
|
|
427
|
-
}
|
|
428
|
-
|
|
429
491
|
declare global {
|
|
430
492
|
interface HTMLElementTagNameMap {
|
|
431
493
|
'roxy-endpoint-form': RoxyEndpointForm;
|
|
@@ -1,26 +1,8 @@
|
|
|
1
1
|
import { css, html, LitElement, nothing } from 'lit';
|
|
2
2
|
import { customElement, property } from 'lit/decorators.js';
|
|
3
|
+
import type { CompatibilityResponse } from '../types/index.js';
|
|
3
4
|
import { baseStyles } from '../utils/base-styles.js';
|
|
4
|
-
|
|
5
|
-
interface GunaCategory {
|
|
6
|
-
name?: string;
|
|
7
|
-
score?: number;
|
|
8
|
-
max?: number;
|
|
9
|
-
maxScore?: number;
|
|
10
|
-
description?: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
interface GunaData {
|
|
14
|
-
total?: number;
|
|
15
|
-
totalScore?: number;
|
|
16
|
-
maxScore?: number;
|
|
17
|
-
percentage?: number;
|
|
18
|
-
isCompatible?: boolean;
|
|
19
|
-
recommendation?: string;
|
|
20
|
-
doshas?: string[];
|
|
21
|
-
doshaCancellations?: string[];
|
|
22
|
-
breakdown?: GunaCategory[];
|
|
23
|
-
}
|
|
5
|
+
import { formatNumber, formatPercent } from '../utils/format.js';
|
|
24
6
|
|
|
25
7
|
const STANDARD_CATEGORIES = [
|
|
26
8
|
'Varna',
|
|
@@ -51,6 +33,14 @@ export class RoxyGunaMilan extends LitElement {
|
|
|
51
33
|
gap: var(--roxy-space-md, 1rem);
|
|
52
34
|
}
|
|
53
35
|
|
|
36
|
+
.score-header {
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
gap: 1rem;
|
|
40
|
+
}
|
|
41
|
+
.score-info {
|
|
42
|
+
flex: 1;
|
|
43
|
+
}
|
|
54
44
|
.score-bar {
|
|
55
45
|
display: grid;
|
|
56
46
|
grid-template-columns: 1fr auto;
|
|
@@ -72,6 +62,26 @@ export class RoxyGunaMilan extends LitElement {
|
|
|
72
62
|
font-size: var(--roxy-text-sm, 0.875rem);
|
|
73
63
|
color: var(--roxy-secondary, #475569);
|
|
74
64
|
}
|
|
65
|
+
.score-ring {
|
|
66
|
+
width: 120px;
|
|
67
|
+
height: 120px;
|
|
68
|
+
flex-shrink: 0;
|
|
69
|
+
}
|
|
70
|
+
.score-ring svg {
|
|
71
|
+
width: 100%;
|
|
72
|
+
height: 100%;
|
|
73
|
+
}
|
|
74
|
+
.score-ring .ring-text {
|
|
75
|
+
font-size: 22px;
|
|
76
|
+
font-weight: 700;
|
|
77
|
+
fill: var(--roxy-fg, #0a0a0a);
|
|
78
|
+
font-family: var(--roxy-font-sans);
|
|
79
|
+
}
|
|
80
|
+
.score-ring .ring-max {
|
|
81
|
+
font-size: 10px;
|
|
82
|
+
fill: var(--roxy-muted, #71717a);
|
|
83
|
+
font-family: var(--roxy-font-sans);
|
|
84
|
+
}
|
|
75
85
|
|
|
76
86
|
table {
|
|
77
87
|
width: 100%;
|
|
@@ -127,47 +137,75 @@ export class RoxyGunaMilan extends LitElement {
|
|
|
127
137
|
}
|
|
128
138
|
.tags .dosha {
|
|
129
139
|
background: color-mix(in srgb, var(--roxy-danger, #dc2626) 16%, transparent);
|
|
130
|
-
color: var(--roxy-danger, #
|
|
140
|
+
color: var(--roxy-danger-fg, #991b1b);
|
|
131
141
|
}
|
|
132
142
|
.tags .cancel {
|
|
133
143
|
background: color-mix(in srgb, var(--roxy-success, #16a34a) 18%, transparent);
|
|
134
|
-
color: var(--roxy-success, #
|
|
144
|
+
color: var(--roxy-success-fg, #166534);
|
|
135
145
|
}
|
|
136
146
|
`,
|
|
137
147
|
];
|
|
138
148
|
|
|
139
149
|
@property({ attribute: false })
|
|
140
|
-
data:
|
|
150
|
+
data: CompatibilityResponse | null = null;
|
|
141
151
|
|
|
142
152
|
render() {
|
|
143
153
|
const d = this.data;
|
|
144
154
|
if (!d)
|
|
145
155
|
return html`<div class="roxy-empty" role="status">No Guna Milan data</div>`;
|
|
146
156
|
|
|
147
|
-
const total = d.total ?? d.totalScore ?? 0;
|
|
148
|
-
const max = d.maxScore ?? 36;
|
|
149
157
|
const breakdown = (d.breakdown ?? []).filter(
|
|
150
|
-
(b) => b
|
|
158
|
+
(b) => b?.category !== undefined,
|
|
151
159
|
);
|
|
152
160
|
|
|
161
|
+
const score = d.total ?? 0;
|
|
162
|
+
const max = d.maxScore ?? 36;
|
|
163
|
+
const pct = (score / max) * 100;
|
|
164
|
+
const trackColor =
|
|
165
|
+
'color-mix(in srgb, var(--roxy-border) 50%, transparent)';
|
|
166
|
+
const fillColor =
|
|
167
|
+
pct >= 70
|
|
168
|
+
? 'var(--roxy-success)'
|
|
169
|
+
: pct >= 50
|
|
170
|
+
? 'var(--roxy-warning)'
|
|
171
|
+
: 'var(--roxy-danger)';
|
|
172
|
+
// SVG circle with r=45: circumference = 2 * pi * 45 = 282.74
|
|
173
|
+
// dasharray segments = pct * 2.827, (100 - pct) * 2.827
|
|
174
|
+
const dashFill = pct * 2.827;
|
|
175
|
+
const dashGap = (100 - pct) * 2.827;
|
|
176
|
+
|
|
153
177
|
return html`<article class="card" aria-label="Guna Milan score">
|
|
154
|
-
<div class="score-
|
|
155
|
-
<div>
|
|
156
|
-
<
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
178
|
+
<div class="score-header">
|
|
179
|
+
<div class="score-info">
|
|
180
|
+
<div class="score-bar">
|
|
181
|
+
<div>
|
|
182
|
+
<span class="total">${formatNumber(d.total, 1)}</span>
|
|
183
|
+
<span class="over"> / ${d.maxScore}</span>
|
|
184
|
+
${
|
|
185
|
+
typeof d.percentage === 'number'
|
|
186
|
+
? html`<small style="margin-left: 0.5rem; color: var(--roxy-muted)">
|
|
187
|
+
${formatPercent(d.percentage, 1)}
|
|
188
|
+
</small>`
|
|
189
|
+
: nothing
|
|
190
|
+
}
|
|
191
|
+
</div>
|
|
192
|
+
${
|
|
193
|
+
d.recommendation
|
|
194
|
+
? html`<span class="recommendation">${d.recommendation}</span>`
|
|
195
|
+
: nothing
|
|
196
|
+
}
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
<div class="score-ring" role="meter" aria-label="Guna milan score" aria-valuemin="0" aria-valuemax="36" aria-valuenow="${score}">
|
|
200
|
+
<svg viewBox="0 0 100 100" aria-hidden="true">
|
|
201
|
+
<circle class="ring-track" cx="50" cy="50" r="45" fill="none" stroke="${trackColor}" stroke-width="8"/>
|
|
202
|
+
<circle class="ring-fill" cx="50" cy="50" r="45" fill="none" stroke="${fillColor}" stroke-width="8"
|
|
203
|
+
stroke-dasharray="${dashFill},${dashGap}" stroke-linecap="round"
|
|
204
|
+
transform="rotate(-90 50 50)"/>
|
|
205
|
+
<text x="50" y="50" text-anchor="middle" dominant-baseline="central" class="ring-text">${score}</text>
|
|
206
|
+
<text x="50" y="64" text-anchor="middle" dominant-baseline="central" class="ring-max">/${max}</text>
|
|
207
|
+
</svg>
|
|
165
208
|
</div>
|
|
166
|
-
${
|
|
167
|
-
d.recommendation
|
|
168
|
-
? html`<span class="recommendation">${d.recommendation}</span>`
|
|
169
|
-
: nothing
|
|
170
|
-
}
|
|
171
209
|
</div>
|
|
172
210
|
|
|
173
211
|
${
|
|
@@ -183,16 +221,16 @@ export class RoxyGunaMilan extends LitElement {
|
|
|
183
221
|
<tbody>
|
|
184
222
|
${breakdown.map((b) => {
|
|
185
223
|
const score = b.score ?? 0;
|
|
186
|
-
const maxScore = b.
|
|
224
|
+
const maxScore = b.maxScore ?? defaultMax(b.category);
|
|
187
225
|
const pct = maxScore ? (score / maxScore) * 100 : 0;
|
|
188
226
|
return html`<tr>
|
|
189
|
-
<td>${b.
|
|
227
|
+
<td>${b.category}</td>
|
|
190
228
|
<td class="bar-cell">
|
|
191
229
|
<div class="mini-bar">
|
|
192
230
|
<span style="width: ${pct}%"></span>
|
|
193
231
|
</div>
|
|
194
232
|
</td>
|
|
195
|
-
<td class="score">${score} / ${maxScore}</td>
|
|
233
|
+
<td class="score">${formatNumber(score, 1)} / ${maxScore}</td>
|
|
196
234
|
</tr>`;
|
|
197
235
|
})}
|
|
198
236
|
</tbody>
|
|
@@ -203,7 +241,10 @@ export class RoxyGunaMilan extends LitElement {
|
|
|
203
241
|
(d.doshas?.length ?? 0) > 0 || (d.doshaCancellations?.length ?? 0) > 0
|
|
204
242
|
? html`<div class="tags">
|
|
205
243
|
${d.doshas?.map((x) => html`<span class="dosha">${x}</span>`)}
|
|
206
|
-
${d.doshaCancellations?.map(
|
|
244
|
+
${d.doshaCancellations?.map(
|
|
245
|
+
(x) =>
|
|
246
|
+
html`<span class="cancel" title=${x.reason}>${x.dosha} cancelled</span>`,
|
|
247
|
+
)}
|
|
207
248
|
</div>`
|
|
208
249
|
: nothing
|
|
209
250
|
}
|
|
@@ -235,7 +276,6 @@ function defaultMax(name?: string): number {
|
|
|
235
276
|
}
|
|
236
277
|
}
|
|
237
278
|
|
|
238
|
-
// Reference list (kept for documentation, used at codegen time)
|
|
239
279
|
export const GUNA_CATEGORIES = STANDARD_CATEGORIES;
|
|
240
280
|
|
|
241
281
|
declare global {
|
|
@@ -1,34 +1,22 @@
|
|
|
1
1
|
import { css, html, LitElement, nothing, svg } from 'lit';
|
|
2
2
|
import { customElement, property } from 'lit/decorators.js';
|
|
3
3
|
import { TRIGRAM_GLYPH } from '../tokens/index.js';
|
|
4
|
+
import type {
|
|
5
|
+
CastReadingResponse,
|
|
6
|
+
GetDailyHexagramResponse,
|
|
7
|
+
GetHexagramResponse,
|
|
8
|
+
GetRandomHexagramResponse,
|
|
9
|
+
Hexagram,
|
|
10
|
+
LookupHexagramResponse,
|
|
11
|
+
} from '../types/index.js';
|
|
4
12
|
import { baseStyles } from '../utils/base-styles.js';
|
|
5
13
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
upperTrigram?: string;
|
|
13
|
-
lowerTrigram?: string;
|
|
14
|
-
judgment?: string;
|
|
15
|
-
image?: string;
|
|
16
|
-
interpretation?: {
|
|
17
|
-
general?: string;
|
|
18
|
-
love?: string;
|
|
19
|
-
career?: string;
|
|
20
|
-
decision?: string;
|
|
21
|
-
advice?: string;
|
|
22
|
-
};
|
|
23
|
-
changingLines?: number[];
|
|
24
|
-
resultingHexagram?: HexagramData;
|
|
25
|
-
dailyMessage?: string;
|
|
26
|
-
hexagram?: HexagramData;
|
|
27
|
-
lines?: number[]; // 6, 7, 8, 9 cast values
|
|
28
|
-
changingLinePositions?: number[];
|
|
29
|
-
seed?: string;
|
|
30
|
-
date?: string;
|
|
31
|
-
}
|
|
14
|
+
type HexagramData =
|
|
15
|
+
| GetHexagramResponse
|
|
16
|
+
| GetRandomHexagramResponse
|
|
17
|
+
| LookupHexagramResponse
|
|
18
|
+
| GetDailyHexagramResponse
|
|
19
|
+
| CastReadingResponse;
|
|
32
20
|
|
|
33
21
|
/**
|
|
34
22
|
* I Ching hexagram card. Renders /iching/hexagrams/{number}, /iching/cast,
|
|
@@ -154,25 +142,48 @@ export class RoxyHexagram extends LitElement {
|
|
|
154
142
|
@property({ type: String, reflect: true })
|
|
155
143
|
mode: 'lookup' | 'cast' | 'daily' = 'lookup';
|
|
156
144
|
|
|
157
|
-
private
|
|
158
|
-
|
|
159
|
-
|
|
145
|
+
private resolveHexagram(): {
|
|
146
|
+
hex: Hexagram;
|
|
147
|
+
lines?: number[];
|
|
148
|
+
changingLinePositions?: number[];
|
|
149
|
+
dailyMessage?: string;
|
|
150
|
+
resultingHexagram?: Hexagram;
|
|
151
|
+
} | null {
|
|
152
|
+
const d = this.data;
|
|
153
|
+
if (!d) return null;
|
|
154
|
+
if ('hexagram' in d && d.hexagram) {
|
|
155
|
+
if ('lines' in d) {
|
|
156
|
+
const cast = d as CastReadingResponse;
|
|
157
|
+
return {
|
|
158
|
+
hex: cast.hexagram as Hexagram,
|
|
159
|
+
lines: cast.lines,
|
|
160
|
+
changingLinePositions: cast.changingLinePositions,
|
|
161
|
+
resultingHexagram: cast.resultingHexagram as Hexagram | undefined,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
const daily = d as GetDailyHexagramResponse;
|
|
160
165
|
return {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
changingLinePositions: this.data.changingLinePositions,
|
|
166
|
+
hex: daily.hexagram as Hexagram,
|
|
167
|
+
dailyMessage: daily.dailyMessage,
|
|
164
168
|
};
|
|
165
169
|
}
|
|
166
|
-
return
|
|
170
|
+
return { hex: d as Hexagram };
|
|
167
171
|
}
|
|
168
172
|
|
|
169
173
|
render() {
|
|
170
|
-
const
|
|
171
|
-
if (!
|
|
174
|
+
const resolved = this.resolveHexagram();
|
|
175
|
+
if (!resolved)
|
|
172
176
|
return html`<div class="roxy-empty" role="status">No hexagram data</div>`;
|
|
173
177
|
|
|
174
|
-
const
|
|
175
|
-
|
|
178
|
+
const {
|
|
179
|
+
hex: h,
|
|
180
|
+
lines: castLines,
|
|
181
|
+
changingLinePositions,
|
|
182
|
+
dailyMessage,
|
|
183
|
+
resultingHexagram,
|
|
184
|
+
} = resolved;
|
|
185
|
+
const lines = castLines ?? this.derivedLines(h);
|
|
186
|
+
const changing = new Set(changingLinePositions ?? []);
|
|
176
187
|
|
|
177
188
|
return html`<article class="card" aria-label="I Ching hexagram">
|
|
178
189
|
<div class="glyphs">
|
|
@@ -229,7 +240,7 @@ export class RoxyHexagram extends LitElement {
|
|
|
229
240
|
</div>
|
|
230
241
|
${h.judgment ? html`<p class="judgment">${h.judgment}</p>` : nothing}
|
|
231
242
|
${h.image ? html`<p class="image">${h.image}</p>` : nothing}
|
|
232
|
-
${
|
|
243
|
+
${dailyMessage ? html`<p class="message">${dailyMessage}</p>` : nothing}
|
|
233
244
|
${
|
|
234
245
|
h.interpretation?.general
|
|
235
246
|
? html`<p>${h.interpretation.general}</p>`
|
|
@@ -242,9 +253,9 @@ export class RoxyHexagram extends LitElement {
|
|
|
242
253
|
.sort((a, b) => a - b)
|
|
243
254
|
.join(', ')}.
|
|
244
255
|
${
|
|
245
|
-
|
|
246
|
-
? html` Becomes hexagram ${
|
|
247
|
-
${
|
|
256
|
+
resultingHexagram?.english
|
|
257
|
+
? html` Becomes hexagram ${resultingHexagram.number}
|
|
258
|
+
${resultingHexagram.english}.`
|
|
248
259
|
: nothing
|
|
249
260
|
}
|
|
250
261
|
</div>`
|
|
@@ -255,8 +266,7 @@ export class RoxyHexagram extends LitElement {
|
|
|
255
266
|
}
|
|
256
267
|
|
|
257
268
|
/** When the API only ships symbol+number with no line array, render six solid yang. */
|
|
258
|
-
private derivedLines(h:
|
|
259
|
-
if (!h.symbol) return Array.from({ length: 6 }, () => 7);
|
|
269
|
+
private derivedLines(h: Hexagram): number[] {
|
|
260
270
|
// Map each character of the unicode hexagram block (U+4DC0..) to broken/solid
|
|
261
271
|
const cp = h.symbol.codePointAt(0) ?? 0;
|
|
262
272
|
if (cp >= 0x4dc0 && cp <= 0x4dff) {
|