@roxyapi/ui 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. package/AGENTS.md +228 -29
  2. package/README.md +291 -19
  3. package/dist/cdn/components/ashtakavarga-grid.js +74 -19
  4. package/dist/cdn/components/ashtakavarga-grid.js.map +2 -2
  5. package/dist/cdn/components/biorhythm-chart.js +18 -4
  6. package/dist/cdn/components/biorhythm-chart.js.map +2 -2
  7. package/dist/cdn/components/choghadiya-grid.js +47 -12
  8. package/dist/cdn/components/choghadiya-grid.js.map +3 -3
  9. package/dist/cdn/components/compatibility-card.js +21 -7
  10. package/dist/cdn/components/compatibility-card.js.map +2 -2
  11. package/dist/cdn/components/dasha-timeline.js +113 -28
  12. package/dist/cdn/components/dasha-timeline.js.map +3 -3
  13. package/dist/cdn/components/data.js +27 -13
  14. package/dist/cdn/components/data.js.map +2 -2
  15. package/dist/cdn/components/divisional-chart.js +225 -118
  16. package/dist/cdn/components/divisional-chart.js.map +4 -4
  17. package/dist/cdn/components/dosha-card.js +18 -4
  18. package/dist/cdn/components/dosha-card.js.map +2 -2
  19. package/dist/cdn/components/endpoint-form.js +25 -11
  20. package/dist/cdn/components/endpoint-form.js.map +2 -2
  21. package/dist/cdn/components/guna-milan.js +20 -6
  22. package/dist/cdn/components/guna-milan.js.map +2 -2
  23. package/dist/cdn/components/hexagram.js +22 -8
  24. package/dist/cdn/components/hexagram.js.map +2 -2
  25. package/dist/cdn/components/horoscope-card.js +20 -6
  26. package/dist/cdn/components/horoscope-card.js.map +2 -2
  27. package/dist/cdn/components/kp-chart.js +19 -5
  28. package/dist/cdn/components/kp-chart.js.map +2 -2
  29. package/dist/cdn/components/kp-planets-table.js +17 -3
  30. package/dist/cdn/components/kp-planets-table.js.map +2 -2
  31. package/dist/cdn/components/kp-ruling-planets.js +17 -3
  32. package/dist/cdn/components/kp-ruling-planets.js.map +2 -2
  33. package/dist/cdn/components/location-search.js +18 -4
  34. package/dist/cdn/components/location-search.js.map +2 -2
  35. package/dist/cdn/components/moon-phase.js +27 -13
  36. package/dist/cdn/components/moon-phase.js.map +2 -2
  37. package/dist/cdn/components/nakshatra-card.js +16 -2
  38. package/dist/cdn/components/nakshatra-card.js.map +2 -2
  39. package/dist/cdn/components/natal-chart.js +79 -40
  40. package/dist/cdn/components/natal-chart.js.map +3 -3
  41. package/dist/cdn/components/numerology-card.js +18 -4
  42. package/dist/cdn/components/numerology-card.js.map +2 -2
  43. package/dist/cdn/components/panchang-table.js +53 -25
  44. package/dist/cdn/components/panchang-table.js.map +3 -3
  45. package/dist/cdn/components/shadbala-table.js +24 -10
  46. package/dist/cdn/components/shadbala-table.js.map +2 -2
  47. package/dist/cdn/components/synastry-chart.js +96 -48
  48. package/dist/cdn/components/synastry-chart.js.map +3 -3
  49. package/dist/cdn/components/tarot-card.js +17 -3
  50. package/dist/cdn/components/tarot-card.js.map +2 -2
  51. package/dist/cdn/components/tarot-spread.js +39 -25
  52. package/dist/cdn/components/tarot-spread.js.map +2 -2
  53. package/dist/cdn/components/transits-table.js +18 -4
  54. package/dist/cdn/components/transits-table.js.map +2 -2
  55. package/dist/cdn/components/vedic-kundli.js +215 -105
  56. package/dist/cdn/components/vedic-kundli.js.map +4 -4
  57. package/dist/cdn/components/vedic-planets-table.js +22 -8
  58. package/dist/cdn/components/vedic-planets-table.js.map +2 -2
  59. package/dist/cdn/components/western-planets-table.js +18 -4
  60. package/dist/cdn/components/western-planets-table.js.map +2 -2
  61. package/dist/cdn/components/yoga-list.js +17 -3
  62. package/dist/cdn/components/yoga-list.js.map +2 -2
  63. package/dist/cdn/roxy-ui.js +1082 -816
  64. package/dist/cdn/roxy-ui.js.map +4 -4
  65. package/dist/components/ashtakavarga-grid.d.ts +13 -1
  66. package/dist/components/ashtakavarga-grid.d.ts.map +1 -1
  67. package/dist/components/ashtakavarga-grid.js +86 -11
  68. package/dist/components/ashtakavarga-grid.js.map +2 -2
  69. package/dist/components/biorhythm-chart.js +14 -0
  70. package/dist/components/biorhythm-chart.js.map +2 -2
  71. package/dist/components/choghadiya-grid.d.ts +6 -0
  72. package/dist/components/choghadiya-grid.d.ts.map +1 -1
  73. package/dist/components/choghadiya-grid.js +50 -2
  74. package/dist/components/choghadiya-grid.js.map +2 -2
  75. package/dist/components/compatibility-card.js +14 -0
  76. package/dist/components/compatibility-card.js.map +2 -2
  77. package/dist/components/dasha-timeline.d.ts +10 -0
  78. package/dist/components/dasha-timeline.d.ts.map +1 -1
  79. package/dist/components/dasha-timeline.js +135 -4
  80. package/dist/components/dasha-timeline.js.map +2 -2
  81. package/dist/components/data.js +14 -0
  82. package/dist/components/data.js.map +2 -2
  83. package/dist/components/divisional-chart.d.ts +9 -6
  84. package/dist/components/divisional-chart.d.ts.map +1 -1
  85. package/dist/components/divisional-chart.js +546 -251
  86. package/dist/components/divisional-chart.js.map +4 -4
  87. package/dist/components/dosha-card.js +14 -0
  88. package/dist/components/dosha-card.js.map +2 -2
  89. package/dist/components/endpoint-form.js +14 -0
  90. package/dist/components/endpoint-form.js.map +2 -2
  91. package/dist/components/guna-milan.js +14 -0
  92. package/dist/components/guna-milan.js.map +2 -2
  93. package/dist/components/hexagram.js +14 -0
  94. package/dist/components/hexagram.js.map +2 -2
  95. package/dist/components/horoscope-card.js +14 -0
  96. package/dist/components/horoscope-card.js.map +2 -2
  97. package/dist/components/kp-chart.js +14 -0
  98. package/dist/components/kp-chart.js.map +2 -2
  99. package/dist/components/kp-planets-table.js +14 -0
  100. package/dist/components/kp-planets-table.js.map +2 -2
  101. package/dist/components/kp-ruling-planets.js +14 -0
  102. package/dist/components/kp-ruling-planets.js.map +2 -2
  103. package/dist/components/location-search.js +14 -0
  104. package/dist/components/location-search.js.map +2 -2
  105. package/dist/components/moon-phase.js +14 -0
  106. package/dist/components/moon-phase.js.map +2 -2
  107. package/dist/components/nakshatra-card.js +14 -0
  108. package/dist/components/nakshatra-card.js.map +2 -2
  109. package/dist/components/natal-chart.d.ts.map +1 -1
  110. package/dist/components/natal-chart.js +76 -6
  111. package/dist/components/natal-chart.js.map +2 -2
  112. package/dist/components/numerology-card.js +14 -0
  113. package/dist/components/numerology-card.js.map +2 -2
  114. package/dist/components/panchang-table.d.ts +1 -0
  115. package/dist/components/panchang-table.d.ts.map +1 -1
  116. package/dist/components/panchang-table.js +37 -1
  117. package/dist/components/panchang-table.js.map +2 -2
  118. package/dist/components/shadbala-table.js +14 -0
  119. package/dist/components/shadbala-table.js.map +2 -2
  120. package/dist/components/synastry-chart.d.ts +6 -0
  121. package/dist/components/synastry-chart.d.ts.map +1 -1
  122. package/dist/components/synastry-chart.js +106 -7
  123. package/dist/components/synastry-chart.js.map +2 -2
  124. package/dist/components/tarot-card.js +14 -0
  125. package/dist/components/tarot-card.js.map +2 -2
  126. package/dist/components/tarot-spread.js +14 -0
  127. package/dist/components/tarot-spread.js.map +2 -2
  128. package/dist/components/transits-table.js +14 -0
  129. package/dist/components/transits-table.js.map +2 -2
  130. package/dist/components/vedic-kundli.d.ts +14 -9
  131. package/dist/components/vedic-kundli.d.ts.map +1 -1
  132. package/dist/components/vedic-kundli.js +537 -245
  133. package/dist/components/vedic-kundli.js.map +4 -4
  134. package/dist/components/vedic-planets-table.js +14 -0
  135. package/dist/components/vedic-planets-table.js.map +2 -2
  136. package/dist/components/western-planets-table.js +14 -0
  137. package/dist/components/western-planets-table.js.map +2 -2
  138. package/dist/components/yoga-list.js +14 -0
  139. package/dist/components/yoga-list.js.map +2 -2
  140. package/dist/index.cjs +1397 -797
  141. package/dist/index.cjs.map +4 -4
  142. package/dist/index.js +1278 -678
  143. package/dist/index.js.map +4 -4
  144. package/dist/styles/tokens.css +8 -23
  145. package/dist/utils/base-styles.d.ts.map +1 -1
  146. package/dist/utils/kundli-render.d.ts +43 -104
  147. package/dist/utils/kundli-render.d.ts.map +1 -1
  148. package/dist/utils/kundli-styles.d.ts +13 -0
  149. package/dist/utils/kundli-styles.d.ts.map +1 -0
  150. package/dist/version.d.ts +1 -1
  151. package/package.json +1 -1
  152. package/src/components/ashtakavarga-grid.ts +73 -11
  153. package/src/components/choghadiya-grid.ts +37 -2
  154. package/src/components/dasha-timeline.ts +135 -4
  155. package/src/components/divisional-chart.ts +40 -97
  156. package/src/components/natal-chart.ts +89 -6
  157. package/src/components/panchang-table.ts +34 -1
  158. package/src/components/synastry-chart.ts +84 -8
  159. package/src/components/vedic-kundli.ts +35 -95
  160. package/src/styles/tokens.css +8 -23
  161. package/src/utils/base-styles.ts +14 -0
  162. package/src/utils/kundli-render.ts +609 -270
  163. package/src/utils/kundli-styles.ts +124 -0
  164. package/src/version.ts +1 -1
