@roxyapi/ui 0.8.1 → 0.10.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 (194) hide show
  1. package/AGENTS.md +54 -13
  2. package/README.md +33 -22
  3. package/THEMING.md +7 -5
  4. package/dist/cdn/components/angel-number-card.js +45 -0
  5. package/dist/cdn/components/angel-number-card.js.map +7 -0
  6. package/dist/cdn/components/angel-number-lookup.js +45 -0
  7. package/dist/cdn/components/angel-number-lookup.js.map +7 -0
  8. package/dist/cdn/components/ashtakavarga-grid.js +3 -3
  9. package/dist/cdn/components/ashtakavarga-grid.js.map +3 -3
  10. package/dist/cdn/components/biorhythm-chart.js +3 -3
  11. package/dist/cdn/components/biorhythm-chart.js.map +3 -3
  12. package/dist/cdn/components/bodygraph.js +8 -8
  13. package/dist/cdn/components/bodygraph.js.map +3 -3
  14. package/dist/cdn/components/choghadiya-grid.js +3 -3
  15. package/dist/cdn/components/choghadiya-grid.js.map +3 -3
  16. package/dist/cdn/components/compatibility-card.js +2 -2
  17. package/dist/cdn/components/compatibility-card.js.map +3 -3
  18. package/dist/cdn/components/crystal-grid.js +45 -0
  19. package/dist/cdn/components/crystal-grid.js.map +7 -0
  20. package/dist/cdn/components/dasha-timeline.js +2 -2
  21. package/dist/cdn/components/dasha-timeline.js.map +3 -3
  22. package/dist/cdn/components/data.js +2 -2
  23. package/dist/cdn/components/data.js.map +3 -3
  24. package/dist/cdn/components/divisional-chart.js +7 -7
  25. package/dist/cdn/components/divisional-chart.js.map +3 -3
  26. package/dist/cdn/components/dosha-card.js +3 -3
  27. package/dist/cdn/components/dosha-card.js.map +3 -3
  28. package/dist/cdn/components/dream-card.js +45 -0
  29. package/dist/cdn/components/dream-card.js.map +7 -0
  30. package/dist/cdn/components/forecast-timeline.js +3 -3
  31. package/dist/cdn/components/forecast-timeline.js.map +3 -3
  32. package/dist/cdn/components/guna-milan.js +3 -3
  33. package/dist/cdn/components/guna-milan.js.map +3 -3
  34. package/dist/cdn/components/hexagram.js +2 -2
  35. package/dist/cdn/components/hexagram.js.map +3 -3
  36. package/dist/cdn/components/horoscope-card.js +3 -3
  37. package/dist/cdn/components/horoscope-card.js.map +3 -3
  38. package/dist/cdn/components/kp-chart.js +2 -2
  39. package/dist/cdn/components/kp-chart.js.map +3 -3
  40. package/dist/cdn/components/kp-planets-table.js +3 -3
  41. package/dist/cdn/components/kp-planets-table.js.map +3 -3
  42. package/dist/cdn/components/kp-ruling-planets.js +3 -3
  43. package/dist/cdn/components/kp-ruling-planets.js.map +3 -3
  44. package/dist/cdn/components/moon-phase.js +3 -3
  45. package/dist/cdn/components/moon-phase.js.map +3 -3
  46. package/dist/cdn/components/nakshatra-card.js +3 -3
  47. package/dist/cdn/components/nakshatra-card.js.map +3 -3
  48. package/dist/cdn/components/natal-chart.js +2 -2
  49. package/dist/cdn/components/natal-chart.js.map +3 -3
  50. package/dist/cdn/components/numerology-card.js +3 -3
  51. package/dist/cdn/components/numerology-card.js.map +3 -3
  52. package/dist/cdn/components/panchang-table.js +2 -2
  53. package/dist/cdn/components/panchang-table.js.map +3 -3
  54. package/dist/cdn/components/shadbala-table.js +3 -3
  55. package/dist/cdn/components/shadbala-table.js.map +3 -3
  56. package/dist/cdn/components/synastry-chart.js +5 -5
  57. package/dist/cdn/components/synastry-chart.js.map +3 -3
  58. package/dist/cdn/components/tarot-card.js.map +3 -3
  59. package/dist/cdn/components/tarot-spread.js +3 -3
  60. package/dist/cdn/components/tarot-spread.js.map +3 -3
  61. package/dist/cdn/components/transits-table.js +3 -3
  62. package/dist/cdn/components/transits-table.js.map +3 -3
  63. package/dist/cdn/components/vedic-kundli.js +16 -16
  64. package/dist/cdn/components/vedic-kundli.js.map +3 -3
  65. package/dist/cdn/components/vedic-planets-table.js +3 -3
  66. package/dist/cdn/components/vedic-planets-table.js.map +3 -3
  67. package/dist/cdn/components/western-planets-table.js +2 -2
  68. package/dist/cdn/components/western-planets-table.js.map +3 -3
  69. package/dist/cdn/components/yoga-list.js +2 -2
  70. package/dist/cdn/components/yoga-list.js.map +3 -3
  71. package/dist/cdn/roxy-ui.js +289 -66
  72. package/dist/cdn/roxy-ui.js.map +4 -4
  73. package/dist/cdn.d.ts +8 -0
  74. package/dist/cdn.d.ts.map +1 -0
  75. package/dist/components/angel-number-card.d.ts +18 -0
  76. package/dist/components/angel-number-card.d.ts.map +1 -0
  77. package/dist/components/angel-number-card.js +2 -0
  78. package/dist/components/angel-number-card.js.map +7 -0
  79. package/dist/components/angel-number-lookup.d.ts +18 -0
  80. package/dist/components/angel-number-lookup.d.ts.map +1 -0
  81. package/dist/components/angel-number-lookup.js +2 -0
  82. package/dist/components/angel-number-lookup.js.map +7 -0
  83. package/dist/components/ashtakavarga-grid.js +1 -1
  84. package/dist/components/ashtakavarga-grid.js.map +3 -3
  85. package/dist/components/biorhythm-chart.js +1 -1
  86. package/dist/components/biorhythm-chart.js.map +3 -3
  87. package/dist/components/bodygraph.js +4 -4
  88. package/dist/components/bodygraph.js.map +3 -3
  89. package/dist/components/choghadiya-grid.js +1 -1
  90. package/dist/components/choghadiya-grid.js.map +3 -3
  91. package/dist/components/compatibility-card.js +1 -1
  92. package/dist/components/compatibility-card.js.map +3 -3
  93. package/dist/components/crystal-grid.d.ts +27 -0
  94. package/dist/components/crystal-grid.d.ts.map +1 -0
  95. package/dist/components/crystal-grid.js +2 -0
  96. package/dist/components/crystal-grid.js.map +7 -0
  97. package/dist/components/dasha-timeline.js +1 -1
  98. package/dist/components/dasha-timeline.js.map +3 -3
  99. package/dist/components/data.js +1 -1
  100. package/dist/components/data.js.map +3 -3
  101. package/dist/components/divisional-chart.js +34 -34
  102. package/dist/components/divisional-chart.js.map +3 -3
  103. package/dist/components/dosha-card.js +1 -1
  104. package/dist/components/dosha-card.js.map +3 -3
  105. package/dist/components/dream-card.d.ts +17 -0
  106. package/dist/components/dream-card.d.ts.map +1 -0
  107. package/dist/components/dream-card.js +2 -0
  108. package/dist/components/dream-card.js.map +7 -0
  109. package/dist/components/forecast-timeline.js.map +3 -3
  110. package/dist/components/guna-milan.js +1 -1
  111. package/dist/components/guna-milan.js.map +3 -3
  112. package/dist/components/hexagram.js +1 -1
  113. package/dist/components/hexagram.js.map +3 -3
  114. package/dist/components/horoscope-card.js +1 -1
  115. package/dist/components/horoscope-card.js.map +3 -3
  116. package/dist/components/kp-chart.js +1 -1
  117. package/dist/components/kp-chart.js.map +3 -3
  118. package/dist/components/kp-planets-table.js +1 -1
  119. package/dist/components/kp-planets-table.js.map +3 -3
  120. package/dist/components/kp-ruling-planets.js +1 -1
  121. package/dist/components/kp-ruling-planets.js.map +3 -3
  122. package/dist/components/moon-phase.js +1 -1
  123. package/dist/components/moon-phase.js.map +3 -3
  124. package/dist/components/nakshatra-card.js +1 -1
  125. package/dist/components/nakshatra-card.js.map +3 -3
  126. package/dist/components/natal-chart.js +5 -5
  127. package/dist/components/natal-chart.js.map +3 -3
  128. package/dist/components/numerology-card.d.ts +7 -3
  129. package/dist/components/numerology-card.d.ts.map +1 -1
  130. package/dist/components/numerology-card.js +1 -1
  131. package/dist/components/numerology-card.js.map +3 -3
  132. package/dist/components/panchang-table.js +1 -1
  133. package/dist/components/panchang-table.js.map +3 -3
  134. package/dist/components/shadbala-table.js +1 -1
  135. package/dist/components/shadbala-table.js.map +3 -3
  136. package/dist/components/synastry-chart.js +4 -4
  137. package/dist/components/synastry-chart.js.map +3 -3
  138. package/dist/components/tarot-card.js +1 -1
  139. package/dist/components/tarot-card.js.map +3 -3
  140. package/dist/components/tarot-spread.js +1 -1
  141. package/dist/components/tarot-spread.js.map +3 -3
  142. package/dist/components/transits-table.js +1 -1
  143. package/dist/components/transits-table.js.map +3 -3
  144. package/dist/components/vedic-kundli.d.ts +18 -0
  145. package/dist/components/vedic-kundli.d.ts.map +1 -1
  146. package/dist/components/vedic-kundli.js +62 -62
  147. package/dist/components/vedic-kundli.js.map +3 -3
  148. package/dist/components/vedic-planets-table.js +1 -1
  149. package/dist/components/vedic-planets-table.js.map +3 -3
  150. package/dist/components/western-planets-table.js +1 -1
  151. package/dist/components/western-planets-table.js.map +3 -3
  152. package/dist/components/yoga-list.js +1 -1
  153. package/dist/components/yoga-list.js.map +3 -3
  154. package/dist/index.cjs +74 -74
  155. package/dist/index.cjs.map +4 -4
  156. package/dist/index.d.ts +5 -0
  157. package/dist/index.d.ts.map +1 -1
  158. package/dist/index.js +74 -74
  159. package/dist/index.js.map +4 -4
  160. package/dist/manifest.d.ts.map +1 -1
  161. package/dist/manifest.json +28 -24
  162. package/dist/styles/tokens-css.d.ts +2 -0
  163. package/dist/styles/tokens-css.d.ts.map +1 -0
  164. package/dist/styles/tokens.css +26 -11
  165. package/dist/types/index.d.ts +1 -1
  166. package/dist/types/index.d.ts.map +1 -1
  167. package/dist/types/types.gen.d.ts +43 -26
  168. package/dist/types/types.gen.d.ts.map +1 -1
  169. package/dist/utils/inject-tokens.d.ts +16 -0
  170. package/dist/utils/inject-tokens.d.ts.map +1 -0
  171. package/dist/utils/kundli-render.d.ts +2 -1
  172. package/dist/utils/kundli-render.d.ts.map +1 -1
  173. package/dist/utils/markup-data.d.ts +34 -0
  174. package/dist/utils/markup-data.d.ts.map +1 -1
  175. package/dist/version.d.ts +1 -1
  176. package/dist/version.d.ts.map +1 -1
  177. package/package.json +1 -1
  178. package/src/cdn.ts +15 -0
  179. package/src/components/angel-number-card.ts +234 -0
  180. package/src/components/angel-number-lookup.ts +208 -0
  181. package/src/components/crystal-grid.ts +191 -0
  182. package/src/components/dream-card.ts +98 -0
  183. package/src/components/numerology-card.ts +22 -10
  184. package/src/components/vedic-kundli.ts +37 -2
  185. package/src/index.ts +14 -0
  186. package/src/manifest.ts +57 -5
  187. package/src/styles/tokens-css.ts +225 -0
  188. package/src/styles/tokens.css +26 -11
  189. package/src/types/index.ts +1 -1
  190. package/src/types/types.gen.ts +43 -26
  191. package/src/utils/inject-tokens.ts +27 -0
  192. package/src/utils/kundli-render.ts +9 -2
  193. package/src/utils/markup-data.ts +45 -0
  194. package/src/version.ts +1 -1
