@roxyapi/ui 0.3.1 → 0.4.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 +27 -1
- package/README.md +115 -14
- package/dist/cdn/components/ashtakavarga-grid.js +74 -19
- package/dist/cdn/components/ashtakavarga-grid.js.map +2 -2
- package/dist/cdn/components/biorhythm-chart.js +18 -4
- package/dist/cdn/components/biorhythm-chart.js.map +2 -2
- package/dist/cdn/components/choghadiya-grid.js +47 -12
- package/dist/cdn/components/choghadiya-grid.js.map +3 -3
- package/dist/cdn/components/compatibility-card.js +21 -7
- package/dist/cdn/components/compatibility-card.js.map +2 -2
- package/dist/cdn/components/dasha-timeline.js +113 -28
- package/dist/cdn/components/dasha-timeline.js.map +3 -3
- package/dist/cdn/components/data.js +27 -13
- package/dist/cdn/components/data.js.map +2 -2
- package/dist/cdn/components/divisional-chart.js +225 -118
- package/dist/cdn/components/divisional-chart.js.map +4 -4
- package/dist/cdn/components/dosha-card.js +18 -4
- package/dist/cdn/components/dosha-card.js.map +2 -2
- package/dist/cdn/components/endpoint-form.js +25 -11
- package/dist/cdn/components/endpoint-form.js.map +2 -2
- package/dist/cdn/components/guna-milan.js +20 -6
- package/dist/cdn/components/guna-milan.js.map +2 -2
- package/dist/cdn/components/hexagram.js +22 -8
- package/dist/cdn/components/hexagram.js.map +2 -2
- package/dist/cdn/components/horoscope-card.js +20 -6
- package/dist/cdn/components/horoscope-card.js.map +2 -2
- package/dist/cdn/components/kp-chart.js +19 -5
- package/dist/cdn/components/kp-chart.js.map +2 -2
- package/dist/cdn/components/kp-planets-table.js +17 -3
- package/dist/cdn/components/kp-planets-table.js.map +2 -2
- package/dist/cdn/components/kp-ruling-planets.js +17 -3
- package/dist/cdn/components/kp-ruling-planets.js.map +2 -2
- package/dist/cdn/components/location-search.js +18 -4
- package/dist/cdn/components/location-search.js.map +2 -2
- package/dist/cdn/components/moon-phase.js +27 -13
- package/dist/cdn/components/moon-phase.js.map +2 -2
- package/dist/cdn/components/nakshatra-card.js +16 -2
- package/dist/cdn/components/nakshatra-card.js.map +2 -2
- package/dist/cdn/components/natal-chart.js +79 -40
- package/dist/cdn/components/natal-chart.js.map +3 -3
- package/dist/cdn/components/numerology-card.js +18 -4
- package/dist/cdn/components/numerology-card.js.map +2 -2
- package/dist/cdn/components/panchang-table.js +53 -25
- package/dist/cdn/components/panchang-table.js.map +3 -3
- package/dist/cdn/components/shadbala-table.js +24 -10
- package/dist/cdn/components/shadbala-table.js.map +2 -2
- package/dist/cdn/components/synastry-chart.js +96 -48
- package/dist/cdn/components/synastry-chart.js.map +3 -3
- package/dist/cdn/components/tarot-card.js +17 -3
- package/dist/cdn/components/tarot-card.js.map +2 -2
- package/dist/cdn/components/tarot-spread.js +39 -25
- package/dist/cdn/components/tarot-spread.js.map +2 -2
- package/dist/cdn/components/transits-table.js +18 -4
- package/dist/cdn/components/transits-table.js.map +2 -2
- package/dist/cdn/components/vedic-kundli.js +215 -105
- package/dist/cdn/components/vedic-kundli.js.map +4 -4
- package/dist/cdn/components/vedic-planets-table.js +22 -8
- package/dist/cdn/components/vedic-planets-table.js.map +2 -2
- package/dist/cdn/components/western-planets-table.js +18 -4
- package/dist/cdn/components/western-planets-table.js.map +2 -2
- package/dist/cdn/components/yoga-list.js +17 -3
- package/dist/cdn/components/yoga-list.js.map +2 -2
- package/dist/cdn/roxy-ui.js +1082 -816
- package/dist/cdn/roxy-ui.js.map +4 -4
- package/dist/components/ashtakavarga-grid.d.ts +13 -1
- package/dist/components/ashtakavarga-grid.d.ts.map +1 -1
- package/dist/components/ashtakavarga-grid.js +86 -11
- package/dist/components/ashtakavarga-grid.js.map +2 -2
- package/dist/components/biorhythm-chart.js +14 -0
- package/dist/components/biorhythm-chart.js.map +2 -2
- package/dist/components/choghadiya-grid.d.ts +6 -0
- package/dist/components/choghadiya-grid.d.ts.map +1 -1
- package/dist/components/choghadiya-grid.js +50 -2
- package/dist/components/choghadiya-grid.js.map +2 -2
- package/dist/components/compatibility-card.js +14 -0
- package/dist/components/compatibility-card.js.map +2 -2
- package/dist/components/dasha-timeline.d.ts +10 -0
- package/dist/components/dasha-timeline.d.ts.map +1 -1
- package/dist/components/dasha-timeline.js +135 -4
- package/dist/components/dasha-timeline.js.map +2 -2
- package/dist/components/data.js +14 -0
- package/dist/components/data.js.map +2 -2
- package/dist/components/divisional-chart.d.ts +9 -6
- package/dist/components/divisional-chart.d.ts.map +1 -1
- package/dist/components/divisional-chart.js +546 -251
- package/dist/components/divisional-chart.js.map +4 -4
- package/dist/components/dosha-card.js +14 -0
- package/dist/components/dosha-card.js.map +2 -2
- package/dist/components/endpoint-form.js +14 -0
- package/dist/components/endpoint-form.js.map +2 -2
- package/dist/components/guna-milan.js +14 -0
- package/dist/components/guna-milan.js.map +2 -2
- package/dist/components/hexagram.js +14 -0
- package/dist/components/hexagram.js.map +2 -2
- package/dist/components/horoscope-card.js +14 -0
- package/dist/components/horoscope-card.js.map +2 -2
- package/dist/components/kp-chart.js +14 -0
- package/dist/components/kp-chart.js.map +2 -2
- package/dist/components/kp-planets-table.js +14 -0
- package/dist/components/kp-planets-table.js.map +2 -2
- package/dist/components/kp-ruling-planets.js +14 -0
- package/dist/components/kp-ruling-planets.js.map +2 -2
- package/dist/components/location-search.js +14 -0
- package/dist/components/location-search.js.map +2 -2
- package/dist/components/moon-phase.js +14 -0
- package/dist/components/moon-phase.js.map +2 -2
- package/dist/components/nakshatra-card.js +14 -0
- package/dist/components/nakshatra-card.js.map +2 -2
- package/dist/components/natal-chart.d.ts.map +1 -1
- package/dist/components/natal-chart.js +76 -6
- package/dist/components/natal-chart.js.map +2 -2
- package/dist/components/numerology-card.js +14 -0
- package/dist/components/numerology-card.js.map +2 -2
- package/dist/components/panchang-table.d.ts +1 -0
- package/dist/components/panchang-table.d.ts.map +1 -1
- package/dist/components/panchang-table.js +37 -1
- package/dist/components/panchang-table.js.map +2 -2
- package/dist/components/shadbala-table.js +14 -0
- package/dist/components/shadbala-table.js.map +2 -2
- package/dist/components/synastry-chart.d.ts +6 -0
- package/dist/components/synastry-chart.d.ts.map +1 -1
- package/dist/components/synastry-chart.js +106 -7
- package/dist/components/synastry-chart.js.map +2 -2
- package/dist/components/tarot-card.js +14 -0
- package/dist/components/tarot-card.js.map +2 -2
- package/dist/components/tarot-spread.js +14 -0
- package/dist/components/tarot-spread.js.map +2 -2
- package/dist/components/transits-table.js +14 -0
- package/dist/components/transits-table.js.map +2 -2
- package/dist/components/vedic-kundli.d.ts +14 -9
- package/dist/components/vedic-kundli.d.ts.map +1 -1
- package/dist/components/vedic-kundli.js +537 -245
- package/dist/components/vedic-kundli.js.map +4 -4
- package/dist/components/vedic-planets-table.js +14 -0
- package/dist/components/vedic-planets-table.js.map +2 -2
- package/dist/components/western-planets-table.js +14 -0
- package/dist/components/western-planets-table.js.map +2 -2
- package/dist/components/yoga-list.js +14 -0
- package/dist/components/yoga-list.js.map +2 -2
- package/dist/index.cjs +1397 -797
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +1278 -678
- package/dist/index.js.map +4 -4
- package/dist/manifest.json +23 -23
- package/dist/styles/tokens.css +8 -23
- package/dist/utils/base-styles.d.ts.map +1 -1
- package/dist/utils/kundli-render.d.ts +43 -104
- package/dist/utils/kundli-render.d.ts.map +1 -1
- package/dist/utils/kundli-styles.d.ts +13 -0
- package/dist/utils/kundli-styles.d.ts.map +1 -0
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/ashtakavarga-grid.ts +73 -11
- package/src/components/choghadiya-grid.ts +37 -2
- package/src/components/dasha-timeline.ts +135 -4
- package/src/components/divisional-chart.ts +40 -97
- package/src/components/natal-chart.ts +89 -6
- package/src/components/panchang-table.ts +34 -1
- package/src/components/synastry-chart.ts +84 -8
- package/src/components/vedic-kundli.ts +35 -95
- package/src/styles/tokens.css +8 -23
- package/src/utils/base-styles.ts +14 -0
- package/src/utils/kundli-render.ts +609 -270
- package/src/utils/kundli-styles.ts +124 -0
- package/src/version.ts +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/guna-milan.ts", "../../src/utils/base-styles.ts", "../../src/utils/format.ts"],
|
|
4
|
-
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { CompatibilityResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber, formatPercent } from '../utils/format.js';\n\nconst STANDARD_CATEGORIES = [\n\t'Varna',\n\t'Vasya',\n\t'Tara',\n\t'Yoni',\n\t'Maitri',\n\t'Gana',\n\t'Bhakoot',\n\t'Nadi',\n];\n\n/**\n * 36-point Ashtakoota score card. Renders /vedic-astrology/compatibility.\n */\n@customElement('roxy-guna-milan')\nexport class RoxyGunaMilan extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.card {\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.score-header {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tgap: 1rem;\n\t\t\t}\n\t\t\t.score-info {\n\t\t\t\tflex: 1;\n\t\t\t}\n\t\t\t.score-bar {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: 1fr auto;\n\t\t\t\talign-items: center;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\t\t\t.total {\n\t\t\t\tfont-size: 2.25rem;\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t\tline-height: 1;\n\t\t\t}\n\t\t\t.over {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\t\t}\n\t\t\t.recommendation {\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\t\t\t.score-ring {\n\t\t\t\twidth: 120px;\n\t\t\t\theight: 120px;\n\t\t\t\tflex-shrink: 0;\n\t\t\t}\n\t\t\t.score-ring svg {\n\t\t\t\twidth: 100%;\n\t\t\t\theight: 100%;\n\t\t\t}\n\t\t\t.score-ring .ring-text {\n\t\t\t\tfont-size: 22px;\n\t\t\t\tfont-weight: 700;\n\t\t\t\tfill: var(--roxy-fg, #0a0a0a);\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t}\n\t\t\t.score-ring .ring-max {\n\t\t\t\tfont-size: 10px;\n\t\t\t\tfill: var(--roxy-muted, #71717a);\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t}\n\n\t\t\ttable {\n\t\t\t\twidth: 100%;\n\t\t\t\tborder-collapse: collapse;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t\tth,\n\t\t\ttd {\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem);\n\t\t\t\tborder-bottom: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\ttext-align: left;\n\t\t\t}\n\t\t\tth {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t\ttd.score {\n\t\t\t\ttext-align: right;\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\ttd.bar-cell {\n\t\t\t\twidth: 30%;\n\t\t\t}\n\t\t\t.mini-bar {\n\t\t\t\theight: 8px;\n\t\t\t\tbackground: var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\toverflow: hidden;\n\t\t\t}\n\t\t\t.mini-bar > span {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 100%;\n\t\t\t\tbackground: var(--roxy-accent, #f59e0b);\n\t\t\t\ttransition:\n\t\t\t\t\twidth var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t}\n\n\t\t\t.tags {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t}\n\t\t\t.tags span {\n\t\t\t\tpadding: 2px 8px;\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t}\n\t\t\t.tags .dosha {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-danger, #dc2626) 16%, transparent);\n\t\t\t\tcolor: var(--roxy-danger-fg, #991b1b);\n\t\t\t}\n\t\t\t.tags .cancel {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-success, #16a34a) 18%, transparent);\n\t\t\t\tcolor: var(--roxy-success-fg, #166534);\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: CompatibilityResponse | null = null;\n\n\trender() {\n\t\tconst d = this.data;\n\t\tif (!d)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No Guna Milan data</div>`;\n\n\t\tconst breakdown = (d.breakdown ?? []).filter(\n\t\t\t(b) => b?.category !== undefined,\n\t\t);\n\n\t\tconst score = d.total ?? 0;\n\t\tconst max = d.maxScore ?? 36;\n\t\tconst pct = (score / max) * 100;\n\t\tconst trackColor =\n\t\t\t'color-mix(in srgb, var(--roxy-border) 50%, transparent)';\n\t\tconst fillColor =\n\t\t\tpct >= 70\n\t\t\t\t? 'var(--roxy-success)'\n\t\t\t\t: pct >= 50\n\t\t\t\t\t? 'var(--roxy-warning)'\n\t\t\t\t\t: 'var(--roxy-danger)';\n\t\t// SVG circle with r=45: circumference = 2 * pi * 45 = 282.74\n\t\t// dasharray segments = pct * 2.827, (100 - pct) * 2.827\n\t\tconst dashFill = pct * 2.827;\n\t\tconst dashGap = (100 - pct) * 2.827;\n\n\t\treturn html`<article class=\"card\" aria-label=\"Guna Milan score\">\n\t\t\t<div class=\"score-header\">\n\t\t\t\t<div class=\"score-info\">\n\t\t\t\t\t<div class=\"score-bar\">\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<span class=\"total\">${formatNumber(d.total, 1)}</span>\n\t\t\t\t\t\t\t<span class=\"over\"> / ${d.maxScore}</span>\n\t\t\t\t\t\t\t${\n\t\t\t\t\t\t\t\ttypeof d.percentage === 'number'\n\t\t\t\t\t\t\t\t\t? html`<small style=\"margin-left: 0.5rem; color: var(--roxy-muted)\">\n\t\t\t\t\t\t\t\t\t\t${formatPercent(d.percentage, 1)}\n\t\t\t\t\t\t\t\t\t</small>`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\td.recommendation\n\t\t\t\t\t\t\t\t? html`<span class=\"recommendation\">${d.recommendation}</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"score-ring\" role=\"meter\" aria-label=\"Guna milan score\" aria-valuemin=\"0\" aria-valuemax=\"36\" aria-valuenow=\"${score}\">\n\t\t\t\t\t<svg viewBox=\"0 0 100 100\" aria-hidden=\"true\">\n\t\t\t\t\t\t<circle class=\"ring-track\" cx=\"50\" cy=\"50\" r=\"45\" fill=\"none\" stroke=\"${trackColor}\" stroke-width=\"8\"/>\n\t\t\t\t\t\t<circle class=\"ring-fill\" cx=\"50\" cy=\"50\" r=\"45\" fill=\"none\" stroke=\"${fillColor}\" stroke-width=\"8\"\n\t\t\t\t\t\t\t\tstroke-dasharray=\"${dashFill},${dashGap}\" stroke-linecap=\"round\"\n\t\t\t\t\t\t\t\ttransform=\"rotate(-90 50 50)\"/>\n\t\t\t\t\t\t<text x=\"50\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\" class=\"ring-text\">${score}</text>\n\t\t\t\t\t\t<text x=\"50\" y=\"64\" text-anchor=\"middle\" dominant-baseline=\"central\" class=\"ring-max\">/${max}</text>\n\t\t\t\t\t</svg>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t${\n\t\t\t\tbreakdown.length > 0\n\t\t\t\t\t? html`<table>\n\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<th>Category</th>\n\t\t\t\t\t\t\t\t<th>Progress</th>\n\t\t\t\t\t\t\t\t<th class=\"score\">Score</th>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t${breakdown.map((b) => {\n\t\t\t\t\t\t\t\tconst score = b.score ?? 0;\n\t\t\t\t\t\t\t\tconst maxScore = b.maxScore ?? defaultMax(b.category);\n\t\t\t\t\t\t\t\tconst pct = maxScore ? (score / maxScore) * 100 : 0;\n\t\t\t\t\t\t\t\treturn html`<tr>\n\t\t\t\t\t\t\t\t\t<td>${b.category}</td>\n\t\t\t\t\t\t\t\t\t<td class=\"bar-cell\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"mini-bar\">\n\t\t\t\t\t\t\t\t\t\t\t<span style=\"width: ${pct}%\"></span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td class=\"score\">${formatNumber(score, 1)} / ${maxScore}</td>\n\t\t\t\t\t\t\t\t</tr>`;\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</tbody>\n\t\t\t\t\t</table>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${\n\t\t\t\t(d.doshas?.length ?? 0) > 0 || (d.doshaCancellations?.length ?? 0) > 0\n\t\t\t\t\t? html`<div class=\"tags\">\n\t\t\t\t\t\t${d.doshas?.map((x) => html`<span class=\"dosha\">${x}</span>`)}\n\t\t\t\t\t\t${d.doshaCancellations?.map(\n\t\t\t\t\t\t\t(x) =>\n\t\t\t\t\t\t\t\thtml`<span class=\"cancel\" title=${x.reason}>${x.dosha} cancelled</span>`,\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t</article>`;\n\t}\n}\n\nfunction defaultMax(name?: string): number {\n\tif (!name) return 1;\n\tswitch (name.toLowerCase()) {\n\t\tcase 'varna':\n\t\t\treturn 1;\n\t\tcase 'vasya':\n\t\t\treturn 2;\n\t\tcase 'tara':\n\t\t\treturn 3;\n\t\tcase 'yoni':\n\t\t\treturn 4;\n\t\tcase 'maitri':\n\t\t\treturn 5;\n\t\tcase 'gana':\n\t\t\treturn 6;\n\t\tcase 'bhakoot':\n\t\t\treturn 7;\n\t\tcase 'nadi':\n\t\t\treturn 8;\n\t\tdefault:\n\t\t\treturn 1;\n\t}\n}\n\nexport const GUNA_CATEGORIES = STANDARD_CATEGORIES;\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-guna-milan': RoxyGunaMilan;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n", "/**\n * Display formatters for ISO timestamps and floats coming back from the API.\n * Every helper returns \"\" for nullish or unparseable input so it falls out of\n * template literals cleanly.\n */\n\nexport function formatTime(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tif (/^\\d{4}-\\d{2}-\\d{2}$/.test(input)) return '';\n\tconst bareTime = /^\\d{2}:\\d{2}(:\\d{2})?$/.test(input);\n\tconst iso = bareTime ? `1970-01-01T${input}` : input;\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleTimeString(undefined, {\n\t\thour: 'numeric',\n\t\tminute: '2-digit',\n\t\thour12: true,\n\t});\n}\n\nexport function formatDate(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tconst d = new Date(\n\t\t/^\\d{4}-\\d{2}-\\d{2}$/.test(input) ? `${input}T00:00:00` : input,\n\t);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleDateString(undefined, {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: 'numeric',\n\t});\n}\n\nexport function formatTimeRange(\n\tt: { start?: string; end?: string } | undefined,\n): string {\n\tif (!t) return '';\n\tconst start = formatTime(t.start);\n\tconst end = formatTime(t.end);\n\tif (start && end) return `${start} - ${end}`;\n\treturn start || end || '';\n}\n\nexport function formatNumber(value: unknown, dp = 1): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\treturn value.toFixed(dp).replace(/\\.?0+$/, '');\n}\n\nexport function formatPercent(value: unknown, dp = 1): string {\n\tconst n = formatNumber(value, dp);\n\treturn n ? `${n}%` : '';\n}\n\n/**\n * CSS class name per aspect type. Used by natal and synastry chart aspect\n * lines so the same color encoding (harmonious vs challenging) applies in\n * both wheels. Keys are lowercase canonical names, values are CSS class\n * suffixes the chart components define in their `:host` styles.\n */\nexport const ASPECT_CLASS: Record<string, string> = {\n\tconjunction: 'aspect-conjunction',\n\tsextile: 'aspect-sextile',\n\tsquare: 'aspect-square',\n\ttrine: 'aspect-trine',\n\topposition: 'aspect-opposition',\n};\n\n/**\n * Normalize the `type` field on an aspect entry to a lowercase, hyphen-separated\n * canonical name (`SEMI_SEXTILE` \u2192 `semi-sextile`). Accepts any aspect-shaped\n * object so both natal and synastry inter-aspect entries can share this.\n */\nexport function normalizeAspect(a: { type?: string }): string {\n\treturn (a.type ?? '').toLowerCase().replace(/_/g, '-');\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { CompatibilityResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber, formatPercent } from '../utils/format.js';\n\nconst STANDARD_CATEGORIES = [\n\t'Varna',\n\t'Vasya',\n\t'Tara',\n\t'Yoni',\n\t'Maitri',\n\t'Gana',\n\t'Bhakoot',\n\t'Nadi',\n];\n\n/**\n * 36-point Ashtakoota score card. Renders /vedic-astrology/compatibility.\n */\n@customElement('roxy-guna-milan')\nexport class RoxyGunaMilan extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.card {\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.score-header {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tgap: 1rem;\n\t\t\t}\n\t\t\t.score-info {\n\t\t\t\tflex: 1;\n\t\t\t}\n\t\t\t.score-bar {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: 1fr auto;\n\t\t\t\talign-items: center;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\t\t\t.total {\n\t\t\t\tfont-size: 2.25rem;\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t\tline-height: 1;\n\t\t\t}\n\t\t\t.over {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\t\t}\n\t\t\t.recommendation {\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\t\t\t.score-ring {\n\t\t\t\twidth: 120px;\n\t\t\t\theight: 120px;\n\t\t\t\tflex-shrink: 0;\n\t\t\t}\n\t\t\t.score-ring svg {\n\t\t\t\twidth: 100%;\n\t\t\t\theight: 100%;\n\t\t\t}\n\t\t\t.score-ring .ring-text {\n\t\t\t\tfont-size: 22px;\n\t\t\t\tfont-weight: 700;\n\t\t\t\tfill: var(--roxy-fg, #0a0a0a);\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t}\n\t\t\t.score-ring .ring-max {\n\t\t\t\tfont-size: 10px;\n\t\t\t\tfill: var(--roxy-muted, #71717a);\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t}\n\n\t\t\ttable {\n\t\t\t\twidth: 100%;\n\t\t\t\tborder-collapse: collapse;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t\tth,\n\t\t\ttd {\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem);\n\t\t\t\tborder-bottom: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\ttext-align: left;\n\t\t\t}\n\t\t\tth {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t\ttd.score {\n\t\t\t\ttext-align: right;\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\ttd.bar-cell {\n\t\t\t\twidth: 30%;\n\t\t\t}\n\t\t\t.mini-bar {\n\t\t\t\theight: 8px;\n\t\t\t\tbackground: var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\toverflow: hidden;\n\t\t\t}\n\t\t\t.mini-bar > span {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 100%;\n\t\t\t\tbackground: var(--roxy-accent, #f59e0b);\n\t\t\t\ttransition:\n\t\t\t\t\twidth var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t}\n\n\t\t\t.tags {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t}\n\t\t\t.tags span {\n\t\t\t\tpadding: 2px 8px;\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t}\n\t\t\t.tags .dosha {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-danger, #dc2626) 16%, transparent);\n\t\t\t\tcolor: var(--roxy-danger-fg, #991b1b);\n\t\t\t}\n\t\t\t.tags .cancel {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-success, #16a34a) 18%, transparent);\n\t\t\t\tcolor: var(--roxy-success-fg, #166534);\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: CompatibilityResponse | null = null;\n\n\trender() {\n\t\tconst d = this.data;\n\t\tif (!d)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No Guna Milan data</div>`;\n\n\t\tconst breakdown = (d.breakdown ?? []).filter(\n\t\t\t(b) => b?.category !== undefined,\n\t\t);\n\n\t\tconst score = d.total ?? 0;\n\t\tconst max = d.maxScore ?? 36;\n\t\tconst pct = (score / max) * 100;\n\t\tconst trackColor =\n\t\t\t'color-mix(in srgb, var(--roxy-border) 50%, transparent)';\n\t\tconst fillColor =\n\t\t\tpct >= 70\n\t\t\t\t? 'var(--roxy-success)'\n\t\t\t\t: pct >= 50\n\t\t\t\t\t? 'var(--roxy-warning)'\n\t\t\t\t\t: 'var(--roxy-danger)';\n\t\t// SVG circle with r=45: circumference = 2 * pi * 45 = 282.74\n\t\t// dasharray segments = pct * 2.827, (100 - pct) * 2.827\n\t\tconst dashFill = pct * 2.827;\n\t\tconst dashGap = (100 - pct) * 2.827;\n\n\t\treturn html`<article class=\"card\" aria-label=\"Guna Milan score\">\n\t\t\t<div class=\"score-header\">\n\t\t\t\t<div class=\"score-info\">\n\t\t\t\t\t<div class=\"score-bar\">\n\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t<span class=\"total\">${formatNumber(d.total, 1)}</span>\n\t\t\t\t\t\t\t<span class=\"over\"> / ${d.maxScore}</span>\n\t\t\t\t\t\t\t${\n\t\t\t\t\t\t\t\ttypeof d.percentage === 'number'\n\t\t\t\t\t\t\t\t\t? html`<small style=\"margin-left: 0.5rem; color: var(--roxy-muted)\">\n\t\t\t\t\t\t\t\t\t\t${formatPercent(d.percentage, 1)}\n\t\t\t\t\t\t\t\t\t</small>`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\td.recommendation\n\t\t\t\t\t\t\t\t? html`<span class=\"recommendation\">${d.recommendation}</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t\t<div class=\"score-ring\" role=\"meter\" aria-label=\"Guna milan score\" aria-valuemin=\"0\" aria-valuemax=\"36\" aria-valuenow=\"${score}\">\n\t\t\t\t\t<svg viewBox=\"0 0 100 100\" aria-hidden=\"true\">\n\t\t\t\t\t\t<circle class=\"ring-track\" cx=\"50\" cy=\"50\" r=\"45\" fill=\"none\" stroke=\"${trackColor}\" stroke-width=\"8\"/>\n\t\t\t\t\t\t<circle class=\"ring-fill\" cx=\"50\" cy=\"50\" r=\"45\" fill=\"none\" stroke=\"${fillColor}\" stroke-width=\"8\"\n\t\t\t\t\t\t\t\tstroke-dasharray=\"${dashFill},${dashGap}\" stroke-linecap=\"round\"\n\t\t\t\t\t\t\t\ttransform=\"rotate(-90 50 50)\"/>\n\t\t\t\t\t\t<text x=\"50\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\" class=\"ring-text\">${score}</text>\n\t\t\t\t\t\t<text x=\"50\" y=\"64\" text-anchor=\"middle\" dominant-baseline=\"central\" class=\"ring-max\">/${max}</text>\n\t\t\t\t\t</svg>\n\t\t\t\t</div>\n\t\t\t</div>\n\n\t\t\t${\n\t\t\t\tbreakdown.length > 0\n\t\t\t\t\t? html`<table>\n\t\t\t\t\t\t<thead>\n\t\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t\t<th>Category</th>\n\t\t\t\t\t\t\t\t<th>Progress</th>\n\t\t\t\t\t\t\t\t<th class=\"score\">Score</th>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t</thead>\n\t\t\t\t\t\t<tbody>\n\t\t\t\t\t\t\t${breakdown.map((b) => {\n\t\t\t\t\t\t\t\tconst score = b.score ?? 0;\n\t\t\t\t\t\t\t\tconst maxScore = b.maxScore ?? defaultMax(b.category);\n\t\t\t\t\t\t\t\tconst pct = maxScore ? (score / maxScore) * 100 : 0;\n\t\t\t\t\t\t\t\treturn html`<tr>\n\t\t\t\t\t\t\t\t\t<td>${b.category}</td>\n\t\t\t\t\t\t\t\t\t<td class=\"bar-cell\">\n\t\t\t\t\t\t\t\t\t\t<div class=\"mini-bar\">\n\t\t\t\t\t\t\t\t\t\t\t<span style=\"width: ${pct}%\"></span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t<td class=\"score\">${formatNumber(score, 1)} / ${maxScore}</td>\n\t\t\t\t\t\t\t\t</tr>`;\n\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t</tbody>\n\t\t\t\t\t</table>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t${\n\t\t\t\t(d.doshas?.length ?? 0) > 0 || (d.doshaCancellations?.length ?? 0) > 0\n\t\t\t\t\t? html`<div class=\"tags\">\n\t\t\t\t\t\t${d.doshas?.map((x) => html`<span class=\"dosha\">${x}</span>`)}\n\t\t\t\t\t\t${d.doshaCancellations?.map(\n\t\t\t\t\t\t\t(x) =>\n\t\t\t\t\t\t\t\thtml`<span class=\"cancel\" title=${x.reason}>${x.dosha} cancelled</span>`,\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t</article>`;\n\t}\n}\n\nfunction defaultMax(name?: string): number {\n\tif (!name) return 1;\n\tswitch (name.toLowerCase()) {\n\t\tcase 'varna':\n\t\t\treturn 1;\n\t\tcase 'vasya':\n\t\t\treturn 2;\n\t\tcase 'tara':\n\t\t\treturn 3;\n\t\tcase 'yoni':\n\t\t\treturn 4;\n\t\tcase 'maitri':\n\t\t\treturn 5;\n\t\tcase 'gana':\n\t\t\treturn 6;\n\t\tcase 'bhakoot':\n\t\t\treturn 7;\n\t\tcase 'nadi':\n\t\t\treturn 8;\n\t\tdefault:\n\t\t\treturn 1;\n\t}\n}\n\nexport const GUNA_CATEGORIES = STANDARD_CATEGORIES;\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-guna-milan': RoxyGunaMilan;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n\n\t/* Force the text-style variant on every Unicode glyph in the component.\n\t * macOS and iOS substitute coloured emoji glyphs for the planetary and\n\t * gender Unicode code points (Mars, Venus, Mercury, etc.) when the\n\t * system colour-emoji font wins font selection. The text-style variant\n\t * keeps glyphs monochrome so they inherit the surrounding fill colour\n\t * and match the brand palette consistently across platforms.\n\t *\n\t * font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,\n\t * Firefox 139+). On older browsers the rule is silently ignored.\n\t */\n\t:host {\n\t\tfont-variant-emoji: text;\n\t}\n`;\n", "/**\n * Display formatters for ISO timestamps and floats coming back from the API.\n * Every helper returns \"\" for nullish or unparseable input so it falls out of\n * template literals cleanly.\n */\n\nexport function formatTime(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tif (/^\\d{4}-\\d{2}-\\d{2}$/.test(input)) return '';\n\tconst bareTime = /^\\d{2}:\\d{2}(:\\d{2})?$/.test(input);\n\tconst iso = bareTime ? `1970-01-01T${input}` : input;\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleTimeString(undefined, {\n\t\thour: 'numeric',\n\t\tminute: '2-digit',\n\t\thour12: true,\n\t});\n}\n\nexport function formatDate(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tconst d = new Date(\n\t\t/^\\d{4}-\\d{2}-\\d{2}$/.test(input) ? `${input}T00:00:00` : input,\n\t);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleDateString(undefined, {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: 'numeric',\n\t});\n}\n\nexport function formatTimeRange(\n\tt: { start?: string; end?: string } | undefined,\n): string {\n\tif (!t) return '';\n\tconst start = formatTime(t.start);\n\tconst end = formatTime(t.end);\n\tif (start && end) return `${start} - ${end}`;\n\treturn start || end || '';\n}\n\nexport function formatNumber(value: unknown, dp = 1): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\treturn value.toFixed(dp).replace(/\\.?0+$/, '');\n}\n\nexport function formatPercent(value: unknown, dp = 1): string {\n\tconst n = formatNumber(value, dp);\n\treturn n ? `${n}%` : '';\n}\n\n/**\n * CSS class name per aspect type. Used by natal and synastry chart aspect\n * lines so the same color encoding (harmonious vs challenging) applies in\n * both wheels. Keys are lowercase canonical names, values are CSS class\n * suffixes the chart components define in their `:host` styles.\n */\nexport const ASPECT_CLASS: Record<string, string> = {\n\tconjunction: 'aspect-conjunction',\n\tsextile: 'aspect-sextile',\n\tsquare: 'aspect-square',\n\ttrine: 'aspect-trine',\n\topposition: 'aspect-opposition',\n};\n\n/**\n * Normalize the `type` field on an aspect entry to a lowercase, hyphen-separated\n * canonical name (`SEMI_SEXTILE` \u2192 `semi-sextile`). Accepts any aspect-shaped\n * object so both natal and synastry inter-aspect entries can share this.\n */\nexport function normalizeAspect(a: { type?: string }): string {\n\treturn (a.type ?? '').toLowerCase().replace(/_/g, '-');\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["css", "score", "pct", "css"]
|
|
7
7
|
}
|
|
@@ -134,6 +134,20 @@ var baseStyles = css`
|
|
|
134
134
|
outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
|
|
135
135
|
outline-offset: 2px;
|
|
136
136
|
}
|
|
137
|
+
|
|
138
|
+
/* Force the text-style variant on every Unicode glyph in the component.
|
|
139
|
+
* macOS and iOS substitute coloured emoji glyphs for the planetary and
|
|
140
|
+
* gender Unicode code points (Mars, Venus, Mercury, etc.) when the
|
|
141
|
+
* system colour-emoji font wins font selection. The text-style variant
|
|
142
|
+
* keeps glyphs monochrome so they inherit the surrounding fill colour
|
|
143
|
+
* and match the brand palette consistently across platforms.
|
|
144
|
+
*
|
|
145
|
+
* font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,
|
|
146
|
+
* Firefox 139+). On older browsers the rule is silently ignored.
|
|
147
|
+
*/
|
|
148
|
+
:host {
|
|
149
|
+
font-variant-emoji: text;
|
|
150
|
+
}
|
|
137
151
|
`;
|
|
138
152
|
|
|
139
153
|
// packages/ui/src/components/hexagram.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/hexagram.ts", "../../src/tokens/index.ts", "../../src/utils/base-styles.ts"],
|
|
4
|
-
"sourcesContent": ["import { css, html, LitElement, nothing, svg } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { TRIGRAM_GLYPH } from '../tokens/index.js';\nimport type {\n\tCastReadingResponse,\n\tGetDailyHexagramResponse,\n\tGetHexagramResponse,\n\tGetRandomHexagramResponse,\n\tHexagram,\n\tLookupHexagramResponse,\n} from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype HexagramData =\n\t| GetHexagramResponse\n\t| GetRandomHexagramResponse\n\t| LookupHexagramResponse\n\t| GetDailyHexagramResponse\n\t| CastReadingResponse;\n\n/**\n * I Ching hexagram card. Renders /iching/hexagrams/{number}, /iching/cast,\n * /iching/daily, /iching/daily/cast.\n */\n@customElement('roxy-hexagram')\nexport class RoxyHexagram extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.card {\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: 6rem 1fr;\n\t\t\t\tgap: var(--roxy-space-lg, 1.5rem);\n\t\t\t}\n\n\t\t\t@container (max-width: 480px) {\n\t\t\t\t.card {\n\t\t\t\t\tgrid-template-columns: 1fr;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t.glyphs {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t\tjustify-items: center;\n\t\t\t}\n\t\t\t.symbol {\n\t\t\t\tfont-size: 3rem;\n\t\t\t\tline-height: 1;\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t}\n\t\t\t.lines {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: 4px;\n\t\t\t\twidth: 4rem;\n\t\t\t}\n\t\t\t.line {\n\t\t\t\tdisplay: flex;\n\t\t\t\tgap: 4px;\n\t\t\t\tjustify-content: center;\n\t\t\t\talign-items: center;\n\t\t\t\theight: 8px;\n\t\t\t}\n\t\t\t.seg {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 6px;\n\t\t\t\tbackground: var(--roxy-fg, #0a0a0a);\n\t\t\t\tborder-radius: 1px;\n\t\t\t}\n\t\t\t.line.broken .seg {\n\t\t\t\twidth: 1.4rem;\n\t\t\t}\n\t\t\t.line.solid .seg {\n\t\t\t\twidth: 3rem;\n\t\t\t}\n\t\t\t.line.changing .seg {\n\t\t\t\tbackground: var(--roxy-accent, #f59e0b);\n\t\t\t}\n\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tletter-spacing: var(--roxy-tracking-tight);\n\t\t\t}\n\t\t\t.subtitle {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tmargin: 0 0 var(--roxy-space-sm, 0.5rem);\n\t\t\t}\n\t\t\t.trigrams {\n\t\t\t\tdisplay: flex;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t\tmargin-bottom: var(--roxy-space-sm, 0.5rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t\t.tri-glyph {\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tmargin-right: 4px;\n\t\t\t\tvertical-align: middle;\n\t\t\t}\n\t\t\t.judgment,\n\t\t\t.image,\n\t\t\t.message {\n\t\t\t\tmargin: 0 0 var(--roxy-space-sm, 0.5rem);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.judgment::before {\n\t\t\t\tcontent: 'Judgment. ';\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\t\t\t.image::before {\n\t\t\t\tcontent: 'Image. ';\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\n\t\t\t.changing {\n\t\t\t\tmargin-top: var(--roxy-space-md, 1rem);\n\t\t\t\tpadding-top: var(--roxy-space-md, 1rem);\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: HexagramData | null = null;\n\n\t@property({ type: String, reflect: true })\n\tmode: 'lookup' | 'cast' | 'daily' = 'lookup';\n\n\tprivate resolveHexagram(): {\n\t\thex: Hexagram;\n\t\tlines?: number[];\n\t\tchangingLinePositions?: number[];\n\t\tdailyMessage?: string;\n\t\tresultingHexagram?: Hexagram;\n\t} | null {\n\t\tconst d = this.data;\n\t\tif (!d) return null;\n\t\tif ('hexagram' in d && d.hexagram) {\n\t\t\tif ('lines' in d) {\n\t\t\t\tconst cast = d as CastReadingResponse;\n\t\t\t\treturn {\n\t\t\t\t\thex: cast.hexagram as Hexagram,\n\t\t\t\t\tlines: cast.lines,\n\t\t\t\t\tchangingLinePositions: cast.changingLinePositions,\n\t\t\t\t\tresultingHexagram: cast.resultingHexagram as Hexagram | undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst daily = d as GetDailyHexagramResponse;\n\t\t\treturn {\n\t\t\t\thex: daily.hexagram as Hexagram,\n\t\t\t\tdailyMessage: daily.dailyMessage,\n\t\t\t};\n\t\t}\n\t\treturn { hex: d as Hexagram };\n\t}\n\n\trender() {\n\t\tconst resolved = this.resolveHexagram();\n\t\tif (!resolved)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No hexagram data</div>`;\n\n\t\tconst {\n\t\t\thex: h,\n\t\t\tlines: castLines,\n\t\t\tchangingLinePositions,\n\t\t\tdailyMessage,\n\t\t\tresultingHexagram,\n\t\t} = resolved;\n\t\tconst lines = castLines ?? this.derivedLines(h);\n\t\tconst changing = new Set(changingLinePositions ?? []);\n\n\t\treturn html`<article class=\"card\" aria-label=\"I Ching hexagram\">\n\t\t\t<div class=\"glyphs\">\n\t\t\t\t${h.symbol ? html`<div class=\"symbol\">${h.symbol}</div>` : nothing}\n\t\t\t\t<div class=\"lines\" aria-hidden=\"true\">\n\t\t\t\t\t${lines\n\t\t\t\t\t\t.slice()\n\t\t\t\t\t\t.reverse()\n\t\t\t\t\t\t.map((l, idx) => {\n\t\t\t\t\t\t\t// reverse so visual top is line 6\n\t\t\t\t\t\t\tconst realIdx = lines.length - 1 - idx + 1;\n\t\t\t\t\t\t\tconst isChanging = changing.has(realIdx);\n\t\t\t\t\t\t\tconst broken = l === 6 || l === 8;\n\t\t\t\t\t\t\tconst cls = `${broken ? 'broken' : 'solid'}${isChanging ? ' changing' : ''}`;\n\t\t\t\t\t\t\treturn html`<div class=\"line ${cls}\">\n\t\t\t\t\t\t\t\t${\n\t\t\t\t\t\t\t\t\tbroken\n\t\t\t\t\t\t\t\t\t\t? svg`<span class=\"seg\"></span><span class=\"seg\"></span>`\n\t\t\t\t\t\t\t\t\t\t: svg`<span class=\"seg\"></span>`\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</div>`;\n\t\t\t\t\t\t})}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2 class=\"title\">\n\t\t\t\t\t${h.number ? html`${h.number}. ` : nothing}${h.english ?? h.chinese ?? 'Hexagram'}\n\t\t\t\t</h2>\n\t\t\t\t<p class=\"subtitle\">\n\t\t\t\t\t${h.chinese ? html`${h.chinese}` : nothing}\n\t\t\t\t\t${h.pinyin ? html` \u00B7 ${h.pinyin}` : nothing}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"trigrams\">\n\t\t\t\t\t${\n\t\t\t\t\t\th.upperTrigram\n\t\t\t\t\t\t\t? html`<div>\n\t\t\t\t\t\t\t\tUpper\n\t\t\t\t\t\t\t\t<span class=\"tri-glyph\"\n\t\t\t\t\t\t\t\t\t>${TRIGRAM_GLYPH[h.upperTrigram] ?? ''}</span\n\t\t\t\t\t\t\t\t>${h.upperTrigram}\n\t\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}\n\t\t\t\t\t${\n\t\t\t\t\t\th.lowerTrigram\n\t\t\t\t\t\t\t? html`<div>\n\t\t\t\t\t\t\t\tLower\n\t\t\t\t\t\t\t\t<span class=\"tri-glyph\"\n\t\t\t\t\t\t\t\t\t>${TRIGRAM_GLYPH[h.lowerTrigram] ?? ''}</span\n\t\t\t\t\t\t\t\t>${h.lowerTrigram}\n\t\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t\t${h.judgment ? html`<p class=\"judgment\">${h.judgment}</p>` : nothing}\n\t\t\t\t${h.image ? html`<p class=\"image\">${h.image}</p>` : nothing}\n\t\t\t\t${dailyMessage ? html`<p class=\"message\">${dailyMessage}</p>` : nothing}\n\t\t\t\t${\n\t\t\t\t\th.interpretation?.general\n\t\t\t\t\t\t? html`<p>${h.interpretation.general}</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\tchanging.size > 0\n\t\t\t\t\t\t? html`<div class=\"changing\">\n\t\t\t\t\t\t\tChanging lines: ${Array.from(changing)\n\t\t\t\t\t\t\t\t.sort((a, b) => a - b)\n\t\t\t\t\t\t\t\t.join(', ')}.\n\t\t\t\t\t\t\t${\n\t\t\t\t\t\t\t\tresultingHexagram?.english\n\t\t\t\t\t\t\t\t\t? html` Becomes hexagram ${resultingHexagram.number}\n\t\t\t\t\t\t\t\t\t\t${resultingHexagram.english}.`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</div>\n\t\t</article>`;\n\t}\n\n\t/** When the API only ships symbol+number with no line array, render six solid yang. */\n\tprivate derivedLines(h: Hexagram): number[] {\n\t\t// Map each character of the unicode hexagram block (U+4DC0..) to broken/solid\n\t\tconst cp = h.symbol.codePointAt(0) ?? 0;\n\t\tif (cp >= 0x4dc0 && cp <= 0x4dff) {\n\t\t\tconst offset = cp - 0x4dc0;\n\t\t\tconst lines: number[] = [];\n\t\t\tfor (let i = 0; i < 6; i++) {\n\t\t\t\tconst broken = (offset >> i) & 1;\n\t\t\t\tlines.push(broken ? 8 : 7);\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\t\treturn Array.from({ length: 6 }, () => 7);\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hexagram': RoxyHexagram;\n\t}\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n\t'North node': '\u260A',\n\t'South node': '\u260B',\n\tChiron: '\u26B7',\n\tLilith: '\u26B8',\n\t'Black moon lilith': '\u26B8',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/**\n * Lowercase rashi keys in canonical zodiac order. Derived from `SIGNS_ORDER`\n * so the two stay in lockstep. The /vedic-astrology/birth-chart response\n * carries planet buckets keyed by these names.\n */\nexport const RASHI_KEYS = SIGNS_ORDER.map((s) =>\n\ts.toLowerCase(),\n) as readonly Lowercase<(typeof SIGNS_ORDER)[number]>[];\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { css, html, LitElement, nothing, svg } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { TRIGRAM_GLYPH } from '../tokens/index.js';\nimport type {\n\tCastReadingResponse,\n\tGetDailyHexagramResponse,\n\tGetHexagramResponse,\n\tGetRandomHexagramResponse,\n\tHexagram,\n\tLookupHexagramResponse,\n} from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\n\ntype HexagramData =\n\t| GetHexagramResponse\n\t| GetRandomHexagramResponse\n\t| LookupHexagramResponse\n\t| GetDailyHexagramResponse\n\t| CastReadingResponse;\n\n/**\n * I Ching hexagram card. Renders /iching/hexagrams/{number}, /iching/cast,\n * /iching/daily, /iching/daily/cast.\n */\n@customElement('roxy-hexagram')\nexport class RoxyHexagram extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.card {\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: 6rem 1fr;\n\t\t\t\tgap: var(--roxy-space-lg, 1.5rem);\n\t\t\t}\n\n\t\t\t@container (max-width: 480px) {\n\t\t\t\t.card {\n\t\t\t\t\tgrid-template-columns: 1fr;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t.glyphs {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t\tjustify-items: center;\n\t\t\t}\n\t\t\t.symbol {\n\t\t\t\tfont-size: 3rem;\n\t\t\t\tline-height: 1;\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t}\n\t\t\t.lines {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: 4px;\n\t\t\t\twidth: 4rem;\n\t\t\t}\n\t\t\t.line {\n\t\t\t\tdisplay: flex;\n\t\t\t\tgap: 4px;\n\t\t\t\tjustify-content: center;\n\t\t\t\talign-items: center;\n\t\t\t\theight: 8px;\n\t\t\t}\n\t\t\t.seg {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 6px;\n\t\t\t\tbackground: var(--roxy-fg, #0a0a0a);\n\t\t\t\tborder-radius: 1px;\n\t\t\t}\n\t\t\t.line.broken .seg {\n\t\t\t\twidth: 1.4rem;\n\t\t\t}\n\t\t\t.line.solid .seg {\n\t\t\t\twidth: 3rem;\n\t\t\t}\n\t\t\t.line.changing .seg {\n\t\t\t\tbackground: var(--roxy-accent, #f59e0b);\n\t\t\t}\n\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tletter-spacing: var(--roxy-tracking-tight);\n\t\t\t}\n\t\t\t.subtitle {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tmargin: 0 0 var(--roxy-space-sm, 0.5rem);\n\t\t\t}\n\t\t\t.trigrams {\n\t\t\t\tdisplay: flex;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t\tmargin-bottom: var(--roxy-space-sm, 0.5rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t\t.tri-glyph {\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tmargin-right: 4px;\n\t\t\t\tvertical-align: middle;\n\t\t\t}\n\t\t\t.judgment,\n\t\t\t.image,\n\t\t\t.message {\n\t\t\t\tmargin: 0 0 var(--roxy-space-sm, 0.5rem);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.judgment::before {\n\t\t\t\tcontent: 'Judgment. ';\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\t\t\t.image::before {\n\t\t\t\tcontent: 'Image. ';\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\n\t\t\t.changing {\n\t\t\t\tmargin-top: var(--roxy-space-md, 1rem);\n\t\t\t\tpadding-top: var(--roxy-space-md, 1rem);\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: HexagramData | null = null;\n\n\t@property({ type: String, reflect: true })\n\tmode: 'lookup' | 'cast' | 'daily' = 'lookup';\n\n\tprivate resolveHexagram(): {\n\t\thex: Hexagram;\n\t\tlines?: number[];\n\t\tchangingLinePositions?: number[];\n\t\tdailyMessage?: string;\n\t\tresultingHexagram?: Hexagram;\n\t} | null {\n\t\tconst d = this.data;\n\t\tif (!d) return null;\n\t\tif ('hexagram' in d && d.hexagram) {\n\t\t\tif ('lines' in d) {\n\t\t\t\tconst cast = d as CastReadingResponse;\n\t\t\t\treturn {\n\t\t\t\t\thex: cast.hexagram as Hexagram,\n\t\t\t\t\tlines: cast.lines,\n\t\t\t\t\tchangingLinePositions: cast.changingLinePositions,\n\t\t\t\t\tresultingHexagram: cast.resultingHexagram as Hexagram | undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst daily = d as GetDailyHexagramResponse;\n\t\t\treturn {\n\t\t\t\thex: daily.hexagram as Hexagram,\n\t\t\t\tdailyMessage: daily.dailyMessage,\n\t\t\t};\n\t\t}\n\t\treturn { hex: d as Hexagram };\n\t}\n\n\trender() {\n\t\tconst resolved = this.resolveHexagram();\n\t\tif (!resolved)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No hexagram data</div>`;\n\n\t\tconst {\n\t\t\thex: h,\n\t\t\tlines: castLines,\n\t\t\tchangingLinePositions,\n\t\t\tdailyMessage,\n\t\t\tresultingHexagram,\n\t\t} = resolved;\n\t\tconst lines = castLines ?? this.derivedLines(h);\n\t\tconst changing = new Set(changingLinePositions ?? []);\n\n\t\treturn html`<article class=\"card\" aria-label=\"I Ching hexagram\">\n\t\t\t<div class=\"glyphs\">\n\t\t\t\t${h.symbol ? html`<div class=\"symbol\">${h.symbol}</div>` : nothing}\n\t\t\t\t<div class=\"lines\" aria-hidden=\"true\">\n\t\t\t\t\t${lines\n\t\t\t\t\t\t.slice()\n\t\t\t\t\t\t.reverse()\n\t\t\t\t\t\t.map((l, idx) => {\n\t\t\t\t\t\t\t// reverse so visual top is line 6\n\t\t\t\t\t\t\tconst realIdx = lines.length - 1 - idx + 1;\n\t\t\t\t\t\t\tconst isChanging = changing.has(realIdx);\n\t\t\t\t\t\t\tconst broken = l === 6 || l === 8;\n\t\t\t\t\t\t\tconst cls = `${broken ? 'broken' : 'solid'}${isChanging ? ' changing' : ''}`;\n\t\t\t\t\t\t\treturn html`<div class=\"line ${cls}\">\n\t\t\t\t\t\t\t\t${\n\t\t\t\t\t\t\t\t\tbroken\n\t\t\t\t\t\t\t\t\t\t? svg`<span class=\"seg\"></span><span class=\"seg\"></span>`\n\t\t\t\t\t\t\t\t\t\t: svg`<span class=\"seg\"></span>`\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</div>`;\n\t\t\t\t\t\t})}\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t\t<div>\n\t\t\t\t<h2 class=\"title\">\n\t\t\t\t\t${h.number ? html`${h.number}. ` : nothing}${h.english ?? h.chinese ?? 'Hexagram'}\n\t\t\t\t</h2>\n\t\t\t\t<p class=\"subtitle\">\n\t\t\t\t\t${h.chinese ? html`${h.chinese}` : nothing}\n\t\t\t\t\t${h.pinyin ? html` \u00B7 ${h.pinyin}` : nothing}\n\t\t\t\t</p>\n\t\t\t\t<div class=\"trigrams\">\n\t\t\t\t\t${\n\t\t\t\t\t\th.upperTrigram\n\t\t\t\t\t\t\t? html`<div>\n\t\t\t\t\t\t\t\tUpper\n\t\t\t\t\t\t\t\t<span class=\"tri-glyph\"\n\t\t\t\t\t\t\t\t\t>${TRIGRAM_GLYPH[h.upperTrigram] ?? ''}</span\n\t\t\t\t\t\t\t\t>${h.upperTrigram}\n\t\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}\n\t\t\t\t\t${\n\t\t\t\t\t\th.lowerTrigram\n\t\t\t\t\t\t\t? html`<div>\n\t\t\t\t\t\t\t\tLower\n\t\t\t\t\t\t\t\t<span class=\"tri-glyph\"\n\t\t\t\t\t\t\t\t\t>${TRIGRAM_GLYPH[h.lowerTrigram] ?? ''}</span\n\t\t\t\t\t\t\t\t>${h.lowerTrigram}\n\t\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t\t${h.judgment ? html`<p class=\"judgment\">${h.judgment}</p>` : nothing}\n\t\t\t\t${h.image ? html`<p class=\"image\">${h.image}</p>` : nothing}\n\t\t\t\t${dailyMessage ? html`<p class=\"message\">${dailyMessage}</p>` : nothing}\n\t\t\t\t${\n\t\t\t\t\th.interpretation?.general\n\t\t\t\t\t\t? html`<p>${h.interpretation.general}</p>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\tchanging.size > 0\n\t\t\t\t\t\t? html`<div class=\"changing\">\n\t\t\t\t\t\t\tChanging lines: ${Array.from(changing)\n\t\t\t\t\t\t\t\t.sort((a, b) => a - b)\n\t\t\t\t\t\t\t\t.join(', ')}.\n\t\t\t\t\t\t\t${\n\t\t\t\t\t\t\t\tresultingHexagram?.english\n\t\t\t\t\t\t\t\t\t? html` Becomes hexagram ${resultingHexagram.number}\n\t\t\t\t\t\t\t\t\t\t${resultingHexagram.english}.`\n\t\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</div>\n\t\t</article>`;\n\t}\n\n\t/** When the API only ships symbol+number with no line array, render six solid yang. */\n\tprivate derivedLines(h: Hexagram): number[] {\n\t\t// Map each character of the unicode hexagram block (U+4DC0..) to broken/solid\n\t\tconst cp = h.symbol.codePointAt(0) ?? 0;\n\t\tif (cp >= 0x4dc0 && cp <= 0x4dff) {\n\t\t\tconst offset = cp - 0x4dc0;\n\t\t\tconst lines: number[] = [];\n\t\t\tfor (let i = 0; i < 6; i++) {\n\t\t\t\tconst broken = (offset >> i) & 1;\n\t\t\t\tlines.push(broken ? 8 : 7);\n\t\t\t}\n\t\t\treturn lines;\n\t\t}\n\t\treturn Array.from({ length: 6 }, () => 7);\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-hexagram': RoxyHexagram;\n\t}\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n\t'North node': '\u260A',\n\t'South node': '\u260B',\n\tChiron: '\u26B7',\n\tLilith: '\u26B8',\n\t'Black moon lilith': '\u26B8',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/**\n * Lowercase rashi keys in canonical zodiac order. Derived from `SIGNS_ORDER`\n * so the two stay in lockstep. The /vedic-astrology/birth-chart response\n * carries planet buckets keyed by these names.\n */\nexport const RASHI_KEYS = SIGNS_ORDER.map((s) =>\n\ts.toLowerCase(),\n) as readonly Lowercase<(typeof SIGNS_ORDER)[number]>[];\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n\n\t/* Force the text-style variant on every Unicode glyph in the component.\n\t * macOS and iOS substitute coloured emoji glyphs for the planetary and\n\t * gender Unicode code points (Mars, Venus, Mercury, etc.) when the\n\t * system colour-emoji font wins font selection. The text-style variant\n\t * keeps glyphs monochrome so they inherit the surrounding fill colour\n\t * and match the brand palette consistently across platforms.\n\t *\n\t * font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,\n\t * Firefox 139+). On older browsers the rule is silently ignored.\n\t */\n\t:host {\n\t\tfont-variant-emoji: text;\n\t}\n`;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["css", "css"]
|
|
7
7
|
}
|
|
@@ -130,6 +130,20 @@ var baseStyles = css`
|
|
|
130
130
|
outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
|
|
131
131
|
outline-offset: 2px;
|
|
132
132
|
}
|
|
133
|
+
|
|
134
|
+
/* Force the text-style variant on every Unicode glyph in the component.
|
|
135
|
+
* macOS and iOS substitute coloured emoji glyphs for the planetary and
|
|
136
|
+
* gender Unicode code points (Mars, Venus, Mercury, etc.) when the
|
|
137
|
+
* system colour-emoji font wins font selection. The text-style variant
|
|
138
|
+
* keeps glyphs monochrome so they inherit the surrounding fill colour
|
|
139
|
+
* and match the brand palette consistently across platforms.
|
|
140
|
+
*
|
|
141
|
+
* font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,
|
|
142
|
+
* Firefox 139+). On older browsers the rule is silently ignored.
|
|
143
|
+
*/
|
|
144
|
+
:host {
|
|
145
|
+
font-variant-emoji: text;
|
|
146
|
+
}
|
|
133
147
|
`;
|
|
134
148
|
|
|
135
149
|
// packages/ui/src/utils/string.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/horoscope-card.ts", "../../src/tokens/index.ts", "../../src/utils/base-styles.ts", "../../src/utils/string.ts"],
|
|
4
|
-
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { SIGN_GLYPH } from '../tokens/index.js';\nimport type {\n\tGetDailyHoroscopeResponse,\n\tGetMonthlyHoroscopeResponse,\n\tGetWeeklyHoroscopeResponse,\n} from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { capitalize } from '../utils/string.js';\n\ntype HoroscopeData =\n\t| GetDailyHoroscopeResponse\n\t| GetWeeklyHoroscopeResponse\n\t| GetMonthlyHoroscopeResponse;\n\n/**\n * Daily, weekly, or monthly horoscope card. Pass `data` from\n * /astrology/horoscope/{sign}/{daily|weekly|monthly}.\n */\n@customElement('roxy-horoscope-card')\nexport class RoxyHoroscopeCard extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.card {\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.head {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.glyph {\n\t\t\t\tfont-size: 2.25rem;\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tline-height: 1;\n\t\t\t}\n\n\t\t\t.title {\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tmargin: 0;\n\t\t\t\tletter-spacing: var(--roxy-tracking-tight);\n\t\t\t\ttext-transform: capitalize;\n\t\t\t}\n\n\t\t\t.date {\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t}\n\n\t\t\t.energy {\n\t\t\t\tmargin-left: auto;\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\t\t\t.energy-bar {\n\t\t\t\tdisplay: inline-block;\n\t\t\t\twidth: 6rem;\n\t\t\t\theight: 6px;\n\t\t\t\tbackground: var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\toverflow: hidden;\n\t\t\t\tmargin-left: 6px;\n\t\t\t\tvertical-align: middle;\n\t\t\t}\n\t\t\t.energy-bar > span {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 100%;\n\t\t\t\tbackground: var(--roxy-accent, #f59e0b);\n\t\t\t\ttransition:\n\t\t\t\t\twidth var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t}\n\n\t\t\t.overview {\n\t\t\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.sections {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.section h3 {\n\t\t\t\tmargin: 0 0 var(--roxy-space-xs, 0.25rem) 0;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t\t.section p {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\n\t\t\t.lucky {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tpadding-top: var(--roxy-space-md, 1rem);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\n\t\t\t.lucky strong {\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\n\t\t\t.compat-wrap {\n\t\t\t\twidth: 100%;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t}\n\t\t\t.compat {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t}\n\t\t\t.compat span {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-accent, #f59e0b) 16%, transparent);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tpadding: 2px 8px;\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\ttext-transform: capitalize;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: HoroscopeData | null = null;\n\n\t@property({ type: String, reflect: true })\n\tperiod: 'daily' | 'weekly' | 'monthly' = 'daily';\n\n\trender() {\n\t\tconst d = this.data;\n\t\tif (!d)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No horoscope data</div>`;\n\n\t\tconst sign = d.sign ?? '';\n\t\tconst glyph = sign ? (SIGN_GLYPH[capitalize(sign)] ?? '') : '';\n\t\tconst energy =\n\t\t\t'energyRating' in d && typeof d.energyRating === 'number'\n\t\t\t\t? d.energyRating\n\t\t\t\t: null;\n\t\tconst dateLabel =\n\t\t\t('date' in d && d.date) ||\n\t\t\t('week' in d && d.week) ||\n\t\t\t('month' in d && d.month) ||\n\t\t\t'';\n\n\t\treturn html`<article\n\t\t\tclass=\"card\"\n\t\t\taria-label=${`${this.period} horoscope for ${sign}`}\n\t\t>\n\t\t\t<header class=\"head\">\n\t\t\t\t<span class=\"glyph\" aria-hidden=\"true\">${glyph}</span>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 class=\"title\">${sign} ${this.period}</h2>\n\t\t\t\t\t${dateLabel ? html`<div class=\"date\">${dateLabel}</div>` : nothing}\n\t\t\t\t</div>\n\t\t\t\t${\n\t\t\t\t\tenergy !== null\n\t\t\t\t\t\t? html`<span class=\"energy\" aria-label=${`Energy ${energy} of 10`}>\n\t\t\t\t\t\t\tEnergy ${energy}/10\n\t\t\t\t\t\t\t<span class=\"energy-bar\"\n\t\t\t\t\t\t\t\t><span style=\"width: ${(energy / 10) * 100}%\"></span\n\t\t\t\t\t\t\t></span>\n\t\t\t\t\t\t</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</header>\n\n\t\t\t${d.overview ? html`<p class=\"overview\">${d.overview}</p>` : nothing}\n\n\t\t\t<div class=\"sections\">\n\t\t\t\t${\n\t\t\t\t\td.love\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Love</h3>\n\t\t\t\t\t\t\t<p>${d.love}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.career\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Career</h3>\n\t\t\t\t\t\t\t<p>${d.career}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.health\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Health</h3>\n\t\t\t\t\t\t\t<p>${d.health}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.finance\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Finance</h3>\n\t\t\t\t\t\t\t<p>${d.finance}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\t'advice' in d && d.advice\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Advice</h3>\n\t\t\t\t\t\t\t<p>${d.advice}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</div>\n\n\t\t\t${(() => {\n\t\t\t\tconst luckyNumber =\n\t\t\t\t\t'luckyNumber' in d && d.luckyNumber !== undefined\n\t\t\t\t\t\t? d.luckyNumber\n\t\t\t\t\t\t: undefined;\n\t\t\t\tconst luckyColor =\n\t\t\t\t\t'luckyColor' in d && d.luckyColor ? d.luckyColor : '';\n\t\t\t\tconst luckyNumbers =\n\t\t\t\t\t'luckyNumbers' in d && d.luckyNumbers ? d.luckyNumbers : [];\n\t\t\t\tconst luckyDays = 'luckyDays' in d && d.luckyDays ? d.luckyDays : [];\n\t\t\t\tconst compatibleSigns = d.compatibleSigns ?? [];\n\t\t\t\tif (\n\t\t\t\t\tluckyNumber === undefined &&\n\t\t\t\t\t!luckyColor &&\n\t\t\t\t\tluckyNumbers.length === 0 &&\n\t\t\t\t\tluckyDays.length === 0 &&\n\t\t\t\t\tcompatibleSigns.length === 0\n\t\t\t\t)\n\t\t\t\t\treturn nothing;\n\t\t\t\treturn html`<div class=\"lucky\">\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyNumber !== undefined\n\t\t\t\t\t\t\t\t? html`<span>Lucky number <strong>${luckyNumber}</strong></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyColor\n\t\t\t\t\t\t\t\t? html`<span>Lucky color <strong>${luckyColor}</strong></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyNumbers.length\n\t\t\t\t\t\t\t\t? html`<span\n\t\t\t\t\t\t\t\t\t>Lucky numbers\n\t\t\t\t\t\t\t\t\t<strong>${luckyNumbers.join(', ')}</strong></span\n\t\t\t\t\t\t\t\t>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyDays.length\n\t\t\t\t\t\t\t\t? html`<span\n\t\t\t\t\t\t\t\t\t>Lucky days <strong>${luckyDays.join(', ')}</strong></span\n\t\t\t\t\t\t\t\t>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tcompatibleSigns.length\n\t\t\t\t\t\t\t\t? html`<span class=\"compat-wrap\">\n\t\t\t\t\t\t\t\t\tBest with\n\t\t\t\t\t\t\t\t\t<span class=\"compat\"\n\t\t\t\t\t\t\t\t\t\t>${compatibleSigns.map(\n\t\t\t\t\t\t\t\t\t\t\t(s) => html`<span>${s}</span>`,\n\t\t\t\t\t\t\t\t\t\t)}</span\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>`;\n\t\t\t})()}\n\t\t</article>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-horoscope-card': RoxyHoroscopeCard;\n\t}\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n\t'North node': '\u260A',\n\t'South node': '\u260B',\n\tChiron: '\u26B7',\n\tLilith: '\u26B8',\n\t'Black moon lilith': '\u26B8',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/**\n * Lowercase rashi keys in canonical zodiac order. Derived from `SIGNS_ORDER`\n * so the two stay in lockstep. The /vedic-astrology/birth-chart response\n * carries planet buckets keyed by these names.\n */\nexport const RASHI_KEYS = SIGNS_ORDER.map((s) =>\n\ts.toLowerCase(),\n) as readonly Lowercase<(typeof SIGNS_ORDER)[number]>[];\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n", "/**\n * Shared string helpers used across components. Single source of truth so the\n * same formatting rules apply to every key/label/title that surfaces in the\n * shadow tree.\n *\n * - `capitalize`: title-cases the first character, lowercases the rest. Used\n * when matching API-supplied planet/sign names against the glyph maps in\n * `tokens/index.ts`, which use canonical TitleCase keys.\n * - `humanize`: turns an API key (`birth_date`, `birthDate`, `mahadasha-end`)\n * into a label suitable for display (\"Birth date\", \"Mahadasha end\").\n */\n\nexport function capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function humanize(s: string): string {\n\treturn s\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.replace(/([a-z])([A-Z])/g, '$1 $2')\n\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { SIGN_GLYPH } from '../tokens/index.js';\nimport type {\n\tGetDailyHoroscopeResponse,\n\tGetMonthlyHoroscopeResponse,\n\tGetWeeklyHoroscopeResponse,\n} from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { capitalize } from '../utils/string.js';\n\ntype HoroscopeData =\n\t| GetDailyHoroscopeResponse\n\t| GetWeeklyHoroscopeResponse\n\t| GetMonthlyHoroscopeResponse;\n\n/**\n * Daily, weekly, or monthly horoscope card. Pass `data` from\n * /astrology/horoscope/{sign}/{daily|weekly|monthly}.\n */\n@customElement('roxy-horoscope-card')\nexport class RoxyHoroscopeCard extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.card {\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.head {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.glyph {\n\t\t\t\tfont-size: 2.25rem;\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tline-height: 1;\n\t\t\t}\n\n\t\t\t.title {\n\t\t\t\tfont-size: var(--roxy-text-xl, 1.5rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tmargin: 0;\n\t\t\t\tletter-spacing: var(--roxy-tracking-tight);\n\t\t\t\ttext-transform: capitalize;\n\t\t\t}\n\n\t\t\t.date {\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t}\n\n\t\t\t.energy {\n\t\t\t\tmargin-left: auto;\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\t\t\t.energy-bar {\n\t\t\t\tdisplay: inline-block;\n\t\t\t\twidth: 6rem;\n\t\t\t\theight: 6px;\n\t\t\t\tbackground: var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\toverflow: hidden;\n\t\t\t\tmargin-left: 6px;\n\t\t\t\tvertical-align: middle;\n\t\t\t}\n\t\t\t.energy-bar > span {\n\t\t\t\tdisplay: block;\n\t\t\t\theight: 100%;\n\t\t\t\tbackground: var(--roxy-accent, #f59e0b);\n\t\t\t\ttransition:\n\t\t\t\t\twidth var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t}\n\n\t\t\t.overview {\n\t\t\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tmargin: 0;\n\t\t\t}\n\n\t\t\t.sections {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\n\t\t\t.section h3 {\n\t\t\t\tmargin: 0 0 var(--roxy-space-xs, 0.25rem) 0;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tletter-spacing: 0.06em;\n\t\t\t}\n\t\t\t.section p {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\n\t\t\t.lucky {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tpadding-top: var(--roxy-space-md, 1rem);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\n\t\t\t.lucky strong {\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\n\t\t\t.compat-wrap {\n\t\t\t\twidth: 100%;\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: center;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t}\n\t\t\t.compat {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t}\n\t\t\t.compat span {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-accent, #f59e0b) 16%, transparent);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tpadding: 2px 8px;\n\t\t\t\tborder-radius: var(--roxy-radius-full, 9999px);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\ttext-transform: capitalize;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: HoroscopeData | null = null;\n\n\t@property({ type: String, reflect: true })\n\tperiod: 'daily' | 'weekly' | 'monthly' = 'daily';\n\n\trender() {\n\t\tconst d = this.data;\n\t\tif (!d)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No horoscope data</div>`;\n\n\t\tconst sign = d.sign ?? '';\n\t\tconst glyph = sign ? (SIGN_GLYPH[capitalize(sign)] ?? '') : '';\n\t\tconst energy =\n\t\t\t'energyRating' in d && typeof d.energyRating === 'number'\n\t\t\t\t? d.energyRating\n\t\t\t\t: null;\n\t\tconst dateLabel =\n\t\t\t('date' in d && d.date) ||\n\t\t\t('week' in d && d.week) ||\n\t\t\t('month' in d && d.month) ||\n\t\t\t'';\n\n\t\treturn html`<article\n\t\t\tclass=\"card\"\n\t\t\taria-label=${`${this.period} horoscope for ${sign}`}\n\t\t>\n\t\t\t<header class=\"head\">\n\t\t\t\t<span class=\"glyph\" aria-hidden=\"true\">${glyph}</span>\n\t\t\t\t<div>\n\t\t\t\t\t<h2 class=\"title\">${sign} ${this.period}</h2>\n\t\t\t\t\t${dateLabel ? html`<div class=\"date\">${dateLabel}</div>` : nothing}\n\t\t\t\t</div>\n\t\t\t\t${\n\t\t\t\t\tenergy !== null\n\t\t\t\t\t\t? html`<span class=\"energy\" aria-label=${`Energy ${energy} of 10`}>\n\t\t\t\t\t\t\tEnergy ${energy}/10\n\t\t\t\t\t\t\t<span class=\"energy-bar\"\n\t\t\t\t\t\t\t\t><span style=\"width: ${(energy / 10) * 100}%\"></span\n\t\t\t\t\t\t\t></span>\n\t\t\t\t\t\t</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</header>\n\n\t\t\t${d.overview ? html`<p class=\"overview\">${d.overview}</p>` : nothing}\n\n\t\t\t<div class=\"sections\">\n\t\t\t\t${\n\t\t\t\t\td.love\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Love</h3>\n\t\t\t\t\t\t\t<p>${d.love}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.career\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Career</h3>\n\t\t\t\t\t\t\t<p>${d.career}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.health\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Health</h3>\n\t\t\t\t\t\t\t<p>${d.health}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\td.finance\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Finance</h3>\n\t\t\t\t\t\t\t<p>${d.finance}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\t'advice' in d && d.advice\n\t\t\t\t\t\t? html`<div class=\"section\">\n\t\t\t\t\t\t\t<h3>Advice</h3>\n\t\t\t\t\t\t\t<p>${d.advice}</p>\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</div>\n\n\t\t\t${(() => {\n\t\t\t\tconst luckyNumber =\n\t\t\t\t\t'luckyNumber' in d && d.luckyNumber !== undefined\n\t\t\t\t\t\t? d.luckyNumber\n\t\t\t\t\t\t: undefined;\n\t\t\t\tconst luckyColor =\n\t\t\t\t\t'luckyColor' in d && d.luckyColor ? d.luckyColor : '';\n\t\t\t\tconst luckyNumbers =\n\t\t\t\t\t'luckyNumbers' in d && d.luckyNumbers ? d.luckyNumbers : [];\n\t\t\t\tconst luckyDays = 'luckyDays' in d && d.luckyDays ? d.luckyDays : [];\n\t\t\t\tconst compatibleSigns = d.compatibleSigns ?? [];\n\t\t\t\tif (\n\t\t\t\t\tluckyNumber === undefined &&\n\t\t\t\t\t!luckyColor &&\n\t\t\t\t\tluckyNumbers.length === 0 &&\n\t\t\t\t\tluckyDays.length === 0 &&\n\t\t\t\t\tcompatibleSigns.length === 0\n\t\t\t\t)\n\t\t\t\t\treturn nothing;\n\t\t\t\treturn html`<div class=\"lucky\">\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyNumber !== undefined\n\t\t\t\t\t\t\t\t? html`<span>Lucky number <strong>${luckyNumber}</strong></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyColor\n\t\t\t\t\t\t\t\t? html`<span>Lucky color <strong>${luckyColor}</strong></span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyNumbers.length\n\t\t\t\t\t\t\t\t? html`<span\n\t\t\t\t\t\t\t\t\t>Lucky numbers\n\t\t\t\t\t\t\t\t\t<strong>${luckyNumbers.join(', ')}</strong></span\n\t\t\t\t\t\t\t\t>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tluckyDays.length\n\t\t\t\t\t\t\t\t? html`<span\n\t\t\t\t\t\t\t\t\t>Lucky days <strong>${luckyDays.join(', ')}</strong></span\n\t\t\t\t\t\t\t\t>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tcompatibleSigns.length\n\t\t\t\t\t\t\t\t? html`<span class=\"compat-wrap\">\n\t\t\t\t\t\t\t\t\tBest with\n\t\t\t\t\t\t\t\t\t<span class=\"compat\"\n\t\t\t\t\t\t\t\t\t\t>${compatibleSigns.map(\n\t\t\t\t\t\t\t\t\t\t\t(s) => html`<span>${s}</span>`,\n\t\t\t\t\t\t\t\t\t\t)}</span\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t</span>`\n\t\t\t\t\t\t\t\t: nothing\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>`;\n\t\t\t})()}\n\t\t</article>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-horoscope-card': RoxyHoroscopeCard;\n\t}\n}\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n\t'North node': '\u260A',\n\t'South node': '\u260B',\n\tChiron: '\u26B7',\n\tLilith: '\u26B8',\n\t'Black moon lilith': '\u26B8',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/**\n * Lowercase rashi keys in canonical zodiac order. Derived from `SIGNS_ORDER`\n * so the two stay in lockstep. The /vedic-astrology/birth-chart response\n * carries planet buckets keyed by these names.\n */\nexport const RASHI_KEYS = SIGNS_ORDER.map((s) =>\n\ts.toLowerCase(),\n) as readonly Lowercase<(typeof SIGNS_ORDER)[number]>[];\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n\n\t/* Force the text-style variant on every Unicode glyph in the component.\n\t * macOS and iOS substitute coloured emoji glyphs for the planetary and\n\t * gender Unicode code points (Mars, Venus, Mercury, etc.) when the\n\t * system colour-emoji font wins font selection. The text-style variant\n\t * keeps glyphs monochrome so they inherit the surrounding fill colour\n\t * and match the brand palette consistently across platforms.\n\t *\n\t * font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,\n\t * Firefox 139+). On older browsers the rule is silently ignored.\n\t */\n\t:host {\n\t\tfont-variant-emoji: text;\n\t}\n`;\n", "/**\n * Shared string helpers used across components. Single source of truth so the\n * same formatting rules apply to every key/label/title that surfaces in the\n * shadow tree.\n *\n * - `capitalize`: title-cases the first character, lowercases the rest. Used\n * when matching API-supplied planet/sign names against the glyph maps in\n * `tokens/index.ts`, which use canonical TitleCase keys.\n * - `humanize`: turns an API key (`birth_date`, `birthDate`, `mahadasha-end`)\n * into a label suitable for display (\"Birth date\", \"Mahadasha end\").\n */\n\nexport function capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function humanize(s: string): string {\n\treturn s\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.replace(/([a-z])([A-Z])/g, '$1 $2')\n\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["css", "css"]
|
|
7
7
|
}
|
|
@@ -97,6 +97,20 @@ var baseStyles = css`
|
|
|
97
97
|
outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
|
|
98
98
|
outline-offset: 2px;
|
|
99
99
|
}
|
|
100
|
+
|
|
101
|
+
/* Force the text-style variant on every Unicode glyph in the component.
|
|
102
|
+
* macOS and iOS substitute coloured emoji glyphs for the planetary and
|
|
103
|
+
* gender Unicode code points (Mars, Venus, Mercury, etc.) when the
|
|
104
|
+
* system colour-emoji font wins font selection. The text-style variant
|
|
105
|
+
* keeps glyphs monochrome so they inherit the surrounding fill colour
|
|
106
|
+
* and match the brand palette consistently across platforms.
|
|
107
|
+
*
|
|
108
|
+
* font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,
|
|
109
|
+
* Firefox 139+). On older browsers the rule is silently ignored.
|
|
110
|
+
*/
|
|
111
|
+
:host {
|
|
112
|
+
font-variant-emoji: text;
|
|
113
|
+
}
|
|
100
114
|
`;
|
|
101
115
|
|
|
102
116
|
// packages/ui/src/utils/format.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/kp-chart.ts", "../../src/utils/base-styles.ts", "../../src/utils/format.ts"],
|
|
4
|
-
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport type { KpChartResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\ntype Tab = 'planets' | 'cusps';\n\n/** A planet or node row, normalized so planets and Rahu/Ketu share a table. */\ninterface KpBody {\n\tname: string;\n\tsign?: string;\n\thouse?: number;\n\tnakshatra?: string;\n\tstarLord?: string;\n\tsubLord?: string;\n\tsubSubLord?: string;\n\tkpNumber?: number;\n\tretrograde?: boolean;\n}\n\n/**\n * KP (Krishnamurti Paddhati) chart. Renders /vedic-astrology/kp/chart: the\n * Ascendant with its full stellar hierarchy, a planets-and-nodes table, and a\n * Placidus cusps table. The cusp and planet sub lords are the primary\n * predictive surface in KP astrology, so each row carries star lord, sub lord,\n * sub-sub lord, and KP number (1-249).\n */\n@customElement('roxy-kp-chart')\nexport class RoxyKpChart extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.wrap {\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\toverflow: auto;\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t}\n\t\t\t.head {\n\t\t\t\tpadding: var(--roxy-space-md, 1rem);\n\t\t\t\tborder-bottom: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t}\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-lg, 1.125rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.asc,\n\t\t\t.ayan {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t\t.asc strong {\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.tablist {\n\t\t\t\tdisplay: flex;\n\t\t\t\tgap: 2px;\n\t\t\t\tpadding: 0 var(--roxy-space-md, 1rem);\n\t\t\t\tborder-bottom: 2px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\t.tab {\n\t\t\t\tpadding: var(--roxy-space-xs, 0.25rem) var(--roxy-space-md, 1rem);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tbackground: none;\n\t\t\t\tborder: none;\n\t\t\t\tborder-bottom: 2px solid transparent;\n\t\t\t\tmargin-bottom: -2px;\n\t\t\t\tcursor: pointer;\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-family: inherit;\n\t\t\t}\n\t\t\t.tab[aria-selected='true'] {\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tborder-bottom-color: var(--roxy-accent, #f59e0b);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.tab:hover:not([aria-selected='true']) {\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\ttable {\n\t\t\t\twidth: 100%;\n\t\t\t\tborder-collapse: collapse;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tmin-width: 620px;\n\t\t\t}\n\t\t\tthead {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-border, #e4e4e7) 20%, transparent);\n\t\t\t}\n\t\t\tth,\n\t\t\ttd {\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\ttext-align: left;\n\t\t\t\twhite-space: nowrap;\n\t\t\t}\n\t\t\tth {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tletter-spacing: 0.04em;\n\t\t\t}\n\t\t\ttbody tr {\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\ttd.body {\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.retro {\n\t\t\t\tcolor: var(--roxy-warning-fg, #9a3412);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tmargin-left: 4px;\n\t\t\t}\n\t\t\t.num {\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: KpChartResponse | null = null;\n\n\t@state()\n\tprivate activeTab: Tab = 'planets';\n\n\t/** Merge the 7 planets and the two nodes into one ordered body list. */\n\tprivate bodies(): KpBody[] {\n\t\tconst d = this.data;\n\t\tif (!d) return [];\n\t\tconst rows: KpBody[] = (d.planets ?? []).map((p) => ({\n\t\t\tname: p.planet,\n\t\t\tsign: p.sign,\n\t\t\thouse: p.house,\n\t\t\tnakshatra: p.nakshatra,\n\t\t\tstarLord: p.starLord,\n\t\t\tsubLord: p.subLord,\n\t\t\tsubSubLord: p.subSubLord,\n\t\t\tkpNumber: p.kpNumber,\n\t\t\tretrograde: p.retrograde,\n\t\t}));\n\t\tconst nodes = d.nodes;\n\t\tfor (const [name, node] of [\n\t\t\t['Rahu', nodes?.rahu],\n\t\t\t['Ketu', nodes?.ketu],\n\t\t] as const) {\n\t\t\tif (node) {\n\t\t\t\trows.push({\n\t\t\t\t\tname,\n\t\t\t\t\tsign: node.sign,\n\t\t\t\t\thouse: node.house,\n\t\t\t\t\tnakshatra: node.nakshatra,\n\t\t\t\t\tstarLord: node.starLord,\n\t\t\t\t\tsubLord: node.subLord,\n\t\t\t\t\tsubSubLord: node.subSubLord,\n\t\t\t\t\tretrograde: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn rows;\n\t}\n\n\tprivate onTabKeyDown(e: KeyboardEvent) {\n\t\tif (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return;\n\t\te.preventDefault();\n\t\tthis.activeTab = this.activeTab === 'planets' ? 'cusps' : 'planets';\n\t\tconst next = this.activeTab;\n\t\trequestAnimationFrame(() => {\n\t\t\tthis.shadowRoot\n\t\t\t\t?.querySelector<HTMLButtonElement>(`#tab-${next}`)\n\t\t\t\t?.focus();\n\t\t});\n\t}\n\n\trender() {\n\t\tif (!this.data)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No KP chart data</div>`;\n\t\tconst d = this.data;\n\t\tconst asc = d.ascendant;\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"KP chart\" tabindex=\"0\">\n\t\t\t<header class=\"head\">\n\t\t\t\t<h2 class=\"title\">KP chart</h2>\n\t\t\t\t${\n\t\t\t\t\tasc\n\t\t\t\t\t\t? html`<div class=\"asc\">\n\t\t\t\t\t\t\tAscendant: <strong>${asc.sign ?? ''}</strong>\n\t\t\t\t\t\t\t${asc.nakshatra ? html`\u00B7 ${asc.nakshatra}` : nothing}\n\t\t\t\t\t\t\t${asc.subLord ? html`\u00B7 sub lord ${asc.subLord}` : nothing}\n\t\t\t\t\t\t\t${typeof asc.kpNumber === 'number' ? html`\u00B7 KP ${asc.kpNumber}` : nothing}\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\ttypeof d.meta?.ayanamsa === 'number'\n\t\t\t\t\t\t? html`<div class=\"ayan\">\n\t\t\t\t\t\t\t${d.meta.ayanamsaType ?? 'Ayanamsa'}: ${formatNumber(d.meta.ayanamsa, 4)}\u00B0\n\t\t\t\t\t\t\t${d.meta.houseSystem ? html`\u00B7 ${d.meta.houseSystem} houses` : nothing}\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</header>\n\n\t\t\t<div\n\t\t\t\tclass=\"tablist\"\n\t\t\t\trole=\"tablist\"\n\t\t\t\taria-label=\"KP chart views\"\n\t\t\t\t@keydown=${this.onTabKeyDown}\n\t\t\t>\n\t\t\t\t${(['planets', 'cusps'] as const).map(\n\t\t\t\t\t(t) => html`<button\n\t\t\t\t\t\tclass=\"tab\"\n\t\t\t\t\t\trole=\"tab\"\n\t\t\t\t\t\tid=\"tab-${t}\"\n\t\t\t\t\t\taria-selected=${this.activeTab === t ? 'true' : 'false'}\n\t\t\t\t\t\taria-controls=\"panel-${t}\"\n\t\t\t\t\t\ttabindex=${this.activeTab === t ? '0' : '-1'}\n\t\t\t\t\t\t@click=${() => {\n\t\t\t\t\t\t\tthis.activeTab = t;\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t${t === 'planets' ? 'Planets' : 'Cusps'}\n\t\t\t\t\t</button>`,\n\t\t\t\t)}\n\t\t\t</div>\n\n\t\t\t<div id=\"panel-${this.activeTab}\" role=\"tabpanel\" aria-labelledby=\"tab-${this.activeTab}\">\n\t\t\t\t${this.activeTab === 'planets' ? this.renderPlanets() : this.renderCusps()}\n\t\t\t</div>\n\t\t</div>`;\n\t}\n\n\tprivate renderPlanets() {\n\t\tconst bodies = this.bodies();\n\t\tif (!bodies.length)\n\t\t\treturn html`<p class=\"roxy-empty\" role=\"status\">No planets</p>`;\n\t\treturn html`<table role=\"table\" aria-label=\"KP planets and nodes\">\n\t\t\t<thead>\n\t\t\t\t<tr>\n\t\t\t\t\t<th scope=\"col\">Body</th>\n\t\t\t\t\t<th scope=\"col\">Sign</th>\n\t\t\t\t\t<th scope=\"col\">House</th>\n\t\t\t\t\t<th scope=\"col\">Nakshatra</th>\n\t\t\t\t\t<th scope=\"col\">Star lord</th>\n\t\t\t\t\t<th scope=\"col\">Sub lord</th>\n\t\t\t\t\t<th scope=\"col\">Sub sub lord</th>\n\t\t\t\t\t<th scope=\"col\">KP no.</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t${bodies.map(\n\t\t\t\t\t(b) => html`<tr>\n\t\t\t\t\t\t<td class=\"body\">\n\t\t\t\t\t\t\t${b.name}${b.retrograde ? html`<span class=\"retro\">R</span>` : nothing}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>${b.sign ?? ''}</td>\n\t\t\t\t\t\t<td class=\"num\">${typeof b.house === 'number' ? b.house : ''}</td>\n\t\t\t\t\t\t<td>${b.nakshatra ?? ''}</td>\n\t\t\t\t\t\t<td>${b.starLord ?? ''}</td>\n\t\t\t\t\t\t<td>${b.subLord ?? ''}</td>\n\t\t\t\t\t\t<td>${b.subSubLord ?? ''}</td>\n\t\t\t\t\t\t<td class=\"num\">${typeof b.kpNumber === 'number' ? b.kpNumber : ''}</td>\n\t\t\t\t\t</tr>`,\n\t\t\t\t)}\n\t\t\t</tbody>\n\t\t</table>`;\n\t}\n\n\tprivate renderCusps() {\n\t\tconst cusps = this.data?.cusps ?? [];\n\t\tif (!cusps.length)\n\t\t\treturn html`<p class=\"roxy-empty\" role=\"status\">No cusps</p>`;\n\t\treturn html`<table role=\"table\" aria-label=\"KP Placidus cusps\">\n\t\t\t<thead>\n\t\t\t\t<tr>\n\t\t\t\t\t<th scope=\"col\">House</th>\n\t\t\t\t\t<th scope=\"col\">Sign</th>\n\t\t\t\t\t<th scope=\"col\">Sign lord</th>\n\t\t\t\t\t<th scope=\"col\">Nakshatra</th>\n\t\t\t\t\t<th scope=\"col\">Star lord</th>\n\t\t\t\t\t<th scope=\"col\">Sub lord</th>\n\t\t\t\t\t<th scope=\"col\">Sub sub lord</th>\n\t\t\t\t\t<th scope=\"col\">KP no.</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t${cusps.map(\n\t\t\t\t\t(c) => html`<tr>\n\t\t\t\t\t\t<td class=\"body num\">${c.house}</td>\n\t\t\t\t\t\t<td>${c.sign ?? ''}</td>\n\t\t\t\t\t\t<td>${c.signLord ?? ''}</td>\n\t\t\t\t\t\t<td>${c.nakshatra ?? ''}</td>\n\t\t\t\t\t\t<td>${c.starLord ?? ''}</td>\n\t\t\t\t\t\t<td>${c.subLord ?? ''}</td>\n\t\t\t\t\t\t<td>${c.subSubLord ?? ''}</td>\n\t\t\t\t\t\t<td class=\"num\">${typeof c.kpNumber === 'number' ? c.kpNumber : ''}</td>\n\t\t\t\t\t</tr>`,\n\t\t\t\t)}\n\t\t\t</tbody>\n\t\t</table>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-kp-chart': RoxyKpChart;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n", "/**\n * Display formatters for ISO timestamps and floats coming back from the API.\n * Every helper returns \"\" for nullish or unparseable input so it falls out of\n * template literals cleanly.\n */\n\nexport function formatTime(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tif (/^\\d{4}-\\d{2}-\\d{2}$/.test(input)) return '';\n\tconst bareTime = /^\\d{2}:\\d{2}(:\\d{2})?$/.test(input);\n\tconst iso = bareTime ? `1970-01-01T${input}` : input;\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleTimeString(undefined, {\n\t\thour: 'numeric',\n\t\tminute: '2-digit',\n\t\thour12: true,\n\t});\n}\n\nexport function formatDate(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tconst d = new Date(\n\t\t/^\\d{4}-\\d{2}-\\d{2}$/.test(input) ? `${input}T00:00:00` : input,\n\t);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleDateString(undefined, {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: 'numeric',\n\t});\n}\n\nexport function formatTimeRange(\n\tt: { start?: string; end?: string } | undefined,\n): string {\n\tif (!t) return '';\n\tconst start = formatTime(t.start);\n\tconst end = formatTime(t.end);\n\tif (start && end) return `${start} - ${end}`;\n\treturn start || end || '';\n}\n\nexport function formatNumber(value: unknown, dp = 1): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\treturn value.toFixed(dp).replace(/\\.?0+$/, '');\n}\n\nexport function formatPercent(value: unknown, dp = 1): string {\n\tconst n = formatNumber(value, dp);\n\treturn n ? `${n}%` : '';\n}\n\n/**\n * CSS class name per aspect type. Used by natal and synastry chart aspect\n * lines so the same color encoding (harmonious vs challenging) applies in\n * both wheels. Keys are lowercase canonical names, values are CSS class\n * suffixes the chart components define in their `:host` styles.\n */\nexport const ASPECT_CLASS: Record<string, string> = {\n\tconjunction: 'aspect-conjunction',\n\tsextile: 'aspect-sextile',\n\tsquare: 'aspect-square',\n\ttrine: 'aspect-trine',\n\topposition: 'aspect-opposition',\n};\n\n/**\n * Normalize the `type` field on an aspect entry to a lowercase, hyphen-separated\n * canonical name (`SEMI_SEXTILE` \u2192 `semi-sextile`). Accepts any aspect-shaped\n * object so both natal and synastry inter-aspect entries can share this.\n */\nexport function normalizeAspect(a: { type?: string }): string {\n\treturn (a.type ?? '').toLowerCase().replace(/_/g, '-');\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport type { KpChartResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\ntype Tab = 'planets' | 'cusps';\n\n/** A planet or node row, normalized so planets and Rahu/Ketu share a table. */\ninterface KpBody {\n\tname: string;\n\tsign?: string;\n\thouse?: number;\n\tnakshatra?: string;\n\tstarLord?: string;\n\tsubLord?: string;\n\tsubSubLord?: string;\n\tkpNumber?: number;\n\tretrograde?: boolean;\n}\n\n/**\n * KP (Krishnamurti Paddhati) chart. Renders /vedic-astrology/kp/chart: the\n * Ascendant with its full stellar hierarchy, a planets-and-nodes table, and a\n * Placidus cusps table. The cusp and planet sub lords are the primary\n * predictive surface in KP astrology, so each row carries star lord, sub lord,\n * sub-sub lord, and KP number (1-249).\n */\n@customElement('roxy-kp-chart')\nexport class RoxyKpChart extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.wrap {\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\toverflow: auto;\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t}\n\t\t\t.head {\n\t\t\t\tpadding: var(--roxy-space-md, 1rem);\n\t\t\t\tborder-bottom: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t}\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-lg, 1.125rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.asc,\n\t\t\t.ayan {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t\t.asc strong {\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.tablist {\n\t\t\t\tdisplay: flex;\n\t\t\t\tgap: 2px;\n\t\t\t\tpadding: 0 var(--roxy-space-md, 1rem);\n\t\t\t\tborder-bottom: 2px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\t.tab {\n\t\t\t\tpadding: var(--roxy-space-xs, 0.25rem) var(--roxy-space-md, 1rem);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tbackground: none;\n\t\t\t\tborder: none;\n\t\t\t\tborder-bottom: 2px solid transparent;\n\t\t\t\tmargin-bottom: -2px;\n\t\t\t\tcursor: pointer;\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-family: inherit;\n\t\t\t}\n\t\t\t.tab[aria-selected='true'] {\n\t\t\t\tcolor: var(--roxy-accent-fg, #b45309);\n\t\t\t\tborder-bottom-color: var(--roxy-accent, #f59e0b);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.tab:hover:not([aria-selected='true']) {\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\ttable {\n\t\t\t\twidth: 100%;\n\t\t\t\tborder-collapse: collapse;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tmin-width: 620px;\n\t\t\t}\n\t\t\tthead {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-border, #e4e4e7) 20%, transparent);\n\t\t\t}\n\t\t\tth,\n\t\t\ttd {\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\ttext-align: left;\n\t\t\t\twhite-space: nowrap;\n\t\t\t}\n\t\t\tth {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tletter-spacing: 0.04em;\n\t\t\t}\n\t\t\ttbody tr {\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\ttd.body {\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.retro {\n\t\t\t\tcolor: var(--roxy-warning-fg, #9a3412);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tmargin-left: 4px;\n\t\t\t}\n\t\t\t.num {\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: KpChartResponse | null = null;\n\n\t@state()\n\tprivate activeTab: Tab = 'planets';\n\n\t/** Merge the 7 planets and the two nodes into one ordered body list. */\n\tprivate bodies(): KpBody[] {\n\t\tconst d = this.data;\n\t\tif (!d) return [];\n\t\tconst rows: KpBody[] = (d.planets ?? []).map((p) => ({\n\t\t\tname: p.planet,\n\t\t\tsign: p.sign,\n\t\t\thouse: p.house,\n\t\t\tnakshatra: p.nakshatra,\n\t\t\tstarLord: p.starLord,\n\t\t\tsubLord: p.subLord,\n\t\t\tsubSubLord: p.subSubLord,\n\t\t\tkpNumber: p.kpNumber,\n\t\t\tretrograde: p.retrograde,\n\t\t}));\n\t\tconst nodes = d.nodes;\n\t\tfor (const [name, node] of [\n\t\t\t['Rahu', nodes?.rahu],\n\t\t\t['Ketu', nodes?.ketu],\n\t\t] as const) {\n\t\t\tif (node) {\n\t\t\t\trows.push({\n\t\t\t\t\tname,\n\t\t\t\t\tsign: node.sign,\n\t\t\t\t\thouse: node.house,\n\t\t\t\t\tnakshatra: node.nakshatra,\n\t\t\t\t\tstarLord: node.starLord,\n\t\t\t\t\tsubLord: node.subLord,\n\t\t\t\t\tsubSubLord: node.subSubLord,\n\t\t\t\t\tretrograde: true,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn rows;\n\t}\n\n\tprivate onTabKeyDown(e: KeyboardEvent) {\n\t\tif (e.key !== 'ArrowRight' && e.key !== 'ArrowLeft') return;\n\t\te.preventDefault();\n\t\tthis.activeTab = this.activeTab === 'planets' ? 'cusps' : 'planets';\n\t\tconst next = this.activeTab;\n\t\trequestAnimationFrame(() => {\n\t\t\tthis.shadowRoot\n\t\t\t\t?.querySelector<HTMLButtonElement>(`#tab-${next}`)\n\t\t\t\t?.focus();\n\t\t});\n\t}\n\n\trender() {\n\t\tif (!this.data)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No KP chart data</div>`;\n\t\tconst d = this.data;\n\t\tconst asc = d.ascendant;\n\n\t\treturn html`<div class=\"wrap\" aria-label=\"KP chart\" tabindex=\"0\">\n\t\t\t<header class=\"head\">\n\t\t\t\t<h2 class=\"title\">KP chart</h2>\n\t\t\t\t${\n\t\t\t\t\tasc\n\t\t\t\t\t\t? html`<div class=\"asc\">\n\t\t\t\t\t\t\tAscendant: <strong>${asc.sign ?? ''}</strong>\n\t\t\t\t\t\t\t${asc.nakshatra ? html`\u00B7 ${asc.nakshatra}` : nothing}\n\t\t\t\t\t\t\t${asc.subLord ? html`\u00B7 sub lord ${asc.subLord}` : nothing}\n\t\t\t\t\t\t\t${typeof asc.kpNumber === 'number' ? html`\u00B7 KP ${asc.kpNumber}` : nothing}\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t\t${\n\t\t\t\t\ttypeof d.meta?.ayanamsa === 'number'\n\t\t\t\t\t\t? html`<div class=\"ayan\">\n\t\t\t\t\t\t\t${d.meta.ayanamsaType ?? 'Ayanamsa'}: ${formatNumber(d.meta.ayanamsa, 4)}\u00B0\n\t\t\t\t\t\t\t${d.meta.houseSystem ? html`\u00B7 ${d.meta.houseSystem} houses` : nothing}\n\t\t\t\t\t\t</div>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</header>\n\n\t\t\t<div\n\t\t\t\tclass=\"tablist\"\n\t\t\t\trole=\"tablist\"\n\t\t\t\taria-label=\"KP chart views\"\n\t\t\t\t@keydown=${this.onTabKeyDown}\n\t\t\t>\n\t\t\t\t${(['planets', 'cusps'] as const).map(\n\t\t\t\t\t(t) => html`<button\n\t\t\t\t\t\tclass=\"tab\"\n\t\t\t\t\t\trole=\"tab\"\n\t\t\t\t\t\tid=\"tab-${t}\"\n\t\t\t\t\t\taria-selected=${this.activeTab === t ? 'true' : 'false'}\n\t\t\t\t\t\taria-controls=\"panel-${t}\"\n\t\t\t\t\t\ttabindex=${this.activeTab === t ? '0' : '-1'}\n\t\t\t\t\t\t@click=${() => {\n\t\t\t\t\t\t\tthis.activeTab = t;\n\t\t\t\t\t\t}}\n\t\t\t\t\t>\n\t\t\t\t\t\t${t === 'planets' ? 'Planets' : 'Cusps'}\n\t\t\t\t\t</button>`,\n\t\t\t\t)}\n\t\t\t</div>\n\n\t\t\t<div id=\"panel-${this.activeTab}\" role=\"tabpanel\" aria-labelledby=\"tab-${this.activeTab}\">\n\t\t\t\t${this.activeTab === 'planets' ? this.renderPlanets() : this.renderCusps()}\n\t\t\t</div>\n\t\t</div>`;\n\t}\n\n\tprivate renderPlanets() {\n\t\tconst bodies = this.bodies();\n\t\tif (!bodies.length)\n\t\t\treturn html`<p class=\"roxy-empty\" role=\"status\">No planets</p>`;\n\t\treturn html`<table role=\"table\" aria-label=\"KP planets and nodes\">\n\t\t\t<thead>\n\t\t\t\t<tr>\n\t\t\t\t\t<th scope=\"col\">Body</th>\n\t\t\t\t\t<th scope=\"col\">Sign</th>\n\t\t\t\t\t<th scope=\"col\">House</th>\n\t\t\t\t\t<th scope=\"col\">Nakshatra</th>\n\t\t\t\t\t<th scope=\"col\">Star lord</th>\n\t\t\t\t\t<th scope=\"col\">Sub lord</th>\n\t\t\t\t\t<th scope=\"col\">Sub sub lord</th>\n\t\t\t\t\t<th scope=\"col\">KP no.</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t${bodies.map(\n\t\t\t\t\t(b) => html`<tr>\n\t\t\t\t\t\t<td class=\"body\">\n\t\t\t\t\t\t\t${b.name}${b.retrograde ? html`<span class=\"retro\">R</span>` : nothing}\n\t\t\t\t\t\t</td>\n\t\t\t\t\t\t<td>${b.sign ?? ''}</td>\n\t\t\t\t\t\t<td class=\"num\">${typeof b.house === 'number' ? b.house : ''}</td>\n\t\t\t\t\t\t<td>${b.nakshatra ?? ''}</td>\n\t\t\t\t\t\t<td>${b.starLord ?? ''}</td>\n\t\t\t\t\t\t<td>${b.subLord ?? ''}</td>\n\t\t\t\t\t\t<td>${b.subSubLord ?? ''}</td>\n\t\t\t\t\t\t<td class=\"num\">${typeof b.kpNumber === 'number' ? b.kpNumber : ''}</td>\n\t\t\t\t\t</tr>`,\n\t\t\t\t)}\n\t\t\t</tbody>\n\t\t</table>`;\n\t}\n\n\tprivate renderCusps() {\n\t\tconst cusps = this.data?.cusps ?? [];\n\t\tif (!cusps.length)\n\t\t\treturn html`<p class=\"roxy-empty\" role=\"status\">No cusps</p>`;\n\t\treturn html`<table role=\"table\" aria-label=\"KP Placidus cusps\">\n\t\t\t<thead>\n\t\t\t\t<tr>\n\t\t\t\t\t<th scope=\"col\">House</th>\n\t\t\t\t\t<th scope=\"col\">Sign</th>\n\t\t\t\t\t<th scope=\"col\">Sign lord</th>\n\t\t\t\t\t<th scope=\"col\">Nakshatra</th>\n\t\t\t\t\t<th scope=\"col\">Star lord</th>\n\t\t\t\t\t<th scope=\"col\">Sub lord</th>\n\t\t\t\t\t<th scope=\"col\">Sub sub lord</th>\n\t\t\t\t\t<th scope=\"col\">KP no.</th>\n\t\t\t\t</tr>\n\t\t\t</thead>\n\t\t\t<tbody>\n\t\t\t\t${cusps.map(\n\t\t\t\t\t(c) => html`<tr>\n\t\t\t\t\t\t<td class=\"body num\">${c.house}</td>\n\t\t\t\t\t\t<td>${c.sign ?? ''}</td>\n\t\t\t\t\t\t<td>${c.signLord ?? ''}</td>\n\t\t\t\t\t\t<td>${c.nakshatra ?? ''}</td>\n\t\t\t\t\t\t<td>${c.starLord ?? ''}</td>\n\t\t\t\t\t\t<td>${c.subLord ?? ''}</td>\n\t\t\t\t\t\t<td>${c.subSubLord ?? ''}</td>\n\t\t\t\t\t\t<td class=\"num\">${typeof c.kpNumber === 'number' ? c.kpNumber : ''}</td>\n\t\t\t\t\t</tr>`,\n\t\t\t\t)}\n\t\t\t</tbody>\n\t\t</table>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-kp-chart': RoxyKpChart;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n\n\t/* Force the text-style variant on every Unicode glyph in the component.\n\t * macOS and iOS substitute coloured emoji glyphs for the planetary and\n\t * gender Unicode code points (Mars, Venus, Mercury, etc.) when the\n\t * system colour-emoji font wins font selection. The text-style variant\n\t * keeps glyphs monochrome so they inherit the surrounding fill colour\n\t * and match the brand palette consistently across platforms.\n\t *\n\t * font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,\n\t * Firefox 139+). On older browsers the rule is silently ignored.\n\t */\n\t:host {\n\t\tfont-variant-emoji: text;\n\t}\n`;\n", "/**\n * Display formatters for ISO timestamps and floats coming back from the API.\n * Every helper returns \"\" for nullish or unparseable input so it falls out of\n * template literals cleanly.\n */\n\nexport function formatTime(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tif (/^\\d{4}-\\d{2}-\\d{2}$/.test(input)) return '';\n\tconst bareTime = /^\\d{2}:\\d{2}(:\\d{2})?$/.test(input);\n\tconst iso = bareTime ? `1970-01-01T${input}` : input;\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleTimeString(undefined, {\n\t\thour: 'numeric',\n\t\tminute: '2-digit',\n\t\thour12: true,\n\t});\n}\n\nexport function formatDate(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tconst d = new Date(\n\t\t/^\\d{4}-\\d{2}-\\d{2}$/.test(input) ? `${input}T00:00:00` : input,\n\t);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleDateString(undefined, {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: 'numeric',\n\t});\n}\n\nexport function formatTimeRange(\n\tt: { start?: string; end?: string } | undefined,\n): string {\n\tif (!t) return '';\n\tconst start = formatTime(t.start);\n\tconst end = formatTime(t.end);\n\tif (start && end) return `${start} - ${end}`;\n\treturn start || end || '';\n}\n\nexport function formatNumber(value: unknown, dp = 1): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\treturn value.toFixed(dp).replace(/\\.?0+$/, '');\n}\n\nexport function formatPercent(value: unknown, dp = 1): string {\n\tconst n = formatNumber(value, dp);\n\treturn n ? `${n}%` : '';\n}\n\n/**\n * CSS class name per aspect type. Used by natal and synastry chart aspect\n * lines so the same color encoding (harmonious vs challenging) applies in\n * both wheels. Keys are lowercase canonical names, values are CSS class\n * suffixes the chart components define in their `:host` styles.\n */\nexport const ASPECT_CLASS: Record<string, string> = {\n\tconjunction: 'aspect-conjunction',\n\tsextile: 'aspect-sextile',\n\tsquare: 'aspect-square',\n\ttrine: 'aspect-trine',\n\topposition: 'aspect-opposition',\n};\n\n/**\n * Normalize the `type` field on an aspect entry to a lowercase, hyphen-separated\n * canonical name (`SEMI_SEXTILE` \u2192 `semi-sextile`). Accepts any aspect-shaped\n * object so both natal and synastry inter-aspect entries can share this.\n */\nexport function normalizeAspect(a: { type?: string }): string {\n\treturn (a.type ?? '').toLowerCase().replace(/_/g, '-');\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["css", "css"]
|
|
7
7
|
}
|
|
@@ -97,6 +97,20 @@ var baseStyles = css`
|
|
|
97
97
|
outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
|
|
98
98
|
outline-offset: 2px;
|
|
99
99
|
}
|
|
100
|
+
|
|
101
|
+
/* Force the text-style variant on every Unicode glyph in the component.
|
|
102
|
+
* macOS and iOS substitute coloured emoji glyphs for the planetary and
|
|
103
|
+
* gender Unicode code points (Mars, Venus, Mercury, etc.) when the
|
|
104
|
+
* system colour-emoji font wins font selection. The text-style variant
|
|
105
|
+
* keeps glyphs monochrome so they inherit the surrounding fill colour
|
|
106
|
+
* and match the brand palette consistently across platforms.
|
|
107
|
+
*
|
|
108
|
+
* font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,
|
|
109
|
+
* Firefox 139+). On older browsers the rule is silently ignored.
|
|
110
|
+
*/
|
|
111
|
+
:host {
|
|
112
|
+
font-variant-emoji: text;
|
|
113
|
+
}
|
|
100
114
|
`;
|
|
101
115
|
|
|
102
116
|
// packages/ui/src/utils/format.ts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/components/kp-planets-table.ts", "../../src/utils/base-styles.ts", "../../src/utils/format.ts"],
|
|
4
|
-
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { KpPlanetsResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\n/**\n * KP planets table with sub-lord and sub-sub-lord columns. Renders\n * /vedic-astrology/kp/planets.\n */\n@customElement('roxy-kp-planets-table')\nexport class RoxyKpPlanetsTable extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.wrap {\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\toverflow: auto;\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t}\n\t\t\t.head {\n\t\t\t\tpadding: var(--roxy-space-md, 1rem);\n\t\t\t\tborder-bottom: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tdisplay: flex;\n\t\t\t\tjustify-content: space-between;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t\t\t}\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-lg, 1.125rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.ayanamsa {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t\ttable {\n\t\t\t\twidth: 100%;\n\t\t\t\tborder-collapse: collapse;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tmin-width: 560px;\n\t\t\t}\n\t\t\tthead {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-border, #e4e4e7) 20%, transparent);\n\t\t\t}\n\t\t\tth,\n\t\t\ttd {\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\ttext-align: left;\n\t\t\t\twhite-space: nowrap;\n\t\t\t}\n\t\t\tth {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tletter-spacing: 0.04em;\n\t\t\t}\n\t\t\ttbody tr {\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\ttd.planet {\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.retro {\n\t\t\t\tcolor: var(--roxy-warning-fg, #9a3412);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tmargin-left: 4px;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: KpPlanetsResponse | null = null;\n\n\trender() {\n\t\tif (!this.data)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No KP data</div>`;\n\t\tconst planets = this.data.planets ?? [];\n\n\t\treturn html`<div\n\t\t\tclass=\"wrap\"\n\t\t\taria-label=\"KP planets table\"\n\t\t\ttabindex=\"0\"\n\t\t>\n\t\t\t<header class=\"head\">\n\t\t\t\t<h2 class=\"title\">KP planets</h2>\n\t\t\t\t${\n\t\t\t\t\ttypeof this.data.ayanamsa === 'number'\n\t\t\t\t\t\t? html`<span class=\"ayanamsa\">Ayanamsa: ${formatNumber(this.data.ayanamsa, 2)}\u00B0</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</header>\n\t\t\t<table role=\"table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th scope=\"col\">Planet</th>\n\t\t\t\t\t\t<th scope=\"col\">Sign</th>\n\t\t\t\t\t\t<th scope=\"col\">Sign lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Nakshatra</th>\n\t\t\t\t\t\t<th scope=\"col\">Star lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Sub lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Sub sub lord</th>\n\t\t\t\t\t\t<th scope=\"col\">KP no.</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t${planets.map(\n\t\t\t\t\t\t(p) => html`<tr>\n\t\t\t\t\t\t\t<td class=\"planet\">\n\t\t\t\t\t\t\t\t${p.planet}\n\t\t\t\t\t\t\t\t${p.retrograde ? html`<span class=\"retro\">R</span>` : nothing}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>${p.sign ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.signLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.nakshatra ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.nakshatraLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.subLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.subSubLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.kpNumber ?? ''}</td>\n\t\t\t\t\t\t</tr>`,\n\t\t\t\t\t)}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-kp-planets-table': RoxyKpPlanetsTable;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n", "/**\n * Display formatters for ISO timestamps and floats coming back from the API.\n * Every helper returns \"\" for nullish or unparseable input so it falls out of\n * template literals cleanly.\n */\n\nexport function formatTime(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tif (/^\\d{4}-\\d{2}-\\d{2}$/.test(input)) return '';\n\tconst bareTime = /^\\d{2}:\\d{2}(:\\d{2})?$/.test(input);\n\tconst iso = bareTime ? `1970-01-01T${input}` : input;\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleTimeString(undefined, {\n\t\thour: 'numeric',\n\t\tminute: '2-digit',\n\t\thour12: true,\n\t});\n}\n\nexport function formatDate(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tconst d = new Date(\n\t\t/^\\d{4}-\\d{2}-\\d{2}$/.test(input) ? `${input}T00:00:00` : input,\n\t);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleDateString(undefined, {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: 'numeric',\n\t});\n}\n\nexport function formatTimeRange(\n\tt: { start?: string; end?: string } | undefined,\n): string {\n\tif (!t) return '';\n\tconst start = formatTime(t.start);\n\tconst end = formatTime(t.end);\n\tif (start && end) return `${start} - ${end}`;\n\treturn start || end || '';\n}\n\nexport function formatNumber(value: unknown, dp = 1): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\treturn value.toFixed(dp).replace(/\\.?0+$/, '');\n}\n\nexport function formatPercent(value: unknown, dp = 1): string {\n\tconst n = formatNumber(value, dp);\n\treturn n ? `${n}%` : '';\n}\n\n/**\n * CSS class name per aspect type. Used by natal and synastry chart aspect\n * lines so the same color encoding (harmonious vs challenging) applies in\n * both wheels. Keys are lowercase canonical names, values are CSS class\n * suffixes the chart components define in their `:host` styles.\n */\nexport const ASPECT_CLASS: Record<string, string> = {\n\tconjunction: 'aspect-conjunction',\n\tsextile: 'aspect-sextile',\n\tsquare: 'aspect-square',\n\ttrine: 'aspect-trine',\n\topposition: 'aspect-opposition',\n};\n\n/**\n * Normalize the `type` field on an aspect entry to a lowercase, hyphen-separated\n * canonical name (`SEMI_SEXTILE` \u2192 `semi-sextile`). Accepts any aspect-shaped\n * object so both natal and synastry inter-aspect entries can share this.\n */\nexport function normalizeAspect(a: { type?: string }): string {\n\treturn (a.type ?? '').toLowerCase().replace(/_/g, '-');\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;AAAA,SAAS,OAAAA,MAAK,MAAM,YAAY,eAAe;AAC/C,SAAS,eAAe,gBAAgB;;;ACDxC,SAAS,WAAW;AAMb,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACqCnB,SAAS,aAAa,OAAgB,KAAK,GAAW;AAC5D,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACjE,SAAO,MAAM,QAAQ,EAAE,EAAE,QAAQ,UAAU,EAAE;AAC9C;;;AFnCO,IAAM,qBAAN,cAAiC,WAAW;AAAA,EAA5C;AAAA;AAkEN,gBAAiC;AAAA;AAAA,EAEjC,SAAS;AACR,QAAI,CAAC,KAAK;AACT,aAAO;AACR,UAAM,UAAU,KAAK,KAAK,WAAW,CAAC;AAEtC,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQJ,OAAO,KAAK,KAAK,aAAa,WAC3B,wCAAwC,aAAa,KAAK,KAAK,UAAU,CAAC,CAAC,aAC3E,OACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAgBG,QAAQ;AAAA,MACT,CAAC,MAAM;AAAA;AAAA,UAEH,EAAE,MAAM;AAAA,UACR,EAAE,aAAa,qCAAqC,OAAO;AAAA;AAAA,aAExD,EAAE,QAAQ,EAAE;AAAA,aACZ,EAAE,YAAY,EAAE;AAAA,aAChB,EAAE,aAAa,EAAE;AAAA,aACjB,EAAE,iBAAiB,EAAE;AAAA,aACrB,EAAE,WAAW,EAAE;AAAA,aACf,EAAE,cAAc,EAAE;AAAA,aAClB,EAAE,YAAY,EAAE;AAAA;AAAA,IAExB,CAAC;AAAA;AAAA;AAAA;AAAA,EAIL;AACD;AAvHa,mBACL,SAAS;AAAA,EACf;AAAA,EACAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4DD;AAGA;AAAA,EADC,SAAS,EAAE,WAAW,MAAM,CAAC;AAAA,GAjElB,mBAkEZ;AAlEY,qBAAN;AAAA,EADN,cAAc,uBAAuB;AAAA,GACzB;",
|
|
4
|
+
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { KpPlanetsResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { formatNumber } from '../utils/format.js';\n\n/**\n * KP planets table with sub-lord and sub-sub-lord columns. Renders\n * /vedic-astrology/kp/planets.\n */\n@customElement('roxy-kp-planets-table')\nexport class RoxyKpPlanetsTable extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.wrap {\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\toverflow: auto;\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t}\n\t\t\t.head {\n\t\t\t\tpadding: var(--roxy-space-md, 1rem);\n\t\t\t\tborder-bottom: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tdisplay: flex;\n\t\t\t\tjustify-content: space-between;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t\t\t}\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-lg, 1.125rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.ayanamsa {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t\ttable {\n\t\t\t\twidth: 100%;\n\t\t\t\tborder-collapse: collapse;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tmin-width: 560px;\n\t\t\t}\n\t\t\tthead {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-border, #e4e4e7) 20%, transparent);\n\t\t\t}\n\t\t\tth,\n\t\t\ttd {\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\ttext-align: left;\n\t\t\t\twhite-space: nowrap;\n\t\t\t}\n\t\t\tth {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\ttext-transform: uppercase;\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tletter-spacing: 0.04em;\n\t\t\t}\n\t\t\ttbody tr {\n\t\t\t\tborder-top: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t}\n\t\t\ttd.planet {\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t}\n\t\t\t.retro {\n\t\t\t\tcolor: var(--roxy-warning-fg, #9a3412);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tmargin-left: 4px;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: KpPlanetsResponse | null = null;\n\n\trender() {\n\t\tif (!this.data)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No KP data</div>`;\n\t\tconst planets = this.data.planets ?? [];\n\n\t\treturn html`<div\n\t\t\tclass=\"wrap\"\n\t\t\taria-label=\"KP planets table\"\n\t\t\ttabindex=\"0\"\n\t\t>\n\t\t\t<header class=\"head\">\n\t\t\t\t<h2 class=\"title\">KP planets</h2>\n\t\t\t\t${\n\t\t\t\t\ttypeof this.data.ayanamsa === 'number'\n\t\t\t\t\t\t? html`<span class=\"ayanamsa\">Ayanamsa: ${formatNumber(this.data.ayanamsa, 2)}\u00B0</span>`\n\t\t\t\t\t\t: nothing\n\t\t\t\t}\n\t\t\t</header>\n\t\t\t<table role=\"table\">\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th scope=\"col\">Planet</th>\n\t\t\t\t\t\t<th scope=\"col\">Sign</th>\n\t\t\t\t\t\t<th scope=\"col\">Sign lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Nakshatra</th>\n\t\t\t\t\t\t<th scope=\"col\">Star lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Sub lord</th>\n\t\t\t\t\t\t<th scope=\"col\">Sub sub lord</th>\n\t\t\t\t\t\t<th scope=\"col\">KP no.</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t${planets.map(\n\t\t\t\t\t\t(p) => html`<tr>\n\t\t\t\t\t\t\t<td class=\"planet\">\n\t\t\t\t\t\t\t\t${p.planet}\n\t\t\t\t\t\t\t\t${p.retrograde ? html`<span class=\"retro\">R</span>` : nothing}\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>${p.sign ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.signLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.nakshatra ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.nakshatraLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.subLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.subSubLord ?? ''}</td>\n\t\t\t\t\t\t\t<td>${p.kpNumber ?? ''}</td>\n\t\t\t\t\t\t</tr>`,\n\t\t\t\t\t)}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-kp-planets-table': RoxyKpPlanetsTable;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n\n\t/* Force the text-style variant on every Unicode glyph in the component.\n\t * macOS and iOS substitute coloured emoji glyphs for the planetary and\n\t * gender Unicode code points (Mars, Venus, Mercury, etc.) when the\n\t * system colour-emoji font wins font selection. The text-style variant\n\t * keeps glyphs monochrome so they inherit the surrounding fill colour\n\t * and match the brand palette consistently across platforms.\n\t *\n\t * font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,\n\t * Firefox 139+). On older browsers the rule is silently ignored.\n\t */\n\t:host {\n\t\tfont-variant-emoji: text;\n\t}\n`;\n", "/**\n * Display formatters for ISO timestamps and floats coming back from the API.\n * Every helper returns \"\" for nullish or unparseable input so it falls out of\n * template literals cleanly.\n */\n\nexport function formatTime(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tif (/^\\d{4}-\\d{2}-\\d{2}$/.test(input)) return '';\n\tconst bareTime = /^\\d{2}:\\d{2}(:\\d{2})?$/.test(input);\n\tconst iso = bareTime ? `1970-01-01T${input}` : input;\n\tconst d = new Date(iso);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleTimeString(undefined, {\n\t\thour: 'numeric',\n\t\tminute: '2-digit',\n\t\thour12: true,\n\t});\n}\n\nexport function formatDate(input: unknown): string {\n\tif (typeof input !== 'string' || input.length === 0) return '';\n\tconst d = new Date(\n\t\t/^\\d{4}-\\d{2}-\\d{2}$/.test(input) ? `${input}T00:00:00` : input,\n\t);\n\tif (Number.isNaN(d.getTime())) return input;\n\treturn d.toLocaleDateString(undefined, {\n\t\tmonth: 'short',\n\t\tday: 'numeric',\n\t\tyear: 'numeric',\n\t});\n}\n\nexport function formatTimeRange(\n\tt: { start?: string; end?: string } | undefined,\n): string {\n\tif (!t) return '';\n\tconst start = formatTime(t.start);\n\tconst end = formatTime(t.end);\n\tif (start && end) return `${start} - ${end}`;\n\treturn start || end || '';\n}\n\nexport function formatNumber(value: unknown, dp = 1): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\treturn value.toFixed(dp).replace(/\\.?0+$/, '');\n}\n\nexport function formatPercent(value: unknown, dp = 1): string {\n\tconst n = formatNumber(value, dp);\n\treturn n ? `${n}%` : '';\n}\n\n/**\n * CSS class name per aspect type. Used by natal and synastry chart aspect\n * lines so the same color encoding (harmonious vs challenging) applies in\n * both wheels. Keys are lowercase canonical names, values are CSS class\n * suffixes the chart components define in their `:host` styles.\n */\nexport const ASPECT_CLASS: Record<string, string> = {\n\tconjunction: 'aspect-conjunction',\n\tsextile: 'aspect-sextile',\n\tsquare: 'aspect-square',\n\ttrine: 'aspect-trine',\n\topposition: 'aspect-opposition',\n};\n\n/**\n * Normalize the `type` field on an aspect entry to a lowercase, hyphen-separated\n * canonical name (`SEMI_SEXTILE` \u2192 `semi-sextile`). Accepts any aspect-shaped\n * object so both natal and synastry inter-aspect entries can share this.\n */\nexport function normalizeAspect(a: { type?: string }): string {\n\treturn (a.type ?? '').toLowerCase().replace(/_/g, '-');\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;AAAA,SAAS,OAAAA,MAAK,MAAM,YAAY,eAAe;AAC/C,SAAS,eAAe,gBAAgB;;;ACDxC,SAAS,WAAW;AAMb,IAAM,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACqCnB,SAAS,aAAa,OAAgB,KAAK,GAAW;AAC5D,MAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACjE,SAAO,MAAM,QAAQ,EAAE,EAAE,QAAQ,UAAU,EAAE;AAC9C;;;AFnCO,IAAM,qBAAN,cAAiC,WAAW;AAAA,EAA5C;AAAA;AAkEN,gBAAiC;AAAA;AAAA,EAEjC,SAAS;AACR,QAAI,CAAC,KAAK;AACT,aAAO;AACR,UAAM,UAAU,KAAK,KAAK,WAAW,CAAC;AAEtC,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQJ,OAAO,KAAK,KAAK,aAAa,WAC3B,wCAAwC,aAAa,KAAK,KAAK,UAAU,CAAC,CAAC,aAC3E,OACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAgBG,QAAQ;AAAA,MACT,CAAC,MAAM;AAAA;AAAA,UAEH,EAAE,MAAM;AAAA,UACR,EAAE,aAAa,qCAAqC,OAAO;AAAA;AAAA,aAExD,EAAE,QAAQ,EAAE;AAAA,aACZ,EAAE,YAAY,EAAE;AAAA,aAChB,EAAE,aAAa,EAAE;AAAA,aACjB,EAAE,iBAAiB,EAAE;AAAA,aACrB,EAAE,WAAW,EAAE;AAAA,aACf,EAAE,cAAc,EAAE;AAAA,aAClB,EAAE,YAAY,EAAE;AAAA;AAAA,IAExB,CAAC;AAAA;AAAA;AAAA;AAAA,EAIL;AACD;AAvHa,mBACL,SAAS;AAAA,EACf;AAAA,EACAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4DD;AAGA;AAAA,EADC,SAAS,EAAE,WAAW,MAAM,CAAC;AAAA,GAjElB,mBAkEZ;AAlEY,qBAAN;AAAA,EADN,cAAc,uBAAuB;AAAA,GACzB;",
|
|
6
6
|
"names": ["css", "css"]
|
|
7
7
|
}
|
|
@@ -97,6 +97,20 @@ var baseStyles = css`
|
|
|
97
97
|
outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
|
|
98
98
|
outline-offset: 2px;
|
|
99
99
|
}
|
|
100
|
+
|
|
101
|
+
/* Force the text-style variant on every Unicode glyph in the component.
|
|
102
|
+
* macOS and iOS substitute coloured emoji glyphs for the planetary and
|
|
103
|
+
* gender Unicode code points (Mars, Venus, Mercury, etc.) when the
|
|
104
|
+
* system colour-emoji font wins font selection. The text-style variant
|
|
105
|
+
* keeps glyphs monochrome so they inherit the surrounding fill colour
|
|
106
|
+
* and match the brand palette consistently across platforms.
|
|
107
|
+
*
|
|
108
|
+
* font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,
|
|
109
|
+
* Firefox 139+). On older browsers the rule is silently ignored.
|
|
110
|
+
*/
|
|
111
|
+
:host {
|
|
112
|
+
font-variant-emoji: text;
|
|
113
|
+
}
|
|
100
114
|
`;
|
|
101
115
|
|
|
102
116
|
// packages/ui/src/components/kp-ruling-planets.ts
|