@roxyapi/ui 0.1.2 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/AGENTS.md +6 -0
  2. package/README.md +327 -14
  3. package/THEMING.md +24 -7
  4. package/dist/cdn/components/ashtakavarga-grid.js +349 -0
  5. package/dist/cdn/components/ashtakavarga-grid.js.map +7 -0
  6. package/dist/cdn/components/biorhythm-chart.js +15 -22
  7. package/dist/cdn/components/biorhythm-chart.js.map +3 -3
  8. package/dist/cdn/components/choghadiya-grid.js +239 -0
  9. package/dist/cdn/components/choghadiya-grid.js.map +7 -0
  10. package/dist/cdn/components/compatibility-card.js +36 -34
  11. package/dist/cdn/components/compatibility-card.js.map +4 -4
  12. package/dist/cdn/components/dasha-timeline.js +35 -39
  13. package/dist/cdn/components/dasha-timeline.js.map +4 -4
  14. package/dist/cdn/components/data.js +9 -9
  15. package/dist/cdn/components/data.js.map +4 -4
  16. package/dist/cdn/components/divisional-chart.js +279 -0
  17. package/dist/cdn/components/divisional-chart.js.map +7 -0
  18. package/dist/cdn/components/dosha-card.js +49 -49
  19. package/dist/cdn/components/dosha-card.js.map +3 -3
  20. package/dist/cdn/components/endpoint-form.js +47 -28
  21. package/dist/cdn/components/endpoint-form.js.map +4 -4
  22. package/dist/cdn/components/guna-milan.js +66 -24
  23. package/dist/cdn/components/guna-milan.js.map +4 -4
  24. package/dist/cdn/components/hexagram.js +26 -26
  25. package/dist/cdn/components/hexagram.js.map +3 -3
  26. package/dist/cdn/components/horoscope-card.js +47 -40
  27. package/dist/cdn/components/horoscope-card.js.map +4 -4
  28. package/dist/cdn/components/kp-planets-table.js +10 -10
  29. package/dist/cdn/components/kp-planets-table.js.map +4 -4
  30. package/dist/cdn/components/location-search.js +6 -6
  31. package/dist/cdn/components/location-search.js.map +3 -3
  32. package/dist/cdn/components/moon-phase.js +18 -18
  33. package/dist/cdn/components/moon-phase.js.map +4 -4
  34. package/dist/cdn/components/natal-chart.js +240 -24
  35. package/dist/cdn/components/natal-chart.js.map +4 -4
  36. package/dist/cdn/components/numerology-card.js +40 -31
  37. package/dist/cdn/components/numerology-card.js.map +4 -4
  38. package/dist/cdn/components/panchang-table.js +30 -30
  39. package/dist/cdn/components/panchang-table.js.map +4 -4
  40. package/dist/cdn/components/shadbala-table.js +312 -0
  41. package/dist/cdn/components/shadbala-table.js.map +7 -0
  42. package/dist/cdn/components/synastry-chart.js +129 -39
  43. package/dist/cdn/components/synastry-chart.js.map +4 -4
  44. package/dist/cdn/components/tarot-card.js +49 -20
  45. package/dist/cdn/components/tarot-card.js.map +3 -3
  46. package/dist/cdn/components/tarot-spread.js +43 -27
  47. package/dist/cdn/components/tarot-spread.js.map +3 -3
  48. package/dist/cdn/components/transits-table.js +391 -0
  49. package/dist/cdn/components/transits-table.js.map +7 -0
  50. package/dist/cdn/components/vedic-kundli.js +63 -27
  51. package/dist/cdn/components/vedic-kundli.js.map +4 -4
  52. package/dist/cdn/components/yoga-list.js +334 -0
  53. package/dist/cdn/components/yoga-list.js.map +7 -0
  54. package/dist/cdn/roxy-ui.js +2104 -544
  55. package/dist/cdn/roxy-ui.js.map +4 -4
  56. package/dist/components/ashtakavarga-grid.d.ts +26 -0
  57. package/dist/components/ashtakavarga-grid.d.ts.map +1 -0
  58. package/dist/components/ashtakavarga-grid.js +457 -0
  59. package/dist/components/ashtakavarga-grid.js.map +7 -0
  60. package/dist/components/biorhythm-chart.d.ts +2 -46
  61. package/dist/components/biorhythm-chart.d.ts.map +1 -1
  62. package/dist/components/biorhythm-chart.js +24 -23
  63. package/dist/components/biorhythm-chart.js.map +2 -2
  64. package/dist/components/choghadiya-grid.d.ts +19 -0
  65. package/dist/components/choghadiya-grid.d.ts.map +1 -0
  66. package/dist/components/choghadiya-grid.js +304 -0
  67. package/dist/components/choghadiya-grid.js.map +7 -0
  68. package/dist/components/compatibility-card.d.ts +2 -27
  69. package/dist/components/compatibility-card.d.ts.map +1 -1
  70. package/dist/components/compatibility-card.js +50 -29
  71. package/dist/components/compatibility-card.js.map +3 -3
  72. package/dist/components/dasha-timeline.d.ts +2 -31
  73. package/dist/components/dasha-timeline.d.ts.map +1 -1
  74. package/dist/components/dasha-timeline.js +32 -30
  75. package/dist/components/dasha-timeline.js.map +3 -3
  76. package/dist/components/data.d.ts +11 -7
  77. package/dist/components/data.d.ts.map +1 -1
  78. package/dist/components/data.js +16 -6
  79. package/dist/components/data.js.map +3 -3
  80. package/dist/components/divisional-chart.d.ts +20 -0
  81. package/dist/components/divisional-chart.d.ts.map +1 -0
  82. package/dist/components/divisional-chart.js +471 -0
  83. package/dist/components/divisional-chart.js.map +7 -0
  84. package/dist/components/dosha-card.d.ts +2 -16
  85. package/dist/components/dosha-card.d.ts.map +1 -1
  86. package/dist/components/dosha-card.js +45 -43
  87. package/dist/components/dosha-card.js.map +2 -2
  88. package/dist/components/endpoint-form.d.ts +2 -0
  89. package/dist/components/endpoint-form.d.ts.map +1 -1
  90. package/dist/components/endpoint-form.js +71 -11
  91. package/dist/components/endpoint-form.js.map +3 -3
  92. package/dist/components/guna-milan.d.ts +2 -20
  93. package/dist/components/guna-milan.d.ts.map +1 -1
  94. package/dist/components/guna-milan.js +79 -20
  95. package/dist/components/guna-milan.js.map +4 -4
  96. package/dist/components/hexagram.d.ts +3 -27
  97. package/dist/components/hexagram.d.ts.map +1 -1
  98. package/dist/components/hexagram.js +48 -15
  99. package/dist/components/hexagram.js.map +2 -2
  100. package/dist/components/horoscope-card.d.ts +2 -20
  101. package/dist/components/horoscope-card.d.ts.map +1 -1
  102. package/dist/components/horoscope-card.js +54 -18
  103. package/dist/components/horoscope-card.js.map +3 -3
  104. package/dist/components/kp-planets-table.d.ts +2 -21
  105. package/dist/components/kp-planets-table.d.ts.map +1 -1
  106. package/dist/components/kp-planets-table.js +10 -4
  107. package/dist/components/kp-planets-table.js.map +3 -3
  108. package/dist/components/location-search.d.ts +5 -14
  109. package/dist/components/location-search.d.ts.map +1 -1
  110. package/dist/components/location-search.js +45 -5
  111. package/dist/components/location-search.js.map +2 -2
  112. package/dist/components/moon-phase.d.ts +4 -21
  113. package/dist/components/moon-phase.d.ts.map +1 -1
  114. package/dist/components/moon-phase.js +34 -4
  115. package/dist/components/moon-phase.js.map +3 -3
  116. package/dist/components/natal-chart.d.ts +9 -43
  117. package/dist/components/natal-chart.d.ts.map +1 -1
  118. package/dist/components/natal-chart.js +346 -79
  119. package/dist/components/natal-chart.js.map +3 -3
  120. package/dist/components/numerology-card.d.ts +5 -37
  121. package/dist/components/numerology-card.d.ts.map +1 -1
  122. package/dist/components/numerology-card.js +58 -30
  123. package/dist/components/numerology-card.js.map +3 -3
  124. package/dist/components/panchang-table.d.ts +3 -62
  125. package/dist/components/panchang-table.d.ts.map +1 -1
  126. package/dist/components/panchang-table.js +62 -32
  127. package/dist/components/panchang-table.js.map +3 -3
  128. package/dist/components/shadbala-table.d.ts +18 -0
  129. package/dist/components/shadbala-table.d.ts.map +1 -0
  130. package/dist/components/shadbala-table.js +400 -0
  131. package/dist/components/shadbala-table.js.map +7 -0
  132. package/dist/components/synastry-chart.d.ts +9 -28
  133. package/dist/components/synastry-chart.d.ts.map +1 -1
  134. package/dist/components/synastry-chart.js +201 -56
  135. package/dist/components/synastry-chart.js.map +3 -3
  136. package/dist/components/tarot-card.d.ts +5 -29
  137. package/dist/components/tarot-card.d.ts.map +1 -1
  138. package/dist/components/tarot-card.js +59 -20
  139. package/dist/components/tarot-card.js.map +2 -2
  140. package/dist/components/tarot-spread.d.ts +2 -24
  141. package/dist/components/tarot-spread.d.ts.map +1 -1
  142. package/dist/components/tarot-spread.js +39 -13
  143. package/dist/components/tarot-spread.js.map +2 -2
  144. package/dist/components/transits-table.d.ts +21 -0
  145. package/dist/components/transits-table.d.ts.map +1 -0
  146. package/dist/components/transits-table.js +515 -0
  147. package/dist/components/transits-table.js.map +7 -0
  148. package/dist/components/vedic-kundli.d.ts +5 -28
  149. package/dist/components/vedic-kundli.d.ts.map +1 -1
  150. package/dist/components/vedic-kundli.js +147 -83
  151. package/dist/components/vedic-kundli.js.map +3 -3
  152. package/dist/components/yoga-list.d.ts +29 -0
  153. package/dist/components/yoga-list.d.ts.map +1 -0
  154. package/dist/components/yoga-list.js +389 -0
  155. package/dist/components/yoga-list.js.map +7 -0
  156. package/dist/index.cjs +3693 -1180
  157. package/dist/index.cjs.map +4 -4
  158. package/dist/index.d.ts +11 -4
  159. package/dist/index.d.ts.map +1 -1
  160. package/dist/index.js +3709 -1196
  161. package/dist/index.js.map +4 -4
  162. package/dist/manifest.d.ts +43 -0
  163. package/dist/manifest.d.ts.map +1 -0
  164. package/dist/manifest.json +7 -2
  165. package/dist/styles/tokens.css +73 -1
  166. package/dist/tokens/index.d.ts +6 -0
  167. package/dist/tokens/index.d.ts.map +1 -1
  168. package/dist/types/index.d.ts +2 -0
  169. package/dist/types/index.d.ts.map +1 -0
  170. package/dist/types/types.gen.d.ts +27811 -0
  171. package/dist/types/types.gen.d.ts.map +1 -0
  172. package/dist/utils/debounce.d.ts +9 -1
  173. package/dist/utils/debounce.d.ts.map +1 -1
  174. package/dist/utils/format.d.ts +29 -0
  175. package/dist/utils/format.d.ts.map +1 -0
  176. package/dist/utils/kundli-render.d.ts +63 -0
  177. package/dist/utils/kundli-render.d.ts.map +1 -0
  178. package/dist/utils/string.d.ts +14 -0
  179. package/dist/utils/string.d.ts.map +1 -0
  180. package/dist/version.d.ts +2 -0
  181. package/dist/version.d.ts.map +1 -0
  182. package/package.json +7 -1
  183. package/src/components/ashtakavarga-grid.ts +354 -0
  184. package/src/components/biorhythm-chart.ts +39 -84
  185. package/src/components/choghadiya-grid.ts +185 -0
  186. package/src/components/compatibility-card.ts +85 -52
  187. package/src/components/dasha-timeline.ts +55 -73
  188. package/src/components/data.ts +28 -16
  189. package/src/components/divisional-chart.ts +214 -0
  190. package/src/components/dosha-card.ts +72 -68
  191. package/src/components/endpoint-form.ts +80 -18
  192. package/src/components/guna-milan.ts +87 -47
  193. package/src/components/hexagram.ts +53 -43
  194. package/src/components/horoscope-card.ts +59 -43
  195. package/src/components/kp-planets-table.ts +8 -27
  196. package/src/components/location-search.ts +47 -23
  197. package/src/components/moon-phase.ts +28 -25
  198. package/src/components/natal-chart.ts +364 -110
  199. package/src/components/numerology-card.ts +86 -84
  200. package/src/components/panchang-table.ts +40 -78
  201. package/src/components/shadbala-table.ts +286 -0
  202. package/src/components/synastry-chart.ts +213 -97
  203. package/src/components/tarot-card.ts +76 -62
  204. package/src/components/tarot-spread.ts +72 -45
  205. package/src/components/transits-table.ts +350 -0
  206. package/src/components/vedic-kundli.ts +59 -173
  207. package/src/components/yoga-list.ts +328 -0
  208. package/src/index.ts +18 -26
  209. package/src/manifest.ts +340 -0
  210. package/src/styles/tokens.css +73 -1
  211. package/src/tokens/index.ts +14 -0
  212. package/src/types/types.gen.ts +3 -3
  213. package/src/utils/debounce.ts +23 -4
  214. package/src/utils/format.ts +75 -0
  215. package/src/utils/kundli-render.ts +197 -0
  216. package/src/utils/string.ts +23 -0
  217. package/src/version.ts +2 -0
  218. package/dist/utils/motion.d.ts +0 -13
  219. package/dist/utils/motion.d.ts.map +0 -1
  220. package/src/utils/motion.ts +0 -18
