@roxyapi/ui 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -2
- package/LICENSE +21 -0
- package/README.md +505 -0
- package/THEMING.md +24 -7
- package/dist/cdn/components/biorhythm-chart.js +15 -22
- package/dist/cdn/components/biorhythm-chart.js.map +3 -3
- package/dist/cdn/components/compatibility-card.js +36 -34
- package/dist/cdn/components/compatibility-card.js.map +4 -4
- package/dist/cdn/components/dasha-timeline.js +35 -39
- package/dist/cdn/components/dasha-timeline.js.map +4 -4
- package/dist/cdn/components/data.js +6 -6
- package/dist/cdn/components/data.js.map +3 -3
- package/dist/cdn/components/dosha-card.js +13 -13
- package/dist/cdn/components/dosha-card.js.map +2 -2
- package/dist/cdn/components/endpoint-form.js +47 -28
- package/dist/cdn/components/endpoint-form.js.map +3 -3
- package/dist/cdn/components/guna-milan.js +18 -18
- package/dist/cdn/components/guna-milan.js.map +4 -4
- package/dist/cdn/components/hexagram.js +26 -26
- package/dist/cdn/components/hexagram.js.map +3 -3
- package/dist/cdn/components/horoscope-card.js +38 -38
- package/dist/cdn/components/horoscope-card.js.map +3 -3
- package/dist/cdn/components/kp-planets-table.js +10 -10
- package/dist/cdn/components/kp-planets-table.js.map +4 -4
- package/dist/cdn/components/location-search.js +6 -6
- package/dist/cdn/components/location-search.js.map +3 -3
- package/dist/cdn/components/moon-phase.js +21 -21
- package/dist/cdn/components/moon-phase.js.map +4 -4
- package/dist/cdn/components/natal-chart.js +61 -19
- package/dist/cdn/components/natal-chart.js.map +4 -4
- package/dist/cdn/components/numerology-card.js +40 -31
- package/dist/cdn/components/numerology-card.js.map +3 -3
- package/dist/cdn/components/panchang-table.js +25 -25
- package/dist/cdn/components/panchang-table.js.map +4 -4
- package/dist/cdn/components/synastry-chart.js +129 -39
- package/dist/cdn/components/synastry-chart.js.map +4 -4
- package/dist/cdn/components/tarot-card.js +49 -20
- package/dist/cdn/components/tarot-card.js.map +3 -3
- package/dist/cdn/components/tarot-spread.js +43 -27
- package/dist/cdn/components/tarot-spread.js.map +3 -3
- package/dist/cdn/components/vedic-kundli.js +23 -9
- package/dist/cdn/components/vedic-kundli.js.map +3 -3
- package/dist/cdn/roxy-ui.js +560 -350
- package/dist/cdn/roxy-ui.js.map +4 -4
- package/dist/components/biorhythm-chart.d.ts +2 -46
- package/dist/components/biorhythm-chart.d.ts.map +1 -1
- package/dist/components/biorhythm-chart.js +24 -23
- package/dist/components/biorhythm-chart.js.map +2 -2
- package/dist/components/compatibility-card.d.ts +2 -27
- package/dist/components/compatibility-card.d.ts.map +1 -1
- package/dist/components/compatibility-card.js +50 -29
- package/dist/components/compatibility-card.js.map +3 -3
- package/dist/components/dasha-timeline.d.ts +2 -31
- package/dist/components/dasha-timeline.d.ts.map +1 -1
- package/dist/components/dasha-timeline.js +32 -30
- package/dist/components/dasha-timeline.js.map +3 -3
- package/dist/components/data.d.ts +6 -0
- package/dist/components/data.d.ts.map +1 -1
- package/dist/components/data.js +9 -1
- package/dist/components/data.js.map +2 -2
- package/dist/components/dosha-card.d.ts +2 -16
- package/dist/components/dosha-card.d.ts.map +1 -1
- package/dist/components/dosha-card.js +12 -13
- package/dist/components/dosha-card.js.map +2 -2
- package/dist/components/endpoint-form.d.ts +2 -0
- package/dist/components/endpoint-form.d.ts.map +1 -1
- package/dist/components/endpoint-form.js +66 -8
- package/dist/components/endpoint-form.js.map +2 -2
- package/dist/components/guna-milan.d.ts +2 -20
- package/dist/components/guna-milan.d.ts.map +1 -1
- package/dist/components/guna-milan.js +22 -12
- package/dist/components/guna-milan.js.map +3 -3
- package/dist/components/hexagram.d.ts +3 -27
- package/dist/components/hexagram.d.ts.map +1 -1
- package/dist/components/hexagram.js +31 -15
- package/dist/components/hexagram.js.map +2 -2
- package/dist/components/horoscope-card.d.ts +2 -20
- package/dist/components/horoscope-card.d.ts.map +1 -1
- package/dist/components/horoscope-card.js +24 -15
- package/dist/components/horoscope-card.js.map +2 -2
- package/dist/components/kp-planets-table.d.ts +2 -21
- package/dist/components/kp-planets-table.d.ts.map +1 -1
- package/dist/components/kp-planets-table.js +10 -4
- package/dist/components/kp-planets-table.js.map +3 -3
- package/dist/components/location-search.d.ts +3 -11
- package/dist/components/location-search.d.ts.map +1 -1
- package/dist/components/location-search.js +45 -5
- package/dist/components/location-search.js.map +2 -2
- package/dist/components/moon-phase.d.ts +4 -21
- package/dist/components/moon-phase.d.ts.map +1 -1
- package/dist/components/moon-phase.js +17 -4
- package/dist/components/moon-phase.js.map +3 -3
- package/dist/components/natal-chart.d.ts +7 -43
- package/dist/components/natal-chart.d.ts.map +1 -1
- package/dist/components/natal-chart.js +130 -70
- package/dist/components/natal-chart.js.map +3 -3
- package/dist/components/numerology-card.d.ts +5 -37
- package/dist/components/numerology-card.d.ts.map +1 -1
- package/dist/components/numerology-card.js +54 -28
- package/dist/components/numerology-card.js.map +2 -2
- package/dist/components/panchang-table.d.ts +3 -62
- package/dist/components/panchang-table.d.ts.map +1 -1
- package/dist/components/panchang-table.js +62 -32
- package/dist/components/panchang-table.js.map +3 -3
- package/dist/components/synastry-chart.d.ts +9 -28
- package/dist/components/synastry-chart.d.ts.map +1 -1
- package/dist/components/synastry-chart.js +178 -38
- package/dist/components/synastry-chart.js.map +3 -3
- package/dist/components/tarot-card.d.ts +5 -29
- package/dist/components/tarot-card.d.ts.map +1 -1
- package/dist/components/tarot-card.js +59 -20
- package/dist/components/tarot-card.js.map +2 -2
- package/dist/components/tarot-spread.d.ts +2 -24
- package/dist/components/tarot-spread.d.ts.map +1 -1
- package/dist/components/tarot-spread.js +39 -13
- package/dist/components/tarot-spread.js.map +2 -2
- package/dist/components/vedic-kundli.d.ts +3 -23
- package/dist/components/vedic-kundli.d.ts.map +1 -1
- package/dist/components/vedic-kundli.js +25 -13
- package/dist/components/vedic-kundli.js.map +2 -2
- package/dist/index.cjs +1149 -358
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1149 -358
- package/dist/index.js.map +4 -4
- package/dist/manifest.d.ts +49 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.json +1 -1
- package/dist/styles/tokens.css +47 -1
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/types.gen.d.ts +27811 -0
- package/dist/types/types.gen.d.ts.map +1 -0
- package/dist/utils/debounce.d.ts +9 -1
- package/dist/utils/debounce.d.ts.map +1 -1
- package/dist/utils/format.d.ts +15 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/package.json +9 -1
- package/src/components/biorhythm-chart.ts +39 -84
- package/src/components/compatibility-card.ts +85 -52
- package/src/components/dasha-timeline.ts +55 -73
- package/src/components/data.ts +20 -1
- package/src/components/dosha-card.ts +18 -31
- package/src/components/endpoint-form.ts +79 -11
- package/src/components/guna-milan.ts +16 -34
- package/src/components/hexagram.ts +53 -43
- package/src/components/horoscope-card.ts +51 -39
- package/src/components/kp-planets-table.ts +8 -27
- package/src/components/location-search.ts +45 -20
- package/src/components/moon-phase.ts +28 -25
- package/src/components/natal-chart.ts +129 -84
- package/src/components/numerology-card.ts +87 -79
- package/src/components/panchang-table.ts +40 -78
- package/src/components/synastry-chart.ts +220 -78
- package/src/components/tarot-card.ts +76 -62
- package/src/components/tarot-spread.ts +72 -45
- package/src/components/vedic-kundli.ts +42 -51
- package/src/index.ts +14 -24
- package/src/manifest.ts +366 -0
- package/src/styles/tokens.css +47 -1
- package/src/tokens/index.ts +5 -0
- package/src/types/types.gen.ts +1 -1
- package/src/utils/debounce.ts +23 -4
- package/src/utils/format.ts +57 -0
- package/src/version.ts +2 -0
|
@@ -31,7 +31,12 @@ var PLANET_GLYPH = {
|
|
|
31
31
|
Ascendant: "Asc",
|
|
32
32
|
Lagna: "La",
|
|
33
33
|
NorthNode: "\u260A",
|
|
34
|
-
SouthNode: "\u260B"
|
|
34
|
+
SouthNode: "\u260B",
|
|
35
|
+
"North node": "\u260A",
|
|
36
|
+
"South node": "\u260B",
|
|
37
|
+
Chiron: "\u26B7",
|
|
38
|
+
Lilith: "\u26B8",
|
|
39
|
+
"Black moon lilith": "\u26B8"
|
|
35
40
|
};
|
|
36
41
|
var SIGN_GLYPH = {
|
|
37
42
|
Aries: "\u2648",
|
|
@@ -47,20 +52,6 @@ var SIGN_GLYPH = {
|
|
|
47
52
|
Aquarius: "\u2652",
|
|
48
53
|
Pisces: "\u2653"
|
|
49
54
|
};
|
|
50
|
-
var SIGNS_ORDER = [
|
|
51
|
-
"Aries",
|
|
52
|
-
"Taurus",
|
|
53
|
-
"Gemini",
|
|
54
|
-
"Cancer",
|
|
55
|
-
"Leo",
|
|
56
|
-
"Virgo",
|
|
57
|
-
"Libra",
|
|
58
|
-
"Scorpio",
|
|
59
|
-
"Sagittarius",
|
|
60
|
-
"Capricorn",
|
|
61
|
-
"Aquarius",
|
|
62
|
-
"Pisces"
|
|
63
|
-
];
|
|
64
55
|
|
|
65
56
|
// packages/ui/src/utils/base-styles.ts
|
|
66
57
|
import { css } from "lit";
|
|
@@ -149,26 +140,6 @@ var baseStyles = css`
|
|
|
149
140
|
`;
|
|
150
141
|
|
|
151
142
|
// packages/ui/src/utils/degree.ts
|
|
152
|
-
function normalizeLongitude(lon) {
|
|
153
|
-
const wrapped = lon % 360;
|
|
154
|
-
return wrapped < 0 ? wrapped + 360 : wrapped;
|
|
155
|
-
}
|
|
156
|
-
function longitudeToSignPosition(longitude) {
|
|
157
|
-
const lon = normalizeLongitude(longitude);
|
|
158
|
-
const signIndex = Math.floor(lon / 30) % 12;
|
|
159
|
-
const within = lon % 30;
|
|
160
|
-
const degree = Math.floor(within);
|
|
161
|
-
const minuteFloat = (within - degree) * 60;
|
|
162
|
-
const minute = Math.floor(minuteFloat);
|
|
163
|
-
const second = Math.round((minuteFloat - minute) * 60);
|
|
164
|
-
return {
|
|
165
|
-
sign: SIGNS_ORDER[signIndex] ?? "Aries",
|
|
166
|
-
signIndex,
|
|
167
|
-
degree,
|
|
168
|
-
minute,
|
|
169
|
-
second
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
143
|
function polarToCartesian(cx, cy, radius, angleDeg) {
|
|
173
144
|
const angleRad = angleDeg * Math.PI / 180;
|
|
174
145
|
return {
|
|
@@ -177,13 +148,21 @@ function polarToCartesian(cx, cy, radius, angleDeg) {
|
|
|
177
148
|
};
|
|
178
149
|
}
|
|
179
150
|
|
|
151
|
+
// packages/ui/src/utils/format.ts
|
|
152
|
+
function formatNumber(value, dp = 1) {
|
|
153
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return "";
|
|
154
|
+
return value.toFixed(dp).replace(/\.?0+$/, "");
|
|
155
|
+
}
|
|
156
|
+
|
|
180
157
|
// packages/ui/src/components/natal-chart.ts
|
|
181
|
-
var SIZE =
|
|
158
|
+
var SIZE = 384;
|
|
182
159
|
var CENTER = SIZE / 2;
|
|
183
160
|
var OUTER_R = 150;
|
|
184
161
|
var SIGN_R = 134;
|
|
185
162
|
var HOUSE_R = 110;
|
|
186
163
|
var PLANET_R = 88;
|
|
164
|
+
var ANGLE_TICK_R = 162;
|
|
165
|
+
var ANGLE_LABEL_R = 176;
|
|
187
166
|
var RoxyNatalChart = class extends LitElement {
|
|
188
167
|
constructor() {
|
|
189
168
|
super(...arguments);
|
|
@@ -191,10 +170,17 @@ var RoxyNatalChart = class extends LitElement {
|
|
|
191
170
|
this.houseSystem = "placidus";
|
|
192
171
|
}
|
|
193
172
|
getPlanets() {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
return
|
|
173
|
+
return this.data?.planets ?? [];
|
|
174
|
+
}
|
|
175
|
+
getAscendant() {
|
|
176
|
+
return this.data?.ascendant?.longitude ?? 0;
|
|
177
|
+
}
|
|
178
|
+
getMidheaven() {
|
|
179
|
+
const m = this.data?.midheaven?.longitude;
|
|
180
|
+
return typeof m === "number" ? m : null;
|
|
181
|
+
}
|
|
182
|
+
toAngle(lon) {
|
|
183
|
+
return 180 + this.getAscendant() - lon;
|
|
198
184
|
}
|
|
199
185
|
render() {
|
|
200
186
|
if (!this.data)
|
|
@@ -205,11 +191,7 @@ var RoxyNatalChart = class extends LitElement {
|
|
|
205
191
|
<header>
|
|
206
192
|
<h2 class="title">Natal chart</h2>
|
|
207
193
|
${this.data.birthDetails ? html`<div class="meta">
|
|
208
|
-
${[
|
|
209
|
-
this.data.birthDetails.date,
|
|
210
|
-
this.data.birthDetails.time,
|
|
211
|
-
this.data.birthDetails.location
|
|
212
|
-
].filter(Boolean).join(" \xB7 ")}
|
|
194
|
+
${[this.data.birthDetails.date, this.data.birthDetails.time].filter(Boolean).join(" \xB7 ")}
|
|
213
195
|
</div>` : nothing}
|
|
214
196
|
</header>
|
|
215
197
|
<svg
|
|
@@ -245,17 +227,38 @@ var RoxyNatalChart = class extends LitElement {
|
|
|
245
227
|
/>
|
|
246
228
|
${this.renderSpokes()} ${this.renderSigns()} ${this.renderHouseNumbers()}
|
|
247
229
|
${this.renderAspects(planets, aspects)} ${this.renderPlanets(planets)}
|
|
230
|
+
${this.renderAngles()}
|
|
248
231
|
</svg>
|
|
249
232
|
<div class="legend">
|
|
250
233
|
<span>${planets.length} planets</span>
|
|
251
234
|
<span>${aspects.length} aspects</span>
|
|
252
|
-
<span
|
|
235
|
+
<span><span class="legend-swatch" style="background: var(--roxy-success)"></span>harmonious</span>
|
|
236
|
+
<span><span class="legend-swatch" style="background: var(--roxy-danger)"></span>challenging</span>
|
|
253
237
|
</div>
|
|
254
238
|
</div>`;
|
|
255
239
|
}
|
|
240
|
+
renderAngles() {
|
|
241
|
+
const asc = this.getAscendant();
|
|
242
|
+
const mc = this.getMidheaven();
|
|
243
|
+
const items = [this.renderAngleMark(asc, "ASC")];
|
|
244
|
+
if (mc !== null) items.push(this.renderAngleMark(mc, "MC"));
|
|
245
|
+
return items;
|
|
246
|
+
}
|
|
247
|
+
renderAngleMark(longitude, label) {
|
|
248
|
+
const angle = this.toAngle(longitude);
|
|
249
|
+
const tickInner = polarToCartesian(CENTER, CENTER, OUTER_R, angle);
|
|
250
|
+
const tickOuter = polarToCartesian(CENTER, CENTER, ANGLE_TICK_R, angle);
|
|
251
|
+
const labelPos = polarToCartesian(CENTER, CENTER, ANGLE_LABEL_R, angle);
|
|
252
|
+
return svg`
|
|
253
|
+
<g>
|
|
254
|
+
<line class="angle-tick" x1=${tickInner.x} y1=${tickInner.y} x2=${tickOuter.x} y2=${tickOuter.y} />
|
|
255
|
+
<text class="angle-marker" x=${labelPos.x} y=${labelPos.y} text-anchor="middle" dominant-baseline="central">${label}</text>
|
|
256
|
+
</g>
|
|
257
|
+
`;
|
|
258
|
+
}
|
|
256
259
|
renderSpokes() {
|
|
257
260
|
return Array.from({ length: 12 }, (_, i) => {
|
|
258
|
-
const angle = i * 30
|
|
261
|
+
const angle = this.toAngle(i * 30);
|
|
259
262
|
const start = polarToCartesian(CENTER, CENTER, HOUSE_R, angle);
|
|
260
263
|
const end = polarToCartesian(CENTER, CENTER, OUTER_R, angle);
|
|
261
264
|
return svg`<line class="wheel-line" x1=${start.x} y1=${start.y} x2=${end.x} y2=${end.y} stroke-width="0.8" />`;
|
|
@@ -277,45 +280,58 @@ var RoxyNatalChart = class extends LitElement {
|
|
|
277
280
|
"Pisces"
|
|
278
281
|
];
|
|
279
282
|
return order.map((sign, i) => {
|
|
280
|
-
const angle = i * 30 + 15
|
|
283
|
+
const angle = this.toAngle(i * 30 + 15);
|
|
281
284
|
const pos = polarToCartesian(CENTER, CENTER, SIGN_R, angle);
|
|
282
285
|
return svg`<text class="sign-glyph" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central">${SIGN_GLYPH[sign]}</text>`;
|
|
283
286
|
});
|
|
284
287
|
}
|
|
285
288
|
renderHouseNumbers() {
|
|
289
|
+
const ascSignIndex = Math.floor(this.getAscendant() / 30);
|
|
286
290
|
return Array.from({ length: 12 }, (_, i) => {
|
|
287
|
-
const angle = i * 30 + 15
|
|
291
|
+
const angle = this.toAngle(i * 30 + 15);
|
|
288
292
|
const pos = polarToCartesian(CENTER, CENTER, HOUSE_R - 12, angle);
|
|
289
|
-
|
|
293
|
+
const houseNum = (i - ascSignIndex + 12) % 12 + 1;
|
|
294
|
+
return svg`<text class="house-num" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central">${houseNum}</text>`;
|
|
290
295
|
});
|
|
291
296
|
}
|
|
292
297
|
renderPlanets(planets) {
|
|
293
298
|
return planets.map((p) => {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
const angle = lon - 90;
|
|
299
|
+
if (!Number.isFinite(p.longitude)) return nothing;
|
|
300
|
+
const angle = this.toAngle(p.longitude);
|
|
297
301
|
const pos = polarToCartesian(CENTER, CENTER, PLANET_R, angle);
|
|
298
|
-
const
|
|
299
|
-
const
|
|
300
|
-
const
|
|
301
|
-
return svg`<text class="planet-glyph" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central"><title>${name}${retro}</title>${
|
|
302
|
+
const glyph = PLANET_GLYPH[capitalize(p.name)] ?? p.name.slice(0, 2);
|
|
303
|
+
const retro = p.isRetrograde ? " R" : "";
|
|
304
|
+
const display = retro ? `${glyph}\u1D3F` : glyph;
|
|
305
|
+
return svg`<text class="planet-glyph" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central"><title>${p.name}${retro}</title>${display}</text>`;
|
|
302
306
|
});
|
|
303
307
|
}
|
|
304
308
|
renderAspects(planets, aspects) {
|
|
305
309
|
const planetMap = /* @__PURE__ */ new Map();
|
|
306
310
|
for (const p of planets) {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if (name) planetMap.set(name, lon);
|
|
311
|
+
if (typeof p.longitude !== "number") continue;
|
|
312
|
+
const name = capitalize(p.name);
|
|
313
|
+
if (name) planetMap.set(name, p.longitude);
|
|
311
314
|
}
|
|
312
315
|
return aspects.map((a) => {
|
|
313
|
-
const l1 = planetMap.get(capitalize(a.planet1
|
|
314
|
-
const l2 = planetMap.get(capitalize(a.planet2
|
|
316
|
+
const l1 = planetMap.get(capitalize(a.planet1));
|
|
317
|
+
const l2 = planetMap.get(capitalize(a.planet2));
|
|
315
318
|
if (l1 === void 0 || l2 === void 0) return nothing;
|
|
316
|
-
const p1 = polarToCartesian(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
+
const p1 = polarToCartesian(
|
|
320
|
+
CENTER,
|
|
321
|
+
CENTER,
|
|
322
|
+
PLANET_R - 18,
|
|
323
|
+
this.toAngle(l1)
|
|
324
|
+
);
|
|
325
|
+
const p2 = polarToCartesian(
|
|
326
|
+
CENTER,
|
|
327
|
+
CENTER,
|
|
328
|
+
PLANET_R - 18,
|
|
329
|
+
this.toAngle(l2)
|
|
330
|
+
);
|
|
331
|
+
const aspectName = normalizeAspect(a);
|
|
332
|
+
const aspectClass = ASPECT_CLASS[aspectName] ?? "aspect-other";
|
|
333
|
+
const orbLabel = formatNumber(a.orb, 1);
|
|
334
|
+
return svg`<line class=${`aspect ${aspectClass}`} x1=${p1.x} y1=${p1.y} x2=${p2.x} y2=${p2.y}><title>${a.planet1} ${aspectName || ""} ${a.planet2}${orbLabel ? ` (orb ${orbLabel}\xB0)` : ""}</title></line>`;
|
|
319
335
|
});
|
|
320
336
|
}
|
|
321
337
|
};
|
|
@@ -373,9 +389,36 @@ RoxyNatalChart.styles = [
|
|
|
373
389
|
}
|
|
374
390
|
|
|
375
391
|
.aspect {
|
|
376
|
-
stroke:
|
|
377
|
-
stroke-width: 0.6;
|
|
392
|
+
stroke-width: 0.8;
|
|
378
393
|
fill: none;
|
|
394
|
+
opacity: 0.55;
|
|
395
|
+
}
|
|
396
|
+
.aspect-trine,
|
|
397
|
+
.aspect-sextile {
|
|
398
|
+
stroke: var(--roxy-success, #16a34a);
|
|
399
|
+
}
|
|
400
|
+
.aspect-square,
|
|
401
|
+
.aspect-opposition {
|
|
402
|
+
stroke: var(--roxy-danger, #dc2626);
|
|
403
|
+
}
|
|
404
|
+
.aspect-conjunction {
|
|
405
|
+
stroke: var(--roxy-accent-fg, #b45309);
|
|
406
|
+
}
|
|
407
|
+
.aspect-other {
|
|
408
|
+
stroke: var(--roxy-muted, #71717a);
|
|
409
|
+
opacity: 0.4;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.angle-marker {
|
|
413
|
+
fill: var(--roxy-accent-fg, #b45309);
|
|
414
|
+
font-size: 10px;
|
|
415
|
+
font-weight: 700;
|
|
416
|
+
font-family: var(--roxy-font-sans);
|
|
417
|
+
letter-spacing: 0.04em;
|
|
418
|
+
}
|
|
419
|
+
.angle-tick {
|
|
420
|
+
stroke: var(--roxy-accent-fg, #b45309);
|
|
421
|
+
stroke-width: 1.5;
|
|
379
422
|
}
|
|
380
423
|
|
|
381
424
|
.legend {
|
|
@@ -385,6 +428,14 @@ RoxyNatalChart.styles = [
|
|
|
385
428
|
flex-wrap: wrap;
|
|
386
429
|
gap: var(--roxy-space-md, 1rem);
|
|
387
430
|
}
|
|
431
|
+
.legend-swatch {
|
|
432
|
+
display: inline-block;
|
|
433
|
+
width: 8px;
|
|
434
|
+
height: 8px;
|
|
435
|
+
border-radius: 50%;
|
|
436
|
+
margin-right: 4px;
|
|
437
|
+
vertical-align: middle;
|
|
438
|
+
}
|
|
388
439
|
`
|
|
389
440
|
];
|
|
390
441
|
__decorateClass([
|
|
@@ -400,8 +451,17 @@ function capitalize(s) {
|
|
|
400
451
|
if (!s) return "";
|
|
401
452
|
return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
|
|
402
453
|
}
|
|
454
|
+
var ASPECT_CLASS = {
|
|
455
|
+
conjunction: "aspect-conjunction",
|
|
456
|
+
sextile: "aspect-sextile",
|
|
457
|
+
square: "aspect-square",
|
|
458
|
+
trine: "aspect-trine",
|
|
459
|
+
opposition: "aspect-opposition"
|
|
460
|
+
};
|
|
461
|
+
function normalizeAspect(a) {
|
|
462
|
+
return (a.type ?? "").toLowerCase().replace(/_/g, "-");
|
|
463
|
+
}
|
|
403
464
|
export {
|
|
404
|
-
RoxyNatalChart
|
|
405
|
-
longitudeToSignPosition
|
|
465
|
+
RoxyNatalChart
|
|
406
466
|
};
|
|
407
467
|
//# sourceMappingURL=natal-chart.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../src/components/natal-chart.ts", "../../src/tokens/index.ts", "../../src/utils/base-styles.ts", "../../src/utils/degree.ts"],
|
|
4
|
-
"sourcesContent": ["import { css, html, LitElement, nothing, svg } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { longitudeToSignPosition, polarToCartesian } from '../utils/degree.js';\n\ninterface PlanetEntry {\n\tname?: string;\n\tplanet?: string;\n\tlongitude?: number;\n\tdegree?: number;\n\tsign?: string;\n\thouse?: number;\n\tretrograde?: boolean;\n\tisRetrograde?: boolean;\n}\n\ninterface AspectEntry {\n\tplanet1?: string;\n\tplanet2?: string;\n\taspect?: string;\n\torb?: number;\n}\n\ninterface HouseEntry {\n\thouse?: number;\n\tnumber?: number;\n\tcusp?: number;\n\tsign?: string;\n}\n\ninterface NatalChartData {\n\tplanets?: PlanetEntry[] | Record<string, PlanetEntry>;\n\thouses?: HouseEntry[];\n\taspects?: AspectEntry[];\n\tascendant?: number | { longitude?: number; sign?: string };\n\tmidheaven?: number | { longitude?: number; sign?: string };\n\tbirthDetails?: {\n\t\tdate?: string;\n\t\ttime?: string;\n\t\tlocation?: string;\n\t};\n}\n\nconst SIZE = 320;\nconst CENTER = SIZE / 2;\nconst OUTER_R = 150;\nconst SIGN_R = 134;\nconst HOUSE_R = 110;\nconst PLANET_R = 88;\n\n/**\n * Western natal chart wheel. Renders the 12 zodiac signs, 12 houses, planet\n * markers, and aspect lines from a /astrology/natal-chart response.\n */\n@customElement('roxy-natal-chart')\nexport class RoxyNatalChart extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.wrap {\n\t\t\t\twidth: 100%;\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.title {\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\tmargin: 0;\n\t\t\t\tcolor: var(--roxy-primary, #0f172a);\n\t\t\t}\n\n\t\t\t.meta {\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\n\t\t\tsvg {\n\t\t\t\tdisplay: block;\n\t\t\t\twidth: 100%;\n\t\t\t\tmax-width: 360px;\n\t\t\t\theight: auto;\n\t\t\t\tmargin: 0 auto;\n\t\t\t}\n\n\t\t\t.wheel-line {\n\t\t\t\tfill: none;\n\t\t\t\tstroke: var(--roxy-border, #e4e4e7);\n\t\t\t}\n\n\t\t\t.sign-glyph {\n\t\t\t\tfill: var(--roxy-secondary, #475569);\n\t\t\t\tfont-size: 14px;\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t}\n\n\t\t\t.planet-glyph {\n\t\t\t\tfill: var(--roxy-accent, #f59e0b);\n\t\t\t\tfont-size: 14px;\n\t\t\t\tfont-weight: 600;\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t}\n\n\t\t\t.house-num {\n\t\t\t\tfill: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: 9px;\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t}\n\n\t\t\t.aspect {\n\t\t\t\tstroke: color-mix(in srgb, var(--roxy-accent, #f59e0b) 32%, transparent);\n\t\t\t\tstroke-width: 0.6;\n\t\t\t\tfill: none;\n\t\t\t}\n\n\t\t\t.legend {\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\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: NatalChartData | null = null;\n\n\t@property({ type: String, attribute: 'house-system', reflect: true })\n\thouseSystem: 'placidus' | 'whole-sign' | 'equal' | 'koch' = 'placidus';\n\n\tprivate getPlanets(): PlanetEntry[] {\n\t\tconst p = this.data?.planets;\n\t\tif (!p) return [];\n\t\tif (Array.isArray(p)) return p;\n\t\treturn Object.entries(p).map(([name, entry]) => ({ ...entry, name }));\n\t}\n\n\trender() {\n\t\tif (!this.data)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No chart data</div>`;\n\t\tconst planets = this.getPlanets();\n\t\tconst aspects = this.data.aspects ?? [];\n\n\t\treturn html`<div class=\"wrap\">\n\t\t\t<header>\n\t\t\t\t<h2 class=\"title\">Natal chart</h2>\n\t\t\t\t${\n\t\t\t\t\tthis.data.birthDetails\n\t\t\t\t\t\t? html`<div class=\"meta\">\n\t\t\t\t\t\t\t${[\n\t\t\t\t\t\t\t\tthis.data.birthDetails.date,\n\t\t\t\t\t\t\t\tthis.data.birthDetails.time,\n\t\t\t\t\t\t\t\tthis.data.birthDetails.location,\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 ')}\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\t\t\t<svg\n\t\t\t\tviewBox=\"0 0 ${SIZE} ${SIZE}\"\n\t\t\t\trole=\"img\"\n\t\t\t\taria-label=\"Natal chart wheel with twelve houses, planets, and aspects\"\n\t\t\t>\n\t\t\t\t<title>Natal chart wheel</title>\n\t\t\t\t<desc>\n\t\t\t\t\tTwelve zodiac sign segments around a circular wheel. Planet glyphs are\n\t\t\t\t\tplaced at their ecliptic longitudes. Aspect lines connect related planets.\n\t\t\t\t</desc>\n\t\t\t\t<circle\n\t\t\t\t\tclass=\"wheel-line\"\n\t\t\t\t\tcx=${CENTER}\n\t\t\t\t\tcy=${CENTER}\n\t\t\t\t\tr=${OUTER_R}\n\t\t\t\t\tstroke-width=\"1.5\"\n\t\t\t\t/>\n\t\t\t\t<circle\n\t\t\t\t\tclass=\"wheel-line\"\n\t\t\t\t\tcx=${CENTER}\n\t\t\t\t\tcy=${CENTER}\n\t\t\t\t\tr=${HOUSE_R}\n\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t/>\n\t\t\t\t<circle\n\t\t\t\t\tclass=\"wheel-line\"\n\t\t\t\t\tcx=${CENTER}\n\t\t\t\t\tcy=${CENTER}\n\t\t\t\t\tr=${PLANET_R - 16}\n\t\t\t\t\tstroke-width=\"0.5\"\n\t\t\t\t/>\n\t\t\t\t${this.renderSpokes()} ${this.renderSigns()} ${this.renderHouseNumbers()}\n\t\t\t\t${this.renderAspects(planets, aspects)} ${this.renderPlanets(planets)}\n\t\t\t</svg>\n\t\t\t<div class=\"legend\">\n\t\t\t\t<span>${planets.length} planets</span>\n\t\t\t\t<span>${aspects.length} aspects</span>\n\t\t\t\t<span>House system: ${this.houseSystem}</span>\n\t\t\t</div>\n\t\t</div>`;\n\t}\n\n\tprivate renderSpokes() {\n\t\treturn Array.from({ length: 12 }, (_, i) => {\n\t\t\tconst angle = i * 30 - 90;\n\t\t\tconst start = polarToCartesian(CENTER, CENTER, HOUSE_R, angle);\n\t\t\tconst end = polarToCartesian(CENTER, CENTER, OUTER_R, angle);\n\t\t\treturn svg`<line class=\"wheel-line\" x1=${start.x} y1=${start.y} x2=${end.x} y2=${end.y} stroke-width=\"0.8\" />`;\n\t\t});\n\t}\n\n\tprivate renderSigns() {\n\t\tconst order = [\n\t\t\t'Aries',\n\t\t\t'Taurus',\n\t\t\t'Gemini',\n\t\t\t'Cancer',\n\t\t\t'Leo',\n\t\t\t'Virgo',\n\t\t\t'Libra',\n\t\t\t'Scorpio',\n\t\t\t'Sagittarius',\n\t\t\t'Capricorn',\n\t\t\t'Aquarius',\n\t\t\t'Pisces',\n\t\t];\n\t\treturn order.map((sign, i) => {\n\t\t\tconst angle = i * 30 + 15 - 90;\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, SIGN_R, angle);\n\t\t\treturn svg`<text class=\"sign-glyph\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${SIGN_GLYPH[sign]}</text>`;\n\t\t});\n\t}\n\n\tprivate renderHouseNumbers() {\n\t\treturn Array.from({ length: 12 }, (_, i) => {\n\t\t\tconst angle = i * 30 + 15 - 90;\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, HOUSE_R - 12, angle);\n\t\t\treturn svg`<text class=\"house-num\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${i + 1}</text>`;\n\t\t});\n\t}\n\n\tprivate renderPlanets(planets: PlanetEntry[]) {\n\t\treturn planets.map((p) => {\n\t\t\tconst lon =\n\t\t\t\ttypeof p.longitude === 'number'\n\t\t\t\t\t? p.longitude\n\t\t\t\t\t: typeof p.degree === 'number'\n\t\t\t\t\t\t? p.degree\n\t\t\t\t\t\t: NaN;\n\t\t\tif (!Number.isFinite(lon)) return nothing;\n\t\t\tconst angle = lon - 90;\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, PLANET_R, angle);\n\t\t\tconst name = p.name ?? p.planet ?? '';\n\t\t\tconst glyph = PLANET_GLYPH[capitalize(name)] ?? name.slice(0, 2);\n\t\t\tconst retro = p.retrograde || p.isRetrograde ? ' R' : '';\n\t\t\treturn svg`<text class=\"planet-glyph\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\"><title>${name}${retro}</title>${glyph}</text>`;\n\t\t});\n\t}\n\n\tprivate renderAspects(planets: PlanetEntry[], aspects: AspectEntry[]) {\n\t\tconst planetMap = new Map<string, number>();\n\t\tfor (const p of planets) {\n\t\t\tconst lon =\n\t\t\t\ttypeof p.longitude === 'number'\n\t\t\t\t\t? p.longitude\n\t\t\t\t\t: typeof p.degree === 'number'\n\t\t\t\t\t\t? p.degree\n\t\t\t\t\t\t: null;\n\t\t\tif (lon === null) continue;\n\t\t\tconst name = capitalize(p.name ?? p.planet ?? '');\n\t\t\tif (name) planetMap.set(name, lon);\n\t\t}\n\t\treturn aspects.map((a) => {\n\t\t\tconst l1 = planetMap.get(capitalize(a.planet1 ?? ''));\n\t\t\tconst l2 = planetMap.get(capitalize(a.planet2 ?? ''));\n\t\t\tif (l1 === undefined || l2 === undefined) return nothing;\n\t\t\tconst p1 = polarToCartesian(CENTER, CENTER, PLANET_R - 18, l1 - 90);\n\t\t\tconst p2 = polarToCartesian(CENTER, CENTER, PLANET_R - 18, l2 - 90);\n\t\t\treturn svg`<line class=\"aspect\" x1=${p1.x} y1=${p1.y} x2=${p2.x} y2=${p2.y} />`;\n\t\t});\n\t}\n}\n\nfunction capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-natal-chart': RoxyNatalChart;\n\t}\n}\n\n// Export for external use\nexport { longitudeToSignPosition };\n", "/**\n * Symbol constants used across components. Single source of truth so chart\n * wheels, card headers, hexagram displays, and panchang tables stay visually\n * consistent.\n */\n\nexport const PLANET_GLYPH: Record<string, string> = {\n\tSun: '\u2609',\n\tMoon: '\u263D',\n\tMercury: '\u263F',\n\tVenus: '\u2640',\n\tEarth: '\u2641',\n\tMars: '\u2642',\n\tJupiter: '\u2643',\n\tSaturn: '\u2644',\n\tUranus: '\u2645',\n\tNeptune: '\u2646',\n\tPluto: '\u2647',\n\tRahu: '\u260A',\n\tKetu: '\u260B',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n\tNorthNode: '\u260A',\n\tSouthNode: '\u260B',\n};\n\nexport const PLANET_ABBR: Record<string, string> = {\n\tSun: 'Su',\n\tMoon: 'Mo',\n\tMercury: 'Me',\n\tVenus: 'Ve',\n\tMars: 'Ma',\n\tJupiter: 'Ju',\n\tSaturn: 'Sa',\n\tUranus: 'Ur',\n\tNeptune: 'Ne',\n\tPluto: 'Pl',\n\tRahu: 'Ra',\n\tKetu: 'Ke',\n\tAscendant: 'Asc',\n\tLagna: 'La',\n};\n\nexport const SIGN_GLYPH: Record<string, string> = {\n\tAries: '\u2648',\n\tTaurus: '\u2649',\n\tGemini: '\u264A',\n\tCancer: '\u264B',\n\tLeo: '\u264C',\n\tVirgo: '\u264D',\n\tLibra: '\u264E',\n\tScorpio: '\u264F',\n\tSagittarius: '\u2650',\n\tCapricorn: '\u2651',\n\tAquarius: '\u2652',\n\tPisces: '\u2653',\n};\n\nexport const SIGN_ABBR: Record<string, string> = {\n\tAries: 'Ar',\n\tTaurus: 'Ta',\n\tGemini: 'Ge',\n\tCancer: 'Cn',\n\tLeo: 'Le',\n\tVirgo: 'Vi',\n\tLibra: 'Li',\n\tScorpio: 'Sc',\n\tSagittarius: 'Sg',\n\tCapricorn: 'Cp',\n\tAquarius: 'Aq',\n\tPisces: 'Pi',\n};\n\nexport const SIGNS_ORDER = [\n\t'Aries',\n\t'Taurus',\n\t'Gemini',\n\t'Cancer',\n\t'Leo',\n\t'Virgo',\n\t'Libra',\n\t'Scorpio',\n\t'Sagittarius',\n\t'Capricorn',\n\t'Aquarius',\n\t'Pisces',\n] as const;\n\n/** Aspect symbols. Used by synastry and natal chart aspect tables. */\nexport const ASPECT_SYMBOL: Record<string, string> = {\n\tconjunction: '\u260C',\n\topposition: '\u260D',\n\ttrine: '\u25B3',\n\tsquare: '\u25A1',\n\tsextile: '\u2731',\n\tquincunx: '\u22BB',\n\tsemisextile: '\u22BC',\n};\n\n/** Trigrams used by I Ching hexagrams. Eight trigrams compose 64 hexagrams. */\nexport const TRIGRAM_GLYPH: Record<string, string> = {\n\theaven: '\u2630',\n\tlake: '\u2631',\n\tfire: '\u2632',\n\tthunder: '\u2633',\n\twind: '\u2634',\n\twater: '\u2635',\n\tmountain: '\u2636',\n\tearth: '\u2637',\n\tHeaven: '\u2630',\n\tLake: '\u2631',\n\tFire: '\u2632',\n\tThunder: '\u2633',\n\tWind: '\u2634',\n\tWater: '\u2635',\n\tMountain: '\u2636',\n\tEarth: '\u2637',\n};\n\n/** Moon phase emoji set. Used by moon phase card. */\nexport const MOON_PHASE_EMOJI: Record<string, string> = {\n\t'new moon': '\uD83C\uDF11',\n\t'waxing crescent': '\uD83C\uDF12',\n\t'first quarter': '\uD83C\uDF13',\n\t'waxing gibbous': '\uD83C\uDF14',\n\t'full moon': '\uD83C\uDF15',\n\t'waning gibbous': '\uD83C\uDF16',\n\t'last quarter': '\uD83C\uDF17',\n\t'waning crescent': '\uD83C\uDF18',\n};\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n", "/**\n * Math helpers for converting raw ecliptic longitude decimals into the\n * sign / degree / minute / second triplet used across chart components.\n */\n\nimport { SIGNS_ORDER } from '../tokens/index.js';\n\nexport interface SignPosition {\n\tsign: string;\n\tsignIndex: number;\n\tdegree: number;\n\tminute: number;\n\tsecond: number;\n}\n\n/**\n * Wrap longitude into [0, 360) so negative or out-of-range values still\n * resolve to a real sign. Robust to wonky upstream data.\n */\nexport function normalizeLongitude(lon: number): number {\n\tconst wrapped = lon % 360;\n\treturn wrapped < 0 ? wrapped + 360 : wrapped;\n}\n\n/**\n * Convert decimal ecliptic longitude (0-360) into sign/degree/minute/second.\n * Used by every chart wheel and aspect table.\n */\nexport function longitudeToSignPosition(longitude: number): SignPosition {\n\tconst lon = normalizeLongitude(longitude);\n\tconst signIndex = Math.floor(lon / 30) % 12;\n\tconst within = lon % 30;\n\tconst degree = Math.floor(within);\n\tconst minuteFloat = (within - degree) * 60;\n\tconst minute = Math.floor(minuteFloat);\n\tconst second = Math.round((minuteFloat - minute) * 60);\n\treturn {\n\t\tsign: SIGNS_ORDER[signIndex] ?? 'Aries',\n\t\tsignIndex,\n\t\tdegree,\n\t\tminute,\n\t\tsecond,\n\t};\n}\n\n/** Compact display string like \"12\u00B0 Leo 34'\". Used in chart labels. */\nexport function formatSignPosition(longitude: number): string {\n\tconst { sign, degree, minute } = longitudeToSignPosition(longitude);\n\treturn `${degree}\u00B0 ${sign} ${String(minute).padStart(2, '0')}'`;\n}\n\n/** Polar to cartesian for SVG wheel positioning. Angle in degrees, 0 at 3 o'clock. */\nexport function polarToCartesian(\n\tcx: number,\n\tcy: number,\n\tradius: number,\n\tangleDeg: number,\n): { x: number; y: number } {\n\tconst angleRad = (angleDeg * Math.PI) / 180;\n\treturn {\n\t\tx: cx + radius * Math.cos(angleRad),\n\t\ty: cy + radius * Math.sin(angleRad),\n\t};\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;AAAA,SAAS,OAAAA,MAAK,MAAM,YAAY,SAAS,WAAW;AACpD,SAAS,eAAe,gBAAgB;;;ACKjC,IAAM,eAAuC;AAAA,EACnD,KAAK;AAAA,EACL,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,WAAW;AAAA,EACX,OAAO;AAAA,EACP,WAAW;AAAA,EACX,WAAW;
|
|
3
|
+
"sources": ["../../src/components/natal-chart.ts", "../../src/tokens/index.ts", "../../src/utils/base-styles.ts", "../../src/utils/degree.ts", "../../src/utils/format.ts"],
|
|
4
|
+
"sourcesContent": ["import { css, html, LitElement, nothing, svg } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';\nimport type { NatalChartResponse } from '../types/index.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { longitudeToSignPosition, polarToCartesian } from '../utils/degree.js';\nimport { formatNumber } from '../utils/format.js';\n\ntype PlanetEntry = NatalChartResponse['planets'][number];\ntype AspectEntry = NatalChartResponse['aspects'][number];\n\nconst SIZE = 384;\nconst CENTER = SIZE / 2;\nconst OUTER_R = 150;\nconst SIGN_R = 134;\nconst HOUSE_R = 110;\nconst PLANET_R = 88;\nconst ANGLE_TICK_R = 162;\nconst ANGLE_LABEL_R = 176;\n\n/**\n * Western natal chart wheel. Renders the 12 zodiac signs, 12 houses, planet\n * markers, and aspect lines from a /astrology/natal-chart response.\n */\n@customElement('roxy-natal-chart')\nexport class RoxyNatalChart extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t.wrap {\n\t\t\t\twidth: 100%;\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.title {\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\tmargin: 0;\n\t\t\t\tcolor: var(--roxy-primary, #0f172a);\n\t\t\t}\n\n\t\t\t.meta {\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\n\t\t\tsvg {\n\t\t\t\tdisplay: block;\n\t\t\t\twidth: 100%;\n\t\t\t\tmax-width: 360px;\n\t\t\t\theight: auto;\n\t\t\t\tmargin: 0 auto;\n\t\t\t}\n\n\t\t\t.wheel-line {\n\t\t\t\tfill: none;\n\t\t\t\tstroke: var(--roxy-border, #e4e4e7);\n\t\t\t}\n\n\t\t\t.sign-glyph {\n\t\t\t\tfill: var(--roxy-secondary, #475569);\n\t\t\t\tfont-size: 14px;\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t}\n\n\t\t\t.planet-glyph {\n\t\t\t\tfill: var(--roxy-accent, #f59e0b);\n\t\t\t\tfont-size: 14px;\n\t\t\t\tfont-weight: 600;\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t}\n\n\t\t\t.house-num {\n\t\t\t\tfill: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: 9px;\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t}\n\n\t\t\t.aspect {\n\t\t\t\tstroke-width: 0.8;\n\t\t\t\tfill: none;\n\t\t\t\topacity: 0.55;\n\t\t\t}\n\t\t\t.aspect-trine,\n\t\t\t.aspect-sextile {\n\t\t\t\tstroke: var(--roxy-success, #16a34a);\n\t\t\t}\n\t\t\t.aspect-square,\n\t\t\t.aspect-opposition {\n\t\t\t\tstroke: var(--roxy-danger, #dc2626);\n\t\t\t}\n\t\t\t.aspect-conjunction {\n\t\t\t\tstroke: var(--roxy-accent-fg, #b45309);\n\t\t\t}\n\t\t\t.aspect-other {\n\t\t\t\tstroke: var(--roxy-muted, #71717a);\n\t\t\t\topacity: 0.4;\n\t\t\t}\n\n\t\t\t.angle-marker {\n\t\t\t\tfill: var(--roxy-accent-fg, #b45309);\n\t\t\t\tfont-size: 10px;\n\t\t\t\tfont-weight: 700;\n\t\t\t\tfont-family: var(--roxy-font-sans);\n\t\t\t\tletter-spacing: 0.04em;\n\t\t\t}\n\t\t\t.angle-tick {\n\t\t\t\tstroke: var(--roxy-accent-fg, #b45309);\n\t\t\t\tstroke-width: 1.5;\n\t\t\t}\n\n\t\t\t.legend {\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\tdisplay: flex;\n\t\t\t\tflex-wrap: wrap;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\t\t\t.legend-swatch {\n\t\t\t\tdisplay: inline-block;\n\t\t\t\twidth: 8px;\n\t\t\t\theight: 8px;\n\t\t\t\tborder-radius: 50%;\n\t\t\t\tmargin-right: 4px;\n\t\t\t\tvertical-align: middle;\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ attribute: false })\n\tdata: NatalChartResponse | null = null;\n\n\t@property({ type: String, attribute: 'house-system', reflect: true })\n\thouseSystem: 'placidus' | 'whole-sign' | 'equal' | 'koch' = 'placidus';\n\n\tprivate getPlanets(): PlanetEntry[] {\n\t\treturn this.data?.planets ?? [];\n\t}\n\n\tprivate getAscendant(): number {\n\t\treturn this.data?.ascendant?.longitude ?? 0;\n\t}\n\n\tprivate getMidheaven(): number | null {\n\t\tconst m = this.data?.midheaven?.longitude;\n\t\treturn typeof m === 'number' ? m : null;\n\t}\n\n\tprivate toAngle(lon: number): number {\n\t\treturn 180 + this.getAscendant() - lon;\n\t}\n\n\trender() {\n\t\tif (!this.data)\n\t\t\treturn html`<div class=\"roxy-empty\" role=\"status\">No chart data</div>`;\n\t\tconst planets = this.getPlanets();\n\t\tconst aspects = this.data.aspects ?? [];\n\n\t\treturn html`<div class=\"wrap\">\n\t\t\t<header>\n\t\t\t\t<h2 class=\"title\">Natal chart</h2>\n\t\t\t\t${\n\t\t\t\t\tthis.data.birthDetails\n\t\t\t\t\t\t? html`<div class=\"meta\">\n\t\t\t\t\t\t\t${[this.data.birthDetails.date, this.data.birthDetails.time]\n\t\t\t\t\t\t\t\t.filter(Boolean)\n\t\t\t\t\t\t\t\t.join(' \u00B7 ')}\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\t\t\t<svg\n\t\t\t\tviewBox=\"0 0 ${SIZE} ${SIZE}\"\n\t\t\t\trole=\"img\"\n\t\t\t\taria-label=\"Natal chart wheel with twelve houses, planets, and aspects\"\n\t\t\t>\n\t\t\t\t<title>Natal chart wheel</title>\n\t\t\t\t<desc>\n\t\t\t\t\tTwelve zodiac sign segments around a circular wheel. Planet glyphs are\n\t\t\t\t\tplaced at their ecliptic longitudes. Aspect lines connect related planets.\n\t\t\t\t</desc>\n\t\t\t\t<circle\n\t\t\t\t\tclass=\"wheel-line\"\n\t\t\t\t\tcx=${CENTER}\n\t\t\t\t\tcy=${CENTER}\n\t\t\t\t\tr=${OUTER_R}\n\t\t\t\t\tstroke-width=\"1.5\"\n\t\t\t\t/>\n\t\t\t\t<circle\n\t\t\t\t\tclass=\"wheel-line\"\n\t\t\t\t\tcx=${CENTER}\n\t\t\t\t\tcy=${CENTER}\n\t\t\t\t\tr=${HOUSE_R}\n\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t/>\n\t\t\t\t<circle\n\t\t\t\t\tclass=\"wheel-line\"\n\t\t\t\t\tcx=${CENTER}\n\t\t\t\t\tcy=${CENTER}\n\t\t\t\t\tr=${PLANET_R - 16}\n\t\t\t\t\tstroke-width=\"0.5\"\n\t\t\t\t/>\n\t\t\t\t${this.renderSpokes()} ${this.renderSigns()} ${this.renderHouseNumbers()}\n\t\t\t\t${this.renderAspects(planets, aspects)} ${this.renderPlanets(planets)}\n\t\t\t\t${this.renderAngles()}\n\t\t\t</svg>\n\t\t\t<div class=\"legend\">\n\t\t\t\t<span>${planets.length} planets</span>\n\t\t\t\t<span>${aspects.length} aspects</span>\n\t\t\t\t<span><span class=\"legend-swatch\" style=\"background: var(--roxy-success)\"></span>harmonious</span>\n\t\t\t\t<span><span class=\"legend-swatch\" style=\"background: var(--roxy-danger)\"></span>challenging</span>\n\t\t\t</div>\n\t\t</div>`;\n\t}\n\n\tprivate renderAngles() {\n\t\tconst asc = this.getAscendant();\n\t\tconst mc = this.getMidheaven();\n\t\tconst items = [this.renderAngleMark(asc, 'ASC')];\n\t\tif (mc !== null) items.push(this.renderAngleMark(mc, 'MC'));\n\t\treturn items;\n\t}\n\n\tprivate renderAngleMark(longitude: number, label: string) {\n\t\tconst angle = this.toAngle(longitude);\n\t\tconst tickInner = polarToCartesian(CENTER, CENTER, OUTER_R, angle);\n\t\tconst tickOuter = polarToCartesian(CENTER, CENTER, ANGLE_TICK_R, angle);\n\t\tconst labelPos = polarToCartesian(CENTER, CENTER, ANGLE_LABEL_R, angle);\n\t\treturn svg`\n\t\t\t<g>\n\t\t\t\t<line class=\"angle-tick\" x1=${tickInner.x} y1=${tickInner.y} x2=${tickOuter.x} y2=${tickOuter.y} />\n\t\t\t\t<text class=\"angle-marker\" x=${labelPos.x} y=${labelPos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${label}</text>\n\t\t\t</g>\n\t\t`;\n\t}\n\n\tprivate renderSpokes() {\n\t\treturn Array.from({ length: 12 }, (_, i) => {\n\t\t\tconst angle = this.toAngle(i * 30);\n\t\t\tconst start = polarToCartesian(CENTER, CENTER, HOUSE_R, angle);\n\t\t\tconst end = polarToCartesian(CENTER, CENTER, OUTER_R, angle);\n\t\t\treturn svg`<line class=\"wheel-line\" x1=${start.x} y1=${start.y} x2=${end.x} y2=${end.y} stroke-width=\"0.8\" />`;\n\t\t});\n\t}\n\n\tprivate renderSigns() {\n\t\tconst order = [\n\t\t\t'Aries',\n\t\t\t'Taurus',\n\t\t\t'Gemini',\n\t\t\t'Cancer',\n\t\t\t'Leo',\n\t\t\t'Virgo',\n\t\t\t'Libra',\n\t\t\t'Scorpio',\n\t\t\t'Sagittarius',\n\t\t\t'Capricorn',\n\t\t\t'Aquarius',\n\t\t\t'Pisces',\n\t\t];\n\t\treturn order.map((sign, i) => {\n\t\t\tconst angle = this.toAngle(i * 30 + 15);\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, SIGN_R, angle);\n\t\t\treturn svg`<text class=\"sign-glyph\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${SIGN_GLYPH[sign]}</text>`;\n\t\t});\n\t}\n\n\tprivate renderHouseNumbers() {\n\t\tconst ascSignIndex = Math.floor(this.getAscendant() / 30);\n\t\treturn Array.from({ length: 12 }, (_, i) => {\n\t\t\tconst angle = this.toAngle(i * 30 + 15);\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, HOUSE_R - 12, angle);\n\t\t\tconst houseNum = ((i - ascSignIndex + 12) % 12) + 1;\n\t\t\treturn svg`<text class=\"house-num\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\">${houseNum}</text>`;\n\t\t});\n\t}\n\n\tprivate renderPlanets(planets: PlanetEntry[]) {\n\t\treturn planets.map((p) => {\n\t\t\tif (!Number.isFinite(p.longitude)) return nothing;\n\t\t\tconst angle = this.toAngle(p.longitude);\n\t\t\tconst pos = polarToCartesian(CENTER, CENTER, PLANET_R, angle);\n\t\t\tconst glyph = PLANET_GLYPH[capitalize(p.name)] ?? p.name.slice(0, 2);\n\t\t\tconst retro = p.isRetrograde ? ' R' : '';\n\t\t\tconst display = retro ? `${glyph}\u1D3F` : glyph;\n\t\t\treturn svg`<text class=\"planet-glyph\" x=${pos.x} y=${pos.y} text-anchor=\"middle\" dominant-baseline=\"central\"><title>${p.name}${retro}</title>${display}</text>`;\n\t\t});\n\t}\n\n\tprivate renderAspects(planets: PlanetEntry[], aspects: AspectEntry[]) {\n\t\tconst planetMap = new Map<string, number>();\n\t\tfor (const p of planets) {\n\t\t\tif (typeof p.longitude !== 'number') continue;\n\t\t\tconst name = capitalize(p.name);\n\t\t\tif (name) planetMap.set(name, p.longitude);\n\t\t}\n\t\treturn aspects.map((a) => {\n\t\t\tconst l1 = planetMap.get(capitalize(a.planet1));\n\t\t\tconst l2 = planetMap.get(capitalize(a.planet2));\n\t\t\tif (l1 === undefined || l2 === undefined) return nothing;\n\t\t\tconst p1 = polarToCartesian(\n\t\t\t\tCENTER,\n\t\t\t\tCENTER,\n\t\t\t\tPLANET_R - 18,\n\t\t\t\tthis.toAngle(l1),\n\t\t\t);\n\t\t\tconst p2 = polarToCartesian(\n\t\t\t\tCENTER,\n\t\t\t\tCENTER,\n\t\t\t\tPLANET_R - 18,\n\t\t\t\tthis.toAngle(l2),\n\t\t\t);\n\t\t\tconst aspectName = normalizeAspect(a);\n\t\t\tconst aspectClass = ASPECT_CLASS[aspectName] ?? 'aspect-other';\n\t\t\tconst orbLabel = formatNumber(a.orb, 1);\n\t\t\treturn svg`<line class=${`aspect ${aspectClass}`} x1=${p1.x} y1=${p1.y} x2=${p2.x} y2=${p2.y}><title>${a.planet1} ${aspectName || ''} ${a.planet2}${orbLabel ? ` (orb ${orbLabel}\u00B0)` : ''}</title></line>`;\n\t\t});\n\t}\n}\n\nfunction capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nconst 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\nfunction normalizeAspect(a: AspectEntry): string {\n\treturn (a.type ?? '').toLowerCase().replace(/_/g, '-');\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-natal-chart': RoxyNatalChart;\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/** 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 * Math helpers for converting raw ecliptic longitude decimals into the\n * sign / degree / minute / second triplet used across chart components.\n */\n\nimport { SIGNS_ORDER } from '../tokens/index.js';\n\nexport interface SignPosition {\n\tsign: string;\n\tsignIndex: number;\n\tdegree: number;\n\tminute: number;\n\tsecond: number;\n}\n\n/**\n * Wrap longitude into [0, 360) so negative or out-of-range values still\n * resolve to a real sign. Robust to wonky upstream data.\n */\nexport function normalizeLongitude(lon: number): number {\n\tconst wrapped = lon % 360;\n\treturn wrapped < 0 ? wrapped + 360 : wrapped;\n}\n\n/**\n * Convert decimal ecliptic longitude (0-360) into sign/degree/minute/second.\n * Used by every chart wheel and aspect table.\n */\nexport function longitudeToSignPosition(longitude: number): SignPosition {\n\tconst lon = normalizeLongitude(longitude);\n\tconst signIndex = Math.floor(lon / 30) % 12;\n\tconst within = lon % 30;\n\tconst degree = Math.floor(within);\n\tconst minuteFloat = (within - degree) * 60;\n\tconst minute = Math.floor(minuteFloat);\n\tconst second = Math.round((minuteFloat - minute) * 60);\n\treturn {\n\t\tsign: SIGNS_ORDER[signIndex] ?? 'Aries',\n\t\tsignIndex,\n\t\tdegree,\n\t\tminute,\n\t\tsecond,\n\t};\n}\n\n/** Compact display string like \"12\u00B0 Leo 34'\". Used in chart labels. */\nexport function formatSignPosition(longitude: number): string {\n\tconst { sign, degree, minute } = longitudeToSignPosition(longitude);\n\treturn `${degree}\u00B0 ${sign} ${String(minute).padStart(2, '0')}'`;\n}\n\n/** Polar to cartesian for SVG wheel positioning. Angle in degrees, 0 at 3 o'clock. */\nexport function polarToCartesian(\n\tcx: number,\n\tcy: number,\n\tradius: number,\n\tangleDeg: number,\n): { x: number; y: number } {\n\tconst angleRad = (angleDeg * Math.PI) / 180;\n\treturn {\n\t\tx: cx + radius * Math.cos(angleRad),\n\t\ty: cy + radius * Math.sin(angleRad),\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\nexport function formatLongitude(value: unknown): string {\n\tif (typeof value !== 'number' || !Number.isFinite(value)) return '';\n\treturn `${formatNumber(value, 2)}\u00B0`;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["css", "css"]
|
|
7
7
|
}
|
|
@@ -1,41 +1,6 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
calculation?: string;
|
|
5
|
-
type?: 'single' | 'master' | string;
|
|
6
|
-
hasKarmicDebt?: boolean;
|
|
7
|
-
karmicDebtNumber?: number;
|
|
8
|
-
karmicDebtMeaning?: string;
|
|
9
|
-
meaning?: string;
|
|
10
|
-
}
|
|
11
|
-
interface CoreNumber {
|
|
12
|
-
number?: number;
|
|
13
|
-
type?: string;
|
|
14
|
-
meaning?: string;
|
|
15
|
-
calculation?: string;
|
|
16
|
-
}
|
|
17
|
-
interface FullChart {
|
|
18
|
-
profile?: {
|
|
19
|
-
fullName?: string;
|
|
20
|
-
birthDate?: string;
|
|
21
|
-
};
|
|
22
|
-
coreNumbers?: Record<string, CoreNumber | number>;
|
|
23
|
-
additionalInsights?: Record<string, unknown>;
|
|
24
|
-
birthDayProfile?: Record<string, unknown>;
|
|
25
|
-
maturityStatus?: string;
|
|
26
|
-
luckyAssociations?: Record<string, unknown>;
|
|
27
|
-
summary?: string;
|
|
28
|
-
}
|
|
29
|
-
interface PersonalYear {
|
|
30
|
-
year?: number;
|
|
31
|
-
personalYear?: number;
|
|
32
|
-
title?: string;
|
|
33
|
-
theme?: string;
|
|
34
|
-
keywords?: string[];
|
|
35
|
-
meaning?: string;
|
|
36
|
-
advice?: string;
|
|
37
|
-
}
|
|
38
|
-
type NumerologyData = NumerologyCommon & FullChart & PersonalYear;
|
|
2
|
+
import type { CalculateExpressionResponse, CalculateLifePathResponse, CalculatePersonalYearResponse, GenerateNumerologyChartResponse } from '../types/index.js';
|
|
3
|
+
type NumerologyData = CalculateLifePathResponse | CalculateExpressionResponse | CalculatePersonalYearResponse | GenerateNumerologyChartResponse;
|
|
39
4
|
/**
|
|
40
5
|
* Numerology card. Renders /numerology/{life-path,expression,personal-year,chart}.
|
|
41
6
|
* Use the `type` attribute to switch the layout.
|
|
@@ -45,6 +10,9 @@ export declare class RoxyNumerologyCard extends LitElement {
|
|
|
45
10
|
data: NumerologyData | null;
|
|
46
11
|
type: 'life-path' | 'expression' | 'personal-year' | 'chart';
|
|
47
12
|
render(): import("lit").TemplateResult<1>;
|
|
13
|
+
private renderNumberCard;
|
|
14
|
+
private renderPersonalYear;
|
|
15
|
+
private renderChart;
|
|
48
16
|
}
|
|
49
17
|
declare global {
|
|
50
18
|
interface HTMLElementTagNameMap {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"numerology-card.d.ts","sourceRoot":"","sources":["../../src/components/numerology-card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"numerology-card.d.ts","sourceRoot":"","sources":["../../src/components/numerology-card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAErD,OAAO,KAAK,EACX,2BAA2B,EAC3B,yBAAyB,EACzB,6BAA6B,EAC7B,+BAA+B,EAC/B,MAAM,mBAAmB,CAAC;AAG3B,KAAK,cAAc,GAChB,yBAAyB,GACzB,2BAA2B,GAC3B,6BAA6B,GAC7B,+BAA+B,CAAC;AAEnC;;;GAGG;AACH,qBACa,kBAAmB,SAAQ,UAAU;IACjD,MAAM,CAAC,MAAM,4BAmGX;IAGF,IAAI,EAAE,cAAc,GAAG,IAAI,CAAQ;IAGnC,IAAI,EAAE,WAAW,GAAG,YAAY,GAAG,eAAe,GAAG,OAAO,CAAe;IAE3E,MAAM;IAeN,OAAO,CAAC,gBAAgB;IAiCxB,OAAO,CAAC,kBAAkB;IAiB1B,OAAO,CAAC,WAAW;CAuBnB;AA6BD,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,sBAAsB,EAAE,kBAAkB,CAAC;KAC3C;CACD"}
|
|
@@ -111,42 +111,63 @@ var RoxyNumerologyCard = class extends LitElement {
|
|
|
111
111
|
if (!d)
|
|
112
112
|
return html`<div class="roxy-empty" role="status">No numerology data</div>`;
|
|
113
113
|
const headerLabel = LABELS[this.type] ?? this.type;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
114
|
+
if ("coreNumbers" in d) return this.renderChart(d, headerLabel);
|
|
115
|
+
if ("personalYear" in d) return this.renderPersonalYear(d, headerLabel);
|
|
116
|
+
return this.renderNumberCard(
|
|
117
|
+
d,
|
|
118
|
+
headerLabel
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
renderNumberCard(d, headerLabel) {
|
|
122
|
+
const keywords = d.meaning?.keywords ?? [];
|
|
123
|
+
return html`<article class="card" aria-label=${headerLabel}>
|
|
122
124
|
<div class="hero">
|
|
123
|
-
${typeof number === "number" ? html`<div class="numeral">${number}</div>` : nothing}
|
|
125
|
+
${typeof d.number === "number" ? html`<div class="numeral">${d.number}</div>` : nothing}
|
|
124
126
|
<div>
|
|
125
127
|
<p class="label">${headerLabel}</p>
|
|
126
|
-
${d.title ? html`<h2 class="title">${d.title}</h2>` :
|
|
127
|
-
${d.type === "master" ? "Master number" : "Single digit"}
|
|
128
|
-
</h2>` : nothing}
|
|
128
|
+
${d.meaning?.title ? html`<h2 class="title">${d.meaning.title}</h2>` : nothing}
|
|
129
129
|
</div>
|
|
130
130
|
</div>
|
|
131
|
-
${d.
|
|
132
|
-
${d.meaning ? html`<p class="meaning">${d.meaning}</p>` : nothing}
|
|
133
|
-
${d.advice ? html`<p>${d.advice}</p>` : nothing}
|
|
131
|
+
${d.meaning?.description ? html`<p class="meaning">${d.meaning.description}</p>` : nothing}
|
|
134
132
|
${d.calculation ? html`<pre class="calc">${d.calculation}</pre>` : nothing}
|
|
135
|
-
${
|
|
136
|
-
${
|
|
137
|
-
</div>` : nothing}
|
|
138
|
-
${cores.length > 0 ? html`<div class="cores">
|
|
139
|
-
${cores.map(([k, v]) => {
|
|
140
|
-
const value = typeof v === "number" ? v : v.number;
|
|
141
|
-
return html`<div class="item">
|
|
142
|
-
<span>${humanize(k)}</span>
|
|
143
|
-
<strong>${value ?? ""}</strong>
|
|
144
|
-
</div>`;
|
|
145
|
-
})}
|
|
133
|
+
${keywords.length > 0 ? html`<div class="chips">
|
|
134
|
+
${keywords.map((k) => html`<span>${k}</span>`)}
|
|
146
135
|
</div>` : nothing}
|
|
147
136
|
${d.hasKarmicDebt && d.karmicDebtNumber ? html`<div class="karmic">
|
|
148
137
|
Karmic debt ${d.karmicDebtNumber}.
|
|
149
|
-
${d.karmicDebtMeaning
|
|
138
|
+
${karmicDebtText(d.karmicDebtMeaning)}
|
|
139
|
+
</div>` : nothing}
|
|
140
|
+
</article>`;
|
|
141
|
+
}
|
|
142
|
+
renderPersonalYear(d, headerLabel) {
|
|
143
|
+
return html`<article class="card" aria-label=${headerLabel}>
|
|
144
|
+
<div class="hero">
|
|
145
|
+
${typeof d.personalYear === "number" ? html`<div class="numeral">${d.personalYear}</div>` : nothing}
|
|
146
|
+
<div>
|
|
147
|
+
<p class="label">${headerLabel}</p>
|
|
148
|
+
${d.theme ? html`<h2 class="title">${d.theme}</h2>` : nothing}
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
${d.forecast ? html`<p class="meaning">${d.forecast}</p>` : nothing}
|
|
152
|
+
${d.advice ? html`<p>${d.advice}</p>` : nothing}
|
|
153
|
+
</article>`;
|
|
154
|
+
}
|
|
155
|
+
renderChart(d, headerLabel) {
|
|
156
|
+
const cores = Object.entries(d.coreNumbers).filter(
|
|
157
|
+
([, v]) => v !== null && v !== void 0
|
|
158
|
+
);
|
|
159
|
+
return html`<article class="card" aria-label=${headerLabel}>
|
|
160
|
+
<div>
|
|
161
|
+
<p class="label">${headerLabel}</p>
|
|
162
|
+
${d.profile?.name ? html`<h2 class="title">${d.profile.name}</h2>` : nothing}
|
|
163
|
+
</div>
|
|
164
|
+
${cores.length > 0 ? html`<div class="cores">
|
|
165
|
+
${cores.map(
|
|
166
|
+
([k, v]) => html`<div class="item">
|
|
167
|
+
<span>${humanize(k)}</span>
|
|
168
|
+
<strong>${v.number ?? ""}</strong>
|
|
169
|
+
</div>`
|
|
170
|
+
)}
|
|
150
171
|
</div>` : nothing}
|
|
151
172
|
</article>`;
|
|
152
173
|
}
|
|
@@ -201,7 +222,8 @@ RoxyNumerologyCard.styles = [
|
|
|
201
222
|
background: color-mix(in srgb, var(--roxy-border, #e4e4e7) 30%, transparent);
|
|
202
223
|
padding: var(--roxy-space-sm, 0.5rem);
|
|
203
224
|
border-radius: var(--roxy-radius-sm, 4px);
|
|
204
|
-
|
|
225
|
+
white-space: pre-wrap;
|
|
226
|
+
overflow-wrap: anywhere;
|
|
205
227
|
}
|
|
206
228
|
|
|
207
229
|
.chips {
|
|
@@ -265,6 +287,10 @@ var LABELS = {
|
|
|
265
287
|
"personal-year": "Personal Year",
|
|
266
288
|
chart: "Numerology chart"
|
|
267
289
|
};
|
|
290
|
+
function karmicDebtText(value) {
|
|
291
|
+
if (!value) return "";
|
|
292
|
+
return [value.description, value.challenge, value.resolution].filter(Boolean).join(" ");
|
|
293
|
+
}
|
|
268
294
|
function humanize(s) {
|
|
269
295
|
return s.replace(/[_-]+/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^\w/, (c) => c.toUpperCase());
|
|
270
296
|
}
|