@@ -90,15 +90,12 @@
90
90
  --roxy-motion-duration: 200ms;
91
91
  --roxy-motion-easing: cubic-bezier(0.4, 0, 0.2, 1);
92
92
 
93
- /* Heat scale: 7-step gradient used by ashtakavarga bindu cells.
94
- * Low bindus (1) are cool green; high bindus (7+) are hot red. */
95
- --roxy-heat-1: #f0fdf4;
96
- --roxy-heat-2: #d1fae5;
97
- --roxy-heat-3: #a7f3d0;
98
- --roxy-heat-4: #fde68a;
99
- --roxy-heat-5: #fdba74;
100
- --roxy-heat-6: #fb923c;
101
- --roxy-heat-7: #ef4444;
93
+ /* Heat scale: a single base hue. Consumers mix it with `transparent` at
94
+ * increasing percentages to paint cooler-to-hotter tiers. The mix-with-
95
+ * transparent approach lets the page bg show through and keeps text
96
+ * colour stable (always --roxy-fg), so the cells read in both themes
97
+ * without per-tier text colours. */
98
+ --roxy-heat: var(--roxy-danger, #ef4444);
102
99
  }
103
100
 
104
101
  /* Dark theme via system preference */
@@ -134,13 +131,7 @@
134
131
  0 4px 6px -1px rgba(0, 0, 0, 0.6), 0 2px 4px -2px rgba(0, 0, 0, 0.5);
