@roxyapi/ui 0.11.0 → 0.12.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.
- package/AGENTS.md +6 -0
- package/README.md +6 -0
- package/components-catalog.json +111 -1
- package/dist/cdn/components/astrocartography-map.js +58 -0
- package/dist/cdn/components/astrocartography-map.js.map +7 -0
- package/dist/cdn/components/divisional-chart.js +7 -7
- package/dist/cdn/components/divisional-chart.js.map +1 -1
- package/dist/cdn/components/dosha-card.js +2 -2
- package/dist/cdn/components/dosha-card.js.map +3 -3
- package/dist/cdn/components/fixed-stars.js +52 -0
- package/dist/cdn/components/fixed-stars.js.map +7 -0
- package/dist/cdn/components/hd-variables.js +2 -2
- package/dist/cdn/components/hd-variables.js.map +3 -3
- package/dist/cdn/components/hexagram.js +3 -3
- package/dist/cdn/components/hexagram.js.map +3 -3
- package/dist/cdn/components/local-space-compass.js +58 -0
- package/dist/cdn/components/local-space-compass.js.map +7 -0
- package/dist/cdn/components/moon-phase.js +3 -3
- package/dist/cdn/components/moon-phase.js.map +3 -3
- package/dist/cdn/components/natal-chart.js +8 -8
- package/dist/cdn/components/natal-chart.js.map +2 -2
- package/dist/cdn/components/positions-table.js +52 -0
- package/dist/cdn/components/positions-table.js.map +7 -0
- package/dist/cdn/components/profection-card.js +52 -0
- package/dist/cdn/components/profection-card.js.map +7 -0
- package/dist/cdn/components/reference-card.js +3 -3
- package/dist/cdn/components/reference-card.js.map +3 -3
- package/dist/cdn/components/relocation-wheel.js +61 -0
- package/dist/cdn/components/relocation-wheel.js.map +7 -0
- package/dist/cdn/components/synastry-chart.js +4 -4
- package/dist/cdn/components/synastry-chart.js.map +2 -2
- package/dist/cdn/components/vedic-kundli.js +5 -5
- package/dist/cdn/components/vedic-kundli.js.map +1 -1
- package/dist/cdn/components/vedic-planets-table.js +2 -2
- package/dist/cdn/components/vedic-planets-table.js.map +1 -1
- package/dist/cdn/components/western-planets-table.js +2 -2
- package/dist/cdn/components/western-planets-table.js.map +1 -1
- package/dist/cdn/components/yoga-list.js +3 -3
- package/dist/cdn/components/yoga-list.js.map +3 -3
- package/dist/cdn/roxy-ui.js +83 -71
- package/dist/cdn/roxy-ui.js.map +4 -4
- package/dist/components/astrocartography-map.d.ts +27 -0
- package/dist/components/astrocartography-map.d.ts.map +1 -0
- package/dist/components/astrocartography-map.js +8 -0
- package/dist/components/astrocartography-map.js.map +7 -0
- package/dist/components/divisional-chart.js +22 -22
- package/dist/components/divisional-chart.js.map +1 -1
- package/dist/components/dosha-card.d.ts.map +1 -1
- package/dist/components/dosha-card.js +1 -1
- package/dist/components/dosha-card.js.map +3 -3
- package/dist/components/fixed-stars.d.ts +21 -0
- package/dist/components/fixed-stars.d.ts.map +1 -0
- package/dist/components/fixed-stars.js +2 -0
- package/dist/components/fixed-stars.js.map +7 -0
- package/dist/components/hd-variables.d.ts.map +1 -1
- package/dist/components/hd-variables.js +1 -1
- package/dist/components/hd-variables.js.map +3 -3
- package/dist/components/hexagram.d.ts +3 -1
- package/dist/components/hexagram.d.ts.map +1 -1
- package/dist/components/hexagram.js +1 -1
- package/dist/components/hexagram.js.map +3 -3
- package/dist/components/local-space-compass.d.ts +23 -0
- package/dist/components/local-space-compass.d.ts.map +1 -0
- package/dist/components/local-space-compass.js +8 -0
- package/dist/components/local-space-compass.js.map +7 -0
- package/dist/components/moon-phase.d.ts.map +1 -1
- package/dist/components/moon-phase.js +1 -1
- package/dist/components/moon-phase.js.map +3 -3
- package/dist/components/natal-chart.d.ts +2 -0
- package/dist/components/natal-chart.d.ts.map +1 -1
- package/dist/components/natal-chart.js +6 -6
- package/dist/components/natal-chart.js.map +2 -2
- package/dist/components/positions-table.d.ts +34 -0
- package/dist/components/positions-table.d.ts.map +1 -0
- package/dist/components/positions-table.js +2 -0
- package/dist/components/positions-table.js.map +7 -0
- package/dist/components/profection-card.d.ts +18 -0
- package/dist/components/profection-card.d.ts.map +1 -0
- package/dist/components/profection-card.js +2 -0
- package/dist/components/profection-card.js.map +7 -0
- package/dist/components/reference-card.d.ts.map +1 -1
- package/dist/components/reference-card.js +1 -1
- package/dist/components/reference-card.js.map +3 -3
- package/dist/components/relocation-wheel.d.ts +21 -0
- package/dist/components/relocation-wheel.d.ts.map +1 -0
- package/dist/components/relocation-wheel.js +11 -0
- package/dist/components/relocation-wheel.js.map +7 -0
- package/dist/components/synastry-chart.js +3 -3
- package/dist/components/synastry-chart.js.map +2 -2
- package/dist/components/vedic-kundli.js +14 -14
- package/dist/components/vedic-kundli.js.map +1 -1
- package/dist/components/vedic-planets-table.js +1 -1
- package/dist/components/vedic-planets-table.js.map +1 -1
- package/dist/components/western-planets-table.js +1 -1
- package/dist/components/western-planets-table.js.map +1 -1
- package/dist/components/yoga-list.d.ts +5 -2
- package/dist/components/yoga-list.d.ts.map +1 -1
- package/dist/components/yoga-list.js +1 -1
- package/dist/components/yoga-list.js.map +3 -3
- package/dist/generated/endpoint-bindings.d.ts.map +1 -1
- package/dist/index.cjs +62 -50
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +62 -50
- package/dist/index.js.map +4 -4
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.json +6 -0
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types.gen.d.ts +7864 -5381
- package/dist/types/types.gen.d.ts.map +1 -1
- package/dist/utils/degree.d.ts +2 -0
- package/dist/utils/degree.d.ts.map +1 -1
- package/dist/utils/planet-color.d.ts +3 -0
- package/dist/utils/planet-color.d.ts.map +1 -0
- package/dist/version.d.ts +1 -1
- package/package.json +2 -1
- package/src/components/astrocartography-map.ts +436 -0
- package/src/components/dosha-card.ts +48 -16
- package/src/components/fixed-stars.ts +254 -0
- package/src/components/hd-variables.ts +30 -2
- package/src/components/hexagram.ts +11 -11
- package/src/components/local-space-compass.ts +299 -0
- package/src/components/moon-phase.ts +21 -2
- package/src/components/natal-chart.ts +36 -24
- package/src/components/positions-table.ts +442 -0
- package/src/components/profection-card.ts +173 -0
- package/src/components/reference-card.ts +40 -8
- package/src/components/relocation-wheel.ts +170 -0
- package/src/components/yoga-list.ts +95 -2
- package/src/generated/endpoint-bindings.ts +62 -0
- package/src/index.ts +6 -0
- package/src/manifest.ts +79 -0
- package/src/types/index.ts +1 -1
- package/src/types/types.gen.ts +7814 -5263
- package/src/utils/degree.ts +11 -0
- package/src/utils/planet-color.ts +45 -0
- package/src/version.ts +1 -1
package/dist/utils/degree.d.ts
CHANGED
|
@@ -21,6 +21,8 @@ export declare function normalizeLongitude(lon: number): number;
|
|
|
21
21
|
export declare function longitudeToSignPosition(longitude: number): SignPosition;
|
|
22
22
|
/** Compact display string like "12° Leo 34'". Used in chart labels. */
|
|
23
23
|
export declare function formatSignPosition(longitude: number): string;
|
|
24
|
+
/** Format a within-sign decimal degree (0-30) as degree-and-minute, e.g. 17.99 to "17°59'". The reference-grade form astrologers read when the sign is already known (asteroids, lots, directed points, fixed stars). */
|
|
25
|
+
export declare function formatDegreeInSign(deg: number): string;
|
|
24
26
|
/**
|
|
25
27
|
* The point diametrically opposite a longitude (e.g. Descendant from
|
|
26
28
|
* Ascendant, IC from MC). Exact derivation, always 180 degrees away.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"degree.d.ts","sourceRoot":"","sources":["../../src/utils/degree.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CAevE;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAK9D;AAED,sFAAsF;AACtF,wBAAgB,gBAAgB,CAC/B,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACd;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAM1B"}
|
|
1
|
+
{"version":3,"file":"degree.d.ts","sourceRoot":"","sources":["../../src/utils/degree.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,CAevE;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED,yNAAyN;AACzN,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAQtD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAEvD;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAK9D;AAED,sFAAsF;AACtF,wBAAgB,gBAAgB,CAC/B,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACd;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAM1B"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Theme-token color for a body, by name with an index fallback. {@link capitalize} matches the canonical TitleCase keys; unmapped or localized names cycle by `index`. */
|
|
2
|
+
export declare function planetColor(name: string, index?: number): string;
|
|
3
|
+
//# sourceMappingURL=planet-color.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planet-color.d.ts","sourceRoot":"","sources":["../../src/utils/planet-color.ts"],"names":[],"mappings":"AAqCA,2KAA2K;AAC3K,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,CAM3D"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const ROXY_UI_VERSION = "0.
|
|
1
|
+
export declare const ROXY_UI_VERSION = "0.12.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
|
+
"version": "0.12.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",
|
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
"url": "https://github.com/RoxyAPI/ui/issues"
|
|
67
67
|
},
|
|
68
68
|
"sideEffects": [
|
|
69
|
+
"./src/components/*.ts",
|
|
69
70
|
"./dist/components/*.js",
|
|
70
71
|
"./dist/cdn/*.js"
|
|
71
72
|
],
|
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
import { css, html, nothing, svg } from 'lit';
|
|
2
|
+
import { customElement } from 'lit/decorators.js';
|
|
3
|
+
import type { AstrocartographyResponse } from '../types/index.js';
|
|
4
|
+
import { RoxyDataElement } from '../utils/base-element.js';
|
|
5
|
+
import { baseStyles } from '../utils/base-styles.js';
|
|
6
|
+
import { chevron, disclosureStyles } from '../utils/disclosure.js';
|
|
7
|
+
import { planetColor } from '../utils/planet-color.js';
|
|
8
|
+
|
|
9
|
+
type LineSet = AstrocartographyResponse['lines'][number];
|
|
10
|
+
type GeoPoint = LineSet['ascendant']['points'][number];
|
|
11
|
+
|
|
12
|
+
// Equirectangular (plate carree) projection in a 360x180 unit canvas: one unit
|
|
13
|
+
// per degree. The SVG scales to the container width; the 2:1 aspect ratio holds.
|
|
14
|
+
const W = 360;
|
|
15
|
+
const H = 180;
|
|
16
|
+
const lonToX = (lon: number): number => lon + 180;
|
|
17
|
+
const latToY = (lat: number): number => 90 - lat;
|
|
18
|
+
|
|
19
|
+
// Reference parallels (degrees). Tropics and polar circles use the current mean
|
|
20
|
+
// obliquity; drawn as dashed guides so the curved rising/setting lines read
|
|
21
|
+
// against real climate bands, not just a bare grid.
|
|
22
|
+
const TROPIC = 23.44;
|
|
23
|
+
const POLAR = 66.56;
|
|
24
|
+
|
|
25
|
+
const formatLon = (lon: number): string =>
|
|
26
|
+
lon === 0 ? '0' : `${Math.abs(lon)}°${lon > 0 ? 'E' : 'W'}`;
|
|
27
|
+
const formatLat = (lat: number): string =>
|
|
28
|
+
lat === 0 ? '0' : `${Math.abs(lat)}°${lat > 0 ? 'N' : 'S'}`;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Split a rising/setting line into screen polylines, breaking the path wherever
|
|
32
|
+
* consecutive samples jump more than 180 degrees of longitude. Without the
|
|
33
|
+
* split, a line that crosses the antimeridian draws a stray horizontal streak
|
|
34
|
+
* straight across the whole map.
|
|
35
|
+
*/
|
|
36
|
+
function toSegments(points: GeoPoint[]): string[] {
|
|
37
|
+
const segments: string[][] = [];
|
|
38
|
+
let current: string[] = [];
|
|
39
|
+
let prevLon: number | null = null;
|
|
40
|
+
for (const p of points) {
|
|
41
|
+
if (prevLon !== null && Math.abs(p.longitude - prevLon) > 180) {
|
|
42
|
+
if (current.length) segments.push(current);
|
|
43
|
+
current = [];
|
|
44
|
+
}
|
|
45
|
+
current.push(`${lonToX(p.longitude)},${latToY(p.latitude)}`);
|
|
46
|
+
prevLon = p.longitude;
|
|
47
|
+
}
|
|
48
|
+
if (current.length) segments.push(current);
|
|
49
|
+
return segments.filter((s) => s.length > 1).map((s) => s.join(' '));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const ANGLE_LABEL: Record<string, string> = {
|
|
53
|
+
mc: 'MC',
|
|
54
|
+
ic: 'IC',
|
|
55
|
+
ascendant: 'AC',
|
|
56
|
+
descendant: 'DC',
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Astrocartography (relocation) world map. Plots the four planetary lines for
|
|
61
|
+
* every body from a /astrology/astrocartography response over a labeled
|
|
62
|
+
* graticule: MC and IC as straight meridians, the Ascendant and Descendant as
|
|
63
|
+
* latitude-sampled curves. Color is per body and theme-token driven; solid
|
|
64
|
+
* lines are the Ascendant and Midheaven, dashed are the Descendant and IC.
|
|
65
|
+
*/
|
|
66
|
+
@customElement('roxy-astrocartography-map')
|
|
67
|
+
export class RoxyAstrocartographyMap extends RoxyDataElement<AstrocartographyResponse> {
|
|
68
|
+
static styles = [
|
|
69
|
+
baseStyles,
|
|
70
|
+
disclosureStyles,
|
|
71
|
+
css`
|
|
72
|
+
.wrap {
|
|
73
|
+
width: 100%;
|
|
74
|
+
background: var(--roxy-surface, #fff);
|
|
75
|
+
color: var(--roxy-fg, #0a0a0a);
|
|
76
|
+
border: 1px solid var(--roxy-border, #e4e4e7);
|
|
77
|
+
border-radius: var(--roxy-radius-md, 8px);
|
|
78
|
+
padding: var(--roxy-space-lg, 1.5rem);
|
|
79
|
+
box-shadow: var(--roxy-shadow-sm);
|
|
80
|
+
display: grid;
|
|
81
|
+
gap: var(--roxy-space-md, 1rem);
|
|
82
|
+
}
|
|
83
|
+
.title {
|
|
84
|
+
font-size: var(--roxy-text-lg, 1.125rem);
|
|
85
|
+
font-weight: var(--roxy-weight-bold, 600);
|
|
86
|
+
margin: 0;
|
|
87
|
+
color: var(--roxy-primary, #0f172a);
|
|
88
|
+
}
|
|
89
|
+
.meta {
|
|
90
|
+
color: var(--roxy-muted, #71717a);
|
|
91
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
92
|
+
}
|
|
93
|
+
svg {
|
|
94
|
+
display: block;
|
|
95
|
+
width: 100%;
|
|
96
|
+
height: auto;
|
|
97
|
+
border-radius: var(--roxy-radius-sm, 4px);
|
|
98
|
+
}
|
|
99
|
+
.map-frame {
|
|
100
|
+
fill: color-mix(in srgb, var(--roxy-border, #e4e4e7) 12%, transparent);
|
|
101
|
+
stroke: var(--roxy-border, #e4e4e7);
|
|
102
|
+
stroke-width: 0.8;
|
|
103
|
+
}
|
|
104
|
+
.grat {
|
|
105
|
+
stroke: var(--roxy-border, #e4e4e7);
|
|
106
|
+
stroke-width: 0.4;
|
|
107
|
+
fill: none;
|
|
108
|
+
}
|
|
109
|
+
.grat-axis {
|
|
110
|
+
stroke: var(--roxy-muted, #71717a);
|
|
111
|
+
stroke-width: 0.6;
|
|
112
|
+
opacity: 0.6;
|
|
113
|
+
}
|
|
114
|
+
.grat-ref {
|
|
115
|
+
stroke: var(--roxy-secondary, #475569);
|
|
116
|
+
stroke-width: 0.4;
|
|
117
|
+
stroke-dasharray: 2 2;
|
|
118
|
+
opacity: 0.5;
|
|
119
|
+
fill: none;
|
|
120
|
+
}
|
|
121
|
+
.axis-label {
|
|
122
|
+
fill: var(--roxy-muted, #71717a);
|
|
123
|
+
font-size: 5px;
|
|
124
|
+
font-family: var(--roxy-font-sans);
|
|
125
|
+
}
|
|
126
|
+
.acg-line {
|
|
127
|
+
fill: none;
|
|
128
|
+
stroke-width: 1;
|
|
129
|
+
opacity: 0.95;
|
|
130
|
+
}
|
|
131
|
+
.acg-line.dashed {
|
|
132
|
+
stroke-dasharray: 4 2.5;
|
|
133
|
+
}
|
|
134
|
+
.acg-glyph {
|
|
135
|
+
font-size: 8px;
|
|
136
|
+
font-family: var(--roxy-font-sans);
|
|
137
|
+
font-weight: 600;
|
|
138
|
+
}
|
|
139
|
+
.birthplace {
|
|
140
|
+
fill: var(--roxy-fg, #0a0a0a);
|
|
141
|
+
font-size: 9px;
|
|
142
|
+
}
|
|
143
|
+
.legend {
|
|
144
|
+
display: flex;
|
|
145
|
+
flex-wrap: wrap;
|
|
146
|
+
gap: var(--roxy-space-xs, 0.25rem) var(--roxy-space-md, 1rem);
|
|
147
|
+
font-size: var(--roxy-text-xs, 0.75rem);
|
|
148
|
+
color: var(--roxy-muted, #71717a);
|
|
149
|
+
}
|
|
150
|
+
.legend-item {
|
|
151
|
+
display: inline-flex;
|
|
152
|
+
align-items: center;
|
|
153
|
+
gap: 0.3rem;
|
|
154
|
+
}
|
|
155
|
+
.legend-swatch {
|
|
156
|
+
width: 14px;
|
|
157
|
+
height: 0;
|
|
158
|
+
border-top-width: 2px;
|
|
159
|
+
border-top-style: solid;
|
|
160
|
+
}
|
|
161
|
+
.legend-note {
|
|
162
|
+
width: 100%;
|
|
163
|
+
color: var(--roxy-muted, #71717a);
|
|
164
|
+
}
|
|
165
|
+
.summary {
|
|
166
|
+
color: var(--roxy-fg, #0a0a0a);
|
|
167
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
168
|
+
margin: 0;
|
|
169
|
+
}
|
|
170
|
+
.interpretations h3 {
|
|
171
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
172
|
+
font-weight: 600;
|
|
173
|
+
color: var(--roxy-muted, #71717a);
|
|
174
|
+
text-transform: uppercase;
|
|
175
|
+
letter-spacing: 0.06em;
|
|
176
|
+
margin: 0 0 var(--roxy-space-sm, 0.5rem);
|
|
177
|
+
}
|
|
178
|
+
.interp-card {
|
|
179
|
+
border: 1px solid var(--roxy-border, #e4e4e7);
|
|
180
|
+
border-radius: var(--roxy-radius-md, 8px);
|
|
181
|
+
padding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);
|
|
182
|
+
margin-bottom: var(--roxy-space-xs, 0.25rem);
|
|
183
|
+
}
|
|
184
|
+
.interp-card summary {
|
|
185
|
+
cursor: pointer;
|
|
186
|
+
font-weight: 500;
|
|
187
|
+
color: var(--roxy-fg, #0a0a0a);
|
|
188
|
+
display: flex;
|
|
189
|
+
align-items: center;
|
|
190
|
+
justify-content: space-between;
|
|
191
|
+
gap: var(--roxy-space-md, 1rem);
|
|
192
|
+
}
|
|
193
|
+
.interp-head {
|
|
194
|
+
display: inline-flex;
|
|
195
|
+
align-items: center;
|
|
196
|
+
gap: 0.5rem;
|
|
197
|
+
}
|
|
198
|
+
.interp-dot {
|
|
199
|
+
width: 10px;
|
|
200
|
+
height: 10px;
|
|
201
|
+
border-radius: 50%;
|
|
202
|
+
}
|
|
203
|
+
.interp-body {
|
|
204
|
+
margin-top: var(--roxy-space-sm, 0.5rem);
|
|
205
|
+
display: grid;
|
|
206
|
+
gap: var(--roxy-space-xs, 0.25rem);
|
|
207
|
+
}
|
|
208
|
+
.interp-line {
|
|
209
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
210
|
+
color: var(--roxy-fg, #0a0a0a);
|
|
211
|
+
}
|
|
212
|
+
.interp-line .code {
|
|
213
|
+
font-weight: 600;
|
|
214
|
+
color: var(--roxy-accent-ink, #b45309);
|
|
215
|
+
margin-right: 0.4rem;
|
|
216
|
+
}
|
|
217
|
+
`,
|
|
218
|
+
];
|
|
219
|
+
|
|
220
|
+
protected renderEmpty() {
|
|
221
|
+
return html`<div class="roxy-empty" role="status">No astrocartography data</div>`;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
protected renderData(data: AstrocartographyResponse) {
|
|
225
|
+
const lines = data.lines ?? [];
|
|
226
|
+
const bd = data.birthDetails;
|
|
227
|
+
return html`<div class="wrap">
|
|
228
|
+
<header>
|
|
229
|
+
<h2 class="title">Astrocartography</h2>
|
|
230
|
+
${
|
|
231
|
+
bd
|
|
232
|
+
? html`<div class="meta">
|
|
233
|
+
${[bd.date, bd.time].filter(Boolean).join(' · ')} ·
|
|
234
|
+
${formatLat(Math.round(bd.latitude))} ${formatLon(Math.round(bd.longitude))}
|
|
235
|
+
</div>`
|
|
236
|
+
: nothing
|
|
237
|
+
}
|
|
238
|
+
</header>
|
|
239
|
+
${this.renderMap(lines, bd)}
|
|
240
|
+
${this.renderLegend(lines)}
|
|
241
|
+
${data.summary ? html`<p class="summary">${data.summary}</p>` : nothing}
|
|
242
|
+
${this.renderInterpretations(lines)}
|
|
243
|
+
</div>`;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
private renderMap(
|
|
247
|
+
lines: LineSet[],
|
|
248
|
+
bd: AstrocartographyResponse['birthDetails'],
|
|
249
|
+
) {
|
|
250
|
+
return html`<svg
|
|
251
|
+
viewBox="0 0 ${W} ${H}"
|
|
252
|
+
role="img"
|
|
253
|
+
aria-label="World map of planetary astrocartography lines"
|
|
254
|
+
>
|
|
255
|
+
<title>Astrocartography world map</title>
|
|
256
|
+
<desc>
|
|
257
|
+
Equirectangular world map. Each body has a Midheaven and Imum Coeli
|
|
258
|
+
meridian and a curved Ascendant and Descendant line, colored per body.
|
|
259
|
+
</desc>
|
|
260
|
+
<rect class="map-frame" x="0" y="0" width=${W} height=${H} />
|
|
261
|
+
${this.renderGraticule()}
|
|
262
|
+
${lines.map((l, i) => this.renderBodyLines(l, i))}
|
|
263
|
+
${
|
|
264
|
+
bd
|
|
265
|
+
? svg`<text class="birthplace" x=${lonToX(bd.longitude)} y=${latToY(bd.latitude)} text-anchor="middle" dominant-baseline="central"><title>Birthplace</title>★</text>`
|
|
266
|
+
: nothing
|
|
267
|
+
}
|
|
268
|
+
</svg>`;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
private renderGraticule() {
|
|
272
|
+
const meridians = [];
|
|
273
|
+
for (let lon = -150; lon <= 150; lon += 30) {
|
|
274
|
+
const x = lonToX(lon);
|
|
275
|
+
const axis = lon === 0;
|
|
276
|
+
meridians.push(
|
|
277
|
+
svg`<line class=${axis ? 'grat-axis' : 'grat'} x1=${x} y1="0" x2=${x} y2=${H} />`,
|
|
278
|
+
);
|
|
279
|
+
meridians.push(
|
|
280
|
+
svg`<text class="axis-label" x=${x} y=${H - 2} text-anchor="middle">${formatLon(lon)}</text>`,
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
const parallels = [];
|
|
284
|
+
for (let lat = -60; lat <= 60; lat += 30) {
|
|
285
|
+
const y = latToY(lat);
|
|
286
|
+
const axis = lat === 0;
|
|
287
|
+
parallels.push(
|
|
288
|
+
svg`<line class=${axis ? 'grat-axis' : 'grat'} x1="0" y1=${y} x2=${W} y2=${y} />`,
|
|
289
|
+
);
|
|
290
|
+
parallels.push(
|
|
291
|
+
svg`<text class="axis-label" x="2" y=${y - 1}>${formatLat(lat)}</text>`,
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
// Tropics and polar circles as dashed climate-band references.
|
|
295
|
+
const refs = [TROPIC, -TROPIC, POLAR, -POLAR].map(
|
|
296
|
+
(lat) =>
|
|
297
|
+
svg`<line class="grat-ref" x1="0" y1=${latToY(lat)} x2=${W} y2=${latToY(lat)} />`,
|
|
298
|
+
);
|
|
299
|
+
return svg`${meridians}${parallels}${refs}`;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
private renderBodyLines(line: LineSet, index: number) {
|
|
303
|
+
const color = planetColor(line.planet, index);
|
|
304
|
+
const glyph = line.symbol || line.planet.slice(0, 2);
|
|
305
|
+
const items = [
|
|
306
|
+
this.renderMeridian(
|
|
307
|
+
line.mc.longitude,
|
|
308
|
+
color,
|
|
309
|
+
glyph,
|
|
310
|
+
line.planet,
|
|
311
|
+
'mc',
|
|
312
|
+
false,
|
|
313
|
+
),
|
|
314
|
+
this.renderMeridian(
|
|
315
|
+
line.ic.longitude,
|
|
316
|
+
color,
|
|
317
|
+
glyph,
|
|
318
|
+
line.planet,
|
|
319
|
+
'ic',
|
|
320
|
+
true,
|
|
321
|
+
),
|
|
322
|
+
this.renderCurve(
|
|
323
|
+
line.ascendant.points,
|
|
324
|
+
color,
|
|
325
|
+
glyph,
|
|
326
|
+
line.planet,
|
|
327
|
+
'ascendant',
|
|
328
|
+
false,
|
|
329
|
+
),
|
|
330
|
+
this.renderCurve(
|
|
331
|
+
line.descendant.points,
|
|
332
|
+
color,
|
|
333
|
+
glyph,
|
|
334
|
+
line.planet,
|
|
335
|
+
'descendant',
|
|
336
|
+
true,
|
|
337
|
+
),
|
|
338
|
+
];
|
|
339
|
+
return svg`${items}`;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
private renderMeridian(
|
|
343
|
+
lon: number,
|
|
344
|
+
color: string,
|
|
345
|
+
glyph: string,
|
|
346
|
+
planet: string,
|
|
347
|
+
angle: string,
|
|
348
|
+
dashed: boolean,
|
|
349
|
+
) {
|
|
350
|
+
const x = lonToX(lon);
|
|
351
|
+
// MC label rides the top edge, IC the bottom, so the two meridians of one
|
|
352
|
+
// body never stack their glyphs at the same point.
|
|
353
|
+
const labelY = angle === 'ic' ? H - 7 : 9;
|
|
354
|
+
return svg`<g>
|
|
355
|
+
<line class=${`acg-line${dashed ? ' dashed' : ''}`} stroke=${color} x1=${x} y1="0" x2=${x} y2=${H}><title>${planet} ${ANGLE_LABEL[angle]} line</title></line>
|
|
356
|
+
<text class="acg-glyph" fill=${color} x=${x} y=${labelY} text-anchor="middle" dominant-baseline="central">${glyph}</text>
|
|
357
|
+
</g>`;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
private renderCurve(
|
|
361
|
+
points: GeoPoint[],
|
|
362
|
+
color: string,
|
|
363
|
+
glyph: string,
|
|
364
|
+
planet: string,
|
|
365
|
+
angle: string,
|
|
366
|
+
dashed: boolean,
|
|
367
|
+
) {
|
|
368
|
+
const segments = toSegments(points ?? []);
|
|
369
|
+
if (segments.length === 0) return nothing;
|
|
370
|
+
// Label at the sample nearest the equator, the most visible band.
|
|
371
|
+
const anchor = (points ?? []).reduce(
|
|
372
|
+
(best, p) => (Math.abs(p.latitude) < Math.abs(best.latitude) ? p : best),
|
|
373
|
+
points[0] ?? { latitude: 0, longitude: 0 },
|
|
374
|
+
);
|
|
375
|
+
return svg`<g>
|
|
376
|
+
${segments.map(
|
|
377
|
+
(pts) =>
|
|
378
|
+
svg`<polyline class=${`acg-line${dashed ? ' dashed' : ''}`} stroke=${color} points=${pts}><title>${planet} ${ANGLE_LABEL[angle]} line</title></polyline>`,
|
|
379
|
+
)}
|
|
380
|
+
<text class="acg-glyph" fill=${color} x=${lonToX(anchor.longitude)} y=${latToY(anchor.latitude)} text-anchor="middle" dominant-baseline="central">${glyph}</text>
|
|
381
|
+
</g>`;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
private renderLegend(lines: LineSet[]) {
|
|
385
|
+
if (lines.length === 0) return nothing;
|
|
386
|
+
return html`<div class="legend">
|
|
387
|
+
${lines.map((l, i) => {
|
|
388
|
+
const color = planetColor(l.planet, i);
|
|
389
|
+
return html`<span class="legend-item">
|
|
390
|
+
<span class="legend-swatch" style=${`border-top-color: ${color}`}></span>
|
|
391
|
+
${l.symbol ? html`${l.symbol} ` : nothing}${l.planet}
|
|
392
|
+
</span>`;
|
|
393
|
+
})}
|
|
394
|
+
<span class="legend-note">Solid lines are the Ascendant and Midheaven, dashed are the Descendant and IC.</span>
|
|
395
|
+
</div>`;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
private renderInterpretations(lines: LineSet[]) {
|
|
399
|
+
if (lines.length === 0) return nothing;
|
|
400
|
+
return html`<section class="interpretations">
|
|
401
|
+
<h3>Planetary lines</h3>
|
|
402
|
+
${lines.map((l, i) => {
|
|
403
|
+
const color = planetColor(l.planet, i);
|
|
404
|
+
const rows: Array<[string, string]> = [
|
|
405
|
+
['MC', l.mc.interpretation],
|
|
406
|
+
['IC', l.ic.interpretation],
|
|
407
|
+
['AC', l.ascendant.interpretation],
|
|
408
|
+
['DC', l.descendant.interpretation],
|
|
409
|
+
];
|
|
410
|
+
return html`<details class="interp-card" name="acg-lines" ?open=${i === 0}>
|
|
411
|
+
<summary>
|
|
412
|
+
<span class="interp-head">
|
|
413
|
+
<span class="interp-dot" style=${`background: ${color}`}></span>
|
|
414
|
+
${l.symbol ? html`${l.symbol} ` : nothing}${l.planet}
|
|
415
|
+
</span>
|
|
416
|
+
${chevron()}
|
|
417
|
+
</summary>
|
|
418
|
+
<div class="interp-body">
|
|
419
|
+
${rows
|
|
420
|
+
.filter(([, text]) => text)
|
|
421
|
+
.map(
|
|
422
|
+
([code, text]) =>
|
|
423
|
+
html`<p class="interp-line"><span class="code">${code}</span>${text}</p>`,
|
|
424
|
+
)}
|
|
425
|
+
</div>
|
|
426
|
+
</details>`;
|
|
427
|
+
})}
|
|
428
|
+
</section>`;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
declare global {
|
|
433
|
+
interface HTMLElementTagNameMap {
|
|
434
|
+
'roxy-astrocartography-map': RoxyAstrocartographyMap;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
@@ -47,6 +47,18 @@ export class RoxyDoshaCard extends RoxyDataElement<DoshaData> {
|
|
|
47
47
|
font-weight: var(--roxy-weight-bold, 600);
|
|
48
48
|
text-transform: capitalize;
|
|
49
49
|
}
|
|
50
|
+
.subtype {
|
|
51
|
+
margin: 0;
|
|
52
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
53
|
+
color: var(--roxy-fg, #0a0a0a);
|
|
54
|
+
}
|
|
55
|
+
.subtype .subtype-label {
|
|
56
|
+
color: var(--roxy-muted, #71717a);
|
|
57
|
+
text-transform: uppercase;
|
|
58
|
+
letter-spacing: 0.06em;
|
|
59
|
+
font-size: var(--roxy-text-xs, 0.75rem);
|
|
60
|
+
margin-right: 0.4rem;
|
|
61
|
+
}
|
|
50
62
|
.badge {
|
|
51
63
|
display: inline-flex;
|
|
52
64
|
align-items: center;
|
|
@@ -135,14 +147,15 @@ export class RoxyDoshaCard extends RoxyDataElement<DoshaData> {
|
|
|
135
147
|
? 1
|
|
136
148
|
: 0;
|
|
137
149
|
const pct = tier * 33;
|
|
150
|
+
// A present dosha is never "good news": keep the ramp in the warning/danger
|
|
151
|
+
// family so a Mild severity does not paint green and read as benign. The bar
|
|
152
|
+
// width already conveys the tier.
|
|
138
153
|
const barColor =
|
|
139
154
|
tier === 3
|
|
140
155
|
? 'var(--roxy-danger)'
|
|
141
|
-
: tier
|
|
156
|
+
: tier >= 1
|
|
142
157
|
? 'var(--roxy-warning)'
|
|
143
|
-
:
|
|
144
|
-
? 'var(--roxy-success)'
|
|
145
|
-
: 'transparent';
|
|
158
|
+
: 'transparent';
|
|
146
159
|
|
|
147
160
|
return html`<article
|
|
148
161
|
class="card"
|
|
@@ -154,6 +167,13 @@ export class RoxyDoshaCard extends RoxyDataElement<DoshaData> {
|
|
|
154
167
|
${present ? 'Present' : 'Absent'}
|
|
155
168
|
</span>
|
|
156
169
|
</header>
|
|
170
|
+
${
|
|
171
|
+
'type' in d && d.type
|
|
172
|
+
? html`<p class="subtype">
|
|
173
|
+
<span class="subtype-label">${this.type === 'sadhesati' ? 'Current phase' : 'Type'}</span>${d.type}
|
|
174
|
+
</p>`
|
|
175
|
+
: nothing
|
|
176
|
+
}
|
|
157
177
|
${
|
|
158
178
|
d.severity
|
|
159
179
|
? html`<div
|
|
@@ -195,18 +215,30 @@ export class RoxyDoshaCard extends RoxyDataElement<DoshaData> {
|
|
|
195
215
|
|
|
196
216
|
private renderEffects(d: DoshaData) {
|
|
197
217
|
if (!d.effects) return nothing;
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
</div
|
|
208
|
-
)
|
|
209
|
-
|
|
218
|
+
// Effects mix flat string fields (marriage, career...) with a nested map
|
|
219
|
+
// (Sadhesati effects.phases: { Rising, Peak, Setting }). Render both; the
|
|
220
|
+
// old string-only filter silently dropped the phase-specific effects, which
|
|
221
|
+
// are the substance of a Sade Sati reading.
|
|
222
|
+
const sections: unknown[] = [];
|
|
223
|
+
for (const [key, value] of Object.entries(
|
|
224
|
+
d.effects as Record<string, unknown>,
|
|
225
|
+
)) {
|
|
226
|
+
if (typeof value === 'string' && value.length > 0) {
|
|
227
|
+
sections.push(html`<div><h3>${key}</h3><p>${value}</p></div>`);
|
|
228
|
+
} else if (value && typeof value === 'object') {
|
|
229
|
+
for (const [nestedKey, nestedValue] of Object.entries(
|
|
230
|
+
value as Record<string, unknown>,
|
|
231
|
+
)) {
|
|
232
|
+
if (typeof nestedValue === 'string' && nestedValue.length > 0) {
|
|
233
|
+
sections.push(
|
|
234
|
+
html`<div><h3>${nestedKey}</h3><p>${nestedValue}</p></div>`,
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
if (sections.length === 0) return nothing;
|
|
241
|
+
return html`<div class="effects">${sections}</div>`;
|
|
210
242
|
}
|
|
211
243
|
}
|
|
212
244
|
|