@@ -0,0 +1,191 @@
1
+ import { css, html, LitElement, nothing } from 'lit';
2
+ import { customElement, property } from 'lit/decorators.js';
3
+ import type {
4
+ GetBirthstonesResponse,
5
+ GetCrystalsByChakraResponse,
6
+ GetCrystalsByElementResponse,
7
+ GetCrystalsByZodiacResponse,
8
+ ListCrystalsResponse,
9
+ SearchCrystalsResponse,
10
+ } from '../types/index.js';
11
+ import { baseStyles } from '../utils/base-styles.js';
12
+ import { MarkupDataController } from '../utils/markup-data.js';
13
+
14
+ /**
15
+ * Any crystal list response that carries a `crystals` summary array. Every crystals endpoint that returns more than one stone shares the `{ name, id, imageUrl, colors }` item shape, so one grid renders them all.
16
+ */
17
+ type CrystalGridData =
18
+ | ListCrystalsResponse
19
+ | GetCrystalsByChakraResponse
20
+ | GetCrystalsByElementResponse
21
+ | GetCrystalsByZodiacResponse
22
+ | GetBirthstonesResponse
23
+ | SearchCrystalsResponse;
24
+
25
+ /**
26
+ * Month number to birthstone month name for the derived heading.
27
+ */
28
+ const MONTHS = [
29
+ 'January',
30
+ 'February',
31
+ 'March',
32
+ 'April',
33
+ 'May',
34
+ 'June',
35
+ 'July',
36
+ 'August',
37
+ 'September',
38
+ 'October',
39
+ 'November',
40
+ 'December',
41
+ ];
42
+
43
+ /**
44
+ * Crystal grid. Renders any crystals list response (/crystals, /crystals/chakra/{chakra}, /crystals/element/{element}, /crystals/zodiac/{sign}, /crystals/birthstone/{month}, /crystals/search) as a responsive gallery of crystal tiles with photo, name, and colour swatches. The heading is derived from the response filter (chakra, element, zodiac sign, or birth month) or set explicitly via the `heading` attribute.
45
+ */
46
+ @customElement('roxy-crystal-grid')
47
+ export class RoxyCrystalGrid extends LitElement {
48
+ static styles = [
49
+ baseStyles,
50
+ css`
51
+ .wrap {
52
+ display: grid;
53
+ gap: var(--roxy-space-md, 1rem);
54
+ }
55
+ .head {
56
+ display: flex;
57
+ align-items: baseline;
58
+ justify-content: space-between;
59
+ gap: var(--roxy-space-sm, 0.5rem);
60
+ flex-wrap: wrap;
61
+ }
62
+ .title {
63
+ margin: 0;
64
+ font-size: var(--roxy-text-lg, 1.125rem);
65
+ font-weight: var(--roxy-weight-bold, 600);
66
+ color: var(--roxy-fg, #0a0a0a);
67
+ }
68
+ .count {
69
+ color: var(--roxy-muted, #71717a);
70
+ font-size: var(--roxy-text-sm, 0.875rem);
71
+ }
72
+ .grid {
73
+ display: grid;
74
+ grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
75
+ gap: var(--roxy-space-md, 1rem);
76
+ margin: 0;
77
+ padding: 0;
78
+ list-style: none;
79
+ }
80
+ .tile {
81
+ display: grid;
82
+ gap: var(--roxy-space-xs, 0.25rem);
83
+ background: var(--roxy-bg, #fff);
84
+ border: 1px solid var(--roxy-border, #e4e4e7);
85
+ border-radius: var(--roxy-radius-md, 8px);
86
+ padding: var(--roxy-space-sm, 0.5rem);
87
+ box-shadow: var(--roxy-shadow-sm);
88
+ }
89
+ .photo {
90
+ aspect-ratio: 1 / 1;
91
+ width: 100%;
92
+ border-radius: var(--roxy-radius-sm, 4px);
93
+ object-fit: cover;
94
+ background: color-mix(in srgb, var(--roxy-border, #e4e4e7) 35%, transparent);
95
+ }
96
+ .name {
97
+ margin: 0;
98
+ font-size: var(--roxy-text-sm, 0.875rem);
99
+ font-weight: var(--roxy-weight-bold, 600);
100
+ color: var(--roxy-fg, #0a0a0a);
101
+ }
102
+ .colors {
103
+ display: flex;
104
+ flex-wrap: wrap;
105
+ gap: 4px;
106
+ }
107
+ .swatch {
108
+ width: 10px;
109
+ height: 10px;
110
+ border-radius: var(--roxy-radius-full, 9999px);
111
+ border: 1px solid color-mix(in srgb, var(--roxy-fg, #0a0a0a) 18%, transparent);
112
+ }
113
+ `,
114
+ ];
115
+
116
+ constructor() {
117
+ super();
118
+ // Enables hydrating `data` from a direct-child
119
+ // <script type="application/json" class="roxy-data"> for server-rendered
120
+ // and cached consumers. The JavaScript `data` property still wins.
121
+ new MarkupDataController(this);
122
+ }
123
+
124
+ @property({ attribute: false })
125
+ data: CrystalGridData | null = null;
126
+
127
+ /**
128
+ * Override the auto-derived grid heading. Empty by default, in which case the heading comes from the response filter (chakra, element, zodiac, or birth month) or falls back to "Crystals".
129
+ */
130
+ @property({ type: String, reflect: true })
131
+ heading = '';
132
+
133
+ render() {
134
+ const d = this.data;
135
+ const crystals = d?.crystals ?? [];
136
+ if (!d || crystals.length === 0)
137
+ return html`<div class="roxy-empty" role="status">No crystals</div>`;
138
+
139
+ const title = this.heading || this.deriveHeading(d);
140
+ const total =
141
+ 'total' in d && typeof d.total === 'number' ? d.total : crystals.length;
142
+
143
+ return html`<section class="wrap" aria-label=${title}>
144
+ <header class="head">
145
+ <h2 class="title">${title}</h2>
146
+ <span class="count">${total} ${total === 1 ? 'crystal' : 'crystals'}</span>
147
+ </header>
148
+ <ul class="grid">
149
+ ${crystals.map(
150
+ (c) => html`<li class="tile">
151
+ ${
152
+ c.imageUrl
153
+ ? html`<img class="photo" src=${c.imageUrl} alt=${c.name ?? 'Crystal'} loading="lazy" />`
154
+ : html`<div class="photo" aria-hidden="true"></div>`
155
+ }
156
+ <p class="name">${c.name}</p>
157
+ ${
158
+ c.colors && c.colors.length > 0
159
+ ? html`<div class="colors" aria-label=${`Colours: ${c.colors.join(', ')}`}>
160
+ ${c.colors.map((col) => html`<span class="swatch" style=${`background:${cssColor(col)}`} title=${col}></span>`)}
161
+ </div>`
162
+ : nothing
163
+ }
164
+ </li>`,
165
+ )}
166
+ </ul>
167
+ </section>`;
168
+ }
169
+
170
+ private deriveHeading(d: CrystalGridData): string {
171
+ if ('chakra' in d && d.chakra) return `${d.chakra} chakra crystals`;
172
+ if ('element' in d && d.element) return `${d.element} element crystals`;
173
+ if ('sign' in d && d.sign) return `Crystals for ${d.sign}`;
174
+ if ('month' in d && typeof d.month === 'number')
175
+ return `${MONTHS[d.month - 1] ?? ''} birthstones`.trim();
176
+ return 'Crystals';
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Map an API colour keyword to a CSS colour. Most crystal colours (violet, purple, green, blue) are valid CSS named colours; multi-word or non-standard values (blue-green, lavender) fall back to the keyword and, if the browser cannot resolve it, the swatch border still renders. Lower-cased and space-stripped so "Blue Green" resolves to the CSS hyphen form where it exists.
182
+ */
183
+ function cssColor(name: string): string {
184
+ return name.trim().toLowerCase().replace(/\s+/g, '');
185
+ }
186
+
187
+ declare global {
188
+ interface HTMLElementTagNameMap {
189
+ 'roxy-crystal-grid': RoxyCrystalGrid;
190
+ }
191
+ }
@@ -0,0 +1,98 @@
1
+ import { css, html, LitElement, nothing } from 'lit';
2
+ import { customElement, property } from 'lit/decorators.js';
3
+ import type { GetDreamSymbolResponse } from '../types/index.js';
4
+ import { baseStyles } from '../utils/base-styles.js';
5
+ import { MarkupDataController } from '../utils/markup-data.js';
6
+
7
+ /**
8
+ * Dream symbol card. Renders /dreams/symbols/{id}: the symbol name as a heading, the full psychological interpretation as the body, and the dictionary letter as a chip for alphabetical context.
9
+ */
10
+ @customElement('roxy-dream-card')
11
+ export class RoxyDreamCard extends LitElement {
12
+ static styles = [
13
+ baseStyles,
14
+ css`
15
+ .card {
16
+ background: var(--roxy-bg, #fff);
17
+ border: 1px solid var(--roxy-border, #e4e4e7);
18
+ border-radius: var(--roxy-radius-md, 8px);
19
+ padding: var(--roxy-space-lg, 1.5rem);
20
+ box-shadow: var(--roxy-shadow-sm);
21
+ display: grid;
22
+ gap: var(--roxy-space-md, 1rem);
23
+ }
24
+ .head {
25
+ display: flex;
26
+ align-items: center;
27
+ gap: var(--roxy-space-md, 1rem);
28
+ }
29
+ .letter {
30
+ display: inline-flex;
31
+ align-items: center;
32
+ justify-content: center;
33
+ width: 2.5rem;
34
+ height: 2.5rem;
35
+ flex: none;
36
+ border-radius: var(--roxy-radius-full, 9999px);
37
+ background: color-mix(in srgb, var(--roxy-accent, #f59e0b) 16%, transparent);
38
+ color: var(--roxy-accent-ink, #b45309);
39
+ font-size: var(--roxy-text-lg, 1.125rem);
40
+ font-weight: var(--roxy-weight-bold, 600);
41
+ text-transform: uppercase;
42
+ font-variant-numeric: tabular-nums;
43
+ }
44
+ .label {
45
+ margin: 0;
46
+ font-size: var(--roxy-text-xs, 0.75rem);
47
+ color: var(--roxy-muted, #71717a);
48
+ text-transform: uppercase;
49
+ letter-spacing: 0.06em;
50
+ }
51
+ .name {
52
+ margin: 0;
53
+ font-size: var(--roxy-text-lg, 1.125rem);
54
+ font-weight: var(--roxy-weight-bold, 600);
55
+ color: var(--roxy-fg, #0a0a0a);
56
+ }
57
+ .meaning {
58
+ margin: 0;
59
+ color: var(--roxy-fg, #0a0a0a);
60
+ line-height: 1.6;
61
+ }
62
+ `,
63
+ ];
64
+
65
+ constructor() {
66
+ super();
67
+ // Enables hydrating `data` from a direct-child
68
+ // <script type="application/json" class="roxy-data"> for server-rendered
69
+ // and cached consumers. The JavaScript `data` property still wins.
70
+ new MarkupDataController(this);
71
+ }
72
+
73
+ @property({ attribute: false })
74
+ data: GetDreamSymbolResponse | null = null;
75
+
76
+ render() {
77
+ const d = this.data;
78
+ if (!d)
79
+ return html`<div class="roxy-empty" role="status">No dream symbol</div>`;
80
+
81
+ return html`<article class="card" aria-label=${d.name ?? 'Dream symbol'}>
82
+ <header class="head">
83
+ ${d.letter ? html`<span class="letter" aria-hidden="true">${d.letter}</span>` : nothing}
84
+ <div>
85
+ <p class="label">Dream symbol</p>
86
+ ${d.name ? html`<h2 class="name">${d.name}</h2>` : nothing}
87
+ </div>
88
+ </header>
89
+ ${d.meaning ? html`<p class="meaning">${d.meaning}</p>` : nothing}
90
+ </article>`;
91
+ }
92
+ }
93
+
94
+ declare global {
95
+ interface HTMLElementTagNameMap {
96
+ 'roxy-dream-card': RoxyDreamCard;
97
+ }
98
+ }
@@ -3,16 +3,26 @@ import { customElement, property } from 'lit/decorators.js';
3
3
  import type {
4
4
  CalculateExpressionResponse,
5
5
  CalculateLifePathResponse,
6
+ CalculatePersonalityResponse,
6
7
  CalculatePersonalYearResponse,
8
+ CalculateSoulUrgeResponse,
7
9
  GenerateNumerologyChartResponse,
8
10
  } from '../types/index.js';
9
11
  import { baseStyles } from '../utils/base-styles.js';
10
12
  import { MarkupDataController } from '../utils/markup-data.js';
11
13
  import { humanize } from '../utils/string.js';
12
14
 
13
- type NumerologyData =
15
+ /**
16
+ * Single-number numerology responses that share the number + meaning + calculation + karmic-debt shape. {@link RoxyNumerologyCard.renderNumberCard} renders any of them; the `type` attribute selects only the heading label.
17
+ */
18
+ type NumberCardData =
14
19
  | CalculateLifePathResponse
15
20
  | CalculateExpressionResponse
21
+ | CalculateSoulUrgeResponse
22
+ | CalculatePersonalityResponse;
23
+
24
+ type NumerologyData =
25
+ | NumberCardData
16
26
  | CalculatePersonalYearResponse
17
27
  | GenerateNumerologyChartResponse;
18
28
 
@@ -135,7 +145,13 @@ export class RoxyNumerologyCard extends LitElement {
135
145
  data: NumerologyData | null = null;
136
146
 
137
147
  @property({ type: String, reflect: true })
138
- type: 'life-path' | 'expression' | 'personal-year' | 'chart' = 'life-path';
148
+ type:
149
+ | 'life-path'
150
+ | 'expression'
151
+ | 'soul-urge'
152
+ | 'personality'
153
+ | 'personal-year'
154
+ | 'chart' = 'life-path';
139
155
 
140
156
  render() {
141
157
  const d = this.data;
@@ -146,16 +162,10 @@ export class RoxyNumerologyCard extends LitElement {
146
162
 
147
163
  if ('coreNumbers' in d) return this.renderChart(d, headerLabel);
148
164
  if ('personalYear' in d) return this.renderPersonalYear(d, headerLabel);
149
- return this.renderNumberCard(
150
- d as CalculateLifePathResponse | CalculateExpressionResponse,
151
- headerLabel,
152
- );
165
+ return this.renderNumberCard(d as NumberCardData, headerLabel);
153
166
  }
154
167
 
155
- private renderNumberCard(
156
- d: CalculateLifePathResponse | CalculateExpressionResponse,
157
- headerLabel: string,
158
- ) {
168
+ private renderNumberCard(d: NumberCardData, headerLabel: string) {
159
169
  const keywords = d.meaning?.keywords ?? [];
160
170
  return html`<article class="card" aria-label=${headerLabel}>
161
171
  <div class="hero">
@@ -230,6 +240,8 @@ export class RoxyNumerologyCard extends LitElement {
230
240
  const LABELS: Record<string, string> = {
231
241
  'life-path': 'Life Path',
232
242
  expression: 'Expression',
243
+ 'soul-urge': 'Soul Urge',
244
+ personality: 'Personality',
233
245
  'personal-year': 'Personal Year',
234
246
  chart: 'Numerology chart',
235
247
  };
@@ -24,6 +24,12 @@ import { tablistStyles } from '../utils/tablist.js';
24
24
  * page sets the initial style via `chart-style` attribute; from there the
25
25
  * user takes over.
26
26
  *
27
+ * The ascendant (house 1) defaults to the Janma Lagna carried in the response
28
+ * `meta`. Set `chart-reference="moon"` to render the Chandra Lagna (Moon as
29
+ * ascendant) from the same response, or `lagna-override="<rashi>"` to pin the
30
+ * reference to any sign (Surya Lagna, Arudha Lagna, a custom point). The same
31
+ * planet-in-sign data feeds every reference; only the house numbering rotates.
32
+ *
27
33
  * Theming flows through CSS custom properties on `:host`, so the chart
28
34
  * adopts the host page palette without runtime color probing.
29
35
  */
@@ -45,9 +51,34 @@ export class RoxyVedicKundli extends LitElement {
45
51
  @property({ type: String, reflect: true, attribute: 'chart-style' })
46
52
  chartStyle: ChartStyle = 'north';
47
53
 
54
+ /**
55
+ * Ascendant reference point. `'lagna'` (default) uses the Janma Lagna from the response; `'moon'` renders the Chandra Lagna (Moon sign as house 1) from the same response. An explicit {@link lagnaOverride} wins over this.
56
+ */
57
+ @property({ type: String, reflect: true, attribute: 'chart-reference' })
58
+ chartReference: 'lagna' | 'moon' = 'lagna';
59
+
60
+ /**
61
+ * Explicit rashi/sign name (case-insensitive, e.g. `"cancer"`) to use as the ascendant, overriding both the Janma Lagna and {@link chartReference}. Empty by default (standard Janma Lagna). Use for Surya Lagna, Arudha Lagna, or any custom reference chart.
62
+ */
63
+ @property({ type: String, reflect: true, attribute: 'lagna-override' })
64
+ lagnaOverride = '';
65
+
66
+ /**
67
+ * Resolve the ascendant override fed to {@link toKundliViewModel}. An explicit `lagna-override` wins; otherwise `chart-reference="moon"` derives the Moon rashi from the response `meta`. Returns `undefined` for the default Janma Lagna path.
68
+ */
69
+ private resolveReference(): string | undefined {
70
+ if (this.lagnaOverride) return this.lagnaOverride;
71
+ if (this.chartReference === 'moon') return this.data?.meta?.Moon?.rashi;
72
+ return undefined;
73
+ }
74
+
48
75
  private viewModel(): KundliViewModel | null {
49
76
  if (!this.data?.meta) return null;
50
- return toKundliViewModel(this.data.meta, 'D1 Rashi');
77
+ return toKundliViewModel(
78
+ this.data.meta,
79
+ 'D1 Rashi',
80
+ this.resolveReference(),
81
+ );
51
82
  }
52
83
 
53
84
  private setStyle = (next: ChartStyle) => {
@@ -58,9 +89,13 @@ export class RoxyVedicKundli extends LitElement {
58
89
  const vm = this.viewModel();
59
90
  if (!vm)
60
91
  return html`<div class="roxy-empty" role="status">No kundli data</div>`;
92
+ const title =
93
+ this.chartReference === 'moon' && !this.lagnaOverride
94
+ ? 'Chandra lagna'
95
+ : 'Vedic kundli';
61
96
  return html`<div class="wrap">
62
97
  <div class="header">
63
- <h2 class="title">Vedic kundli</h2>
98
+ <h2 class="title">${title}</h2>
64
99
  ${renderKundliStyleTablist(this.chartStyle, this.setStyle)}
65
100
  </div>
66
101
  <svg
package/src/index.ts CHANGED
@@ -5,6 +5,9 @@
5
5
  * import '@roxyapi/ui/components/natal-chart';
6
6
  */
7
7
 
8
+ // Angel numbers
9
+ export { RoxyAngelNumberCard } from './components/angel-number-card.js';
10
+ export { RoxyAngelNumberLookup } from './components/angel-number-lookup.js';
8
11
  export { RoxyAshtakavargaGrid } from './components/ashtakavarga-grid.js';
9
12
  // Biorhythm
10
13
  export { RoxyBiorhythmChart } from './components/biorhythm-chart.js';
@@ -12,11 +15,15 @@ export { RoxyBiorhythmChart } from './components/biorhythm-chart.js';
12
15
  export { RoxyBodygraph } from './components/bodygraph.js';
13
16
  export { RoxyChoghadiyaGrid } from './components/choghadiya-grid.js';
14
17
  export { RoxyCompatibilityCard } from './components/compatibility-card.js';
18
+ // Crystals
19
+ export { RoxyCrystalGrid } from './components/crystal-grid.js';
15
20
  export { RoxyDashaTimeline } from './components/dasha-timeline.js';
16
21
  // Generic fallback first so it is always available for nested rendering
17
22
  export { RoxyData } from './components/data.js';
18
23
  export { RoxyDivisionalChart } from './components/divisional-chart.js';
19
24
  export { RoxyDoshaCard } from './components/dosha-card.js';
25
+ // Dreams
26
+ export { RoxyDreamCard } from './components/dream-card.js';
20
27
  // Helpers
21
28
  export { RoxyEndpointForm } from './components/endpoint-form.js';
22
29
  // Forecast
@@ -48,6 +55,13 @@ export { RoxyVedicPlanetsTable } from './components/vedic-planets-table.js';
48
55
  export { RoxyWesternPlanetsTable } from './components/western-planets-table.js';
49
56
  export { RoxyYogaList } from './components/yoga-list.js';
50
57
 
58
+ // SSR helpers for the server-rendered hydration path (Pattern 7). Safe writers
59
+ // for the inline <script class="roxy-data"> the MarkupDataController reads.
60
+ export {
61
+ roxyDataScript,
62
+ serializeRoxyData,
63
+ } from './utils/markup-data.js';
64
+
51
65
  import { ROXY_COMPONENTS, type RoxyComponentSlug } from './manifest.js';
52
66
 
53
67
  export {
package/src/manifest.ts CHANGED
@@ -130,10 +130,11 @@ export const ROXY_COMPONENTS: readonly RoxyComponent[] = [
130
130
  slug: 'vedic-kundli',
131
131
  heading: 'Vedic kundli',
132
132
  description:
133
- 'South, North, or East Indian Vedic kundli for /vedic-astrology/birth-chart with per-planet degree and nakshatra detail',
133
+ 'South, North, or East Indian Vedic kundli for /vedic-astrology/birth-chart with per-planet degree and nakshatra detail, plus an optional Chandra Lagna (Moon-as-ascendant) reference view',
134
134
  docsLabel: 'Vedic',
135
135
  endpointLabel: 'POST /vedic-astrology/birth-chart',
136
- docsSummary: 'South, North, or East Indian kundli with degree detail',
136
+ docsSummary:
137
+ 'South, North, or East Indian kundli with degree detail and optional Chandra Lagna view',
137
138
  topic: 'Vedic',
138
139
  },
139
140
  {
@@ -305,11 +306,12 @@ export const ROXY_COMPONENTS: readonly RoxyComponent[] = [
305
306
  slug: 'numerology-card',
306
307
  heading: 'Life path number',
307
308
  description:
308
- 'Numerology card for life path, expression, personal year, or full chart',
309
+ 'Numerology card for life path, expression, soul urge, personality, personal year, or full chart',
309
310
  docsLabel: 'Numerology',
310
311
  endpointLabel:
311
- 'POST /numerology/{life-path,expression,personal-year,chart}',
312
- docsSummary: 'Life path, expression, personal year, full chart',
312
+ 'POST /numerology/{life-path,expression,soul-urge,personality,personal-year,chart}',
313
+ docsSummary:
314
+ 'Life path, expression, soul urge, personality, personal year, full chart',
313
315
  topic: 'Numerology',
314
316
  },
315
317
  {
@@ -386,6 +388,56 @@ export const ROXY_COMPONENTS: readonly RoxyComponent[] = [
386
388
  docsSummary: 'Hexagram with trigrams, judgment, image, changing lines',
387
389
  topic: 'I Ching',
388
390
  },
391
+ {
392
+ pascal: 'RoxyCrystalGrid',
393
+ tag: 'roxy-crystal-grid',
394
+ slug: 'crystal-grid',
395
+ heading: 'Crystal grid',
396
+ description:
397
+ 'Responsive crystal gallery with photo, name, and colour swatches from any crystals list response',
398
+ docsLabel: 'Crystals',
399
+ endpointLabel:
400
+ 'GET /crystals, /crystals/chakra/{chakra}, /crystals/element/{element}, /crystals/zodiac/{sign}, /crystals/birthstone/{month}, /crystals/search',
401
+ docsSummary: 'Crystal gallery tiles with photo, name, and colour swatches',
402
+ topic: 'Crystals',
403
+ },
404
+ {
405
+ pascal: 'RoxyDreamCard',
406
+ tag: 'roxy-dream-card',
407
+ slug: 'dream-card',
408
+ heading: 'Dream symbol',
409
+ description:
410
+ 'Dream symbol card with the symbol name, full interpretation, and dictionary letter',
411
+ docsLabel: 'Dreams',
412
+ endpointLabel: 'GET /dreams/symbols/{id}',
413
+ docsSummary: 'Symbol name, interpretation body, and letter chip',
414
+ topic: 'Dreams',
415
+ },
416
+ {
417
+ pascal: 'RoxyAngelNumberCard',
418
+ tag: 'roxy-angel-number-card',
419
+ slug: 'angel-number-card',
420
+ heading: 'Angel number',
421
+ description:
422
+ 'Angel number card with title, core message, badges, keywords, life-area interpretations, affirmation, and action steps',
423
+ docsLabel: 'Angel Numbers',
424
+ endpointLabel: 'GET /angel-numbers/numbers/{number}',
425
+ docsSummary:
426
+ 'Number meaning with spiritual, love, career, and twin flame sections',
427
+ topic: 'Angel Numbers',
428
+ },
429
+ {
430
+ pascal: 'RoxyAngelNumberLookup',
431
+ tag: 'roxy-angel-number-lookup',
432
+ slug: 'angel-number-lookup',
433
+ heading: 'Angel number lookup',
434
+ description:
435
+ 'Angel number sequence analysis with pattern classification, the known meaning when present, and a digit-root fallback for any number',
436
+ docsLabel: 'Angel Numbers',
437
+ endpointLabel: 'GET /angel-numbers/lookup',
438
+ docsSummary: 'Pattern analysis plus known meaning and digit-root fallback',
439
+ topic: 'Angel Numbers',
440
+ },
389
441
  {
390
442
  pascal: 'RoxyEndpointForm',
391
443
  tag: 'roxy-endpoint-form',