135
132
  --roxy-shadow-lg: 0 12px 24px -8px rgba(0, 0, 0, 0.7);
136
133
 
137
- --roxy-heat-1: #052e16;
138
- --roxy-heat-2: #14532d;
139
- --roxy-heat-3: #166534;
140
- --roxy-heat-4: #92400e;
141
- --roxy-heat-5: #b45309;
142
- --roxy-heat-6: #c2410c;
143
- --roxy-heat-7: #b91c1c;
134
+ --roxy-heat: var(--roxy-danger, #ef4444);
144
135
  }
145
136
  }
146
137
 
@@ -205,13 +196,7 @@
205
196
  0 4px 6px -1px rgba(0, 0, 0, 0.6), 0 2px 4px -2px rgba(0, 0, 0, 0.5);
206
197
  --roxy-shadow-lg: 0 12px 24px -8px rgba(0, 0, 0, 0.7);
207
198
 
208
- --roxy-heat-1: #052e16;
209
- --roxy-heat-2: #14532d;
210
- --roxy-heat-3: #166534;
211
- --roxy-heat-4: #92400e;
212
- --roxy-heat-5: #b45309;
213
- --roxy-heat-6: #c2410c;
214
- --roxy-heat-7: #b91c1c;
199
+ --roxy-heat: var(--roxy-danger, #ef4444);
215
200
  }
216
201
 
217
202
  /* Reduced motion override */