@@ -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",
@@ -61,6 +66,9 @@ var SIGNS_ORDER = [
61
66
  "Aquarius",
62
67
  "Pisces"
63
68
  ];
69
+ var RASHI_KEYS = SIGNS_ORDER.map(
70
+ (s) => s.toLowerCase()
71
+ );
64
72
 
65
73
  // packages/ui/src/utils/base-styles.ts
66
74
  import { css } from "lit";
@@ -149,26 +157,6 @@ var baseStyles = css`
149
157
  `;
150
158
 
151
159
  // 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
160
  function polarToCartesian(cx, cy, radius, angleDeg) {
173
161
  const angleRad = angleDeg * Math.PI / 180;
174
162
  return {
@@ -177,13 +165,37 @@ function polarToCartesian(cx, cy, radius, angleDeg) {
177
165
  };
178
166
  }
179
167
 
168
+ // packages/ui/src/utils/format.ts
169
+ function formatNumber(value, dp = 1) {
170
+ if (typeof value !== "number" || !Number.isFinite(value)) return "";
171
+ return value.toFixed(dp).replace(/\.?0+$/, "");
172
+ }
173
+ var ASPECT_CLASS = {
174
+ conjunction: "aspect-conjunction",
175
+ sextile: "aspect-sextile",
176
+ square: "aspect-square",
177
+ trine: "aspect-trine",
178
+ opposition: "aspect-opposition"
179
+ };
180
+ function normalizeAspect(a) {
181
+ return (a.type ?? "").toLowerCase().replace(/_/g, "-");
182
+ }
183
+
184
+ // packages/ui/src/utils/string.ts
185
+ function capitalize(s) {
186
+ if (!s) return "";
187
+ return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
188
+ }
189
+
180
190
  // packages/ui/src/components/natal-chart.ts
181
- var SIZE = 320;
191
+ var SIZE = 420;
182
192
  var CENTER = SIZE / 2;
183
- var OUTER_R = 150;
184
- var SIGN_R = 134;
185
- var HOUSE_R = 110;
186
- var PLANET_R = 88;
193
+ var OUTER_R = 164;
194
+ var SIGN_R = 146;
195
+ var HOUSE_R = 120;
196
+ var PLANET_R = 96;
197
+ var ANGLE_TICK_R = 178;
198
+ var ANGLE_LABEL_R = 196;
187
199
  var RoxyNatalChart = class extends LitElement {
188
200
  constructor() {
189
201
  super(...arguments);
@@ -191,10 +203,17 @@ var RoxyNatalChart = class extends LitElement {
191
203
  this.houseSystem = "placidus";
192
204
  }
193
205
  getPlanets() {
194
- const p = this.data?.planets;
195
- if (!p) return [];
196
- if (Array.isArray(p)) return p;
197
- return Object.entries(p).map(([name, entry]) => ({ ...entry, name }));
206
+ return this.data?.planets ?? [];
207
+ }
208
+ getAscendant() {
209
+ return this.data?.ascendant?.longitude ?? 0;
210
+ }
211
+ getMidheaven() {
212
+ const m = this.data?.midheaven?.longitude;
213
+ return typeof m === "number" ? m : null;
214
+ }
215
+ toAngle(lon) {
216
+ return 180 + this.getAscendant() - lon;
198
217
  }
199
218
  render() {
200
219
  if (!this.data)
@@ -205,11 +224,7 @@ var RoxyNatalChart = class extends LitElement {
205
224
  <header>
206
225
  <h2 class="title">Natal chart</h2>
207
226
  ${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 ")}
227
+ ${[this.data.birthDetails.date, this.data.birthDetails.time].filter(Boolean).join(" \xB7 ")}
213
228
  </div>` : nothing}
214
229
  </header>
215
230
  <svg
@@ -245,77 +260,169 @@ var RoxyNatalChart = class extends LitElement {
245
260
  />
246
261
  ${this.renderSpokes()} ${this.renderSigns()} ${this.renderHouseNumbers()}
247
262
  ${this.renderAspects(planets, aspects)} ${this.renderPlanets(planets)}
263
+ ${this.renderAngles()}
248
264
  </svg>
249
265
  <div class="legend">
250
266
  <span>${planets.length} planets</span>
251
267
  <span>${aspects.length} aspects</span>
252
- <span>House system: ${this.houseSystem}</span>
268
+ <span><span class="legend-swatch" style="background: var(--roxy-success)"></span>harmonious</span>
269
+ <span><span class="legend-swatch" style="background: var(--roxy-danger)"></span>challenging</span>
253
270
  </div>
271
+ ${this.renderDetails()}
272
+ ${this.renderInterpretations()}
254
273
  </div>`;
255
274
  }
275
+ renderAngles() {
276
+ const asc = this.getAscendant();
277
+ const mc = this.getMidheaven();
278
+ const items = [this.renderAngleMark(asc, "ASC")];
279
+ if (mc !== null) items.push(this.renderAngleMark(mc, "MC"));
280
+ return items;
281
+ }
282
+ renderAngleMark(longitude, label) {
283
+ const angle = this.toAngle(longitude);
284
+ const tickInner = polarToCartesian(CENTER, CENTER, OUTER_R, angle);
285
+ const tickOuter = polarToCartesian(CENTER, CENTER, ANGLE_TICK_R, angle);
286
+ const labelPos = polarToCartesian(CENTER, CENTER, ANGLE_LABEL_R, angle);
287
+ return svg`
288
+ <g>
289
+ <line class="angle-tick" x1=${tickInner.x} y1=${tickInner.y} x2=${tickOuter.x} y2=${tickOuter.y} />
290
+ <text class="angle-marker" x=${labelPos.x} y=${labelPos.y} text-anchor="middle" dominant-baseline="central">${label}</text>
291
+ </g>
292
+ `;
293
+ }
256
294
  renderSpokes() {
257
295
  return Array.from({ length: 12 }, (_, i) => {
258
- const angle = i * 30 - 90;
296
+ const angle = this.toAngle(i * 30);
259
297
  const start = polarToCartesian(CENTER, CENTER, HOUSE_R, angle);
260
298
  const end = polarToCartesian(CENTER, CENTER, OUTER_R, angle);
261
299
  return svg`<line class="wheel-line" x1=${start.x} y1=${start.y} x2=${end.x} y2=${end.y} stroke-width="0.8" />`;
262
300
  });
263
301
  }
264
302
  renderSigns() {
265
- const order = [
266
- "Aries",
267
- "Taurus",
268
- "Gemini",
269
- "Cancer",
270
- "Leo",
271
- "Virgo",
272
- "Libra",
273
- "Scorpio",
274
- "Sagittarius",
275
- "Capricorn",
276
- "Aquarius",
277
- "Pisces"
278
- ];
279
- return order.map((sign, i) => {
280
- const angle = i * 30 + 15 - 90;
303
+ return SIGNS_ORDER.map((sign, i) => {
304
+ const angle = this.toAngle(i * 30 + 15);
281
305
  const pos = polarToCartesian(CENTER, CENTER, SIGN_R, angle);
282
306
  return svg`<text class="sign-glyph" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central">${SIGN_GLYPH[sign]}</text>`;
283
307
  });
284
308
  }
285
309
  renderHouseNumbers() {
310
+ const ascSignIndex = Math.floor(this.getAscendant() / 30);
286
311
  return Array.from({ length: 12 }, (_, i) => {
287
- const angle = i * 30 + 15 - 90;
312
+ const angle = this.toAngle(i * 30 + 15);
288
313
  const pos = polarToCartesian(CENTER, CENTER, HOUSE_R - 12, angle);
289
- return svg`<text class="house-num" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central">${i + 1}</text>`;
314
+ const houseNum = (i - ascSignIndex + 12) % 12 + 1;
315
+ return svg`<text class="house-num" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central">${houseNum}</text>`;
290
316
  });
291
317
  }
292
318
  renderPlanets(planets) {
293
319
  return planets.map((p) => {
294
- const lon = typeof p.longitude === "number" ? p.longitude : typeof p.degree === "number" ? p.degree : NaN;
295
- if (!Number.isFinite(lon)) return nothing;
296
- const angle = lon - 90;
320
+ if (!Number.isFinite(p.longitude)) return nothing;
321
+ const angle = this.toAngle(p.longitude);
297
322
  const pos = polarToCartesian(CENTER, CENTER, PLANET_R, angle);
298
- const name = p.name ?? p.planet ?? "";
299
- const glyph = PLANET_GLYPH[capitalize(name)] ?? name.slice(0, 2);
300
- const retro = p.retrograde || p.isRetrograde ? " R" : "";
301
- return svg`<text class="planet-glyph" x=${pos.x} y=${pos.y} text-anchor="middle" dominant-baseline="central"><title>${name}${retro}</title>${glyph}</text>`;
323
+ const glyph = PLANET_GLYPH[capitalize(p.name)] ?? p.name.slice(0, 2);
324
+ const retro = p.isRetrograde ? " R" : "";
325
+ const display = retro ? `${glyph}\u1D3F` : glyph;
326
+ 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
327
  });
303
328
  }
329
+ renderDetails() {
330
+ const summary = this.data?.summary;
331
+ const ai = this.data?.aspectsInterpretation;
332
+ if (!summary && !ai) return nothing;
333
+ const retrogrades = summary?.retrogradePlanets ?? [];
334
+ const elementDist = summary?.elementDistribution ?? {};
335
+ const modalityDist = summary?.modalityDistribution ?? {};
336
+ const elementMax = Math.max(1, ...Object.values(elementDist));
337
+ const modalityMax = Math.max(1, ...Object.values(modalityDist));
338
+ return html`<div class="details">
339
+ ${summary?.dominantElement || summary?.dominantModality ? html`<div class="pill-row">
340
+ ${summary.dominantElement ? html`<span class="pill">Dominant element: ${summary.dominantElement}</span>` : nothing}
341
+ ${summary.dominantModality ? html`<span class="pill">Dominant modality: ${summary.dominantModality}</span>` : nothing}
342
+ </div>` : nothing}
343
+ ${ai ? html`<div class="pill-row">
344
+ <span class="pill pill--success">Harmonious ${ai.harmonious}</span>
345
+ <span class="pill pill--danger">Challenging ${ai.challenging}</span>
346
+ <span class="pill pill--muted">Neutral ${ai.neutral}</span>
347
+ </div>` : nothing}
348
+ ${retrogrades.length > 0 ? html`<div class="pill-row">
349
+ ${retrogrades.map((p) => {
350
+ const glyph = PLANET_GLYPH[p] ?? p.slice(0, 2);
351
+ return html`<span class="pill pill--muted">${glyph} ${p} R</span>`;
352
+ })}
353
+ </div>` : nothing}
354
+ ${ai?.summary ? html`<p class="summary">${ai.summary}</p>` : nothing}
355
+ ${Object.keys(elementDist).length > 0 || Object.keys(modalityDist).length > 0 ? html`<div class="dist-grid">
356
+ ${Object.keys(elementDist).length > 0 ? html`<div class="dist-section">
357
+ <h3>Elements</h3>
358
+ ${Object.entries(elementDist).map(
359
+ ([label, count]) => html`<div class="dist-row">
360
+ <span>${label}</span>
361
+ <div class="dist-bar"><span style="width: ${Math.round(count / elementMax * 100)}%"></span></div>
362
+ <span>${count}</span>
363
+ </div>`
364
+ )}
365
+ </div>` : nothing}
366
+ ${Object.keys(modalityDist).length > 0 ? html`<div class="dist-section">
367
+ <h3>Modalities</h3>
368
+ ${Object.entries(modalityDist).map(
369
+ ([label, count]) => html`<div class="dist-row">
370
+ <span>${label}</span>
371
+ <div class="dist-bar"><span style="width: ${Math.round(count / modalityMax * 100)}%"></span></div>
372
+ <span>${count}</span>
373
+ </div>`
374
+ )}
375
+ </div>` : nothing}
376
+ </div>` : nothing}
377
+ </div>`;
378
+ }
379
+ renderInterpretations() {
380
+ const planets = this.getPlanets().filter((p) => p.interpretation);
381
+ if (planets.length === 0) return nothing;
382
+ return html`<section class="interpretations">
383
+ <h3>Planet readings</h3>
384
+ ${planets.map((p) => {
385
+ const interp = p.interpretation;
386
+ const glyph = PLANET_GLYPH[capitalize(p.name)] ?? "";
387
+ const deg = formatNumber(p.degree ?? 0, 1);
388
+ return html`<details class="interp-card">
389
+ <summary>${glyph} ${p.name} <small>${p.sign ?? ""} ${deg}</small></summary>
390
+ <div class="interp-body">
391
+ ${interp.summary ? html`<p class="interp-summary">${interp.summary}</p>` : nothing}
392
+ ${interp.detailed ? html`<p class="interp-detail">${interp.detailed}</p>` : nothing}
393
+ ${interp.keywords?.length ? html`<div class="interp-keywords">${interp.keywords.map((k) => html`<span class="kw">${k}</span>`)}</div>` : nothing}
394
+ </div>
395
+ </details>`;
396
+ })}
397
+ </section>`;
398
+ }
304
399
  renderAspects(planets, aspects) {
305
400
  const planetMap = /* @__PURE__ */ new Map();
306
401
  for (const p of planets) {
307
- const lon = typeof p.longitude === "number" ? p.longitude : typeof p.degree === "number" ? p.degree : null;
308
- if (lon === null) continue;
309
- const name = capitalize(p.name ?? p.planet ?? "");
310
- if (name) planetMap.set(name, lon);
402
+ if (typeof p.longitude !== "number") continue;
403
+ const name = capitalize(p.name);
404
+ if (name) planetMap.set(name, p.longitude);
311
405
  }
312
406
  return aspects.map((a) => {
313
- const l1 = planetMap.get(capitalize(a.planet1 ?? ""));
314
- const l2 = planetMap.get(capitalize(a.planet2 ?? ""));
407
+ const l1 = planetMap.get(capitalize(a.planet1));
408
+ const l2 = planetMap.get(capitalize(a.planet2));
315
409
  if (l1 === void 0 || l2 === void 0) return nothing;
316
- const p1 = polarToCartesian(CENTER, CENTER, PLANET_R - 18, l1 - 90);
317
- const p2 = polarToCartesian(CENTER, CENTER, PLANET_R - 18, l2 - 90);
318
- return svg`<line class="aspect" x1=${p1.x} y1=${p1.y} x2=${p2.x} y2=${p2.y} />`;
410
+ const p1 = polarToCartesian(
411
+ CENTER,
412
+ CENTER,
413
+ PLANET_R - 18,
414
+ this.toAngle(l1)
415
+ );
416
+ const p2 = polarToCartesian(
417
+ CENTER,
418
+ CENTER,
419
+ PLANET_R - 18,
420
+ this.toAngle(l2)
421
+ );
422
+ const aspectName = normalizeAspect(a);
423
+ const aspectClass = ASPECT_CLASS[aspectName] ?? "aspect-other";
424
+ const orbLabel = formatNumber(a.orb, 1);
425
+ 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
426
  });
320
427
  }
321
428
  };
@@ -373,9 +480,36 @@ RoxyNatalChart.styles = [
373
480
  }
374
481
 
375
482
  .aspect {
376
- stroke: color-mix(in srgb, var(--roxy-accent, #f59e0b) 32%, transparent);
377
- stroke-width: 0.6;
483
+ stroke-width: 0.8;
378
484
  fill: none;
485
+ opacity: 0.55;
486
+ }
487
+ .aspect-trine,
488
+ .aspect-sextile {
489
+ stroke: var(--roxy-success, #16a34a);
490
+ }
491
+ .aspect-square,
492
+ .aspect-opposition {
493
+ stroke: var(--roxy-danger, #dc2626);
494
+ }
495
+ .aspect-conjunction {
496
+ stroke: var(--roxy-accent-fg, #b45309);
497
+ }
498
+ .aspect-other {
499
+ stroke: var(--roxy-muted, #71717a);
500
+ opacity: 0.4;
501
+ }
502
+
503
+ .angle-marker {
504
+ fill: var(--roxy-accent-fg, #b45309);
505
+ font-size: 10px;
506
+ font-weight: 700;
507
+ font-family: var(--roxy-font-sans);
508
+ letter-spacing: 0.04em;
509
+ }
510
+ .angle-tick {
511
+ stroke: var(--roxy-accent-fg, #b45309);
512
+ stroke-width: 1.5;
379
513
  }
380
514
 
381
515
  .legend {
@@ -385,6 +519,144 @@ RoxyNatalChart.styles = [
385
519
  flex-wrap: wrap;
386
520
  gap: var(--roxy-space-md, 1rem);
387
521
  }
522
+ .legend-swatch {
523
+ display: inline-block;
524
+ width: 8px;
525
+ height: 8px;
526
+ border-radius: 50%;
527
+ margin-right: 4px;
528
+ vertical-align: middle;
529
+ }
530
+
531
+ .details {
532
+ margin-top: var(--roxy-space-md, 1rem);
533
+ }
534
+
535
+ .pill-row {
536
+ display: flex;
537
+ flex-wrap: wrap;
538
+ gap: var(--roxy-space-xs, 0.25rem);
539
+ margin-bottom: var(--roxy-space-xs, 0.25rem);
540
+ }
541
+
542
+ .pill {
543
+ padding: 2px 8px;
544
+ border-radius: var(--roxy-radius-sm, 4px);
545
+ font-size: var(--roxy-text-xs, 0.75rem);
546
+ background: color-mix(in srgb, var(--roxy-fg, #0f172a) 8%, transparent);
547
+ color: var(--roxy-fg, #0f172a);
548
+ }
549
+
550
+ .pill--success {
551
+ background: color-mix(in srgb, var(--roxy-success, #16a34a) 15%, transparent);
552
+ color: var(--roxy-success, #16a34a);
553
+ }
554
+
555
+ .pill--danger {
556
+ background: color-mix(in srgb, var(--roxy-danger, #dc2626) 15%, transparent);
557
+ color: var(--roxy-danger, #dc2626);
558
+ }
559
+
560
+ .pill--muted {
561
+ background: color-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent);
562
+ color: var(--roxy-fg, #0a0a0a);
563
+ }
564
+
565
+ .summary {
566
+ color: var(--roxy-fg, #0f172a);
567
+ font-size: var(--roxy-text-sm, 0.875rem);
568
+ margin: var(--roxy-space-md, 1rem) 0;
569
+ }
570
+
571
+ .dist-grid {
572
+ display: grid;
573
+ grid-template-columns: 1fr 1fr;
574
+ gap: var(--roxy-space-md, 1rem);
575
+ }
576
+
577
+ @container (max-width: 639px) {
578
+ .dist-grid {
579
+ grid-template-columns: 1fr;
580
+ }
581
+ }
582
+
583
+ .dist-section h3 {
584
+ font-size: var(--roxy-text-xs, 0.75rem);
585
+ font-weight: var(--roxy-weight-bold, 600);
586
+ color: var(--roxy-muted, #71717a);
587
+ margin: 0 0 var(--roxy-space-xs, 0.25rem);
588
+ text-transform: uppercase;
589
+ letter-spacing: 0.05em;
590
+ }
591
+
592
+ .dist-row {
593
+ display: grid;
594
+ grid-template-columns: 4rem 1fr 1.5rem;
595
+ align-items: center;
596
+ gap: var(--roxy-space-xs, 0.25rem);
597
+ font-size: var(--roxy-text-xs, 0.75rem);
598
+ color: var(--roxy-fg, #0f172a);
599
+ margin-bottom: 4px;
600
+ }
601
+
602
+ .dist-bar {
603
+ background: color-mix(in srgb, var(--roxy-accent, #f59e0b) 20%, transparent);
604
+ height: 6px;
605
+ border-radius: 3px;
606
+ }
607
+
608
+ .dist-bar > span {
609
+ display: block;
610
+ height: 100%;
611
+ background: var(--roxy-accent, #f59e0b);
612
+ border-radius: 3px;
613
+ }
614
+
615
+ .interpretations {
616
+ margin-top: var(--roxy-space-md, 1rem);
617
+ }
618
+ .interpretations h3 {
619
+ font-size: var(--roxy-text-sm, 0.875rem);
620
+ font-weight: 600;
621
+ color: var(--roxy-muted, #71717a);
622
+ text-transform: uppercase;
623
+ letter-spacing: 0.06em;
624
+ margin: 0 0 var(--roxy-space-sm, 0.5rem);
625
+ }
626
+ .interp-card {
627
+ border: 1px solid var(--roxy-border, #e4e4e7);
628
+ border-radius: var(--roxy-radius-md, 8px);
629
+ padding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);
630
+ margin-bottom: var(--roxy-space-xs, 0.25rem);
631
+ }
632
+ .interp-card summary {
633
+ cursor: pointer;
634
+ font-weight: 500;
635
+ color: var(--roxy-fg, #0f172a);
636
+ }
637
+ .interp-card summary small {
638
+ color: var(--roxy-muted, #71717a);
639
+ margin-left: 0.5em;
640
+ font-weight: 400;
641
+ }
642
+ .interp-body {
643
+ margin-top: var(--roxy-space-xs, 0.25rem);
644
+ color: var(--roxy-fg, #0f172a);
645
+ font-size: var(--roxy-text-sm, 0.875rem);
646
+ }
647
+ .interp-keywords {
648
+ display: flex;
649
+ flex-wrap: wrap;
650
+ gap: 0.25rem;
651
+ margin-top: 0.5rem;
652
+ }
653
+ .interp-keywords .kw {
654
+ padding: 1px 8px;
655
+ border-radius: 9999px;
656
+ background: color-mix(in srgb, var(--roxy-accent, #f59e0b) 14%, transparent);
657
+ color: var(--roxy-accent-fg, #b45309);
658
+ font-size: var(--roxy-text-xs, 0.75rem);
659
+ }
388
660
  `
389
661
  ];
390
662
  __decorateClass([
@@ -396,12 +668,7 @@ __decorateClass([
396
668
  RoxyNatalChart = __decorateClass([
397
669
  customElement("roxy-natal-chart")
398
670
  ], RoxyNatalChart);
399
- function capitalize(s) {
400
- if (!s) return "";
401
- return s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();
402
- }
403
671
  export {
404
- RoxyNatalChart,
405
- longitudeToSignPosition
672
+ RoxyNatalChart
406
673
  };
407
674
  //# sourceMappingURL=natal-chart.js.map