@roxyapi/ui 0.9.0 → 0.11.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 +53 -27
- package/README.md +42 -12
- package/components-catalog.json +1022 -0
- package/dist/cdn/components/angel-number-card.js +52 -0
- package/dist/cdn/components/angel-number-card.js.map +7 -0
- package/dist/cdn/components/angel-number-lookup.js +52 -0
- package/dist/cdn/components/angel-number-lookup.js.map +7 -0
- package/dist/cdn/components/ashtakavarga-grid.js +10 -3
- package/dist/cdn/components/ashtakavarga-grid.js.map +4 -4
- package/dist/cdn/components/aspects-table.js +52 -0
- package/dist/cdn/components/aspects-table.js.map +7 -0
- package/dist/cdn/components/biorhythm-chart.js +10 -3
- package/dist/cdn/components/biorhythm-chart.js.map +4 -4
- package/dist/cdn/components/bodygraph.js +17 -10
- package/dist/cdn/components/bodygraph.js.map +4 -4
- package/dist/cdn/components/choghadiya-grid.js +10 -3
- package/dist/cdn/components/choghadiya-grid.js.map +4 -4
- package/dist/cdn/components/compatibility-card.js +10 -3
- package/dist/cdn/components/compatibility-card.js.map +4 -4
- package/dist/cdn/components/crystal-card.js +52 -0
- package/dist/cdn/components/crystal-card.js.map +7 -0
- package/dist/cdn/components/crystal-grid.js +52 -0
- package/dist/cdn/components/crystal-grid.js.map +7 -0
- package/dist/cdn/components/dasha-timeline.js +10 -3
- package/dist/cdn/components/dasha-timeline.js.map +4 -4
- package/dist/cdn/components/data.js +10 -3
- package/dist/cdn/components/data.js.map +4 -4
- package/dist/cdn/components/divisional-chart.js +31 -24
- package/dist/cdn/components/divisional-chart.js.map +4 -4
- package/dist/cdn/components/dosha-card.js +10 -3
- package/dist/cdn/components/dosha-card.js.map +4 -4
- package/dist/cdn/components/dream-card.js +52 -0
- package/dist/cdn/components/dream-card.js.map +7 -0
- package/dist/cdn/components/dream-search.js +52 -0
- package/dist/cdn/components/dream-search.js.map +7 -0
- package/dist/cdn/components/endpoint-form.js +3 -3
- package/dist/cdn/components/endpoint-form.js.map +3 -3
- package/dist/cdn/components/forecast-digest.js +52 -0
- package/dist/cdn/components/forecast-digest.js.map +7 -0
- package/dist/cdn/components/forecast-timeline.js +10 -3
- package/dist/cdn/components/forecast-timeline.js.map +4 -4
- package/dist/cdn/components/guna-milan.js +10 -3
- package/dist/cdn/components/guna-milan.js.map +4 -4
- package/dist/cdn/components/hd-connection.js +52 -0
- package/dist/cdn/components/hd-connection.js.map +7 -0
- package/dist/cdn/components/hd-penta.js +52 -0
- package/dist/cdn/components/hd-penta.js.map +7 -0
- package/dist/cdn/components/hd-variables.js +52 -0
- package/dist/cdn/components/hd-variables.js.map +7 -0
- package/dist/cdn/components/hexagram.js +10 -3
- package/dist/cdn/components/hexagram.js.map +4 -4
- package/dist/cdn/components/hora-table.js +52 -0
- package/dist/cdn/components/hora-table.js.map +7 -0
- package/dist/cdn/components/horoscope-card.js +10 -3
- package/dist/cdn/components/horoscope-card.js.map +4 -4
- package/dist/cdn/components/kp-chart.js +10 -3
- package/dist/cdn/components/kp-chart.js.map +4 -4
- package/dist/cdn/components/kp-planets-table.js +10 -3
- package/dist/cdn/components/kp-planets-table.js.map +4 -4
- package/dist/cdn/components/kp-ruling-planets.js +10 -3
- package/dist/cdn/components/kp-ruling-planets.js.map +4 -4
- package/dist/cdn/components/location-search.js +3 -3
- package/dist/cdn/components/location-search.js.map +2 -2
- package/dist/cdn/components/moon-phase.js +10 -3
- package/dist/cdn/components/moon-phase.js.map +4 -4
- package/dist/cdn/components/nakshatra-card.js +10 -3
- package/dist/cdn/components/nakshatra-card.js.map +4 -4
- package/dist/cdn/components/natal-chart.js +16 -9
- package/dist/cdn/components/natal-chart.js.map +4 -4
- package/dist/cdn/components/numerology-card.js +10 -3
- package/dist/cdn/components/numerology-card.js.map +4 -4
- package/dist/cdn/components/panchang-table.js +10 -3
- package/dist/cdn/components/panchang-table.js.map +4 -4
- package/dist/cdn/components/reference-card.js +52 -0
- package/dist/cdn/components/reference-card.js.map +7 -0
- package/dist/cdn/components/shadbala-table.js +10 -3
- package/dist/cdn/components/shadbala-table.js.map +4 -4
- package/dist/cdn/components/synastry-chart.js +16 -9
- package/dist/cdn/components/synastry-chart.js.map +4 -4
- package/dist/cdn/components/tarot-card.js +10 -3
- package/dist/cdn/components/tarot-card.js.map +4 -4
- package/dist/cdn/components/tarot-catalog.js +52 -0
- package/dist/cdn/components/tarot-catalog.js.map +7 -0
- package/dist/cdn/components/tarot-spread.js +10 -3
- package/dist/cdn/components/tarot-spread.js.map +4 -4
- package/dist/cdn/components/transits-table.js +10 -3
- package/dist/cdn/components/transits-table.js.map +4 -4
- package/dist/cdn/components/vedic-aspects.js +52 -0
- package/dist/cdn/components/vedic-aspects.js.map +7 -0
- package/dist/cdn/components/vedic-kundli.js +31 -24
- package/dist/cdn/components/vedic-kundli.js.map +4 -4
- package/dist/cdn/components/vedic-planets-table.js +10 -3
- package/dist/cdn/components/vedic-planets-table.js.map +4 -4
- package/dist/cdn/components/western-planets-table.js +10 -3
- package/dist/cdn/components/western-planets-table.js.map +4 -4
- package/dist/cdn/components/yoga-list.js +10 -3
- package/dist/cdn/components/yoga-list.js.map +4 -4
- package/dist/cdn/roxy-ui.js +92 -81
- package/dist/cdn/roxy-ui.js.map +4 -4
- package/dist/components/angel-number-card.d.ts +17 -0
- package/dist/components/angel-number-card.d.ts.map +1 -0
- package/dist/components/angel-number-card.js +2 -0
- package/dist/components/angel-number-card.js.map +7 -0
- package/dist/components/angel-number-lookup.d.ts +21 -0
- package/dist/components/angel-number-lookup.d.ts.map +1 -0
- package/dist/components/angel-number-lookup.js +2 -0
- package/dist/components/angel-number-lookup.js.map +7 -0
- package/dist/components/ashtakavarga-grid.d.ts +4 -5
- package/dist/components/ashtakavarga-grid.d.ts.map +1 -1
- package/dist/components/ashtakavarga-grid.js +1 -1
- package/dist/components/ashtakavarga-grid.js.map +4 -4
- package/dist/components/aspects-table.d.ts +23 -0
- package/dist/components/aspects-table.d.ts.map +1 -0
- package/dist/components/aspects-table.js +2 -0
- package/dist/components/aspects-table.js.map +7 -0
- package/dist/components/biorhythm-chart.d.ts +4 -5
- package/dist/components/biorhythm-chart.d.ts.map +1 -1
- package/dist/components/biorhythm-chart.js +1 -1
- package/dist/components/biorhythm-chart.js.map +4 -4
- package/dist/components/bodygraph.d.ts +4 -5
- package/dist/components/bodygraph.d.ts.map +1 -1
- package/dist/components/bodygraph.js +9 -9
- package/dist/components/bodygraph.js.map +4 -4
- package/dist/components/choghadiya-grid.d.ts +4 -5
- package/dist/components/choghadiya-grid.d.ts.map +1 -1
- package/dist/components/choghadiya-grid.js +1 -1
- package/dist/components/choghadiya-grid.js.map +4 -4
- package/dist/components/compatibility-card.d.ts +4 -5
- package/dist/components/compatibility-card.d.ts.map +1 -1
- package/dist/components/compatibility-card.js +1 -1
- package/dist/components/compatibility-card.js.map +4 -4
- package/dist/components/crystal-card.d.ts +19 -0
- package/dist/components/crystal-card.d.ts.map +1 -0
- package/dist/components/crystal-card.js +2 -0
- package/dist/components/crystal-card.js.map +7 -0
- package/dist/components/crystal-grid.d.ts +26 -0
- package/dist/components/crystal-grid.d.ts.map +1 -0
- package/dist/components/crystal-grid.js +2 -0
- package/dist/components/crystal-grid.js.map +7 -0
- package/dist/components/dasha-timeline.d.ts +4 -5
- package/dist/components/dasha-timeline.d.ts.map +1 -1
- package/dist/components/dasha-timeline.js +1 -1
- package/dist/components/dasha-timeline.js.map +4 -4
- package/dist/components/data.d.ts +5 -8
- package/dist/components/data.d.ts.map +1 -1
- package/dist/components/data.js +1 -1
- package/dist/components/data.js.map +4 -4
- package/dist/components/divisional-chart.d.ts +4 -5
- package/dist/components/divisional-chart.d.ts.map +1 -1
- package/dist/components/divisional-chart.js +59 -59
- package/dist/components/divisional-chart.js.map +4 -4
- package/dist/components/dosha-card.d.ts +4 -5
- package/dist/components/dosha-card.d.ts.map +1 -1
- package/dist/components/dosha-card.js +1 -1
- package/dist/components/dosha-card.js.map +4 -4
- package/dist/components/dream-card.d.ts +16 -0
- package/dist/components/dream-card.d.ts.map +1 -0
- package/dist/components/dream-card.js +2 -0
- package/dist/components/dream-card.js.map +7 -0
- package/dist/components/dream-search.d.ts +18 -0
- package/dist/components/dream-search.d.ts.map +1 -0
- package/dist/components/dream-search.js +2 -0
- package/dist/components/dream-search.js.map +7 -0
- package/dist/components/endpoint-form.d.ts +10 -5
- package/dist/components/endpoint-form.d.ts.map +1 -1
- package/dist/components/endpoint-form.js +1 -1
- package/dist/components/endpoint-form.js.map +3 -3
- package/dist/components/forecast-digest.d.ts +19 -0
- package/dist/components/forecast-digest.d.ts.map +1 -0
- package/dist/components/forecast-digest.js +2 -0
- package/dist/components/forecast-digest.js.map +7 -0
- package/dist/components/forecast-timeline.d.ts +8 -6
- package/dist/components/forecast-timeline.d.ts.map +1 -1
- package/dist/components/forecast-timeline.js +1 -1
- package/dist/components/forecast-timeline.js.map +4 -4
- package/dist/components/guna-milan.d.ts +4 -5
- package/dist/components/guna-milan.d.ts.map +1 -1
- package/dist/components/guna-milan.js +1 -1
- package/dist/components/guna-milan.js.map +4 -4
- package/dist/components/hd-connection.d.ts +18 -0
- package/dist/components/hd-connection.d.ts.map +1 -0
- package/dist/components/hd-connection.js +2 -0
- package/dist/components/hd-connection.js.map +7 -0
- package/dist/components/hd-penta.d.ts +18 -0
- package/dist/components/hd-penta.d.ts.map +1 -0
- package/dist/components/hd-penta.js +2 -0
- package/dist/components/hd-penta.js.map +7 -0
- package/dist/components/hd-variables.d.ts +17 -0
- package/dist/components/hd-variables.d.ts.map +1 -0
- package/dist/components/hd-variables.js +2 -0
- package/dist/components/hd-variables.js.map +7 -0
- package/dist/components/hexagram.d.ts +4 -5
- package/dist/components/hexagram.d.ts.map +1 -1
- package/dist/components/hexagram.js +1 -1
- package/dist/components/hexagram.js.map +4 -4
- package/dist/components/hora-table.d.ts +17 -0
- package/dist/components/hora-table.d.ts.map +1 -0
- package/dist/components/hora-table.js +2 -0
- package/dist/components/hora-table.js.map +7 -0
- package/dist/components/horoscope-card.d.ts +4 -5
- package/dist/components/horoscope-card.d.ts.map +1 -1
- package/dist/components/horoscope-card.js +1 -1
- package/dist/components/horoscope-card.js.map +4 -4
- package/dist/components/kp-chart.d.ts +4 -5
- package/dist/components/kp-chart.d.ts.map +1 -1
- package/dist/components/kp-chart.js +1 -1
- package/dist/components/kp-chart.js.map +4 -4
- package/dist/components/kp-planets-table.d.ts +4 -5
- package/dist/components/kp-planets-table.d.ts.map +1 -1
- package/dist/components/kp-planets-table.js +1 -1
- package/dist/components/kp-planets-table.js.map +4 -4
- package/dist/components/kp-ruling-planets.d.ts +4 -5
- package/dist/components/kp-ruling-planets.d.ts.map +1 -1
- package/dist/components/kp-ruling-planets.js +1 -1
- package/dist/components/kp-ruling-planets.js.map +4 -4
- package/dist/components/location-search.js +1 -1
- package/dist/components/location-search.js.map +2 -2
- package/dist/components/moon-phase.d.ts +5 -5
- package/dist/components/moon-phase.d.ts.map +1 -1
- package/dist/components/moon-phase.js +1 -1
- package/dist/components/moon-phase.js.map +4 -4
- package/dist/components/nakshatra-card.d.ts +4 -5
- package/dist/components/nakshatra-card.d.ts.map +1 -1
- package/dist/components/nakshatra-card.js +1 -1
- package/dist/components/nakshatra-card.js.map +4 -4
- package/dist/components/natal-chart.d.ts +4 -5
- package/dist/components/natal-chart.d.ts.map +1 -1
- package/dist/components/natal-chart.js +8 -8
- package/dist/components/natal-chart.js.map +4 -4
- package/dist/components/numerology-card.d.ts +15 -10
- package/dist/components/numerology-card.d.ts.map +1 -1
- package/dist/components/numerology-card.js +1 -1
- package/dist/components/numerology-card.js.map +4 -4
- package/dist/components/panchang-table.d.ts +4 -5
- package/dist/components/panchang-table.d.ts.map +1 -1
- package/dist/components/panchang-table.js +1 -1
- package/dist/components/panchang-table.js.map +4 -4
- package/dist/components/reference-card.d.ts +19 -0
- package/dist/components/reference-card.d.ts.map +1 -0
- package/dist/components/reference-card.js +2 -0
- package/dist/components/reference-card.js.map +7 -0
- package/dist/components/shadbala-table.d.ts +4 -5
- package/dist/components/shadbala-table.d.ts.map +1 -1
- package/dist/components/shadbala-table.js +1 -1
- package/dist/components/shadbala-table.js.map +4 -4
- package/dist/components/synastry-chart.d.ts +4 -5
- package/dist/components/synastry-chart.d.ts.map +1 -1
- package/dist/components/synastry-chart.js +7 -7
- package/dist/components/synastry-chart.js.map +4 -4
- package/dist/components/tarot-card.d.ts +4 -5
- package/dist/components/tarot-card.d.ts.map +1 -1
- package/dist/components/tarot-card.js +1 -1
- package/dist/components/tarot-card.js.map +4 -4
- package/dist/components/tarot-catalog.d.ts +20 -0
- package/dist/components/tarot-catalog.d.ts.map +1 -0
- package/dist/components/tarot-catalog.js +2 -0
- package/dist/components/tarot-catalog.js.map +7 -0
- package/dist/components/tarot-spread.d.ts +7 -8
- package/dist/components/tarot-spread.d.ts.map +1 -1
- package/dist/components/tarot-spread.js +1 -1
- package/dist/components/tarot-spread.js.map +4 -4
- package/dist/components/transits-table.d.ts +4 -5
- package/dist/components/transits-table.d.ts.map +1 -1
- package/dist/components/transits-table.js +1 -1
- package/dist/components/transits-table.js.map +4 -4
- package/dist/components/vedic-aspects.d.ts +16 -0
- package/dist/components/vedic-aspects.d.ts.map +1 -0
- package/dist/components/vedic-aspects.js +2 -0
- package/dist/components/vedic-aspects.js.map +7 -0
- package/dist/components/vedic-kundli.d.ts +22 -5
- package/dist/components/vedic-kundli.d.ts.map +1 -1
- package/dist/components/vedic-kundli.js +63 -63
- package/dist/components/vedic-kundli.js.map +4 -4
- package/dist/components/vedic-planets-table.d.ts +4 -5
- package/dist/components/vedic-planets-table.d.ts.map +1 -1
- package/dist/components/vedic-planets-table.js +1 -1
- package/dist/components/vedic-planets-table.js.map +4 -4
- package/dist/components/western-planets-table.d.ts +4 -5
- package/dist/components/western-planets-table.d.ts.map +1 -1
- package/dist/components/western-planets-table.js +1 -1
- package/dist/components/western-planets-table.js.map +4 -4
- package/dist/components/yoga-list.d.ts +6 -7
- package/dist/components/yoga-list.d.ts.map +1 -1
- package/dist/components/yoga-list.js +1 -1
- package/dist/components/yoga-list.js.map +4 -4
- package/dist/generated/endpoint-bindings.d.ts +15 -0
- package/dist/generated/endpoint-bindings.d.ts.map +1 -0
- package/dist/index.cjs +73 -73
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +71 -71
- package/dist/index.js.map +4 -4
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.json +39 -24
- package/dist/styles/tokens-css.d.ts +1 -1
- package/dist/styles/tokens-css.d.ts.map +1 -1
- package/dist/styles/tokens.css +4 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types.gen.d.ts +1103 -164
- package/dist/types/types.gen.d.ts.map +1 -1
- package/dist/utils/angel-sections.d.ts +14 -0
- package/dist/utils/angel-sections.d.ts.map +1 -0
- package/dist/utils/base-element.d.ts +73 -0
- package/dist/utils/base-element.d.ts.map +1 -0
- package/dist/utils/base-styles.d.ts.map +1 -1
- package/dist/utils/fetch-controller.d.ts +60 -0
- package/dist/utils/fetch-controller.d.ts.map +1 -0
- package/dist/utils/kundli-render.d.ts +2 -1
- package/dist/utils/kundli-render.d.ts.map +1 -1
- package/dist/utils/kundli-styles.d.ts.map +1 -1
- package/dist/utils/markup-data.d.ts +34 -0
- package/dist/utils/markup-data.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/components/angel-number-card.ts +210 -0
- package/src/components/angel-number-lookup.ts +207 -0
- package/src/components/ashtakavarga-grid.ts +15 -20
- package/src/components/aspects-table.ts +329 -0
- package/src/components/biorhythm-chart.ts +14 -18
- package/src/components/bodygraph.ts +9 -20
- package/src/components/choghadiya-grid.ts +15 -19
- package/src/components/compatibility-card.ts +9 -19
- package/src/components/crystal-card.ts +242 -0
- package/src/components/crystal-grid.ts +182 -0
- package/src/components/dasha-timeline.ts +9 -20
- package/src/components/data.ts +8 -27
- package/src/components/divisional-chart.ts +10 -18
- package/src/components/dosha-card.ts +8 -19
- package/src/components/dream-card.ts +88 -0
- package/src/components/dream-search.ts +135 -0
- package/src/components/endpoint-form.ts +149 -55
- package/src/components/forecast-digest.ts +213 -0
- package/src/components/forecast-timeline.ts +24 -19
- package/src/components/guna-milan.ts +8 -19
- package/src/components/hd-connection.ts +188 -0
- package/src/components/hd-penta.ts +165 -0
- package/src/components/hd-variables.ts +128 -0
- package/src/components/hexagram.ts +10 -18
- package/src/components/hora-table.ts +149 -0
- package/src/components/horoscope-card.ts +9 -19
- package/src/components/kp-chart.ts +11 -20
- package/src/components/kp-planets-table.ts +11 -20
- package/src/components/kp-ruling-planets.ts +8 -18
- package/src/components/moon-phase.ts +10 -19
- package/src/components/nakshatra-card.ts +11 -20
- package/src/components/natal-chart.ts +20 -23
- package/src/components/numerology-card.ts +90 -31
- package/src/components/panchang-table.ts +9 -19
- package/src/components/reference-card.ts +212 -0
- package/src/components/shadbala-table.ts +15 -18
- package/src/components/synastry-chart.ts +17 -20
- package/src/components/tarot-card.ts +9 -20
- package/src/components/tarot-catalog.ts +129 -0
- package/src/components/tarot-spread.ts +20 -21
- package/src/components/transits-table.ts +17 -20
- package/src/components/vedic-aspects.ts +188 -0
- package/src/components/vedic-kundli.ts +46 -19
- package/src/components/vedic-planets-table.ts +11 -19
- package/src/components/western-planets-table.ts +11 -19
- package/src/components/yoga-list.ts +17 -23
- package/src/generated/endpoint-bindings.ts +655 -0
- package/src/index.ts +27 -0
- package/src/manifest.ts +198 -6
- package/src/styles/tokens-css.ts +4 -0
- package/src/styles/tokens.css +4 -0
- package/src/types/index.ts +1 -1
- package/src/types/types.gen.ts +1123 -164
- package/src/utils/angel-sections.ts +38 -0
- package/src/utils/base-element.ts +183 -0
- package/src/utils/base-styles.ts +33 -0
- package/src/utils/fetch-controller.ts +166 -0
- package/src/utils/kundli-render.ts +9 -2
- package/src/utils/kundli-styles.ts +7 -1
- package/src/utils/markup-data.ts +45 -0
- package/src/version.ts +1 -1
|
@@ -22,7 +22,12 @@ interface OpenApiSchema extends OpenApiSchemaRef {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
interface FieldDef {
|
|
25
|
+
/** Unique storage + input key: the property name, or "group.name" for a nested object field. */
|
|
26
|
+
key: string;
|
|
27
|
+
/** Schema property name (the label source), e.g. "date". */
|
|
25
28
|
name: string;
|
|
29
|
+
/** Parent object key for a nested schema (person1/person2); undefined for a flat field. */
|
|
30
|
+
group?: string;
|
|
26
31
|
type: string;
|
|
27
32
|
required: boolean;
|
|
28
33
|
description?: string;
|
|
@@ -66,9 +71,10 @@ async function loadSpec(url: string): Promise<OpenApiDoc> {
|
|
|
66
71
|
* `roxy-submit` CustomEvent with the validated payload on submit. The caller
|
|
67
72
|
* decides what to do (call the SDK, render a chart, navigate).
|
|
68
73
|
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
74
|
+
* At runtime the component fetches the OpenAPI spec (its `spec-url`, default
|
|
75
|
+
* /api/v2/openapi.json) and builds the fields from the operation's request
|
|
76
|
+
* schema: types, enums, required flags, and property order all come from the
|
|
77
|
+
* spec, so a new endpoint gets a working form with no per-endpoint code.
|
|
72
78
|
*/
|
|
73
79
|
@customElement('roxy-endpoint-form')
|
|
74
80
|
export class RoxyEndpointForm extends LitElement {
|
|
@@ -95,6 +101,20 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
95
101
|
align-items: start;
|
|
96
102
|
gap: var(--roxy-space-md, 1rem);
|
|
97
103
|
}
|
|
104
|
+
.person-group {
|
|
105
|
+
border: 1px solid var(--roxy-border, #e4e4e7);
|
|
106
|
+
border-radius: var(--roxy-radius-md, 8px);
|
|
107
|
+
padding: var(--roxy-space-md, 1rem);
|
|
108
|
+
margin: 0 0 var(--roxy-space-md, 1rem);
|
|
109
|
+
display: grid;
|
|
110
|
+
gap: var(--roxy-space-md, 1rem);
|
|
111
|
+
min-inline-size: 0;
|
|
112
|
+
}
|
|
113
|
+
.person-group legend {
|
|
114
|
+
padding: 0 var(--roxy-space-xs, 0.25rem);
|
|
115
|
+
font-weight: var(--roxy-weight-bold, 600);
|
|
116
|
+
text-transform: capitalize;
|
|
117
|
+
}
|
|
98
118
|
.field {
|
|
99
119
|
display: flex;
|
|
100
120
|
flex-direction: column;
|
|
@@ -191,15 +211,16 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
191
211
|
@property({ type: String, attribute: 'submit-label' })
|
|
192
212
|
submitLabel = 'Submit';
|
|
193
213
|
|
|
214
|
+
/** Prefill values, keyed by field name. Used by `remember` mode to restore the last submission. JS property only. */
|
|
215
|
+
@property({ attribute: false })
|
|
216
|
+
initialValues?: Record<string, unknown>;
|
|
217
|
+
|
|
194
218
|
@state()
|
|
195
219
|
private fields: FieldDef[] = [];
|
|
196
220
|
|
|
197
221
|
@state()
|
|
198
222
|
private values: Record<string, unknown> = {};
|
|
199
223
|
|
|
200
|
-
@state()
|
|
201
|
-
private hasLocation = false;
|
|
202
|
-
|
|
203
224
|
@state()
|
|
204
225
|
private loaded = false;
|
|
205
226
|
|
|
@@ -251,16 +272,40 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
251
272
|
const required = new Set(bodySchema.required ?? []);
|
|
252
273
|
for (const [name, sub] of Object.entries(bodySchema.properties)) {
|
|
253
274
|
const resolved = this.resolve(sub, schemas) ?? {};
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
required
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
275
|
+
// Nested object (e.g. person1/person2 on synastry / guna-milan):
|
|
276
|
+
// expand into a labelled group of sub-fields keyed "group.sub".
|
|
277
|
+
if (resolved.type === 'object' && resolved.properties) {
|
|
278
|
+
const subRequired = new Set(resolved.required ?? []);
|
|
279
|
+
for (const [subName, subSchema] of Object.entries(
|
|
280
|
+
resolved.properties,
|
|
281
|
+
)) {
|
|
282
|
+
const r = this.resolve(subSchema, schemas) ?? {};
|
|
283
|
+
fields.push({
|
|
284
|
+
key: `${name}.${subName}`,
|
|
285
|
+
name: subName,
|
|
286
|
+
group: name,
|
|
287
|
+
type: this.fieldType(r),
|
|
288
|
+
required: required.has(name) && subRequired.has(subName),
|
|
289
|
+
description: r.description,
|
|
290
|
+
enum: r.enum,
|
|
291
|
+
min: r.minimum,
|
|
292
|
+
max: r.maximum,
|
|
293
|
+
default: r.default,
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
} else {
|
|
297
|
+
fields.push({
|
|
298
|
+
key: name,
|
|
299
|
+
name,
|
|
300
|
+
type: this.fieldType(resolved),
|
|
301
|
+
required: required.has(name),
|
|
302
|
+
description: resolved.description,
|
|
303
|
+
enum: resolved.enum,
|
|
304
|
+
min: resolved.minimum,
|
|
305
|
+
max: resolved.maximum,
|
|
306
|
+
default: resolved.default,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
264
309
|
}
|
|
265
310
|
}
|
|
266
311
|
|
|
@@ -268,6 +313,7 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
268
313
|
if (param.in === 'path' || param.in === 'query') {
|
|
269
314
|
const resolved = this.resolve(param.schema, schemas) ?? {};
|
|
270
315
|
fields.push({
|
|
316
|
+
key: param.name,
|
|
271
317
|
name: param.name,
|
|
272
318
|
type: this.fieldType(resolved),
|
|
273
319
|
required: !!param.required,
|
|
@@ -279,15 +325,22 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
279
325
|
}
|
|
280
326
|
|
|
281
327
|
this.fields = fields;
|
|
282
|
-
this.hasLocation =
|
|
283
|
-
fields.some((f) => f.name === 'latitude') &&
|
|
284
|
-
fields.some((f) => f.name === 'longitude') &&
|
|
285
|
-
fields.some((f) => f.name === 'timezone');
|
|
286
328
|
|
|
287
|
-
// Pre-fill defaults
|
|
329
|
+
// Pre-fill: schema defaults first, then any remembered/initial values
|
|
330
|
+
// (only for fields this endpoint has) so a stale stored payload from
|
|
331
|
+
// another endpoint cannot inject unknown keys. Remembered values are the
|
|
332
|
+
// previously-submitted shape (nested per group), so read them by group.
|
|
288
333
|
const init: Record<string, unknown> = {};
|
|
289
334
|
for (const f of fields) {
|
|
290
|
-
if (f.default !== undefined) init[f.
|
|
335
|
+
if (f.default !== undefined) init[f.key] = f.default;
|
|
336
|
+
const remembered = f.group
|
|
337
|
+
? (
|
|
338
|
+
this.initialValues?.[f.group] as
|
|
339
|
+
| Record<string, unknown>
|
|
340
|
+
| undefined
|
|
341
|
+
)?.[f.name]
|
|
342
|
+
: this.initialValues?.[f.name];
|
|
343
|
+
if (remembered !== undefined) init[f.key] = remembered;
|
|
291
344
|
}
|
|
292
345
|
this.values = init;
|
|
293
346
|
this.loaded = true;
|
|
@@ -336,43 +389,67 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
336
389
|
this.values = { ...this.values, [name]: value };
|
|
337
390
|
}
|
|
338
391
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
392
|
+
/** True when the fields in `group` (or the flat top level) carry latitude+longitude+timezone, so a location-search can autofill them. */
|
|
393
|
+
private groupHasLocation(group?: string): boolean {
|
|
394
|
+
const inGroup = this.fields.filter((f) => f.group === group);
|
|
395
|
+
return (['latitude', 'longitude', 'timezone'] as const).every((n) =>
|
|
396
|
+
inGroup.some((f) => f.name === n),
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** Location-select handler bound to a group: fills that group's lat/lng/timezone keys (flat top level when group is undefined). */
|
|
401
|
+
private onLocationFor(group?: string) {
|
|
402
|
+
const prefix = group ? `${group}.` : '';
|
|
403
|
+
return (e: Event) => {
|
|
404
|
+
const detail = (e as CustomEvent).detail as {
|
|
405
|
+
latitude?: number;
|
|
406
|
+
longitude?: number;
|
|
407
|
+
timezone?: string;
|
|
408
|
+
utcOffset?: number;
|
|
409
|
+
};
|
|
410
|
+
if (!detail) return;
|
|
347
411
|
this.values = {
|
|
348
412
|
...this.values,
|
|
349
|
-
latitude: detail.latitude,
|
|
350
|
-
longitude: detail.longitude,
|
|
351
|
-
timezone: detail.timezone ?? detail.utcOffset,
|
|
413
|
+
[`${prefix}latitude`]: detail.latitude,
|
|
414
|
+
[`${prefix}longitude`]: detail.longitude,
|
|
415
|
+
[`${prefix}timezone`]: detail.timezone ?? detail.utcOffset,
|
|
352
416
|
};
|
|
353
|
-
}
|
|
354
|
-
}
|
|
417
|
+
};
|
|
418
|
+
}
|
|
355
419
|
|
|
356
420
|
private onSubmit = (e: Event) => {
|
|
357
421
|
e.preventDefault();
|
|
358
422
|
const missing = this.fields
|
|
359
423
|
.filter((f) => f.required)
|
|
360
424
|
.filter(
|
|
361
|
-
(f) => this.values[f.
|
|
425
|
+
(f) => this.values[f.key] === undefined || this.values[f.key] === '',
|
|
362
426
|
);
|
|
363
427
|
if (missing.length > 0) {
|
|
364
428
|
this.dispatchEvent(
|
|
365
429
|
new CustomEvent('roxy-validation-error', {
|
|
366
|
-
detail: { missing: missing.map((m) => m.
|
|
430
|
+
detail: { missing: missing.map((m) => m.key) },
|
|
367
431
|
bubbles: true,
|
|
368
432
|
composed: true,
|
|
369
433
|
}),
|
|
370
434
|
);
|
|
371
435
|
return;
|
|
372
436
|
}
|
|
437
|
+
// Reconstruct the request shape: grouped fields nest as { group: { name: value } }.
|
|
438
|
+
const out: Record<string, unknown> = {};
|
|
439
|
+
for (const f of this.fields) {
|
|
440
|
+
const v = this.values[f.key];
|
|
441
|
+
if (v === undefined || v === '') continue;
|
|
442
|
+
if (f.group) {
|
|
443
|
+
const g = (out[f.group] as Record<string, unknown> | undefined) ?? {};
|
|
444
|
+
g[f.name] = v;
|
|
445
|
+
out[f.group] = g;
|
|
446
|
+
} else {
|
|
447
|
+
out[f.name] = v;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
373
450
|
this.dispatchEvent(
|
|
374
451
|
new CustomEvent('roxy-submit', {
|
|
375
|
-
detail: { endpoint: this.endpoint, values:
|
|
452
|
+
detail: { endpoint: this.endpoint, values: out },
|
|
376
453
|
bubbles: true,
|
|
377
454
|
composed: true,
|
|
378
455
|
}),
|
|
@@ -393,14 +470,14 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
393
470
|
|
|
394
471
|
const renderField = (f: FieldDef) => {
|
|
395
472
|
if (
|
|
396
|
-
this.
|
|
473
|
+
this.groupHasLocation(f.group) &&
|
|
397
474
|
(f.name === 'latitude' ||
|
|
398
475
|
f.name === 'longitude' ||
|
|
399
476
|
f.name === 'timezone')
|
|
400
477
|
) {
|
|
401
478
|
return nothing;
|
|
402
479
|
}
|
|
403
|
-
const inputId = `roxy-form-${f.
|
|
480
|
+
const inputId = `roxy-form-${f.key}`;
|
|
404
481
|
return html`<div class="field">
|
|
405
482
|
<label for=${inputId}>
|
|
406
483
|
${humanize(f.name)}${f.required ? html`<span class="req" aria-hidden="true">*</span>` : nothing}
|
|
@@ -410,13 +487,13 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
410
487
|
? html`<select
|
|
411
488
|
id=${inputId}
|
|
412
489
|
?required=${f.required}
|
|
413
|
-
@change=${(e: Event) => this.setValue(f.
|
|
490
|
+
@change=${(e: Event) => this.setValue(f.key, (e.target as HTMLSelectElement).value)}
|
|
414
491
|
>
|
|
415
492
|
<option value="">Choose</option>
|
|
416
493
|
${f.enum.map(
|
|
417
494
|
(
|
|
418
495
|
opt,
|
|
419
|
-
) => html`<option value=${opt} ?selected=${this.values[f.
|
|
496
|
+
) => html`<option value=${opt} ?selected=${this.values[f.key] === opt}>
|
|
420
497
|
${opt}
|
|
421
498
|
</option>`,
|
|
422
499
|
)}
|
|
@@ -428,10 +505,10 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
428
505
|
min=${f.min ?? ''}
|
|
429
506
|
max=${f.max ?? ''}
|
|
430
507
|
step=${f.type === 'number' ? 'any' : ''}
|
|
431
|
-
.value=${(this.values[f.
|
|
508
|
+
.value=${(this.values[f.key] ?? '') as string}
|
|
432
509
|
@input=${(e: Event) =>
|
|
433
510
|
this.setValue(
|
|
434
|
-
f.
|
|
511
|
+
f.key,
|
|
435
512
|
this.coerce(f.type, (e.target as HTMLInputElement).value),
|
|
436
513
|
)}
|
|
437
514
|
/>`
|
|
@@ -440,25 +517,42 @@ export class RoxyEndpointForm extends LitElement {
|
|
|
440
517
|
</div>`;
|
|
441
518
|
};
|
|
442
519
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
520
|
+
// Ordered list of field groups: the flat top level (undefined) plus each
|
|
521
|
+
// nested object (person1/person2). Order follows first appearance.
|
|
522
|
+
const groups: (string | undefined)[] = [];
|
|
523
|
+
for (const f of this.fields) {
|
|
524
|
+
if (!groups.includes(f.group)) groups.push(f.group);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
const locationBlock = (group?: string) =>
|
|
528
|
+
this.groupHasLocation(group)
|
|
529
|
+
? html`<div class="location-block">
|
|
530
|
+
<label>${group ? `${humanize(group)} location` : 'Birth location'}</label>
|
|
449
531
|
<roxy-location-search
|
|
450
|
-
@roxy-location-select=${this.
|
|
532
|
+
@roxy-location-select=${this.onLocationFor(group)}
|
|
451
533
|
placeholder="City of birth"
|
|
452
534
|
></roxy-location-search>
|
|
453
535
|
<small class="help">
|
|
454
536
|
Required: latitude, longitude, timezone. Pick a city to autofill.
|
|
455
537
|
</small>
|
|
456
538
|
</div>`
|
|
457
|
-
|
|
458
|
-
|
|
539
|
+
: nothing;
|
|
540
|
+
|
|
541
|
+
const groupBody = (group?: string) => html`${locationBlock(group)}
|
|
459
542
|
<div class="fields">
|
|
460
|
-
${this.fields.map((f) => renderField(f))}
|
|
461
|
-
</div
|
|
543
|
+
${this.fields.filter((f) => f.group === group).map((f) => renderField(f))}
|
|
544
|
+
</div>`;
|
|
545
|
+
|
|
546
|
+
return html`<form @submit=${this.onSubmit}>
|
|
547
|
+
<h2 class="title">${humanize(this.endpoint.split('/').pop() ?? '')}</h2>
|
|
548
|
+
${groups.map((g) =>
|
|
549
|
+
g === undefined
|
|
550
|
+
? groupBody(undefined)
|
|
551
|
+
: html`<fieldset class="person-group">
|
|
552
|
+
<legend>${humanize(g)}</legend>
|
|
553
|
+
${groupBody(g)}
|
|
554
|
+
</fieldset>`,
|
|
555
|
+
)}
|
|
462
556
|
<button class="submit" type="submit">${this.submitLabel}</button>
|
|
463
557
|
</form>`;
|
|
464
558
|
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { css, html, nothing } from 'lit';
|
|
2
|
+
import { customElement } from 'lit/decorators.js';
|
|
3
|
+
import type { GenerateDigestResponse } from '../types/index.js';
|
|
4
|
+
import { RoxyDataElement } from '../utils/base-element.js';
|
|
5
|
+
import { baseStyles } from '../utils/base-styles.js';
|
|
6
|
+
import { formatDate, formatNumber } from '../utils/format.js';
|
|
7
|
+
import { humanize } from '../utils/string.js';
|
|
8
|
+
|
|
9
|
+
type DigestWindow = NonNullable<GenerateDigestResponse['windows']>[number];
|
|
10
|
+
type DigestEvent = NonNullable<DigestWindow['top']>[number];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Forecast digest: the rolled-up reading across the next 24 hours, 7, 30, and 90 days. Renders /forecast/digest. Each window shows how many events fall in it, a per-domain breakdown (western, vedic, biorhythm), and the few highest-significance events with a significance bar coloured by domain. Use it as the at-a-glance period summary that pairs with the day-by-day roxy-forecast-timeline.
|
|
14
|
+
*/
|
|
15
|
+
@customElement('roxy-forecast-digest')
|
|
16
|
+
export class RoxyForecastDigest extends RoxyDataElement<GenerateDigestResponse> {
|
|
17
|
+
static styles = [
|
|
18
|
+
baseStyles,
|
|
19
|
+
css`
|
|
20
|
+
.wrap {
|
|
21
|
+
background: var(--roxy-surface, #fff);
|
|
22
|
+
color: var(--roxy-fg, #0a0a0a);
|
|
23
|
+
border: 1px solid var(--roxy-border, #e4e4e7);
|
|
24
|
+
border-radius: var(--roxy-radius-md, 8px);
|
|
25
|
+
padding: var(--roxy-space-lg, 1.5rem);
|
|
26
|
+
box-shadow: var(--roxy-shadow-sm);
|
|
27
|
+
display: grid;
|
|
28
|
+
gap: var(--roxy-space-md, 1rem);
|
|
29
|
+
}
|
|
30
|
+
.head {
|
|
31
|
+
display: flex;
|
|
32
|
+
justify-content: space-between;
|
|
33
|
+
align-items: baseline;
|
|
34
|
+
gap: var(--roxy-space-md, 1rem);
|
|
35
|
+
flex-wrap: wrap;
|
|
36
|
+
}
|
|
37
|
+
.title {
|
|
38
|
+
font-size: var(--roxy-text-lg, 1.125rem);
|
|
39
|
+
font-weight: var(--roxy-weight-bold, 600);
|
|
40
|
+
margin: 0;
|
|
41
|
+
}
|
|
42
|
+
.subtitle {
|
|
43
|
+
color: var(--roxy-muted, #71717a);
|
|
44
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
45
|
+
margin: 0;
|
|
46
|
+
}
|
|
47
|
+
.window {
|
|
48
|
+
display: grid;
|
|
49
|
+
gap: var(--roxy-space-sm, 0.5rem);
|
|
50
|
+
padding-top: var(--roxy-space-md, 1rem);
|
|
51
|
+
border-top: 1px solid var(--roxy-border, #e4e4e7);
|
|
52
|
+
}
|
|
53
|
+
.window:first-of-type {
|
|
54
|
+
border-top: none;
|
|
55
|
+
padding-top: 0;
|
|
56
|
+
}
|
|
57
|
+
.window-head {
|
|
58
|
+
display: flex;
|
|
59
|
+
align-items: baseline;
|
|
60
|
+
gap: 0.5rem;
|
|
61
|
+
flex-wrap: wrap;
|
|
62
|
+
}
|
|
63
|
+
.window-label {
|
|
64
|
+
font-weight: var(--roxy-weight-bold, 600);
|
|
65
|
+
}
|
|
66
|
+
.window-count {
|
|
67
|
+
margin-left: auto;
|
|
68
|
+
color: var(--roxy-muted, #71717a);
|
|
69
|
+
font-size: var(--roxy-text-xs, 0.75rem);
|
|
70
|
+
font-variant-numeric: tabular-nums;
|
|
71
|
+
}
|
|
72
|
+
.domains {
|
|
73
|
+
display: flex;
|
|
74
|
+
flex-wrap: wrap;
|
|
75
|
+
gap: 0.4rem;
|
|
76
|
+
}
|
|
77
|
+
.domain-chip {
|
|
78
|
+
display: inline-flex;
|
|
79
|
+
align-items: center;
|
|
80
|
+
gap: 0.35rem;
|
|
81
|
+
font-size: var(--roxy-text-xs, 0.75rem);
|
|
82
|
+
color: var(--roxy-muted, #71717a);
|
|
83
|
+
}
|
|
84
|
+
.swatch {
|
|
85
|
+
width: 0.65rem;
|
|
86
|
+
height: 0.65rem;
|
|
87
|
+
border-radius: 2px;
|
|
88
|
+
display: inline-block;
|
|
89
|
+
}
|
|
90
|
+
.sw-western {
|
|
91
|
+
background: var(--roxy-accent, #f59e0b);
|
|
92
|
+
}
|
|
93
|
+
.sw-vedic {
|
|
94
|
+
background: var(--roxy-info, #2563eb);
|
|
95
|
+
}
|
|
96
|
+
.sw-biorhythm {
|
|
97
|
+
background: var(--roxy-success, #16a34a);
|
|
98
|
+
}
|
|
99
|
+
.event {
|
|
100
|
+
display: grid;
|
|
101
|
+
grid-template-columns: auto 1fr;
|
|
102
|
+
gap: 0.25rem 0.6rem;
|
|
103
|
+
align-items: baseline;
|
|
104
|
+
}
|
|
105
|
+
.event-date {
|
|
106
|
+
color: var(--roxy-muted, #71717a);
|
|
107
|
+
font-size: var(--roxy-text-xs, 0.75rem);
|
|
108
|
+
font-variant-numeric: tabular-nums;
|
|
109
|
+
white-space: nowrap;
|
|
110
|
+
}
|
|
111
|
+
.event-desc {
|
|
112
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
113
|
+
line-height: 1.4;
|
|
114
|
+
}
|
|
115
|
+
.sig {
|
|
116
|
+
grid-column: 2;
|
|
117
|
+
height: 4px;
|
|
118
|
+
border-radius: 2px;
|
|
119
|
+
background: color-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent);
|
|
120
|
+
overflow: hidden;
|
|
121
|
+
}
|
|
122
|
+
.sig-fill {
|
|
123
|
+
display: block;
|
|
124
|
+
height: 100%;
|
|
125
|
+
border-radius: 2px;
|
|
126
|
+
}
|
|
127
|
+
.sig-fill.western {
|
|
128
|
+
background: var(--roxy-accent, #f59e0b);
|
|
129
|
+
}
|
|
130
|
+
.sig-fill.vedic {
|
|
131
|
+
background: var(--roxy-info, #2563eb);
|
|
132
|
+
}
|
|
133
|
+
.sig-fill.biorhythm {
|
|
134
|
+
background: var(--roxy-success, #16a34a);
|
|
135
|
+
}
|
|
136
|
+
.quiet {
|
|
137
|
+
color: var(--roxy-muted, #71717a);
|
|
138
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
139
|
+
font-style: italic;
|
|
140
|
+
}
|
|
141
|
+
`,
|
|
142
|
+
];
|
|
143
|
+
|
|
144
|
+
protected renderEmpty() {
|
|
145
|
+
return html`<div class="roxy-empty" role="status">No digest data</div>`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
protected renderData(d: GenerateDigestResponse) {
|
|
149
|
+
const windows = d.windows ?? [];
|
|
150
|
+
if (windows.length === 0) return this.renderEmpty();
|
|
151
|
+
const range = [formatDate(d.startDate), formatDate(d.endDate)]
|
|
152
|
+
.filter(Boolean)
|
|
153
|
+
.join(' – ');
|
|
154
|
+
|
|
155
|
+
return html`<div class="wrap" aria-label="Forecast digest">
|
|
156
|
+
<div class="head">
|
|
157
|
+
<h2 class="title">Forecast Digest</h2>
|
|
158
|
+
${range ? html`<p class="subtitle">${range}</p>` : nothing}
|
|
159
|
+
</div>
|
|
160
|
+
${windows.map((w) => this.renderWindow(w))}
|
|
161
|
+
</div>`;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private windowLabel(days: number | undefined): string {
|
|
165
|
+
if (days === 1) return 'Next 24 hours';
|
|
166
|
+
return typeof days === 'number' ? `Next ${days} days` : 'Window';
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private renderWindow(w: DigestWindow) {
|
|
170
|
+
const top = w.top ?? [];
|
|
171
|
+
const byDomain = w.byDomain ?? {};
|
|
172
|
+
const domains = Object.entries(byDomain) as Array<[string, number]>;
|
|
173
|
+
return html`<section class="window">
|
|
174
|
+
<div class="window-head">
|
|
175
|
+
<span class="window-label">${this.windowLabel(w.days)}</span>
|
|
176
|
+
<span class="window-count">${w.count ?? 0} event${w.count === 1 ? '' : 's'}</span>
|
|
177
|
+
</div>
|
|
178
|
+
${
|
|
179
|
+
domains.length > 0
|
|
180
|
+
? html`<div class="domains">
|
|
181
|
+
${domains.map(
|
|
182
|
+
([dom, n]) => html`<span class="domain-chip">
|
|
183
|
+
<span class="swatch sw-${dom}"></span>${humanize(dom)} ${n}
|
|
184
|
+
</span>`,
|
|
185
|
+
)}
|
|
186
|
+
</div>`
|
|
187
|
+
: nothing
|
|
188
|
+
}
|
|
189
|
+
${
|
|
190
|
+
top.length > 0
|
|
191
|
+
? html`<div role="list">${top.map((e) => this.renderEvent(e))}</div>`
|
|
192
|
+
: html`<p class="quiet">No notable events.</p>`
|
|
193
|
+
}
|
|
194
|
+
</section>`;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private renderEvent(e: DigestEvent) {
|
|
198
|
+
const sig = typeof e.significance === 'number' ? e.significance : 0;
|
|
199
|
+
return html`<div class="event" role="listitem">
|
|
200
|
+
<span class="event-date">${formatDate(e.date)}</span>
|
|
201
|
+
<span class="event-desc">${e.description ?? humanize(e.type ?? '')}</span>
|
|
202
|
+
<span class="sig" role="img" aria-label="significance ${formatNumber(sig, 0)} of 100">
|
|
203
|
+
<span class="sig-fill ${e.domain}" style="width:${Math.max(0, Math.min(100, sig))}%"></span>
|
|
204
|
+
</span>
|
|
205
|
+
</div>`;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
declare global {
|
|
210
|
+
interface HTMLElementTagNameMap {
|
|
211
|
+
'roxy-forecast-digest': RoxyForecastDigest;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
-
import { css, html,
|
|
2
|
-
import { customElement
|
|
1
|
+
import { css, html, nothing } from 'lit';
|
|
2
|
+
import { customElement } from 'lit/decorators.js';
|
|
3
3
|
import { ASPECT_SYMBOL } from '../tokens/index.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
FindSignificantDatesResponse,
|
|
6
|
+
ForecastTransitsResponse,
|
|
7
|
+
GenerateTimelineResponse,
|
|
8
|
+
} from '../types/index.js';
|
|
9
|
+
import { RoxyDataElement } from '../utils/base-element.js';
|
|
5
10
|
import { baseStyles } from '../utils/base-styles.js';
|
|
6
11
|
import { ASPECT_CLASS, formatDate, formatNumber } from '../utils/format.js';
|
|
7
|
-
import { MarkupDataController } from '../utils/markup-data.js';
|
|
8
12
|
import { capitalize, humanize } from '../utils/string.js';
|
|
9
13
|
|
|
14
|
+
/** Timeline, significant-dates, and forecast-transits all return the same `{ events, startDate, endDate, birthData, count }` shape. */
|
|
15
|
+
type ForecastTimelineData =
|
|
16
|
+
| GenerateTimelineResponse
|
|
17
|
+
| FindSignificantDatesResponse
|
|
18
|
+
| ForecastTransitsResponse;
|
|
19
|
+
|
|
10
20
|
type ForecastEvent = GenerateTimelineResponse['events'][number];
|
|
11
21
|
type ForecastDomain = ForecastEvent['domain'];
|
|
12
22
|
|
|
@@ -38,11 +48,17 @@ const DOMAIN_ORDER: readonly ForecastDomain[] = [
|
|
|
38
48
|
* Theming flows through `--roxy-*` custom properties on `:host`.
|
|
39
49
|
*/
|
|
40
50
|
@customElement('roxy-forecast-timeline')
|
|
41
|
-
export class RoxyForecastTimeline extends
|
|
51
|
+
export class RoxyForecastTimeline extends RoxyDataElement<ForecastTimelineData> {
|
|
42
52
|
static styles = [
|
|
43
53
|
baseStyles,
|
|
44
54
|
css`
|
|
45
55
|
.wrap {
|
|
56
|
+
background: var(--roxy-surface, #fff);
|
|
57
|
+
color: var(--roxy-fg, #0a0a0a);
|
|
58
|
+
border: 1px solid var(--roxy-border, #e4e4e7);
|
|
59
|
+
border-radius: var(--roxy-radius-md, 8px);
|
|
60
|
+
padding: var(--roxy-space-lg, 1.5rem);
|
|
61
|
+
box-shadow: var(--roxy-shadow-sm);
|
|
46
62
|
display: grid;
|
|
47
63
|
gap: var(--roxy-space-md, 1rem);
|
|
48
64
|
}
|
|
@@ -195,22 +211,11 @@ export class RoxyForecastTimeline extends LitElement {
|
|
|
195
211
|
`,
|
|
196
212
|
];
|
|
197
213
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
// Enables hydrating `data` from a direct-child
|
|
201
|
-
// <script type="application/json" class="roxy-data"> for server-rendered
|
|
202
|
-
// and cached consumers. The JavaScript `data` property still wins.
|
|
203
|
-
new MarkupDataController(this);
|
|
214
|
+
protected renderEmpty() {
|
|
215
|
+
return html`<div class="roxy-empty" role="status">No forecast data</div>`;
|
|
204
216
|
}
|
|
205
217
|
|
|
206
|
-
|
|
207
|
-
data: GenerateTimelineResponse | null = null;
|
|
208
|
-
|
|
209
|
-
render() {
|
|
210
|
-
const d = this.data;
|
|
211
|
-
if (!d)
|
|
212
|
-
return html`<div class="roxy-empty" role="status">No forecast data</div>`;
|
|
213
|
-
|
|
218
|
+
protected renderData(d: ForecastTimelineData) {
|
|
214
219
|
const events = d.events ?? [];
|
|
215
220
|
const grouped = this.groupByDate(events);
|
|
216
221
|
const present = DOMAIN_ORDER.filter((dom) =>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { css, html,
|
|
2
|
-
import { customElement
|
|
1
|
+
import { css, html, nothing } from 'lit';
|
|
2
|
+
import { customElement } from 'lit/decorators.js';
|
|
3
3
|
import type { CompatibilityResponse } from '../types/index.js';
|
|
4
|
+
import { RoxyDataElement } from '../utils/base-element.js';
|
|
4
5
|
import { baseStyles } from '../utils/base-styles.js';
|
|
5
6
|
import { formatNumber, formatPercent } from '../utils/format.js';
|
|
6
|
-
import { MarkupDataController } from '../utils/markup-data.js';
|
|
7
7
|
|
|
8
8
|
const STANDARD_CATEGORIES = [
|
|
9
9
|
'Varna',
|
|
@@ -20,12 +20,12 @@ const STANDARD_CATEGORIES = [
|
|
|
20
20
|
* 36-point Ashtakoota score card. Renders /vedic-astrology/compatibility.
|
|
21
21
|
*/
|
|
22
22
|
@customElement('roxy-guna-milan')
|
|
23
|
-
export class RoxyGunaMilan extends
|
|
23
|
+
export class RoxyGunaMilan extends RoxyDataElement<CompatibilityResponse> {
|
|
24
24
|
static styles = [
|
|
25
25
|
baseStyles,
|
|
26
26
|
css`
|
|
27
27
|
.card {
|
|
28
|
-
background: var(--roxy-
|
|
28
|
+
background: var(--roxy-surface, #fff);
|
|
29
29
|
border: 1px solid var(--roxy-border, #e4e4e7);
|
|
30
30
|
border-radius: var(--roxy-radius-md, 8px);
|
|
31
31
|
padding: var(--roxy-space-lg, 1.5rem);
|
|
@@ -147,22 +147,11 @@ export class RoxyGunaMilan extends LitElement {
|
|
|
147
147
|
`,
|
|
148
148
|
];
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
// Enables hydrating `data` from a direct-child
|
|
153
|
-
// <script type="application/json" class="roxy-data"> for server-rendered
|
|
154
|
-
// and cached consumers. The JavaScript `data` property still wins.
|
|
155
|
-
new MarkupDataController(this);
|
|
150
|
+
protected renderEmpty() {
|
|
151
|
+
return html`<div class="roxy-empty" role="status">No Guna Milan data</div>`;
|
|
156
152
|
}
|
|
157
153
|
|
|
158
|
-
|
|
159
|
-
data: CompatibilityResponse | null = null;
|
|
160
|
-
|
|
161
|
-
render() {
|
|
162
|
-
const d = this.data;
|
|
163
|
-
if (!d)
|
|
164
|
-
return html`<div class="roxy-empty" role="status">No Guna Milan data</div>`;
|
|
165
|
-
|
|
154
|
+
protected renderData(d: CompatibilityResponse) {
|
|
166
155
|
const breakdown = (d.breakdown ?? []).filter(
|
|
167
156
|
(b) => b?.category !== undefined,
|
|
168
157
|
);
|