@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
|
@@ -1,53 +1,22 @@
|
|
|
1
1
|
import { css, html, LitElement, nothing, svg } from 'lit';
|
|
2
2
|
import { customElement, property } from 'lit/decorators.js';
|
|
3
3
|
import { PLANET_GLYPH, SIGN_GLYPH } from '../tokens/index.js';
|
|
4
|
+
import type { NatalChartResponse } from '../types/index.js';
|
|
4
5
|
import { baseStyles } from '../utils/base-styles.js';
|
|
5
6
|
import { longitudeToSignPosition, polarToCartesian } from '../utils/degree.js';
|
|
7
|
+
import { formatNumber } from '../utils/format.js';
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
planet?: string;
|
|
10
|
-
longitude?: number;
|
|
11
|
-
degree?: number;
|
|
12
|
-
sign?: string;
|
|
13
|
-
house?: number;
|
|
14
|
-
retrograde?: boolean;
|
|
15
|
-
isRetrograde?: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface AspectEntry {
|
|
19
|
-
planet1?: string;
|
|
20
|
-
planet2?: string;
|
|
21
|
-
aspect?: string;
|
|
22
|
-
orb?: number;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
interface HouseEntry {
|
|
26
|
-
house?: number;
|
|
27
|
-
number?: number;
|
|
28
|
-
cusp?: number;
|
|
29
|
-
sign?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface NatalChartData {
|
|
33
|
-
planets?: PlanetEntry[] | Record<string, PlanetEntry>;
|
|
34
|
-
houses?: HouseEntry[];
|
|
35
|
-
aspects?: AspectEntry[];
|
|
36
|
-
ascendant?: number | { longitude?: number; sign?: string };
|
|
37
|
-
midheaven?: number | { longitude?: number; sign?: string };
|
|
38
|
-
birthDetails?: {
|
|
39
|
-
date?: string;
|
|
40
|
-
time?: string;
|
|
41
|
-
location?: string;
|
|
42
|
-
};
|
|
43
|
-
}
|
|
9
|
+
type PlanetEntry = NatalChartResponse['planets'][number];
|
|
10
|
+
type AspectEntry = NatalChartResponse['aspects'][number];
|
|
44
11
|
|
|
45
|
-
const SIZE =
|
|
12
|
+
const SIZE = 384;
|
|
46
13
|
const CENTER = SIZE / 2;
|
|
47
14
|
const OUTER_R = 150;
|
|
48
15
|
const SIGN_R = 134;
|
|
49
16
|
const HOUSE_R = 110;
|
|
50
17
|
const PLANET_R = 88;
|
|
18
|
+
const ANGLE_TICK_R = 162;
|
|
19
|
+
const ANGLE_LABEL_R = 176;
|
|
51
20
|
|
|
52
21
|
/**
|
|
53
22
|
* Western natal chart wheel. Renders the 12 zodiac signs, 12 houses, planet
|
|
@@ -109,9 +78,36 @@ export class RoxyNatalChart extends LitElement {
|
|
|
109
78
|
}
|
|
110
79
|
|
|
111
80
|
.aspect {
|
|
112
|
-
stroke:
|
|
113
|
-
stroke-width: 0.6;
|
|
81
|
+
stroke-width: 0.8;
|
|
114
82
|
fill: none;
|
|
83
|
+
opacity: 0.55;
|
|
84
|
+
}
|
|
85
|
+
.aspect-trine,
|
|
86
|
+
.aspect-sextile {
|
|
87
|
+
stroke: var(--roxy-success, #16a34a);
|
|
88
|
+
}
|
|
89
|
+
.aspect-square,
|
|
90
|
+
.aspect-opposition {
|
|
91
|
+
stroke: var(--roxy-danger, #dc2626);
|
|
92
|
+
}
|
|
93
|
+
.aspect-conjunction {
|
|
94
|
+
stroke: var(--roxy-accent-fg, #b45309);
|
|
95
|
+
}
|
|
96
|
+
.aspect-other {
|
|
97
|
+
stroke: var(--roxy-muted, #71717a);
|
|
98
|
+
opacity: 0.4;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.angle-marker {
|
|
102
|
+
fill: var(--roxy-accent-fg, #b45309);
|
|
103
|
+
font-size: 10px;
|
|
104
|
+
font-weight: 700;
|
|
105
|
+
font-family: var(--roxy-font-sans);
|
|
106
|
+
letter-spacing: 0.04em;
|
|
107
|
+
}
|
|
108
|
+
.angle-tick {
|
|
109
|
+
stroke: var(--roxy-accent-fg, #b45309);
|
|
110
|
+
stroke-width: 1.5;
|
|
115
111
|
}
|
|
116
112
|
|
|
117
113
|
.legend {
|
|
@@ -121,20 +117,38 @@ export class RoxyNatalChart extends LitElement {
|
|
|
121
117
|
flex-wrap: wrap;
|
|
122
118
|
gap: var(--roxy-space-md, 1rem);
|
|
123
119
|
}
|
|
120
|
+
.legend-swatch {
|
|
121
|
+
display: inline-block;
|
|
122
|
+
width: 8px;
|
|
123
|
+
height: 8px;
|
|
124
|
+
border-radius: 50%;
|
|
125
|
+
margin-right: 4px;
|
|
126
|
+
vertical-align: middle;
|
|
127
|
+
}
|
|
124
128
|
`,
|
|
125
129
|
];
|
|
126
130
|
|
|
127
131
|
@property({ attribute: false })
|
|
128
|
-
data:
|
|
132
|
+
data: NatalChartResponse | null = null;
|
|
129
133
|
|
|
130
134
|
@property({ type: String, attribute: 'house-system', reflect: true })
|
|
131
135
|
houseSystem: 'placidus' | 'whole-sign' | 'equal' | 'koch' = 'placidus';
|
|
132
136
|
|
|
133
137
|
private getPlanets(): PlanetEntry[] {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
return this.data?.planets ?? [];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private getAscendant(): number {
|
|
142
|
+
return this.data?.ascendant?.longitude ?? 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private getMidheaven(): number | null {
|
|
146
|
+
const m = this.data?.midheaven?.longitude;
|
|
147
|
+
return typeof m === 'number' ? m : null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private toAngle(lon: number): number {
|
|
151
|
+
return 180 + this.getAscendant() - lon;
|
|
138
152
|
}
|
|
139
153
|
|
|
140
154
|
render() {
|
|
@@ -149,11 +163,7 @@ export class RoxyNatalChart extends LitElement {
|
|
|
149
163
|
${
|
|
150
164
|
this.data.birthDetails
|
|
151
165
|
? html`<div class="meta">
|
|
152
|
-
${[
|
|
153
|
-
this.data.birthDetails.date,
|
|
154
|
-
this.data.birthDetails.time,
|
|
155
|
-
this.data.birthDetails.location,
|
|
156
|
-
]
|
|
166
|
+
${[this.data.birthDetails.date, this.data.birthDetails.time]
|
|
157
167
|
.filter(Boolean)
|
|
158
168
|
.join(' · ')}
|
|
159
169
|
</div>`
|
|
@@ -193,18 +203,41 @@ export class RoxyNatalChart extends LitElement {
|
|
|
193
203
|
/>
|
|
194
204
|
${this.renderSpokes()} ${this.renderSigns()} ${this.renderHouseNumbers()}
|
|
195
205
|
${this.renderAspects(planets, aspects)} ${this.renderPlanets(planets)}
|
|
206
|
+
${this.renderAngles()}
|
|
196
207
|
</svg>
|
|
197
208
|
<div class="legend">
|
|
198
209
|
<span>${planets.length} planets</span>
|
|
199
210
|
<span>${aspects.length} aspects</span>
|
|
200
|
-
<span
|
|
211
|
+
<span><span class="legend-swatch" style="background: var(--roxy-success)"></span>harmonious</span>
|
|
212
|
+
<span><span class="legend-swatch" style="background: var(--roxy-danger)"></span>challenging</span>
|
|
201
213
|
</div>
|
|
202
214
|
</div>`;
|
|
203
215
|
}
|
|
204
216
|
|
|
217
|
+
private renderAngles() {
|
|
218
|
+
const asc = this.getAscendant();
|
|
219
|
+
const mc = this.getMidheaven();
|
|
220
|
+
const items = [this.renderAngleMark(asc, 'ASC')];
|
|
221
|
+
if (mc !== null) items.push(this.renderAngleMark(mc, 'MC'));
|
|
222
|
+
return items;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
private renderAngleMark(longitude: number, label: string) {
|
|
226
|
+
const angle = this.toAngle(longitude);
|
|
227
|
+
const tickInner = polarToCartesian(CENTER, CENTER, OUTER_R, angle);
|
|
228
|
+
const tickOuter = polarToCartesian(CENTER, CENTER, ANGLE_TICK_R, angle);
|
|
229
|
+
const labelPos = polarToCartesian(CENTER, CENTER, ANGLE_LABEL_R, angle);
|
|
230
|
+
return svg`
|
|
231
|
+
<g>
|
|
232
|
+
<line class="angle-tick" x1=${tickInner.x} y1=${tickInner.y} x2=${tickOuter.x} y2=${tickOuter.y} />
|
|
233
|
+
<text class="angle-marker" x=${labelPos.x} y=${labelPos.y} text-anchor="middle" dominant-baseline="central">${label}</text>
|
|
234
|
+
</g>
|
|
235
|
+
`;
|
|
236
|
+
}
|
|
237
|
+
|
|
205
238
|
private renderSpokes() {
|
|
206
239
|
return Array.from({ length: 12 }, (_, i) => {
|
|
207
|
-
const angle = i * 30
|
|
240
|
+
const angle = this.toAngle(i * 30);
|
|
208
241
|
const start = polarToCartesian(CENTER, CENTER, HOUSE_R, angle);
|
|
209
242
|
const end = polarToCartesian(CENTER, CENTER, OUTER_R, angle);
|
|
210
243
|
return svg`<line class="wheel-line" x1=${start.x} y1=${start.y} x2=${end.x} y2=${end.y} stroke-width="0.8" />`;
|
|
@@ -227,58 +260,61 @@ export class RoxyNatalChart extends LitElement {
|
|
|
227
260
|
'Pisces',
|
|
228
261
|
];
|
|
229
262
|
return order.map((sign, i) => {
|
|
230
|
-
const angle = i * 30 + 15
|
|
263
|
+
const angle = this.toAngle(i * 30 + 15);
|
|
231
264
|
const pos = polarToCartesian(CENTER, CENTER, SIGN_R, angle);
|
|
232
265
|
return svg`<text class="sign-glyph" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central">${SIGN_GLYPH[sign]}</text>`;
|
|
233
266
|
});
|
|
234
267
|
}
|
|
235
268
|
|
|
236
269
|
private renderHouseNumbers() {
|
|
270
|
+
const ascSignIndex = Math.floor(this.getAscendant() / 30);
|
|
237
271
|
return Array.from({ length: 12 }, (_, i) => {
|
|
238
|
-
const angle = i * 30 + 15
|
|
272
|
+
const angle = this.toAngle(i * 30 + 15);
|
|
239
273
|
const pos = polarToCartesian(CENTER, CENTER, HOUSE_R - 12, angle);
|
|
240
|
-
|
|
274
|
+
const houseNum = ((i - ascSignIndex + 12) % 12) + 1;
|
|
275
|
+
return svg`<text class="house-num" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central">${houseNum}</text>`;
|
|
241
276
|
});
|
|
242
277
|
}
|
|
243
278
|
|
|
244
279
|
private renderPlanets(planets: PlanetEntry[]) {
|
|
245
280
|
return planets.map((p) => {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
? p.longitude
|
|
249
|
-
: typeof p.degree === 'number'
|
|
250
|
-
? p.degree
|
|
251
|
-
: NaN;
|
|
252
|
-
if (!Number.isFinite(lon)) return nothing;
|
|
253
|
-
const angle = lon - 90;
|
|
281
|
+
if (!Number.isFinite(p.longitude)) return nothing;
|
|
282
|
+
const angle = this.toAngle(p.longitude);
|
|
254
283
|
const pos = polarToCartesian(CENTER, CENTER, PLANET_R, angle);
|
|
255
|
-
const
|
|
256
|
-
const
|
|
257
|
-
const
|
|
258
|
-
return svg`<text class="planet-glyph" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central"><title>${name}${retro}</title>${
|
|
284
|
+
const glyph = PLANET_GLYPH[capitalize(p.name)] ?? p.name.slice(0, 2);
|
|
285
|
+
const retro = p.isRetrograde ? ' R' : '';
|
|
286
|
+
const display = retro ? `${glyph}ᴿ` : glyph;
|
|
287
|
+
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>`;
|
|
259
288
|
});
|
|
260
289
|
}
|
|
261
290
|
|
|
262
291
|
private renderAspects(planets: PlanetEntry[], aspects: AspectEntry[]) {
|
|
263
292
|
const planetMap = new Map<string, number>();
|
|
264
293
|
for (const p of planets) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
: typeof p.degree === 'number'
|
|
269
|
-
? p.degree
|
|
270
|
-
: null;
|
|
271
|
-
if (lon === null) continue;
|
|
272
|
-
const name = capitalize(p.name ?? p.planet ?? '');
|
|
273
|
-
if (name) planetMap.set(name, lon);
|
|
294
|
+
if (typeof p.longitude !== 'number') continue;
|
|
295
|
+
const name = capitalize(p.name);
|
|
296
|
+
if (name) planetMap.set(name, p.longitude);
|
|
274
297
|
}
|
|
275
298
|
return aspects.map((a) => {
|
|
276
|
-
const l1 = planetMap.get(capitalize(a.planet1
|
|
277
|
-
const l2 = planetMap.get(capitalize(a.planet2
|
|
299
|
+
const l1 = planetMap.get(capitalize(a.planet1));
|
|
300
|
+
const l2 = planetMap.get(capitalize(a.planet2));
|
|
278
301
|
if (l1 === undefined || l2 === undefined) return nothing;
|
|
279
|
-
const p1 = polarToCartesian(
|
|
280
|
-
|
|
281
|
-
|
|
302
|
+
const p1 = polarToCartesian(
|
|
303
|
+
CENTER,
|
|
304
|
+
CENTER,
|
|
305
|
+
PLANET_R - 18,
|
|
306
|
+
this.toAngle(l1),
|
|
307
|
+
);
|
|
308
|
+
const p2 = polarToCartesian(
|
|
309
|
+
CENTER,
|
|
310
|
+
CENTER,
|
|
311
|
+
PLANET_R - 18,
|
|
312
|
+
this.toAngle(l2),
|
|
313
|
+
);
|
|
314
|
+
const aspectName = normalizeAspect(a);
|
|
315
|
+
const aspectClass = ASPECT_CLASS[aspectName] ?? 'aspect-other';
|
|
316
|
+
const orbLabel = formatNumber(a.orb, 1);
|
|
317
|
+
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}°)` : ''}</title></line>`;
|
|
282
318
|
});
|
|
283
319
|
}
|
|
284
320
|
}
|
|
@@ -288,11 +324,20 @@ function capitalize(s: string): string {
|
|
|
288
324
|
return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
|
|
289
325
|
}
|
|
290
326
|
|
|
327
|
+
const ASPECT_CLASS: Record<string, string> = {
|
|
328
|
+
conjunction: 'aspect-conjunction',
|
|
329
|
+
sextile: 'aspect-sextile',
|
|
330
|
+
square: 'aspect-square',
|
|
331
|
+
trine: 'aspect-trine',
|
|
332
|
+
opposition: 'aspect-opposition',
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
function normalizeAspect(a: AspectEntry): string {
|
|
336
|
+
return (a.type ?? '').toLowerCase().replace(/_/g, '-');
|
|
337
|
+
}
|
|
338
|
+
|
|
291
339
|
declare global {
|
|
292
340
|
interface HTMLElementTagNameMap {
|
|
293
341
|
'roxy-natal-chart': RoxyNatalChart;
|
|
294
342
|
}
|
|
295
343
|
}
|
|
296
|
-
|
|
297
|
-
// Export for external use
|
|
298
|
-
export { longitudeToSignPosition };
|
|
@@ -1,45 +1,18 @@
|
|
|
1
1
|
import { css, html, LitElement, nothing } from 'lit';
|
|
2
2
|
import { customElement, property } from 'lit/decorators.js';
|
|
3
|
+
import type {
|
|
4
|
+
CalculateExpressionResponse,
|
|
5
|
+
CalculateLifePathResponse,
|
|
6
|
+
CalculatePersonalYearResponse,
|
|
7
|
+
GenerateNumerologyChartResponse,
|
|
8
|
+
} from '../types/index.js';
|
|
3
9
|
import { baseStyles } from '../utils/base-styles.js';
|
|
4
10
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
karmicDebtNumber?: number;
|
|
11
|
-
karmicDebtMeaning?: string;
|
|
12
|
-
meaning?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface CoreNumber {
|
|
16
|
-
number?: number;
|
|
17
|
-
type?: string;
|
|
18
|
-
meaning?: string;
|
|
19
|
-
calculation?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
interface FullChart {
|
|
23
|
-
profile?: { fullName?: string; birthDate?: string };
|
|
24
|
-
coreNumbers?: Record<string, CoreNumber | number>;
|
|
25
|
-
additionalInsights?: Record<string, unknown>;
|
|
26
|
-
birthDayProfile?: Record<string, unknown>;
|
|
27
|
-
maturityStatus?: string;
|
|
28
|
-
luckyAssociations?: Record<string, unknown>;
|
|
29
|
-
summary?: string;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
interface PersonalYear {
|
|
33
|
-
year?: number;
|
|
34
|
-
personalYear?: number;
|
|
35
|
-
title?: string;
|
|
36
|
-
theme?: string;
|
|
37
|
-
keywords?: string[];
|
|
38
|
-
meaning?: string;
|
|
39
|
-
advice?: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
type NumerologyData = NumerologyCommon & FullChart & PersonalYear;
|
|
11
|
+
type NumerologyData =
|
|
12
|
+
| CalculateLifePathResponse
|
|
13
|
+
| CalculateExpressionResponse
|
|
14
|
+
| CalculatePersonalYearResponse
|
|
15
|
+
| GenerateNumerologyChartResponse;
|
|
43
16
|
|
|
44
17
|
/**
|
|
45
18
|
* Numerology card. Renders /numerology/{life-path,expression,personal-year,chart}.
|
|
@@ -97,7 +70,8 @@ export class RoxyNumerologyCard extends LitElement {
|
|
|
97
70
|
background: color-mix(in srgb, var(--roxy-border, #e4e4e7) 30%, transparent);
|
|
98
71
|
padding: var(--roxy-space-sm, 0.5rem);
|
|
99
72
|
border-radius: var(--roxy-radius-sm, 4px);
|
|
100
|
-
|
|
73
|
+
white-space: pre-wrap;
|
|
74
|
+
overflow-wrap: anywhere;
|
|
101
75
|
}
|
|
102
76
|
|
|
103
77
|
.chips {
|
|
@@ -159,62 +133,83 @@ export class RoxyNumerologyCard extends LitElement {
|
|
|
159
133
|
return html`<div class="roxy-empty" role="status">No numerology data</div>`;
|
|
160
134
|
|
|
161
135
|
const headerLabel = LABELS[this.type] ?? this.type;
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
136
|
+
|
|
137
|
+
if ('coreNumbers' in d) return this.renderChart(d, headerLabel);
|
|
138
|
+
if ('personalYear' in d) return this.renderPersonalYear(d, headerLabel);
|
|
139
|
+
return this.renderNumberCard(
|
|
140
|
+
d as CalculateLifePathResponse | CalculateExpressionResponse,
|
|
141
|
+
headerLabel,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
private renderNumberCard(
|
|
146
|
+
d: CalculateLifePathResponse | CalculateExpressionResponse,
|
|
147
|
+
headerLabel: string,
|
|
148
|
+
) {
|
|
149
|
+
const keywords = d.meaning?.keywords ?? [];
|
|
150
|
+
return html`<article class="card" aria-label=${headerLabel}>
|
|
173
151
|
<div class="hero">
|
|
174
|
-
${typeof number === 'number' ? html`<div class="numeral">${number}</div>` : nothing}
|
|
152
|
+
${typeof d.number === 'number' ? html`<div class="numeral">${d.number}</div>` : nothing}
|
|
175
153
|
<div>
|
|
176
154
|
<p class="label">${headerLabel}</p>
|
|
177
|
-
${
|
|
178
|
-
d.title
|
|
179
|
-
? html`<h2 class="title">${d.title}</h2>`
|
|
180
|
-
: d.type
|
|
181
|
-
? html`<h2 class="title">
|
|
182
|
-
${d.type === 'master' ? 'Master number' : 'Single digit'}
|
|
183
|
-
</h2>`
|
|
184
|
-
: nothing
|
|
185
|
-
}
|
|
155
|
+
${d.meaning?.title ? html`<h2 class="title">${d.meaning.title}</h2>` : nothing}
|
|
186
156
|
</div>
|
|
187
157
|
</div>
|
|
188
|
-
${d.
|
|
189
|
-
${d.meaning ? html`<p class="meaning">${d.meaning}</p>` : nothing}
|
|
190
|
-
${d.advice ? html`<p>${d.advice}</p>` : nothing}
|
|
158
|
+
${d.meaning?.description ? html`<p class="meaning">${d.meaning.description}</p>` : nothing}
|
|
191
159
|
${d.calculation ? html`<pre class="calc">${d.calculation}</pre>` : nothing}
|
|
192
160
|
${
|
|
193
|
-
|
|
161
|
+
keywords.length > 0
|
|
194
162
|
? html`<div class="chips">
|
|
195
|
-
${
|
|
163
|
+
${keywords.map((k) => html`<span>${k}</span>`)}
|
|
196
164
|
</div>`
|
|
197
165
|
: nothing
|
|
198
166
|
}
|
|
199
167
|
${
|
|
200
|
-
|
|
201
|
-
? html`<div class="
|
|
202
|
-
${
|
|
203
|
-
|
|
204
|
-
typeof v === 'number' ? v : (v as CoreNumber).number;
|
|
205
|
-
return html`<div class="item">
|
|
206
|
-
<span>${humanize(k)}</span>
|
|
207
|
-
<strong>${value ?? ''}</strong>
|
|
208
|
-
</div>`;
|
|
209
|
-
})}
|
|
168
|
+
d.hasKarmicDebt && d.karmicDebtNumber
|
|
169
|
+
? html`<div class="karmic">
|
|
170
|
+
Karmic debt ${d.karmicDebtNumber}.
|
|
171
|
+
${karmicDebtText(d.karmicDebtMeaning)}
|
|
210
172
|
</div>`
|
|
211
173
|
: nothing
|
|
212
174
|
}
|
|
175
|
+
</article>`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private renderPersonalYear(
|
|
179
|
+
d: CalculatePersonalYearResponse,
|
|
180
|
+
headerLabel: string,
|
|
181
|
+
) {
|
|
182
|
+
return html`<article class="card" aria-label=${headerLabel}>
|
|
183
|
+
<div class="hero">
|
|
184
|
+
${typeof d.personalYear === 'number' ? html`<div class="numeral">${d.personalYear}</div>` : nothing}
|
|
185
|
+
<div>
|
|
186
|
+
<p class="label">${headerLabel}</p>
|
|
187
|
+
${d.theme ? html`<h2 class="title">${d.theme}</h2>` : nothing}
|
|
188
|
+
</div>
|
|
189
|
+
</div>
|
|
190
|
+
${d.forecast ? html`<p class="meaning">${d.forecast}</p>` : nothing}
|
|
191
|
+
${d.advice ? html`<p>${d.advice}</p>` : nothing}
|
|
192
|
+
</article>`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private renderChart(d: GenerateNumerologyChartResponse, headerLabel: string) {
|
|
196
|
+
const cores = Object.entries(d.coreNumbers).filter(
|
|
197
|
+
([, v]) => v !== null && v !== undefined,
|
|
198
|
+
);
|
|
199
|
+
return html`<article class="card" aria-label=${headerLabel}>
|
|
200
|
+
<div>
|
|
201
|
+
<p class="label">${headerLabel}</p>
|
|
202
|
+
${d.profile?.name ? html`<h2 class="title">${d.profile.name}</h2>` : nothing}
|
|
203
|
+
</div>
|
|
213
204
|
${
|
|
214
|
-
|
|
215
|
-
? html`<div class="
|
|
216
|
-
|
|
217
|
-
|
|
205
|
+
cores.length > 0
|
|
206
|
+
? html`<div class="cores">
|
|
207
|
+
${cores.map(
|
|
208
|
+
([k, v]) => html`<div class="item">
|
|
209
|
+
<span>${humanize(k)}</span>
|
|
210
|
+
<strong>${v.number ?? ''}</strong>
|
|
211
|
+
</div>`,
|
|
212
|
+
)}
|
|
218
213
|
</div>`
|
|
219
214
|
: nothing
|
|
220
215
|
}
|
|
@@ -229,6 +224,19 @@ const LABELS: Record<string, string> = {
|
|
|
229
224
|
chart: 'Numerology chart',
|
|
230
225
|
};
|
|
231
226
|
|
|
227
|
+
type KarmicDebtMeaning = {
|
|
228
|
+
description: string;
|
|
229
|
+
challenge: string;
|
|
230
|
+
resolution: string;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
function karmicDebtText(value: KarmicDebtMeaning | undefined): string {
|
|
234
|
+
if (!value) return '';
|
|
235
|
+
return [value.description, value.challenge, value.resolution]
|
|
236
|
+
.filter(Boolean)
|
|
237
|
+
.join(' ');
|
|
238
|
+
}
|
|
239
|
+
|
|
232
240
|
function humanize(s: string): string {
|
|
233
241
|
return s
|
|
234
242
|
.replace(/[_-]+/g, ' ')
|