@@ -1 +1 @@
1
- {"version":3,"file":"base-styles.d.ts","sourceRoot":"","sources":["../../src/utils/base-styles.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,UAAU,yBAkFtB,CAAC"}
1
+ {"version":3,"file":"base-styles.d.ts","sourceRoot":"","sources":["../../src/utils/base-styles.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,UAAU,yBAgGtB,CAAC"}
@@ -1,19 +1,9 @@
1
1
  import type { TemplateResult } from 'lit';
2
- import { nothing } from 'lit';
3
- export declare const KUNDLI_SIZE = 300;
4
- export declare const KUNDLI_CENTER = 150;
5
2
  /**
6
- * Maps a lowercase rashi key (e.g. "aries") back to its canonical sign name
7
- * (e.g. "Aries"). Used by every kundli consumer to bridge spec lowercase
8
- * rashi keys to the title-cased SIGNS_ORDER tokens.
9
- */
10
- export declare const RASHI_TO_SIGN: Record<string, string>;
11
- /**
12
- * A planet placed in a kundli house. This is a render-only view model, not an
13
- * API type: it carries just enough per-graha detail to draw a compact label
14
- * (abbreviation plus degree-within-sign plus retrograde mark) and a rich SVG
15
- * `<title>` tooltip (full position, nakshatra, pada, avastha). Both the D1
16
- * birth chart and the Dx divisional charts feed it from their `meta` map.
3
+ * A graha placed inside a kundli cell. Render-only view model fed from a
4
+ * `meta` map on the API response. Carries enough detail to draw a compact
5
+ * in-cell label (abbreviation, whole degree, retrograde mark) and a rich SVG
6
+ * `<title>` tooltip (exact position, nakshatra, pada, avastha).
17
7
  */
18
8
  export interface PlacedGraha {
19
9
  graha: string;
@@ -26,102 +16,35 @@ export interface PlacedGraha {
26
16
  isRetrograde?: boolean;
27
17
  awastha?: string;
28
18
  }
29
- export interface HouseDef {
30
- /** 1-based cell number. For the sign-fixed styles (south, east) this is the rashi index, Aries = 1. */
31
- number: number;
32
- /** Sign name (TitleCase, e.g. "Aries"). */
33
- sign: string;
34
- /** Planets occupying this house, with full detail for label + tooltip. */
35
- planets: PlacedGraha[];
36
- /** Whether this house is the ascendant (Lagna). */
37
- isLagna: boolean;
38
- }
39
- /**
40
- * South Indian fixed-house square grid: house centers for planet text labels.
41
- * House 1 is fixed top-center; positions are in the 300x300 viewBox.
42
- */
43
- export declare const SOUTH_HOUSE_CENTERS: Record<number, {
44
- x: number;
45
- y: number;
46
- }>;
47
- /**
48
- * South Indian sign abbreviation positions (slightly outward from center).
49
- */
50
- export declare const SOUTH_SIGN_POSITIONS: Record<number, {
51
- x: number;
52
- y: number;
53
- }>;
54
19
  /**
55
- * North Indian style: 12 triangular house positions.
56
- * Lagna (house 1) is the top diamond, numbered clockwise.
57
- * Centers represent the visual midpoint of each triangular cell.
58
- */
59
- export declare const NORTH_HOUSE_CENTERS: Record<number, {
60
- x: number;
61
- y: number;
62
- }>;
63
- /**
64
- * East Indian style: a fixed-sign square (like South Indian) cut by both
65
- * diagonals and an inner diamond joining the side midpoints, giving 12 cells.
66
- * The four inner-diamond quadrilaterals hold the cardinal-position signs
67
- * (cell 1, 4, 7, 10) and the eight corner half-triangles fill between them,
68
- * laid out clockwise from the top so cell `n` holds the n-th rashi (Aries = 1).
69
- * Centers are the visual midpoints of those cells in the 300x300 viewBox,
70
- * derived from the frame geometry (square 10..290, diagonals, side-midpoint
71
- * diamond).
20
+ * Unified view model used by every kundli style. Caller passes a graha-keyed
21
+ * `meta` map (from `/vedic-astrology/birth-chart`, `/divisional-chart`, or
22
+ * `/navamsa`) through {@link toKundliViewModel} to produce this shape.
72
23
  *
73
- * @remarks The cell geometry is exact; the rashi-to-cell order follows the
74
- * common clockwise-from-top convention and is slated for a regional
75
- * reference-image confirmation pass (see docs/todo.md "East Indian polish").
76
- */
77
- export declare const EAST_HOUSE_CENTERS: Record<number, {
78
- x: number;
79
- y: number;
80
- }>;
81
- /**
82
- * East Indian sign abbreviation positions, nudged toward the outer edge of
83
- * every cell so the abbreviation and the planet stack do not collide.
84
- */
85
- export declare const EAST_SIGN_POSITIONS: Record<number, {
86
- x: number;
87
- y: number;
88
- }>;
89
- /**
90
- * Render a single south-Indian house group: lagna highlight, sign
91
- * abbreviation, planet labels with degree and tooltip.
92
- */
93
- export declare function renderSouthHouseGroup(h: HouseDef): TemplateResult | typeof nothing;
94
- /**
95
- * Render a north-Indian-style kundli wheel frame (grid lines only).
96
- * Returns the SVG structural lines; call `renderNorthHouseGroup` for content.
97
- */
98
- export declare function renderNorthFrame(): TemplateResult;
99
- /**
100
- * Render a north-Indian house group (sign abbr + house number + planets).
101
- */
102
- export declare function renderNorthHouseGroup(h: HouseDef): TemplateResult | typeof nothing;
103
- /**
104
- * Render the south-Indian square frame (border diamond + inner square + radial lines).
105
- */
106
- export declare function renderSouthFrame(): TemplateResult;
107
- /**
108
- * Render the east-Indian square frame: outer square, both diagonals, and the
109
- * inner diamond joining the four side midpoints. Twelve triangular cells.
24
+ * `placements` is keyed by lowercase rashi name (`"aries"`, `"taurus"`, ...)
25
+ * so the sign-fixed styles can index directly. The Lagna entry is not
26
+ * counted as a planet; it only flags the ascendant cell.
110
27
  */
111
- export declare function renderEastFrame(): TemplateResult;
28
+ export interface KundliViewModel {
29
+ lagnaSign: string;
30
+ placements: Record<string, PlacedGraha[]>;
31
+ divisionLabel?: string;
32
+ }
112
33
  /**
113
- * Render an east-Indian house group. East Indian charts are sign-fixed like
114
- * the south style, so this mirrors `renderSouthHouseGroup` with the east cell
115
- * centers and a smaller line height to fit the triangular cells.
34
+ * Kundli regional styles. Sign-fixed (south, east) and house-fixed (north).
35
+ * Exposed so consumers can type their own `chart-style` attribute reflection.
116
36
  */
117
- export declare function renderEastHouseGroup(h: HouseDef): TemplateResult | typeof nothing;
37
+ export type ChartStyle = 'south' | 'north' | 'east';
118
38
  /**
119
- * Bucket a graha-keyed `meta` map (from a D1 or Dx chart response) into the 12
120
- * sign-indexed houses. Shared by the kundli and divisional chart components so
121
- * both render the same rich per-graha detail. The Lagna entry is consumed only
122
- * to flag the ascendant cell, not rendered as a planet.
39
+ * Bucket a graha-keyed `meta` map (D1 birth chart or D2..D60 divisional
40
+ * chart) into the unified {@link KundliViewModel} the renderer consumes. The
41
+ * Lagna entry is recognised by `graha === 'Lagna'` (or key `"Lagna"`) and
42
+ * sets `lagnaSign`; it is not bucketed as a placed planet.
43
+ *
44
+ * @param meta - Graha-keyed map; missing rashi entries are skipped.
45
+ * @param divisionLabel - Optional title written inside the chart centre.
123
46
  */
124
- export declare function buildHousesFromMeta(meta: Record<string, {
47
+ export declare function toKundliViewModel(meta: Record<string, {
125
48
  graha?: string;
126
49
  rashi?: string;
127
50
  longitude?: number;
@@ -132,5 +55,21 @@ export declare function buildHousesFromMeta(meta: Record<string, {
132
55
  };
133
56
  isRetrograde?: boolean;
134
57
  awastha?: string;
135
- }>): HouseDef[];
58
+ }>, divisionLabel?: string): KundliViewModel;
59
+ /**
60
+ * Render the kundli body for the requested style. Returns the SVG inner
61
+ * content; the caller wraps it in an `<svg>` element with the canonical
62
+ * viewBox `0 0 400 400` and applies its own theming CSS.
63
+ */
64
+ export declare function renderKundliSvg(vm: KundliViewModel, style: ChartStyle): TemplateResult;
65
+ /**
66
+ * Render a WAI-ARIA-compliant tablist that lets the end user switch between
67
+ * South / North / East kundli styles at runtime. The hosting component owns
68
+ * the `chartStyle` state; this helper renders the buttons and wires the
69
+ * arrow-key navigation plus click handler.
70
+ *
71
+ * @param active - The currently selected style.
72
+ * @param setStyle - Callback the host component uses to update its state.
73
+ */
74
+ export declare function renderKundliStyleTablist(active: ChartStyle, setStyle: (next: ChartStyle) => void): TemplateResult;
136
75
  //# sourceMappingURL=kundli-render.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"kundli-render.d.ts","sourceRoot":"","sources":["../../src/utils/kundli-render.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"kundli-render.d.ts","sourceRoot":"","sources":["../../src/utils/kundli-render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,KAAK,CAAC;AA+B1C;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,eAAe;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAsGpD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,MAAM,CACX,MAAM,EACN;IACC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,CACD,EACD,aAAa,CAAC,EAAE,MAAM,GACpB,eAAe,CAoBjB;AAmdD;;;;GAIG;AACH,wBAAgB,eAAe,CAC9B,EAAE,EAAE,eAAe,EACnB,KAAK,EAAE,UAAU,GACf,cAAc,CAShB;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACvC,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,GAClC,cAAc,CAkChB"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Shared CSS for every kundli renderer (`<roxy-vedic-kundli>`,
3
+ * `<roxy-divisional-chart>`, and any future `<roxy-navamsa-chart>`). Centralises
4
+ * the SVG layout (responsive viewBox + aspect ratio), the line/text classes,
5
+ * and the Lagna highlight so the three components stay visually identical.
6
+ *
7
+ * @remarks Font sizes are written in viewBox user units (the chart is 400×400
8
+ * inside a 1:1 aspect-ratio container), so they scale linearly from a 320px
9
+ * phone surface to a wall projector without raster loss. The Lagna palette
10
+ * tracks `--roxy-accent` so host themes flow through unchanged.
11
+ */
12
+ export declare const kundliStyles: import("lit").CSSResult;
13
+ //# sourceMappingURL=kundli-styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kundli-styles.d.ts","sourceRoot":"","sources":["../../src/utils/kundli-styles.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,yBA8GxB,CAAC"}
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const ROXY_UI_VERSION = "0.3.0";
1
+ export declare const ROXY_UI_VERSION = "0.4.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roxyapi/ui",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Web components for the RoxyAPI catalog. Drop-in charts, tables, cards, forms for astrology, tarot, numerology, biorhythm, I Ching, crystals, dreams, angel numbers, and more. One key, beautiful in 30 minutes.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -129,27 +129,68 @@ export class RoxyAshtakavargaGrid extends LitElement {
129
129
  border-bottom: none;
130
130
  }
131
131
 
132
- /* Heat cells */
132
+ /* Heat cells. Single base hue (var --roxy-heat) mixed with
133
+ * transparent at increasing percentages produces seven readable
134
+ * tiers in both light and dark themes. Text colour stays
135
+ * var(--roxy-fg) so it inverts with the host theme without
136
+ * per-tier overrides. */
133
137
  .heat-cell {
134
138
  border-radius: var(--roxy-radius-sm, 4px);
135
139
  font-weight: var(--roxy-weight-bold, 600);
136
140
  min-width: 2rem;
137
141
  font-variant-numeric: tabular-nums;
142
+ color: var(--roxy-fg, currentColor);
138
143
  }
139
144
 
140
- .heat-1 { background: var(--roxy-heat-1, #f0fdf4); color: var(--roxy-fg, #0a0a0a); }
141
- .heat-2 { background: var(--roxy-heat-2, #d1fae5); color: var(--roxy-fg, #0a0a0a); }
142
- .heat-3 { background: var(--roxy-heat-3, #a7f3d0); color: var(--roxy-fg, #0a0a0a); }
143
- .heat-4 { background: var(--roxy-heat-4, #fde68a); color: var(--roxy-fg, #0a0a0a); }
144
- .heat-5 { background: var(--roxy-heat-5, #fdba74); color: var(--roxy-fg, #0a0a0a); }
145
- .heat-6 { background: var(--roxy-heat-6, #fb923c); color: var(--roxy-fg, #0a0a0a); }
146
- .heat-7 { background: var(--roxy-heat-7, #ef4444); color: var(--roxy-fg, #0a0a0a); }
145
+ .heat-1 { background: color-mix(in srgb, var(--roxy-heat, #ef4444) 6%, transparent); }
146
+ .heat-2 { background: color-mix(in srgb, var(--roxy-heat, #ef4444) 14%, transparent); }
147
+ .heat-3 { background: color-mix(in srgb, var(--roxy-heat, #ef4444) 26%, transparent); }
148
+ .heat-4 { background: color-mix(in srgb, var(--roxy-heat, #ef4444) 40%, transparent); }
149
+ .heat-5 { background: color-mix(in srgb, var(--roxy-heat, #ef4444) 55%, transparent); }
150
+ .heat-6 { background: color-mix(in srgb, var(--roxy-heat, #ef4444) 72%, transparent); }
151
+ .heat-7 { background: color-mix(in srgb, var(--roxy-heat, #ef4444) 90%, transparent); }
147
152
 
148
153
  /* Bhinna grid: planet header column narrower */
149
154
  .bhinna-table th:first-child,
150
155
  .bhinna-table td:first-child {
151
156
  min-width: 5rem;
152
157
  }
158
+
159
+ /* Tight cells below 480px so the 14-column bhinna grid stops
160
+ * overflowing the viewport. The wrapper keeps overflow-x:auto as
161
+ * a fallback for very long content. */
162
+ @container (max-width: 480px) {
163
+ .bhinna-table th,
164
+ .bhinna-table td {
165
+ padding: 0.3rem 0.35rem;
166
+ font-size: var(--roxy-text-xs, 0.75rem);
167
+ }
168
+ .bhinna-table th:first-child,
169
+ .bhinna-table td:first-child {
170
+ min-width: 3.5rem;
171
+ }
172
+ .heat-cell {
173
+ min-width: 1.5rem;
174
+ }
175
+ }
176
+ /* Visual cue that the bhinna table is scrollable below the breakpoint:
177
+ * a soft gradient at the right edge so users see there is more to scroll. */
178
+ .overflow-scroll {
179
+ mask-image: linear-gradient(
180
+ to right,
181
+ transparent 0,
182
+ black 0.5rem,
183
+ black calc(100% - 1rem),
184
+ transparent 100%
185
+ );
186
+ -webkit-mask-image: linear-gradient(
187
+ to right,
188
+ transparent 0,
189
+ black 0.5rem,
190
+ black calc(100% - 1rem),
191
+ transparent 100%
192
+ );
193
+ }
153
194
  `,
154
195
  ];
155
196
 
@@ -237,7 +278,11 @@ export class RoxyAshtakavargaGrid extends LitElement {
237
278
  });
238
279
  }
239
280
 
240
- private heatClass(count: number): string {
281
+ /**
282
+ * Bhinna bindus per planet per sign run 0..8 (sum of 0/1 contributions
283
+ * from each of the 8 reference points). Bucket directly by raw count.
284
+ */
285
+ private bhinnaHeat(count: number): string {
241
286
  if (count <= 1) return 'heat-1';
242
287
  if (count <= 2) return 'heat-2';
243
288
  if (count <= 3) return 'heat-3';
@@ -247,6 +292,23 @@ export class RoxyAshtakavargaGrid extends LitElement {
247
292
  return 'heat-7';
248
293
  }
249
294
 
295
+ /**
296
+ * Sarva bindus per sign are the column total across all 7 planets, range
297
+ * roughly 0..56 with typical values 20..40. Bucketed per classical
298
+ * interpretation: 25 below par, 25..30 average, 30..40 strong, 40+ very
299
+ * strong. Bucket spans intentionally widen at the extremes so a single
300
+ * outlier sign reads as exceptional.
301
+ */
302
+ private sarvaHeat(count: number): string {
303
+ if (count <= 18) return 'heat-1';
304
+ if (count <= 23) return 'heat-2';
305
+ if (count <= 28) return 'heat-3';
306
+ if (count <= 32) return 'heat-4';
307
+ if (count <= 37) return 'heat-5';
308
+ if (count <= 42) return 'heat-6';
309
+ return 'heat-7';
310
+ }
311
+
250
312
  private renderSarva(signs: AshtakavargaResponse['signs']) {
251
313
  const sav = this.data!.sarvashtakavarga;
252
314
  if (!sav) return html`<p class="roxy-empty">No sarvashtakavarga data</p>`;
@@ -262,7 +324,7 @@ export class RoxyAshtakavargaGrid extends LitElement {
262
324
  <tbody>
263
325
  ${signs.map((sign, i) => {
264
326
  const count = sav.bindus[i] ?? 0;
265
- const hc = this.heatClass(count);
327
+ const hc = this.sarvaHeat(count);
266
328
  return html`<tr>
267
329
  <td>
268
330
  <div class="planet-cell">
@@ -306,7 +368,7 @@ export class RoxyAshtakavargaGrid extends LitElement {
306
368
  (row) => html`<tr>
307
369
  <td>${row.planet}</td>
308
370
  ${row.bindus.map((count) => {
309
- const hc = this.heatClass(count);
371
+ const hc = this.bhinnaHeat(count);
310
372
  return html`<td class="${`heat-cell ${hc}`}">${count}</td>`;
311
373
  })}
312
374
  <td>${row.total}</td>
@@ -92,6 +92,21 @@ export class RoxyChoghadiyaGrid extends LitElement {
92
92
  background: transparent;
93
93
  color: var(--roxy-fg, #0a0a0a);
94
94
  }
95
+ .cho-tile.now {
96
+ outline: 2px solid var(--roxy-accent, #f59e0b);
97
+ outline-offset: 1px;
98
+ box-shadow: 0 0 0 4px
99
+ color-mix(in srgb, var(--roxy-accent, #f59e0b) 18%, transparent);
100
+ }
101
+ .now-badge {
102
+ display: inline-block;
103
+ margin-left: 0.4em;
104
+ font-size: var(--roxy-text-xs, 0.75rem);
105
+ font-weight: var(--roxy-weight-bold, 600);
106
+ color: var(--roxy-accent-fg, #b45309);
107
+ text-transform: uppercase;
108
+ letter-spacing: 0.06em;
109
+ }
95
110
  .tile-name {
96
111
  font-size: var(--roxy-text-base, 1rem);
97
112
  font-weight: var(--roxy-weight-bold, 600);
@@ -120,6 +135,19 @@ export class RoxyChoghadiyaGrid extends LitElement {
120
135
  @property({ attribute: false })
121
136
  data: GetChoghadiyaResponse | null = null;
122
137
 
138
+ /**
139
+ * True when the current wall-clock time falls inside this period. Both
140
+ * `start` and `end` are ISO 8601 with timezone, so the comparison is
141
+ * timezone-aware via the host's `Date` parsing.
142
+ */
143
+ private isCurrent(period: ChoghadiyaPeriod): boolean {
144
+ const now = Date.now();
145
+ const start = Date.parse(period.start);
146
+ const end = Date.parse(period.end);
147
+ if (Number.isNaN(start) || Number.isNaN(end)) return false;
148
+ return now >= start && now < end;
149
+ }
150
+
123
151
  private renderTile(period: ChoghadiyaPeriod) {
124
152
  const effectClass =
125
153
  period.effect === 'Good'
@@ -127,10 +155,17 @@ export class RoxyChoghadiyaGrid extends LitElement {
127
155
  : period.effect === 'Bad'
128
156
  ? 'bad'
129
157
  : 'neutral';
158
+ const current = this.isCurrent(period);
130
159
  const lordGlyph = PLANET_GLYPH[capitalize(period.lord)] ?? '';
131
160
  const timeRange = `${fmtTime(period.start)} - ${fmtTime(period.end)}`;
132
- return html`<div class="cho-tile ${effectClass}" role="listitem">
133
- <span class="tile-name">${period.name}</span>
161
+ return html`<div
162
+ class="cho-tile ${effectClass}${current ? ' now' : ''}"
163
+ role="listitem"
164
+ aria-current=${current ? 'time' : 'false'}
165
+ >
166
+ <span class="tile-name">
167
+ ${period.name}${current ? html`<span class="now-badge">Now</span>` : nothing}
168
+ </span>
134
169
  <span class="tile-time" aria-label="Time range">${timeRange}</span>
135
170
  <span class="tile-lord">
136
171
  ${lordGlyph ? html`<span aria-hidden="true">${lordGlyph}</span>` : nothing}
@@ -68,6 +68,13 @@ export class RoxyDashaTimeline extends LitElement {
68
68
  color: var(--roxy-fg, #0a0a0a);
69
69
  }
70
70
 
71
+ .balance {
72
+ font-size: var(--roxy-text-sm, 0.875rem);
73
+ color: var(--roxy-muted, #71717a);
74
+ border-left: 2px solid var(--roxy-border, #e4e4e7);
75
+ padding-left: var(--roxy-space-sm, 0.5rem);
76
+ margin: 0;
77
+ }
71
78
  .timeline {
72
79
  display: grid;
73
80
  gap: var(--roxy-space-xs, 0.25rem);
@@ -79,26 +86,69 @@ export class RoxyDashaTimeline extends LitElement {
79
86
  align-items: center;
80
87
  font-size: var(--roxy-text-sm, 0.875rem);
81
88
  }
89
+ .bar.now strong {
90
+ color: var(--roxy-accent-fg, #b45309);
91
+ }
92
+ .now-badge {
93
+ display: inline-block;
94
+ margin-left: 0.4em;
95
+ font-size: var(--roxy-text-xs, 0.75rem);
96
+ font-weight: var(--roxy-weight-bold, 600);
97
+ color: var(--roxy-accent-fg, #b45309);
98
+ text-transform: uppercase;
99
+ letter-spacing: 0.06em;
100
+ }
82
101
  .bar-track {
102
+ position: relative;
83
103
  height: 14px;
84
104
  background: var(--roxy-border, #e4e4e7);
85
105
  border-radius: var(--roxy-radius-full, 9999px);
86
106
  overflow: hidden;
87
107
  }
88
- .bar-track > span {
108
+ .bar-fill {
89
109
  display: block;
90
110
  height: 100%;
91
111
  background: var(--roxy-accent, #f59e0b);
112
+ opacity: 0.45;
92
113
  transition:
93
114
  width var(--roxy-motion-duration, 200ms)
94
115
  var(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));
95
116
  }
117
+ .bar-now .bar-fill {
118
+ opacity: 1;
119
+ }
120
+ .bar-progress {
121
+ position: absolute;
122
+ top: -2px;
123
+ bottom: -2px;
124
+ width: 2px;
125
+ background: var(--roxy-accent-fg, #b45309);
126
+ border-radius: 2px;
127
+ box-shadow: 0 0 0 2px
128
+ color-mix(in srgb, var(--roxy-accent, #f59e0b) 35%, transparent);
129
+ }
96
130
  .dates {
97
131
  color: var(--roxy-muted, #71717a);
98
132
  font-size: var(--roxy-text-xs, 0.75rem);
99
133
  font-variant-numeric: tabular-nums;
100
134
  text-align: right;
101
135
  }
136
+ details.interp {
137
+ border: 1px solid var(--roxy-border, #e4e4e7);
138
+ border-radius: var(--roxy-radius-md, 8px);
139
+ padding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);
140
+ background: var(--roxy-bg, #fff);
141
+ }
142
+ details.interp summary {
143
+ cursor: pointer;
144
+ font-size: var(--roxy-text-sm, 0.875rem);
145
+ font-weight: var(--roxy-weight-bold, 600);
146
+ }
147
+ details.interp p {
148
+ margin: var(--roxy-space-sm, 0.5rem) 0 0;
149
+ font-size: var(--roxy-text-sm, 0.875rem);
150
+ color: var(--roxy-muted, #71717a);
151
+ }
102
152
  `,
103
153
  ];
104
154
 
@@ -139,6 +189,7 @@ export class RoxyDashaTimeline extends LitElement {
139
189
  }
140
190
  </header>
141
191
 
192
+ ${this.renderBirthBalance(d)}
142
193
  ${this.period === 'current' ? this.renderCurrent(d) : nothing}
143
194
  ${
144
195
  periods.length > 0
@@ -147,9 +198,37 @@ export class RoxyDashaTimeline extends LitElement {
147
198
  </div>`
148
199
  : nothing
149
200
  }
201
+ ${this.renderActiveInterpretation(periods)}
150
202
  </div>`;
151
203
  }
152
204
 
205
+ private renderBirthBalance(d: DashaData) {
206
+ if (!('birthDashaBalance' in d) || !d.birthDashaBalance) return nothing;
207
+ const b = d.birthDashaBalance;
208
+ const lord = 'nakshatraLord' in d && d.nakshatraLord ? d.nakshatraLord : '';
209
+ const yrs = b.years ?? 0;
210
+ const mo = b.months ?? 0;
211
+ const da = b.days ?? 0;
212
+ const parts: string[] = [];
213
+ if (yrs) parts.push(`${yrs}y`);
214
+ if (mo) parts.push(`${mo}m`);
215
+ if (da) parts.push(`${da}d`);
216
+ const remaining = parts.length ? parts.join(' ') : '0d';
217
+ return html`<p class="balance">
218
+ Birth dasha balance: ${remaining} of
219
+ ${lord ? html`<strong>${lord}</strong>` : 'the opening mahadasha'} remained at birth.
220
+ </p>`;
221
+ }
222
+
223
+ private renderActiveInterpretation(periods: DashaPeriod[]) {
224
+ const active = periods.find((p) => this.isCurrent(p));
225
+ if (!active?.interpretation) return nothing;
226
+ return html`<details class="interp">
227
+ <summary>${active.planet} mahadasha interpretation</summary>
228
+ <p>${active.interpretation}</p>
229
+ </details>`;
230
+ }
231
+
153
232
  private renderCurrent(d: DashaData) {
154
233
  if (!('mahadasha' in d)) return nothing;
155
234
  return html`<div class="current">
@@ -201,12 +280,64 @@ export class RoxyDashaTimeline extends LitElement {
201
280
  return [];
202
281
  }
203
282
 
283
+ /** True when the current wall-clock time falls between the period's start and end. */
284
+ private isCurrent(p: DashaPeriod): boolean {
285
+ if (!p.startDate || !p.endDate) return false;
286
+ const now = Date.now();
287
+ const start = Date.parse(p.startDate);
288
+ const end = Date.parse(p.endDate);
289
+ if (Number.isNaN(start) || Number.isNaN(end)) return false;
290
+ return now >= start && now < end;
291
+ }
292
+
293
+ /**
294
+ * Fractional progress (0..1) through a period at the current time. Used to
295
+ * draw a vertical "now" marker inside the active bar. Returns -1 outside the
296
+ * period so the caller can skip the marker.
297
+ */
298
+ private progressIn(p: DashaPeriod): number {
299
+ if (!p.startDate || !p.endDate) return -1;
300
+ const start = Date.parse(p.startDate);
301
+ const end = Date.parse(p.endDate);
302
+ const now = Date.now();
303
+ if (
304
+ Number.isNaN(start) ||
305
+ Number.isNaN(end) ||
306
+ now < start ||
307
+ now >= end ||
308
+ end <= start
309
+ ) {
310
+ return -1;
311
+ }
312
+ return (now - start) / (end - start);
313
+ }
314
+
204
315
  private renderBar(p: DashaPeriod, max: number) {
205
316
  const years = p.durationYears;
206
317
  const width = max > 0 ? (years / max) * 100 : 0;
207
- return html`<div class="bar" role="listitem">
208
- <span>${p.planet}</span>
209
- <span class="bar-track"><span style="width: ${width}%"></span></span>
318
+ const current = this.isCurrent(p);
319
+ const progress = current ? this.progressIn(p) : -1;
320
+ const trackClass = current ? 'bar-track bar-now' : 'bar-track';
321
+ return html`<div
322
+ class=${current ? 'bar now' : 'bar'}
323
+ role="listitem"
324
+ aria-current=${current ? 'time' : 'false'}
325
+ >
326
+ <span>
327
+ <strong>${p.planet}</strong>${current ? html`<span class="now-badge">Now</span>` : nothing}
328
+ </span>
329
+ <span class=${trackClass}>
330
+ <span class="bar-fill" style="width: ${width}%"></span>
331
+ ${
332
+ progress >= 0
333
+ ? html`<span
334
+ class="bar-progress"
335
+ style="left: ${progress * width}%"
336
+ aria-hidden="true"
337
+ ></span>`
338
+ : nothing
339
+ }
340
+ </span>
210
341
  <span class="dates">
211
342
  ${p.startDate ? formatYear(p.startDate) : ''}
212
343
  ${p.endDate ? html`- ${formatYear(p.endDate)}` : ''}