@roxyapi/ui 0.0.1 → 0.1.1
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 +169 -0
- package/THEMING.md +129 -0
- package/dist/cdn/components/biorhythm-chart.js +261 -0
- package/dist/cdn/components/biorhythm-chart.js.map +7 -0
- package/dist/cdn/components/compatibility-card.js +257 -0
- package/dist/cdn/components/compatibility-card.js.map +7 -0
- package/dist/cdn/components/dasha-timeline.js +244 -0
- package/dist/cdn/components/dasha-timeline.js.map +7 -0
- package/dist/cdn/components/data.js +258 -0
- package/dist/cdn/components/data.js.map +7 -0
- package/dist/cdn/components/dosha-card.js +254 -0
- package/dist/cdn/components/dosha-card.js.map +7 -0
- package/dist/cdn/components/endpoint-form.js +253 -0
- package/dist/cdn/components/endpoint-form.js.map +7 -0
- package/dist/cdn/components/guna-milan.js +256 -0
- package/dist/cdn/components/guna-milan.js.map +7 -0
- package/dist/cdn/components/hexagram.js +275 -0
- package/dist/cdn/components/hexagram.js.map +7 -0
- package/dist/cdn/components/horoscope-card.js +302 -0
- package/dist/cdn/components/horoscope-card.js.map +7 -0
- package/dist/cdn/components/kp-planets-table.js +224 -0
- package/dist/cdn/components/kp-planets-table.js.map +7 -0
- package/dist/cdn/components/location-search.js +267 -0
- package/dist/cdn/components/location-search.js.map +7 -0
- package/dist/cdn/components/moon-phase.js +251 -0
- package/dist/cdn/components/moon-phase.js.map +7 -0
- package/dist/cdn/components/natal-chart.js +237 -0
- package/dist/cdn/components/natal-chart.js.map +7 -0
- package/dist/cdn/components/numerology-card.js +252 -0
- package/dist/cdn/components/numerology-card.js.map +7 -0
- package/dist/cdn/components/panchang-table.js +234 -0
- package/dist/cdn/components/panchang-table.js.map +7 -0
- package/dist/cdn/components/synastry-chart.js +303 -0
- package/dist/cdn/components/synastry-chart.js.map +7 -0
- package/dist/cdn/components/tarot-card.js +260 -0
- package/dist/cdn/components/tarot-card.js.map +7 -0
- package/dist/cdn/components/tarot-spread.js +261 -0
- package/dist/cdn/components/tarot-spread.js.map +7 -0
- package/dist/cdn/components/vedic-kundli.js +189 -0
- package/dist/cdn/components/vedic-kundli.js.map +7 -0
- package/dist/cdn/roxy-ui.js +2552 -0
- package/dist/cdn/roxy-ui.js.map +7 -0
- package/dist/cdn/widgets.js +114 -0
- package/dist/components/biorhythm-chart.d.ts +66 -0
- package/dist/components/biorhythm-chart.d.ts.map +1 -0
- package/dist/components/biorhythm-chart.js +318 -0
- package/dist/components/biorhythm-chart.js.map +7 -0
- package/dist/components/compatibility-card.d.ts +46 -0
- package/dist/components/compatibility-card.d.ts.map +1 -0
- package/dist/components/compatibility-card.js +279 -0
- package/dist/components/compatibility-card.js.map +7 -0
- package/dist/components/dasha-timeline.d.ts +53 -0
- package/dist/components/dasha-timeline.d.ts.map +1 -0
- package/dist/components/dasha-timeline.js +269 -0
- package/dist/components/dasha-timeline.js.map +7 -0
- package/dist/components/data.d.ts +40 -0
- package/dist/components/data.d.ts.map +1 -0
- package/dist/components/data.js +339 -0
- package/dist/components/data.js.map +7 -0
- package/dist/components/dosha-card.d.ts +35 -0
- package/dist/components/dosha-card.d.ts.map +1 -0
- package/dist/components/dosha-card.js +278 -0
- package/dist/components/dosha-card.js.map +7 -0
- package/dist/components/endpoint-form.d.ts +39 -0
- package/dist/components/endpoint-form.d.ts.map +1 -0
- package/dist/components/endpoint-form.js +432 -0
- package/dist/components/endpoint-form.js.map +7 -0
- package/dist/components/guna-milan.d.ts +35 -0
- package/dist/components/guna-milan.d.ts.map +1 -0
- package/dist/components/guna-milan.js +302 -0
- package/dist/components/guna-milan.js.map +7 -0
- package/dist/components/hexagram.d.ts +47 -0
- package/dist/components/hexagram.d.ts.map +1 -0
- package/dist/components/hexagram.js +334 -0
- package/dist/components/hexagram.js.map +7 -0
- package/dist/components/horoscope-card.d.ts +38 -0
- package/dist/components/horoscope-card.d.ts.map +1 -0
- package/dist/components/horoscope-card.js +332 -0
- package/dist/components/horoscope-card.js.map +7 -0
- package/dist/components/kp-planets-table.d.ts +36 -0
- package/dist/components/kp-planets-table.d.ts.map +1 -0
- package/dist/components/kp-planets-table.js +227 -0
- package/dist/components/kp-planets-table.js.map +7 -0
- package/dist/components/location-search.d.ts +56 -0
- package/dist/components/location-search.d.ts.map +1 -0
- package/dist/components/location-search.js +401 -0
- package/dist/components/location-search.js.map +7 -0
- package/dist/components/moon-phase.d.ts +38 -0
- package/dist/components/moon-phase.d.ts.map +1 -0
- package/dist/components/moon-phase.js +284 -0
- package/dist/components/moon-phase.js.map +7 -0
- package/dist/components/natal-chart.d.ts +65 -0
- package/dist/components/natal-chart.d.ts.map +1 -0
- package/dist/components/natal-chart.js +407 -0
- package/dist/components/natal-chart.js.map +7 -0
- package/dist/components/numerology-card.d.ts +55 -0
- package/dist/components/numerology-card.d.ts.map +1 -0
- package/dist/components/numerology-card.js +274 -0
- package/dist/components/numerology-card.js.map +7 -0
- package/dist/components/panchang-table.d.ts +77 -0
- package/dist/components/panchang-table.d.ts.map +1 -0
- package/dist/components/panchang-table.js +285 -0
- package/dist/components/panchang-table.js.map +7 -0
- package/dist/components/synastry-chart.d.ts +52 -0
- package/dist/components/synastry-chart.d.ts.map +1 -0
- package/dist/components/synastry-chart.js +415 -0
- package/dist/components/synastry-chart.js.map +7 -0
- package/dist/components/tarot-card.d.ts +47 -0
- package/dist/components/tarot-card.d.ts.map +1 -0
- package/dist/components/tarot-card.js +281 -0
- package/dist/components/tarot-card.js.map +7 -0
- package/dist/components/tarot-spread.d.ts +42 -0
- package/dist/components/tarot-spread.d.ts.map +1 -0
- package/dist/components/tarot-spread.js +271 -0
- package/dist/components/tarot-spread.js.map +7 -0
- package/dist/components/vedic-kundli.d.ts +45 -0
- package/dist/components/vedic-kundli.d.ts.map +1 -0
- package/dist/components/vedic-kundli.js +325 -0
- package/dist/components/vedic-kundli.js.map +7 -0
- package/dist/index.cjs +4174 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4154 -0
- package/dist/index.js.map +7 -0
- package/dist/manifest.json +24 -0
- package/dist/styles/tokens.css +147 -0
- package/dist/tokens/index.d.ts +17 -0
- package/dist/tokens/index.d.ts.map +1 -0
- package/dist/utils/base-styles.d.ts +6 -0
- package/dist/utils/base-styles.d.ts.map +1 -0
- package/dist/utils/debounce.d.ts +5 -0
- package/dist/utils/debounce.d.ts.map +1 -0
- package/dist/utils/degree.d.ts +29 -0
- package/dist/utils/degree.d.ts.map +1 -0
- package/dist/utils/motion.d.ts +13 -0
- package/dist/utils/motion.d.ts.map +1 -0
- package/package.json +69 -3
- package/src/components/biorhythm-chart.ts +290 -0
- package/src/components/compatibility-card.ts +231 -0
- package/src/components/dasha-timeline.ts +251 -0
- package/src/components/data.ts +287 -0
- package/src/components/dosha-card.ts +215 -0
- package/src/components/endpoint-form.ts +433 -0
- package/src/components/guna-milan.ts +245 -0
- package/src/components/hexagram.ts +279 -0
- package/src/components/horoscope-card.ts +291 -0
- package/src/components/kp-planets-table.ts +156 -0
- package/src/components/location-search.ts +335 -0
- package/src/components/moon-phase.ts +221 -0
- package/src/components/natal-chart.ts +298 -0
- package/src/components/numerology-card.ts +243 -0
- package/src/components/panchang-table.ts +265 -0
- package/src/components/synastry-chart.ts +341 -0
- package/src/components/tarot-card.ts +235 -0
- package/src/components/tarot-spread.ts +224 -0
- package/src/components/vedic-kundli.ts +257 -0
- package/src/index.ts +61 -0
- package/src/styles/tokens.css +147 -0
- package/src/tokens/index.ts +130 -0
- package/src/types/index.ts +3 -0
- package/src/types/types.gen.ts +28526 -0
- package/src/utils/base-styles.ts +89 -0
- package/src/utils/debounce.ts +13 -0
- package/src/utils/degree.ts +64 -0
- package/src/utils/motion.ts +18 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
export interface CityResult {
|
|
3
|
+
city: string;
|
|
4
|
+
province?: string;
|
|
5
|
+
country: string;
|
|
6
|
+
iso2?: string;
|
|
7
|
+
latitude: number;
|
|
8
|
+
longitude: number;
|
|
9
|
+
timezone: string;
|
|
10
|
+
utcOffset: number;
|
|
11
|
+
population?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Stateful location search input. Calls /location/search and emits
|
|
15
|
+
* `roxy-location-select` CustomEvent with the chosen city. Required for any
|
|
16
|
+
* chart endpoint.
|
|
17
|
+
*
|
|
18
|
+
* Lifted from jyotish-vedic-astrology-app/src/components/city-search.tsx,
|
|
19
|
+
* keeping the 300ms debounce and click-outside behavior, replacing React
|
|
20
|
+
* state with Lit reactive properties and using direct fetch to RoxyAPI.
|
|
21
|
+
*
|
|
22
|
+
* Attributes:
|
|
23
|
+
* api-key optional. Direct call to roxyapi.com when set.
|
|
24
|
+
* publishable-key optional. Browser-safe pk_* key with allowed_origins.
|
|
25
|
+
* endpoint optional. Override URL (default https://roxyapi.com/api/v2/location/search).
|
|
26
|
+
* placeholder optional. Input placeholder.
|
|
27
|
+
* default-value optional. Pre-filled query.
|
|
28
|
+
*/
|
|
29
|
+
export declare class RoxyLocationSearch extends LitElement {
|
|
30
|
+
static styles: import("lit").CSSResult[];
|
|
31
|
+
apiKey?: string;
|
|
32
|
+
publishableKey?: string;
|
|
33
|
+
endpoint: string;
|
|
34
|
+
placeholder: string;
|
|
35
|
+
defaultValue: string;
|
|
36
|
+
private query;
|
|
37
|
+
private results;
|
|
38
|
+
private isOpen;
|
|
39
|
+
private isLoading;
|
|
40
|
+
private highlight;
|
|
41
|
+
private clickOutsideHandler?;
|
|
42
|
+
private debouncedFetch;
|
|
43
|
+
connectedCallback(): void;
|
|
44
|
+
disconnectedCallback(): void;
|
|
45
|
+
private fetchResults;
|
|
46
|
+
private onInput;
|
|
47
|
+
private select;
|
|
48
|
+
private onKeyDown;
|
|
49
|
+
render(): import("lit").TemplateResult<1>;
|
|
50
|
+
}
|
|
51
|
+
declare global {
|
|
52
|
+
interface HTMLElementTagNameMap {
|
|
53
|
+
'roxy-location-search': RoxyLocationSearch;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=location-search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"location-search.d.ts","sourceRoot":"","sources":["../../src/components/location-search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAKrD,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAOD;;;;;;;;;;;;;;;GAeG;AACH,qBACa,kBAAmB,SAAQ,UAAU;IACjD,MAAM,CAAC,MAAM,4BAwGX;IAGF,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,QAAQ,SAAgD;IAGxD,WAAW,SAAiB;IAG5B,YAAY,SAAM;IAGlB,OAAO,CAAC,KAAK,CAAM;IAGnB,OAAO,CAAC,OAAO,CAAoB;IAGnC,OAAO,CAAC,MAAM,CAAS;IAGvB,OAAO,CAAC,SAAS,CAAS;IAG1B,OAAO,CAAC,SAAS,CAAM;IAEvB,OAAO,CAAC,mBAAmB,CAAC,CAA0B;IACtD,OAAO,CAAC,cAAc,CAEd;IAER,iBAAiB,IAAI,IAAI;IAUzB,oBAAoB,IAAI,IAAI;YAOd,YAAY;IAyB1B,OAAO,CAAC,OAAO,CAUb;IAEF,OAAO,CAAC,MAAM;IAad,OAAO,CAAC,SAAS,CAsBf;IAEF,MAAM;CAwDN;AAED,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,sBAAsB,EAAE,kBAAkB,CAAC;KAC3C;CACD"}
|
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result) __defProp(target, key, result);
|
|
9
|
+
return result;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// packages/ui/src/components/location-search.ts
|
|
13
|
+
import { css as css2, html, LitElement, nothing } from "lit";
|
|
14
|
+
import { customElement, property, state } from "lit/decorators.js";
|
|
15
|
+
|
|
16
|
+
// packages/ui/src/utils/base-styles.ts
|
|
17
|
+
import { css } from "lit";
|
|
18
|
+
var baseStyles = css`
|
|
19
|
+
:host {
|
|
20
|
+
display: block;
|
|
21
|
+
container-type: inline-size;
|
|
22
|
+
font-family: var(
|
|
23
|
+
--roxy-font-sans,
|
|
24
|
+
system-ui,
|
|
25
|
+
-apple-system,
|
|
26
|
+
BlinkMacSystemFont,
|
|
27
|
+
'Segoe UI',
|
|
28
|
+
Roboto,
|
|
29
|
+
sans-serif
|
|
30
|
+
);
|
|
31
|
+
color: var(--roxy-fg, #0a0a0a);
|
|
32
|
+
background: transparent;
|
|
33
|
+
font-size: var(--roxy-text-base, 1rem);
|
|
34
|
+
line-height: var(--roxy-leading-normal, 1.5);
|
|
35
|
+
animation: roxy-fade-in var(--roxy-motion-duration, 200ms)
|
|
36
|
+
var(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
*,
|
|
40
|
+
*::before,
|
|
41
|
+
*::after {
|
|
42
|
+
box-sizing: border-box;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@keyframes roxy-fade-in {
|
|
46
|
+
from {
|
|
47
|
+
opacity: 0;
|
|
48
|
+
transform: translateY(2px);
|
|
49
|
+
}
|
|
50
|
+
to {
|
|
51
|
+
opacity: 1;
|
|
52
|
+
transform: translateY(0);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@media (prefers-reduced-motion: reduce) {
|
|
57
|
+
:host {
|
|
58
|
+
animation: none;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.roxy-skeleton {
|
|
63
|
+
background: linear-gradient(
|
|
64
|
+
90deg,
|
|
65
|
+
var(--roxy-border, #e4e4e7) 0%,
|
|
66
|
+
color-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,
|
|
67
|
+
var(--roxy-border, #e4e4e7) 100%
|
|
68
|
+
);
|
|
69
|
+
background-size: 200% 100%;
|
|
70
|
+
animation: roxy-shimmer 1.4s ease-in-out infinite;
|
|
71
|
+
border-radius: var(--roxy-radius-md, 8px);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@keyframes roxy-shimmer {
|
|
75
|
+
0% {
|
|
76
|
+
background-position: 200% 0;
|
|
77
|
+
}
|
|
78
|
+
100% {
|
|
79
|
+
background-position: -200% 0;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@media (prefers-reduced-motion: reduce) {
|
|
84
|
+
.roxy-skeleton {
|
|
85
|
+
animation: none;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.roxy-empty {
|
|
90
|
+
padding: var(--roxy-space-lg, 1.5rem);
|
|
91
|
+
color: var(--roxy-muted, #71717a);
|
|
92
|
+
text-align: center;
|
|
93
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
:host(:focus-within) .roxy-card {
|
|
97
|
+
outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
|
|
98
|
+
outline-offset: 2px;
|
|
99
|
+
}
|
|
100
|
+
`;
|
|
101
|
+
|
|
102
|
+
// packages/ui/src/utils/debounce.ts
|
|
103
|
+
function debounce(fn, wait) {
|
|
104
|
+
let timer;
|
|
105
|
+
return ((...args) => {
|
|
106
|
+
if (timer) clearTimeout(timer);
|
|
107
|
+
timer = setTimeout(() => fn(...args), wait);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// packages/ui/src/components/location-search.ts
|
|
112
|
+
var RoxyLocationSearch = class extends LitElement {
|
|
113
|
+
constructor() {
|
|
114
|
+
super(...arguments);
|
|
115
|
+
this.endpoint = "https://roxyapi.com/api/v2/location/search";
|
|
116
|
+
this.placeholder = "Search city";
|
|
117
|
+
this.defaultValue = "";
|
|
118
|
+
this.query = "";
|
|
119
|
+
this.results = [];
|
|
120
|
+
this.isOpen = false;
|
|
121
|
+
this.isLoading = false;
|
|
122
|
+
this.highlight = -1;
|
|
123
|
+
this.debouncedFetch = debounce((q) => {
|
|
124
|
+
void this.fetchResults(q);
|
|
125
|
+
}, 300);
|
|
126
|
+
this.onInput = (e) => {
|
|
127
|
+
const value = e.target.value;
|
|
128
|
+
this.query = value;
|
|
129
|
+
if (value.length < 2) {
|
|
130
|
+
this.results = [];
|
|
131
|
+
this.isOpen = false;
|
|
132
|
+
this.highlight = -1;
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.debouncedFetch(value);
|
|
136
|
+
};
|
|
137
|
+
this.onKeyDown = (e) => {
|
|
138
|
+
if (!this.isOpen || this.results.length === 0) {
|
|
139
|
+
if (e.key === "ArrowDown" && this.query.length >= 2) {
|
|
140
|
+
void this.fetchResults(this.query);
|
|
141
|
+
e.preventDefault();
|
|
142
|
+
}
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
if (e.key === "ArrowDown") {
|
|
146
|
+
e.preventDefault();
|
|
147
|
+
this.highlight = (this.highlight + 1) % this.results.length;
|
|
148
|
+
} else if (e.key === "ArrowUp") {
|
|
149
|
+
e.preventDefault();
|
|
150
|
+
this.highlight = (this.highlight - 1 + this.results.length) % this.results.length;
|
|
151
|
+
} else if (e.key === "Enter") {
|
|
152
|
+
e.preventDefault();
|
|
153
|
+
const target = this.results[this.highlight] ?? this.results[0];
|
|
154
|
+
if (target) this.select(target);
|
|
155
|
+
} else if (e.key === "Escape") {
|
|
156
|
+
this.isOpen = false;
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
connectedCallback() {
|
|
161
|
+
super.connectedCallback();
|
|
162
|
+
this.query = this.defaultValue;
|
|
163
|
+
this.clickOutsideHandler = (e) => {
|
|
164
|
+
const path = e.composedPath();
|
|
165
|
+
if (!path.includes(this)) this.isOpen = false;
|
|
166
|
+
};
|
|
167
|
+
document.addEventListener("mousedown", this.clickOutsideHandler);
|
|
168
|
+
}
|
|
169
|
+
disconnectedCallback() {
|
|
170
|
+
super.disconnectedCallback();
|
|
171
|
+
if (this.clickOutsideHandler) {
|
|
172
|
+
document.removeEventListener("mousedown", this.clickOutsideHandler);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
async fetchResults(q) {
|
|
176
|
+
this.isLoading = true;
|
|
177
|
+
try {
|
|
178
|
+
const url = new URL(this.endpoint);
|
|
179
|
+
url.searchParams.set("q", q);
|
|
180
|
+
url.searchParams.set("limit", "8");
|
|
181
|
+
const headers = {
|
|
182
|
+
Accept: "application/json"
|
|
183
|
+
};
|
|
184
|
+
if (this.apiKey) headers["X-API-Key"] = this.apiKey;
|
|
185
|
+
if (this.publishableKey) headers["X-API-Key"] = this.publishableKey;
|
|
186
|
+
const res = await fetch(url, { headers });
|
|
187
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
188
|
+
const json = await res.json();
|
|
189
|
+
this.results = json.cities ?? [];
|
|
190
|
+
this.isOpen = this.results.length > 0;
|
|
191
|
+
this.highlight = this.results.length > 0 ? 0 : -1;
|
|
192
|
+
} catch (_err) {
|
|
193
|
+
this.results = [];
|
|
194
|
+
this.isOpen = false;
|
|
195
|
+
} finally {
|
|
196
|
+
this.isLoading = false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
select(city) {
|
|
200
|
+
this.query = `${city.city}${city.province ? `, ${city.province}` : ""}, ${city.country}`;
|
|
201
|
+
this.isOpen = false;
|
|
202
|
+
this.results = [];
|
|
203
|
+
this.dispatchEvent(
|
|
204
|
+
new CustomEvent("roxy-location-select", {
|
|
205
|
+
detail: city,
|
|
206
|
+
bubbles: true,
|
|
207
|
+
composed: true
|
|
208
|
+
})
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
render() {
|
|
212
|
+
return html`<div class="field">
|
|
213
|
+
<input
|
|
214
|
+
type="text"
|
|
215
|
+
role="combobox"
|
|
216
|
+
aria-expanded=${this.isOpen ? "true" : "false"}
|
|
217
|
+
aria-controls="roxy-location-listbox"
|
|
218
|
+
aria-autocomplete="list"
|
|
219
|
+
autocomplete="off"
|
|
220
|
+
placeholder=${this.placeholder}
|
|
221
|
+
.value=${this.query}
|
|
222
|
+
@input=${this.onInput}
|
|
223
|
+
@keydown=${this.onKeyDown}
|
|
224
|
+
@focus=${() => {
|
|
225
|
+
if (this.results.length > 0) this.isOpen = true;
|
|
226
|
+
}}
|
|
227
|
+
/>
|
|
228
|
+
${this.isLoading ? html`<span class="spinner" role="status" aria-label="Loading"></span>` : nothing}
|
|
229
|
+
${this.isOpen ? html`<ul
|
|
230
|
+
id="roxy-location-listbox"
|
|
231
|
+
class="results"
|
|
232
|
+
role="listbox"
|
|
233
|
+
>
|
|
234
|
+
${this.results.length === 0 ? html`<li class="empty" role="status">No cities found</li>` : this.results.map(
|
|
235
|
+
(city, idx) => html`<li role="presentation">
|
|
236
|
+
<button
|
|
237
|
+
type="button"
|
|
238
|
+
class="option"
|
|
239
|
+
role="option"
|
|
240
|
+
aria-selected=${this.highlight === idx ? "true" : "false"}
|
|
241
|
+
@click=${() => this.select(city)}
|
|
242
|
+
@mouseenter=${() => {
|
|
243
|
+
this.highlight = idx;
|
|
244
|
+
}}
|
|
245
|
+
>
|
|
246
|
+
<span class="city">${city.city}</span>
|
|
247
|
+
<span class="where"
|
|
248
|
+
>${city.province ? html`${city.province}, ` : ""}${city.country}</span
|
|
249
|
+
>
|
|
250
|
+
<span class="tz"
|
|
251
|
+
>UTC${city.utcOffset >= 0 ? "+" : ""}${city.utcOffset}</span
|
|
252
|
+
>
|
|
253
|
+
</button>
|
|
254
|
+
</li>`
|
|
255
|
+
)}
|
|
256
|
+
</ul>` : nothing}
|
|
257
|
+
</div>`;
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
RoxyLocationSearch.styles = [
|
|
261
|
+
baseStyles,
|
|
262
|
+
css2`
|
|
263
|
+
:host {
|
|
264
|
+
display: block;
|
|
265
|
+
position: relative;
|
|
266
|
+
}
|
|
267
|
+
.field {
|
|
268
|
+
position: relative;
|
|
269
|
+
}
|
|
270
|
+
input {
|
|
271
|
+
width: 100%;
|
|
272
|
+
padding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);
|
|
273
|
+
font-size: var(--roxy-text-base, 1rem);
|
|
274
|
+
font-family: inherit;
|
|
275
|
+
color: var(--roxy-fg, #0a0a0a);
|
|
276
|
+
background: var(--roxy-bg, #fff);
|
|
277
|
+
border: 1px solid var(--roxy-border, #e4e4e7);
|
|
278
|
+
border-radius: var(--roxy-radius-md, 8px);
|
|
279
|
+
transition:
|
|
280
|
+
border-color var(--roxy-motion-duration, 200ms)
|
|
281
|
+
var(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));
|
|
282
|
+
box-sizing: border-box;
|
|
283
|
+
}
|
|
284
|
+
input:focus {
|
|
285
|
+
outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
|
|
286
|
+
outline-offset: 2px;
|
|
287
|
+
border-color: var(--roxy-accent-fg, #b45309);
|
|
288
|
+
}
|
|
289
|
+
.spinner {
|
|
290
|
+
position: absolute;
|
|
291
|
+
right: 12px;
|
|
292
|
+
top: 50%;
|
|
293
|
+
transform: translateY(-50%);
|
|
294
|
+
width: 14px;
|
|
295
|
+
height: 14px;
|
|
296
|
+
border: 2px solid var(--roxy-muted, #71717a);
|
|
297
|
+
border-top-color: transparent;
|
|
298
|
+
border-radius: 50%;
|
|
299
|
+
animation: roxy-spin 700ms linear infinite;
|
|
300
|
+
}
|
|
301
|
+
@keyframes roxy-spin {
|
|
302
|
+
to {
|
|
303
|
+
transform: translateY(-50%) rotate(360deg);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
@media (prefers-reduced-motion: reduce) {
|
|
307
|
+
.spinner {
|
|
308
|
+
animation: none;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.results {
|
|
313
|
+
position: absolute;
|
|
314
|
+
z-index: 50;
|
|
315
|
+
top: calc(100% + 4px);
|
|
316
|
+
left: 0;
|
|
317
|
+
right: 0;
|
|
318
|
+
background: var(--roxy-bg, #fff);
|
|
319
|
+
border: 1px solid var(--roxy-border, #e4e4e7);
|
|
320
|
+
border-radius: var(--roxy-radius-md, 8px);
|
|
321
|
+
box-shadow: var(--roxy-shadow-md);
|
|
322
|
+
max-height: 22rem;
|
|
323
|
+
overflow-y: auto;
|
|
324
|
+
animation: roxy-fade-in var(--roxy-motion-duration, 200ms)
|
|
325
|
+
var(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));
|
|
326
|
+
}
|
|
327
|
+
.option {
|
|
328
|
+
display: flex;
|
|
329
|
+
align-items: baseline;
|
|
330
|
+
gap: var(--roxy-space-sm, 0.5rem);
|
|
331
|
+
width: 100%;
|
|
332
|
+
padding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);
|
|
333
|
+
background: transparent;
|
|
334
|
+
border: 0;
|
|
335
|
+
text-align: left;
|
|
336
|
+
font-family: inherit;
|
|
337
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
338
|
+
color: var(--roxy-fg, #0a0a0a);
|
|
339
|
+
cursor: pointer;
|
|
340
|
+
transition: background-color var(--roxy-motion-duration, 200ms);
|
|
341
|
+
}
|
|
342
|
+
.option:hover,
|
|
343
|
+
.option[aria-selected='true'] {
|
|
344
|
+
background: color-mix(in srgb, var(--roxy-accent, #f59e0b) 10%, transparent);
|
|
345
|
+
}
|
|
346
|
+
.option .city {
|
|
347
|
+
font-weight: var(--roxy-weight-bold, 600);
|
|
348
|
+
}
|
|
349
|
+
.option .where {
|
|
350
|
+
color: var(--roxy-muted, #71717a);
|
|
351
|
+
flex-grow: 1;
|
|
352
|
+
}
|
|
353
|
+
.option .tz {
|
|
354
|
+
color: var(--roxy-muted, #71717a);
|
|
355
|
+
font-size: var(--roxy-text-xs, 0.75rem);
|
|
356
|
+
font-variant-numeric: tabular-nums;
|
|
357
|
+
}
|
|
358
|
+
.empty {
|
|
359
|
+
padding: var(--roxy-space-md, 1rem);
|
|
360
|
+
color: var(--roxy-muted, #71717a);
|
|
361
|
+
font-size: var(--roxy-text-sm, 0.875rem);
|
|
362
|
+
}
|
|
363
|
+
`
|
|
364
|
+
];
|
|
365
|
+
__decorateClass([
|
|
366
|
+
property({ type: String, attribute: "api-key" })
|
|
367
|
+
], RoxyLocationSearch.prototype, "apiKey", 2);
|
|
368
|
+
__decorateClass([
|
|
369
|
+
property({ type: String, attribute: "publishable-key" })
|
|
370
|
+
], RoxyLocationSearch.prototype, "publishableKey", 2);
|
|
371
|
+
__decorateClass([
|
|
372
|
+
property({ type: String })
|
|
373
|
+
], RoxyLocationSearch.prototype, "endpoint", 2);
|
|
374
|
+
__decorateClass([
|
|
375
|
+
property({ type: String })
|
|
376
|
+
], RoxyLocationSearch.prototype, "placeholder", 2);
|
|
377
|
+
__decorateClass([
|
|
378
|
+
property({ type: String, attribute: "default-value" })
|
|
379
|
+
], RoxyLocationSearch.prototype, "defaultValue", 2);
|
|
380
|
+
__decorateClass([
|
|
381
|
+
state()
|
|
382
|
+
], RoxyLocationSearch.prototype, "query", 2);
|
|
383
|
+
__decorateClass([
|
|
384
|
+
state()
|
|
385
|
+
], RoxyLocationSearch.prototype, "results", 2);
|
|
386
|
+
__decorateClass([
|
|
387
|
+
state()
|
|
388
|
+
], RoxyLocationSearch.prototype, "isOpen", 2);
|
|
389
|
+
__decorateClass([
|
|
390
|
+
state()
|
|
391
|
+
], RoxyLocationSearch.prototype, "isLoading", 2);
|
|
392
|
+
__decorateClass([
|
|
393
|
+
state()
|
|
394
|
+
], RoxyLocationSearch.prototype, "highlight", 2);
|
|
395
|
+
RoxyLocationSearch = __decorateClass([
|
|
396
|
+
customElement("roxy-location-search")
|
|
397
|
+
], RoxyLocationSearch);
|
|
398
|
+
export {
|
|
399
|
+
RoxyLocationSearch
|
|
400
|
+
};
|
|
401
|
+
//# sourceMappingURL=location-search.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/components/location-search.ts", "../../src/utils/base-styles.ts", "../../src/utils/debounce.ts"],
|
|
4
|
+
"sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { debounce } from '../utils/debounce.js';\n\nexport interface CityResult {\n\tcity: string;\n\tprovince?: string;\n\tcountry: string;\n\tiso2?: string;\n\tlatitude: number;\n\tlongitude: number;\n\ttimezone: string;\n\tutcOffset: number;\n\tpopulation?: number;\n}\n\ninterface CitySearchResponse {\n\ttotal?: number;\n\tcities?: CityResult[];\n}\n\n/**\n * Stateful location search input. Calls /location/search and emits\n * `roxy-location-select` CustomEvent with the chosen city. Required for any\n * chart endpoint.\n *\n * Lifted from jyotish-vedic-astrology-app/src/components/city-search.tsx,\n * keeping the 300ms debounce and click-outside behavior, replacing React\n * state with Lit reactive properties and using direct fetch to RoxyAPI.\n *\n * Attributes:\n * api-key optional. Direct call to roxyapi.com when set.\n * publishable-key optional. Browser-safe pk_* key with allowed_origins.\n * endpoint optional. Override URL (default https://roxyapi.com/api/v2/location/search).\n * placeholder optional. Input placeholder.\n * default-value optional. Pre-filled query.\n */\n@customElement('roxy-location-search')\nexport class RoxyLocationSearch extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\t:host {\n\t\t\t\tdisplay: block;\n\t\t\t\tposition: relative;\n\t\t\t}\n\t\t\t.field {\n\t\t\t\tposition: relative;\n\t\t\t}\n\t\t\tinput {\n\t\t\t\twidth: 100%;\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\t\t\tfont-family: inherit;\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\ttransition:\n\t\t\t\t\tborder-color var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t\tbox-sizing: border-box;\n\t\t\t}\n\t\t\tinput:focus {\n\t\t\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\t\t\toutline-offset: 2px;\n\t\t\t\tborder-color: var(--roxy-accent-fg, #b45309);\n\t\t\t}\n\t\t\t.spinner {\n\t\t\t\tposition: absolute;\n\t\t\t\tright: 12px;\n\t\t\t\ttop: 50%;\n\t\t\t\ttransform: translateY(-50%);\n\t\t\t\twidth: 14px;\n\t\t\t\theight: 14px;\n\t\t\t\tborder: 2px solid var(--roxy-muted, #71717a);\n\t\t\t\tborder-top-color: transparent;\n\t\t\t\tborder-radius: 50%;\n\t\t\t\tanimation: roxy-spin 700ms linear infinite;\n\t\t\t}\n\t\t\t@keyframes roxy-spin {\n\t\t\t\tto {\n\t\t\t\t\ttransform: translateY(-50%) rotate(360deg);\n\t\t\t\t}\n\t\t\t}\n\t\t\t@media (prefers-reduced-motion: reduce) {\n\t\t\t\t.spinner {\n\t\t\t\t\tanimation: none;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t.results {\n\t\t\t\tposition: absolute;\n\t\t\t\tz-index: 50;\n\t\t\t\ttop: calc(100% + 4px);\n\t\t\t\tleft: 0;\n\t\t\t\tright: 0;\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tbox-shadow: var(--roxy-shadow-md);\n\t\t\t\tmax-height: 22rem;\n\t\t\t\toverflow-y: auto;\n\t\t\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t}\n\t\t\t.option {\n\t\t\t\tdisplay: flex;\n\t\t\t\talign-items: baseline;\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t\t\t\twidth: 100%;\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\tbackground: transparent;\n\t\t\t\tborder: 0;\n\t\t\t\ttext-align: left;\n\t\t\t\tfont-family: inherit;\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tcursor: pointer;\n\t\t\t\ttransition: background-color var(--roxy-motion-duration, 200ms);\n\t\t\t}\n\t\t\t.option:hover,\n\t\t\t.option[aria-selected='true'] {\n\t\t\t\tbackground: color-mix(in srgb, var(--roxy-accent, #f59e0b) 10%, transparent);\n\t\t\t}\n\t\t\t.option .city {\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.option .where {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tflex-grow: 1;\n\t\t\t}\n\t\t\t.option .tz {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t\tfont-variant-numeric: tabular-nums;\n\t\t\t}\n\t\t\t.empty {\n\t\t\t\tpadding: var(--roxy-space-md, 1rem);\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ type: String, attribute: 'api-key' })\n\tapiKey?: string;\n\n\t@property({ type: String, attribute: 'publishable-key' })\n\tpublishableKey?: string;\n\n\t@property({ type: String })\n\tendpoint = 'https://roxyapi.com/api/v2/location/search';\n\n\t@property({ type: String })\n\tplaceholder = 'Search city';\n\n\t@property({ type: String, attribute: 'default-value' })\n\tdefaultValue = '';\n\n\t@state()\n\tprivate query = '';\n\n\t@state()\n\tprivate results: CityResult[] = [];\n\n\t@state()\n\tprivate isOpen = false;\n\n\t@state()\n\tprivate isLoading = false;\n\n\t@state()\n\tprivate highlight = -1;\n\n\tprivate clickOutsideHandler?: (e: MouseEvent) => void;\n\tprivate debouncedFetch = debounce((q: string) => {\n\t\tvoid this.fetchResults(q);\n\t}, 300);\n\n\tconnectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tthis.query = this.defaultValue;\n\t\tthis.clickOutsideHandler = (e: MouseEvent) => {\n\t\t\tconst path = e.composedPath();\n\t\t\tif (!path.includes(this)) this.isOpen = false;\n\t\t};\n\t\tdocument.addEventListener('mousedown', this.clickOutsideHandler);\n\t}\n\n\tdisconnectedCallback(): void {\n\t\tsuper.disconnectedCallback();\n\t\tif (this.clickOutsideHandler) {\n\t\t\tdocument.removeEventListener('mousedown', this.clickOutsideHandler);\n\t\t}\n\t}\n\n\tprivate async fetchResults(q: string) {\n\t\tthis.isLoading = true;\n\t\ttry {\n\t\t\tconst url = new URL(this.endpoint);\n\t\t\turl.searchParams.set('q', q);\n\t\t\turl.searchParams.set('limit', '8');\n\t\t\tconst headers: Record<string, string> = {\n\t\t\t\tAccept: 'application/json',\n\t\t\t};\n\t\t\tif (this.apiKey) headers['X-API-Key'] = this.apiKey;\n\t\t\tif (this.publishableKey) headers['X-API-Key'] = this.publishableKey;\n\t\t\tconst res = await fetch(url, { headers });\n\t\t\tif (!res.ok) throw new Error(`HTTP ${res.status}`);\n\t\t\tconst json = (await res.json()) as CitySearchResponse;\n\t\t\tthis.results = json.cities ?? [];\n\t\t\tthis.isOpen = this.results.length > 0;\n\t\t\tthis.highlight = this.results.length > 0 ? 0 : -1;\n\t\t} catch (_err) {\n\t\t\tthis.results = [];\n\t\t\tthis.isOpen = false;\n\t\t} finally {\n\t\t\tthis.isLoading = false;\n\t\t}\n\t}\n\n\tprivate onInput = (e: Event) => {\n\t\tconst value = (e.target as HTMLInputElement).value;\n\t\tthis.query = value;\n\t\tif (value.length < 2) {\n\t\t\tthis.results = [];\n\t\t\tthis.isOpen = false;\n\t\t\tthis.highlight = -1;\n\t\t\treturn;\n\t\t}\n\t\tthis.debouncedFetch(value);\n\t};\n\n\tprivate select(city: CityResult) {\n\t\tthis.query = `${city.city}${city.province ? `, ${city.province}` : ''}, ${city.country}`;\n\t\tthis.isOpen = false;\n\t\tthis.results = [];\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-location-select', {\n\t\t\t\tdetail: city,\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t}\n\n\tprivate onKeyDown = (e: KeyboardEvent) => {\n\t\tif (!this.isOpen || this.results.length === 0) {\n\t\t\tif (e.key === 'ArrowDown' && this.query.length >= 2) {\n\t\t\t\tvoid this.fetchResults(this.query);\n\t\t\t\te.preventDefault();\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tif (e.key === 'ArrowDown') {\n\t\t\te.preventDefault();\n\t\t\tthis.highlight = (this.highlight + 1) % this.results.length;\n\t\t} else if (e.key === 'ArrowUp') {\n\t\t\te.preventDefault();\n\t\t\tthis.highlight =\n\t\t\t\t(this.highlight - 1 + this.results.length) % this.results.length;\n\t\t} else if (e.key === 'Enter') {\n\t\t\te.preventDefault();\n\t\t\tconst target = this.results[this.highlight] ?? this.results[0];\n\t\t\tif (target) this.select(target);\n\t\t} else if (e.key === 'Escape') {\n\t\t\tthis.isOpen = false;\n\t\t}\n\t};\n\n\trender() {\n\t\treturn html`<div class=\"field\">\n\t\t\t<input\n\t\t\t\ttype=\"text\"\n\t\t\t\trole=\"combobox\"\n\t\t\t\taria-expanded=${this.isOpen ? 'true' : 'false'}\n\t\t\t\taria-controls=\"roxy-location-listbox\"\n\t\t\t\taria-autocomplete=\"list\"\n\t\t\t\tautocomplete=\"off\"\n\t\t\t\tplaceholder=${this.placeholder}\n\t\t\t\t.value=${this.query}\n\t\t\t\t@input=${this.onInput}\n\t\t\t\t@keydown=${this.onKeyDown}\n\t\t\t\t@focus=${() => {\n\t\t\t\t\tif (this.results.length > 0) this.isOpen = true;\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t${this.isLoading ? html`<span class=\"spinner\" role=\"status\" aria-label=\"Loading\"></span>` : nothing}\n\t\t\t${\n\t\t\t\tthis.isOpen\n\t\t\t\t\t? html`<ul\n\t\t\t\t\t\tid=\"roxy-location-listbox\"\n\t\t\t\t\t\tclass=\"results\"\n\t\t\t\t\t\trole=\"listbox\"\n\t\t\t\t\t>\n\t\t\t\t\t\t${\n\t\t\t\t\t\t\tthis.results.length === 0\n\t\t\t\t\t\t\t\t? html`<li class=\"empty\" role=\"status\">No cities found</li>`\n\t\t\t\t\t\t\t\t: this.results.map(\n\t\t\t\t\t\t\t\t\t\t(city, idx) => html`<li role=\"presentation\">\n\t\t\t\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\t\t\t\tclass=\"option\"\n\t\t\t\t\t\t\t\t\t\t\trole=\"option\"\n\t\t\t\t\t\t\t\t\t\t\taria-selected=${this.highlight === idx ? 'true' : 'false'}\n\t\t\t\t\t\t\t\t\t\t\t@click=${() => this.select(city)}\n\t\t\t\t\t\t\t\t\t\t\t@mouseenter=${() => {\n\t\t\t\t\t\t\t\t\t\t\t\tthis.highlight = idx;\n\t\t\t\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"city\">${city.city}</span>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"where\"\n\t\t\t\t\t\t\t\t\t\t\t\t>${city.province ? html`${city.province}, ` : ''}${city.country}</span\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span class=\"tz\"\n\t\t\t\t\t\t\t\t\t\t\t\t>UTC${city.utcOffset >= 0 ? '+' : ''}${city.utcOffset}</span\n\t\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t\t\t\t</li>`,\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t}\n\t\t\t\t\t</ul>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t</div>`;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-location-search': RoxyLocationSearch;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n`;\n", "/**\n * Lightweight debounce for input handlers. Used by location search.\n */\nexport function debounce<F extends (...args: never[]) => unknown>(\n\tfn: F,\n\twait: number,\n): F {\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\treturn ((...args: Parameters<F>) => {\n\t\tif (timer) clearTimeout(timer);\n\t\ttimer = setTimeout(() => fn(...args), wait);\n\t}) as F;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["css", "css"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
interface MoonPhaseData {
|
|
3
|
+
date?: string;
|
|
4
|
+
phase?: string;
|
|
5
|
+
illumination?: number;
|
|
6
|
+
age?: number;
|
|
7
|
+
sign?: string;
|
|
8
|
+
degree?: number;
|
|
9
|
+
distance?: number;
|
|
10
|
+
meaning?: {
|
|
11
|
+
name?: string;
|
|
12
|
+
symbol?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
keywords?: string[];
|
|
15
|
+
};
|
|
16
|
+
month?: string;
|
|
17
|
+
year?: number;
|
|
18
|
+
phases?: Array<MoonPhaseData>;
|
|
19
|
+
upcoming?: Array<MoonPhaseData>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Moon phase card. Renders /astrology/moon-phase/{current,upcoming,calendar/...}.
|
|
23
|
+
*/
|
|
24
|
+
export declare class RoxyMoonPhase extends LitElement {
|
|
25
|
+
static styles: import("lit").CSSResult[];
|
|
26
|
+
data: MoonPhaseData | null;
|
|
27
|
+
mode: 'current' | 'upcoming' | 'calendar';
|
|
28
|
+
render(): import("lit").TemplateResult<1>;
|
|
29
|
+
private renderSingle;
|
|
30
|
+
private renderListItem;
|
|
31
|
+
}
|
|
32
|
+
declare global {
|
|
33
|
+
interface HTMLElementTagNameMap {
|
|
34
|
+
'roxy-moon-phase': RoxyMoonPhase;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=moon-phase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"moon-phase.d.ts","sourceRoot":"","sources":["../../src/components/moon-phase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,UAAU,EAAW,MAAM,KAAK,CAAC;AAKrD,UAAU,aAAa;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;IAC9B,QAAQ,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC;CAChC;AAED;;GAEG;AACH,qBACa,aAAc,SAAQ,UAAU;IAC5C,MAAM,CAAC,MAAM,4BAqFX;IAGF,IAAI,EAAE,aAAa,GAAG,IAAI,CAAQ;IAGlC,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,CAAa;IAEtD,MAAM;IAmBN,OAAO,CAAC,YAAY;IA2DpB,OAAO,CAAC,cAAc;CAQtB;AAOD,OAAO,CAAC,MAAM,CAAC;IACd,UAAU,qBAAqB;QAC9B,iBAAiB,EAAE,aAAa,CAAC;KACjC;CACD"}
|