@qodin-co/sol 0.1.3 → 0.1.4

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/README.md CHANGED
@@ -1,470 +1,451 @@
1
- <div align="center">
2
-
3
- <img src=".github/banner.png" alt="@qodin-co/sol — solar-aware React widgets" width="100%" />
4
-
5
- <br />
6
- <br />
7
-
8
- <a href="https://www.npmjs.com/package/@qodin-co/sol">
9
- <img src="https://img.shields.io/npm/v/@qodin-co/sol?style=flat-square&color=111&labelColor=111&logo=npm" alt="npm version" />
10
- </a>
11
- <a href="https://www.npmjs.com/package/@qodin-co/sol">
12
- <img src="https://img.shields.io/npm/dm/@qodin-co/sol?style=flat-square&color=111&labelColor=111" alt="npm downloads" />
13
- </a>
14
- <a href="https://github.com/qodin-co/sol/blob/main/LICENSE">
15
- <img src="https://img.shields.io/npm/l/@qodin-co/sol?style=flat-square&color=111&labelColor=111" alt="license" />
16
- </a>
17
- <a href="https://github.com/qodin-co/sol/actions/workflows/validate.yml">
18
- <img src="https://img.shields.io/github/actions/workflow/status/qodin-co/sol/validate.yml?style=flat-square&color=111&labelColor=111&label=ci" alt="CI" />
19
- </a>
20
-
21
- <br />
22
- <br />
23
-
24
- **Solar-aware React widgets that follow the real position of the sun.**
25
-
26
- [npm](https://www.npmjs.com/package/@qodin-co/sol) · [GitHub](https://github.com/qodin-co/sol) · withsol.app — launching soon
27
-
28
- </div>
29
-
30
- ---
31
-
32
- ```bash
33
- bun add @qodin-co/sol
34
- # or
35
- npm install @qodin-co/sol
36
- ```
37
-
38
- `@qodin-co/sol` gives you a full `SolarWidget`, a `CompactWidget`, 10 skins, 9 solar phases, optional live weather, optional flag display, and a dev-only timeline scrubber via `SolarDevTools`. No solar API required — solar position is computed locally from latitude, longitude, timezone, and current time.
39
-
40
- ---
41
-
42
- ## Features
43
-
44
- - **2 widget variants** — `SolarWidget` (full card) and `CompactWidget` (slim pill/bar)
45
- - **10 skins** — `foundry`, `paper`, `signal`, `meridian`, `mineral`, `aurora`, `tide`, `void`, `sundial`, `parchment`
46
- - **9 solar phases** — `midnight`, `night`, `dawn`, `sunrise`, `morning`, `solar-noon`, `afternoon`, `sunset`, `dusk`
47
- - **Built-in fallback strategy** — geolocation → browser timezone → timezone centroid
48
- - **Optional live weather** — powered by Open-Meteo (no API key required)
49
- - **Dev preview tooling** — `SolarDevTools` lets you scrub through the day and preview phase colors
50
-
51
- ---
52
-
53
- ## Installation
54
-
55
- Import the package styles once at your app root — no Tailwind setup required:
56
-
57
- ```ts
58
- import '@qodin-co/sol/styles.css';
59
- ```
60
-
61
- ---
62
-
63
- ## Quick Start
64
-
65
- ### 1. Wrap your app
66
-
67
- ```tsx
68
- import '@qodin-co/sol/styles.css';
69
- import { SolarThemeProvider } from '@qodin-co/sol';
70
-
71
- export function AppProviders({ children }: { children: React.ReactNode }) {
72
- return (
73
- <SolarThemeProvider initialSkin="foundry">
74
- {children}
75
- </SolarThemeProvider>
76
- );
77
- }
78
- ```
79
-
80
- ### 2. Render a widget
81
-
82
- ```tsx
83
- import { SolarWidget } from '@qodin-co/sol';
84
-
85
- export default function Page() {
86
- return (
87
- <SolarWidget
88
- skin="foundry"
89
- showWeather
90
- showFlag
91
- hoverEffect
92
- />
93
- );
94
- }
95
- ```
96
-
97
- ### 3. Or use the compact variant
98
-
99
- ```tsx
100
- import { CompactWidget } from '@qodin-co/sol';
101
-
102
- export default function HeaderStatus() {
103
- return (
104
- <CompactWidget
105
- skin="signal"
106
- showWeather
107
- showFlag
108
- size="md"
109
- />
110
- );
111
- }
112
- ```
113
-
114
- ---
115
-
116
- ## Provider Setup
117
-
118
- `SolarThemeProvider` is the shared runtime for solar phase computation, timezone, coordinates, skin selection, and live/manual overrides.
119
-
120
- ### Basic
121
-
122
- ```tsx
123
- <SolarThemeProvider initialSkin="paper">
124
- <App />
125
- </SolarThemeProvider>
126
- ```
127
-
128
- ### Location is automatic
129
-
130
- `SolarThemeProvider` resolves the user's location automatically using a 3-step fallback:
131
-
132
- 1. **Browser Geolocation API** — most accurate (requires user permission)
133
- 2. **Browser timezone** (`Intl.DateTimeFormat`) instant, no permission needed
134
- 3. **Timezone centroid lookup** — maps the IANA timezone to approximate city coordinates
135
-
136
- Solar phases are accurate to ~15–30 minutes from timezone alone, and refine to exact values when geolocation is granted.
137
-
138
- ### Override location (optional)
139
-
140
- ```tsx
141
- <SolarThemeProvider
142
- initialSkin="meridian"
143
- latitude={37.7749}
144
- longitude={-122.4194}
145
- timezone="America/Los_Angeles"
146
- >
147
- <App />
148
- </SolarThemeProvider>
149
- ```
150
-
151
- > These props override automatic resolution. Omit them to let Sol detect location automatically.
152
-
153
- ### With global CSS variables
154
-
155
- ```tsx
156
- <SolarThemeProvider applyThemeToDocument initialSkin="aurora">
157
- <App />
158
- </SolarThemeProvider>
159
- ```
160
-
161
- Exposes variables like `--solar-accent`, `--solar-bg-base`, `--solar-text-primary` for use in your own styles.
162
-
163
- ### Provider Props
164
-
165
- | Prop | Type | Default | Description |
166
- |---|---|---|---|
167
- | `children` | `ReactNode` | — | Required |
168
- | `initialSkin` | `DesignMode` | `'foundry'` | Default skin |
169
- | `skin` | `DesignMode` | — | Controlled skin override |
170
- | `onSkinChange` | `(skin: DesignMode) => void` | — | Callback when skin changes |
171
- | `applyThemeToDocument` | `boolean` | `false` | Write CSS vars + data attrs to `<html>` |
172
- | `latitude` | `number \| null` | — | Explicit latitude override |
173
- | `longitude` | `number \| null` | — | Explicit longitude override |
174
- | `timezone` | `string \| null` | — | Explicit IANA timezone override |
175
-
176
- ---
177
-
178
- ## SolarWidget
179
-
180
- ```tsx
181
- <SolarWidget
182
- skin="foundry"
183
- position="bottom-right"
184
- expandDirection="top-left"
185
- size="lg"
186
- showWeather
187
- showFlag
188
- hoverEffect
189
- />
190
- ```
191
-
192
- ### Props
193
-
194
- | Prop | Type | Default | Description |
195
- |---|---|---|---|
196
- | `skin` | `DesignMode` | provider skin | Skin override for this widget |
197
- | `position` | `AnchorPosition \| 'inline'` | `'inline'` | Fixed viewport anchoring |
198
- | `expandDirection` | `AnchorPosition` | `'bottom-right'` | Direction the card opens |
199
- | `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `'lg'` | Widget size |
200
- | `showWeather` | `boolean` | `false` | Enable live weather display |
201
- | `showFlag` | `boolean` | `false` | Show country flag |
202
- | `hoverEffect` | `boolean` | `false` | Enable hover animation |
203
- | `phaseOverride` | `SolarPhase \| null` | — | Force a discrete phase |
204
- | `timeOverride` | `Date \| null` | — | Simulate a specific time |
205
- | `weatherCategoryOverride` | `WeatherCategory \| null` | — | Force weather condition |
206
- | `customPalettes` | `Partial<Record<SolarPhase, { bg: [string, string, string] }>>` | — | Override phase colors |
207
- | `className` | `string` | — | Wrapper CSS class |
208
- | `style` | `CSSProperties` | — | Wrapper inline style |
209
-
210
- ---
211
-
212
- ## CompactWidget
213
-
214
- ```tsx
215
- <CompactWidget
216
- skin="signal"
217
- size="md"
218
- showWeather
219
- showFlag
220
- showTemperature
221
- />
222
- ```
223
-
224
- ### Props
225
-
226
- | Prop | Type | Default | Description |
227
- |---|---|---|---|
228
- | `skin` | `DesignMode` | provider skin | Skin override |
229
- | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Compact size |
230
- | `showWeather` | `boolean` | `false` | Show weather icon |
231
- | `showFlag` | `boolean` | `false` | Show country flag |
232
- | `showTemperature` | `boolean` | `true` | Show live temperature |
233
- | `phaseOverride` | `SolarPhase \| null` | — | Force a discrete phase |
234
- | `timeOverride` | `Date \| null` | — | Simulate a time |
235
- | `weatherCategoryOverride` | `WeatherCategory \| null` | — | Force weather condition |
236
- | `className` | `string` | — | Wrapper CSS class |
237
- | `style` | `CSSProperties` | — | Wrapper inline style |
238
-
239
- ---
240
-
241
- ## Skins
242
-
243
- 10 skins, each with a full widget and compact variant. If `skin` is omitted on a widget, it uses the provider's active skin.
244
-
245
- ```ts
246
- type DesignMode =
247
- | 'aurora' // luminous ethereal
248
- | 'foundry' // warm volumetric industrial
249
- | 'tide' // fluid organic wave
250
- | 'void' // minimal negative space
251
- | 'mineral' // faceted crystal gem
252
- | 'meridian' // hairline geometric
253
- | 'signal' // pixel/blocky lo-fi
254
- | 'paper' // flat ink editorial
255
- | 'sundial' // roman/classical carved
256
- | 'parchment'; // document strokes
257
- ```
258
-
259
- ---
260
-
261
- ## Positioning
262
-
263
- ```tsx
264
- <SolarWidget /> // inline (default)
265
- <SolarWidget position="bottom-right" /> // fixed to viewport
266
- <SolarWidget position="bottom-right" expandDirection="top-left" /> // with expand direction
267
- ```
268
-
269
- Supported positions: `top-left` `top-center` `top-right` `center-left` `center` `center-right` `bottom-left` `bottom-center` `bottom-right` `inline`
270
-
271
- ---
272
-
273
- ## Weather
274
-
275
- ```tsx
276
- <SolarWidget showWeather />
277
-
278
- // Force a category for preview
279
- <SolarWidget showWeather weatherCategoryOverride="thunder" />
280
- ```
281
-
282
- Powered by [Open-Meteo](https://open-meteo.com/) — free, no API key. Available categories: `clear` `partly-cloudy` `overcast` `fog` `drizzle` `rain` `heavy-rain` `snow` `heavy-snow` `thunder`
283
-
284
- ---
285
-
286
- ## Phase & Time Overrides
287
-
288
- ```tsx
289
- // Force a discrete phase
290
- <SolarWidget phaseOverride="sunset" />
291
-
292
- // Simulate a specific time (with blend)
293
- const preview = new Date();
294
- preview.setHours(6, 45, 0, 0);
295
- <SolarWidget timeOverride={preview} />
296
- ```
297
-
298
- Use `timeOverride` for realistic continuous previews. Use `phaseOverride` for simple hard overrides.
299
-
300
- ---
301
-
302
- ## Custom Palettes
303
-
304
- ```tsx
305
- <SolarWidget
306
- skin="foundry"
307
- customPalettes={{
308
- dawn: { bg: ['#20122a', '#7f3b5d', '#f5a66e'] },
309
- sunset: { bg: ['#2e0f18', '#b84a3d', '#ffbe7a'] },
310
- }}
311
- />
312
- ```
313
-
314
- ---
315
-
316
- ## SolarDevTools
317
-
318
- A dev-only bottom-fixed pill for scrubbing through the day. Imported from a dedicated subpath — never included in production bundles unless explicitly imported.
319
-
320
- ```tsx
321
- import { SolarDevTools } from '@qodin-co/sol/devtools';
322
-
323
- // Vite
324
- {import.meta.env.DEV && <SolarDevTools />}
325
-
326
- // Next.js
327
- {process.env.NODE_ENV === 'development' && <SolarDevTools />}
328
- ```
329
-
330
- ### Full example
331
-
332
- ```tsx
333
- import '@qodin-co/sol/styles.css';
334
- import { SolarThemeProvider, SolarWidget } from '@qodin-co/sol';
335
- import { SolarDevTools } from '@qodin-co/sol/devtools';
336
-
337
- export default function Demo() {
338
- return (
339
- <SolarThemeProvider initialSkin="foundry">
340
- <SolarWidget showWeather showFlag />
341
- {process.env.NODE_ENV === 'development' && (
342
- <SolarDevTools position="bottom-center" />
343
- )}
344
- </SolarThemeProvider>
345
- );
346
- }
347
- ```
348
-
349
- ### Props
350
-
351
- | Prop | Type | Default | Description |
352
- |---|---|---|---|
353
- | `defaultOpen` | `boolean` | `false` | Start expanded |
354
- | `position` | `'bottom-left' \| 'bottom-center' \| 'bottom-right'` | `'bottom-center'` | Pill position |
355
- | `enabled` | `boolean` | `true` | Programmatic enable/disable |
356
-
357
- ---
358
-
359
- ## useSolarTheme
360
-
361
- ```tsx
362
- import { useSolarTheme } from '@qodin-co/sol';
363
-
364
- function DebugPanel() {
365
- const { phase, timezone, latitude, longitude, design } = useSolarTheme();
366
- return (
367
- <pre>{JSON.stringify({ phase, timezone, latitude, longitude, design }, null, 2)}</pre>
368
- );
369
- }
370
- ```
371
-
372
- ### Return shape
373
-
374
- | Property | Type | Description |
375
- |---|---|---|
376
- | `phase` | `SolarPhase` | Current active phase |
377
- | `blend` | `SolarBlend` | Phase blend state (phase, nextPhase, t) |
378
- | `isDaytime` | `boolean` | Whether the sun is above the horizon |
379
- | `brightness` | `number` | 0–1 brightness value |
380
- | `mode` | `'light' \| 'dim' \| 'dark'` | Current light mode |
381
- | `accentColor` | `string` | Active accent hex |
382
- | `timezone` | `string \| null` | Resolved timezone |
383
- | `latitude` | `number \| null` | Resolved latitude |
384
- | `longitude` | `number \| null` | Resolved longitude |
385
- | `coordsReady` | `boolean` | Whether coordinates have resolved |
386
- | `design` | `DesignMode` | Active skin name |
387
- | `activeSkin` | `SkinDefinition` | Full skin definition object |
388
- | `setOverridePhase` | `(phase \| null) => void` | Set/clear phase override |
389
- | `setDesign` | `(skin: DesignMode) => void` | Change active skin |
390
-
391
- ---
392
-
393
- ## Multiple Widgets
394
-
395
- ```tsx
396
- <SolarThemeProvider initialSkin="foundry">
397
- <SolarWidget skin="foundry" position="bottom-left" showWeather />
398
- <CompactWidget skin="signal" />
399
- <SolarWidget skin="aurora" position="bottom-right" />
400
- </SolarThemeProvider>
401
- ```
402
-
403
- Each widget can have its own skin. The provider manages shared solar state.
404
-
405
- ---
406
-
407
- ## TypeScript
408
-
409
- ```ts
410
- import type {
411
- DesignMode,
412
- SolarPhase,
413
- SolarBlend,
414
- WeatherCategory,
415
- ExpandDirection,
416
- WidgetSize,
417
- CompactSize,
418
- SkinDefinition,
419
- WidgetPalette,
420
- SolarTheme,
421
- } from '@qodin-co/sol';
422
- ```
423
-
424
- ---
425
-
426
- ## SSR / Hydration Notes
427
-
428
- Sol is client-aware and uses browser APIs for geolocation, timezone, and storage. The provider falls back safely when coordinates are not yet resolved. Use the `ClientOnly` wrapper if you encounter hydration mismatches in SSR frameworks.
429
-
430
- ---
431
-
432
- ## What's Included
433
-
434
- | | |
435
- |---|---|
436
- | | Full widget + compact widget |
437
- | ✅ | 10 skins with full + compact variants |
438
- | | Solar math (NOAA equations, no external API) |
439
- | | Timezone fallback logic |
440
- | | Optional live weather (Open-Meteo) |
441
- | | Skin-aware country flags |
442
- | ✅ | Dev timeline scrubber |
443
- | | Compiled CSS (no Tailwind required) |
444
- | ❌ | No solar API key needed |
445
- | ❌ | No weather API key needed |
446
- | ❌ | No Tailwind in your app |
447
- | ❌ | No geolocation permission required |
448
-
449
- ---
450
-
451
- ## Coming Soon
452
-
453
- **SOL** website is launching soon — a dedicated site for Sol with full documentation, live skin previews, and a playground to explore every phase and skin combination.
454
-
455
- Sol is actively being developed. Things in progress:
456
-
457
- - **Seasonal theme system** — 4 seasons (Summer, Autumn, Winter, Spring) that blend automatically with the existing 9-phase system, computed from date and location with no configuration required
458
- - More skins
459
- - Vue and Svelte adapters
460
- - Deep token override system
461
-
462
- Follow the repo or watch releases to stay updated.
463
-
464
- ---
465
-
466
- <div align="center">
467
-
468
- MIT © [qodin](https://github.com/qodin-co)
469
-
1
+ <div align="center">
2
+
3
+ <img src=".github/banner.png" alt="@qodin-co/sol — solar-aware React widgets" width="100%" />
4
+
5
+ <br />
6
+ <br />
7
+
8
+ <a href="https://www.npmjs.com/package/@qodin-co/sol">
9
+ <img src="https://img.shields.io/npm/v/@qodin-co/sol?style=flat-square&color=111&labelColor=111&logo=npm" alt="npm version" />
10
+ </a>
11
+ <a href="https://www.npmjs.com/package/@qodin-co/sol">
12
+ <img src="https://img.shields.io/npm/dm/@qodin-co/sol?style=flat-square&color=111&labelColor=111" alt="npm downloads" />
13
+ </a>
14
+ <a href="https://github.com/qodin-co/sol/blob/main/LICENSE">
15
+ <img src="https://img.shields.io/npm/l/@qodin-co/sol?style=flat-square&color=111&labelColor=111" alt="license" />
16
+ </a>
17
+ <a href="https://github.com/qodin-co/sol/actions/workflows/validate.yml">
18
+ <img src="https://img.shields.io/github/actions/workflow/status/qodin-co/sol/validate.yml?style=flat-square&color=111&labelColor=111&label=ci" alt="CI" />
19
+ </a>
20
+
21
+ <br />
22
+ <br />
23
+
24
+ **Solar-aware React widgets that follow the real position of the sun.**
25
+
26
+ [npm](https://www.npmjs.com/package/@qodin-co/sol) · [GitHub](https://github.com/qodin-co/sol) · withsol.app — launching soon
27
+
28
+ </div>
29
+
30
+ ---
31
+
32
+ ```bash
33
+ bun add @qodin-co/sol
34
+ # or
35
+ npm install @qodin-co/sol
36
+ ```
37
+
38
+ `@qodin-co/sol` gives you a full `SolarWidget`, a `CompactWidget`, 10 skins, 9 solar phases, optional live weather, optional flag display, and a dev-only timeline scrubber via `SolarDevTools`. No solar API required — solar position is computed locally from latitude, longitude, timezone, and current time.
39
+
40
+ ---
41
+
42
+ ## Features
43
+
44
+ - **2 widget variants** — `SolarWidget` (full card) and `CompactWidget` (slim pill/bar)
45
+ - **10 skins** — `foundry`, `paper`, `signal`, `meridian`, `mineral`, `aurora`, `tide`, `void`, `sundial`, `parchment`
46
+ - **9 solar phases** — `midnight`, `night`, `dawn`, `sunrise`, `morning`, `solar-noon`, `afternoon`, `sunset`, `dusk`
47
+ - **Built-in fallback strategy** — geolocation → browser timezone → timezone centroid
48
+ - **Optional live weather** — powered by Open-Meteo (no API key required)
49
+ - **Dev preview tooling** — `SolarDevTools` lets you scrub through the day and preview phase colors
50
+
51
+ ---
52
+
53
+ ## Installation
54
+
55
+ Import the package styles once at your app root — no Tailwind setup required:
56
+
57
+ ```ts
58
+ import '@qodin-co/sol/styles.css';
59
+ ```
60
+
61
+ ---
62
+
63
+ ## Quick Start
64
+
65
+ ### 1. Wrap your app
66
+
67
+ ```tsx
68
+ import '@qodin-co/sol/styles.css';
69
+ import { SolarThemeProvider } from '@qodin-co/sol';
70
+
71
+ export function AppProviders({ children }: { children: React.ReactNode }) {
72
+ return (
73
+ <SolarThemeProvider initialDesign="foundry">
74
+ {children}
75
+ </SolarThemeProvider>
76
+ );
77
+ }
78
+ ```
79
+
80
+ ### 2. Render a widget
81
+
82
+ ```tsx
83
+ import { SolarWidget } from '@qodin-co/sol';
84
+
85
+ export default function Page() {
86
+ return (
87
+ <SolarWidget
88
+ showWeather
89
+ showFlag
90
+ hoverEffect
91
+ />
92
+ );
93
+ }
94
+ ```
95
+
96
+ ### 3. Or use the compact variant
97
+
98
+ ```tsx
99
+ import { CompactWidget } from '@qodin-co/sol';
100
+
101
+ export default function HeaderStatus() {
102
+ return (
103
+ <CompactWidget
104
+ design="signal"
105
+ showWeather
106
+ showFlag
107
+ size="md"
108
+ />
109
+ );
110
+ }
111
+ ```
112
+
113
+ ---
114
+
115
+ ## Provider Setup
116
+
117
+ `SolarThemeProvider` is the shared runtime for solar phase computation, timezone, coordinates, skin selection, and live/manual overrides.
118
+
119
+ ### Basic
120
+
121
+ ```tsx
122
+ <SolarThemeProvider initialDesign="paper">
123
+ <App />
124
+ </SolarThemeProvider>
125
+ ```
126
+
127
+ ### Location is automatic
128
+
129
+ `SolarThemeProvider` resolves the user's location automatically using a 3-step fallback:
130
+
131
+ 1. **Browser Geolocation API** — most accurate (requires user permission)
132
+ 2. **Browser timezone** (`Intl.DateTimeFormat`) instant, no permission needed
133
+ 3. **Timezone centroid lookup** — maps the IANA timezone to approximate city coordinates
134
+
135
+ Solar phases are accurate to ~15–30 minutes from timezone alone, and refine to exact values when geolocation is granted.
136
+
137
+ ### Override location (optional)
138
+
139
+ ```tsx
140
+ <SolarThemeProvider
141
+ initialDesign="meridian"
142
+ >
143
+ <App />
144
+ </SolarThemeProvider>
145
+ ```
146
+
147
+ > These props override automatic resolution. Omit them to let Sol detect location automatically.
148
+
149
+ ### With global CSS variables
150
+
151
+ ```tsx
152
+ <SolarThemeProvider initialDesign="aurora">
153
+ <App />
154
+ </SolarThemeProvider>
155
+ ```
156
+
157
+ ### Provider Props
158
+
159
+ | Prop | Type | Default | Description |
160
+ |---|---|---|---|
161
+ | `children` | `ReactNode` | | Required |
162
+ | `initialDesign` | `DesignMode` | `'foundry'` | Default design/skin |
163
+ | `isolated` | `boolean` | `false` | Scope CSS vars to wrapper instead of `:root` |
164
+
165
+ ---
166
+
167
+ ## SolarWidget
168
+
169
+ ```tsx
170
+ <SolarWidget
171
+ expandDirection="top-left"
172
+ size="lg"
173
+ showWeather
174
+ showFlag
175
+ hoverEffect
176
+ />
177
+ ```
178
+
179
+ ### Props
180
+
181
+ | Prop | Type | Default | Description |
182
+ |---|---|---|---|
183
+ | `expandDirection` | `ExpandDirection` | `'bottom-right'` | Direction the card opens |
184
+ | `size` | `WidgetSize` | `'lg'` | Widget size |
185
+ | `showWeather` | `boolean` | `false` | Enable live weather display |
186
+ | `showFlag` | `boolean` | `false` | Show country flag |
187
+ | `hoverEffect` | `boolean` | `false` | Enable hover animation |
188
+ | `phaseOverride` | `SolarPhase` | — | Force a discrete phase |
189
+ | `simulatedDate` | `Date` | — | Simulate a specific time |
190
+ | `weatherCategoryOverride` | `WeatherCategory \| null` | — | Force weather condition |
191
+ | `customPalettes` | `CustomPalettes` | — | Override phase colors |
192
+ | `forceExpanded` | `boolean` | — | Lock expanded/collapsed state |
193
+
194
+ ---
195
+
196
+ ## CompactWidget
197
+
198
+ ```tsx
199
+ <CompactWidget
200
+ design="signal"
201
+ size="md"
202
+ showWeather
203
+ showFlag
204
+ showTemperature
205
+ />
206
+ ```
207
+
208
+ ### Props
209
+
210
+ | Prop | Type | Default | Description |
211
+ |---|---|---|---|
212
+ | `design` | `DesignMode` | provider design | Design/skin override |
213
+ | `size` | `CompactSize` | `'md'` | Compact size |
214
+ | `showWeather` | `boolean` | `false` | Show weather icon |
215
+ | `showFlag` | `boolean` | `false` | Show country flag |
216
+ | `showTemperature` | `boolean` | `true` | Show live temperature |
217
+ | `overridePhase` | `SolarPhase \| null` | — | Force a discrete phase |
218
+ | `simulatedDate` | `Date` | — | Simulate a time |
219
+ | `className` | `string` | — | Wrapper CSS class |
220
+
221
+ ---
222
+
223
+ ## Skins
224
+
225
+ 10 designs, each with a full widget and compact variant. If `design` is omitted on a widget, it uses the provider's active design.
226
+
227
+ ```ts
228
+ type DesignMode =
229
+ | 'aurora' // luminous ethereal
230
+ | 'foundry' // warm volumetric industrial
231
+ | 'tide' // fluid organic wave
232
+ | 'void' // minimal negative space
233
+ | 'mineral' // faceted crystal gem
234
+ | 'meridian' // hairline geometric
235
+ | 'signal' // pixel/blocky lo-fi
236
+ | 'paper' // flat ink editorial
237
+ | 'sundial' // roman/classical carved
238
+ | 'parchment'; // document strokes
239
+ ```
240
+
241
+ ---
242
+
243
+ ## Positioning
244
+
245
+ ```tsx
246
+ <SolarWidget /> // inline (default)
247
+ <SolarWidget position="bottom-right" /> // fixed to viewport
248
+ <SolarWidget position="bottom-right" expandDirection="top-left" /> // with expand direction
249
+ ```
250
+
251
+ Supported positions: `top-left` `top-center` `top-right` `center-left` `center` `center-right` `bottom-left` `bottom-center` `bottom-right` `inline`
252
+
253
+ ---
254
+
255
+ ## Weather
256
+
257
+ ```tsx
258
+ <SolarWidget showWeather />
259
+
260
+ // Force a category for preview
261
+ <SolarWidget showWeather weatherCategoryOverride="thunder" />
262
+ ```
263
+
264
+ Powered by [Open-Meteo](https://open-meteo.com/) — free, no API key. Available categories: `clear` `partly-cloudy` `overcast` `fog` `drizzle` `rain` `heavy-rain` `snow` `heavy-snow` `thunder`
265
+
266
+ ---
267
+
268
+ ## Phase & Time Overrides
269
+
270
+ ```tsx
271
+ // Force a discrete phase
272
+ <SolarWidget phaseOverride="sunset" />
273
+
274
+ // Simulate a specific time (with blend)
275
+ const preview = new Date();
276
+ preview.setHours(6, 45, 0, 0);
277
+ <SolarWidget simulatedDate={preview} />
278
+ ```
279
+
280
+ Use `simulatedDate` for realistic continuous previews. Use `phaseOverride` for simple hard overrides.
281
+
282
+ ---
283
+
284
+ ## Custom Palettes
285
+
286
+ ```tsx
287
+ <SolarWidget
288
+ customPalettes={{
289
+ dawn: { bg: ['#20122a', '#7f3b5d', '#f5a66e'] },
290
+ sunset: { bg: ['#2e0f18', '#b84a3d', '#ffbe7a'] },
291
+ }}
292
+ />
293
+ ```
294
+
295
+ ---
296
+
297
+ ## SolarDevTools
298
+
299
+ A dev-only bottom-fixed pill for scrubbing through the day. Imported from a dedicated subpath — never included in production bundles unless explicitly imported.
300
+
301
+ ```tsx
302
+ import { SolarDevTools } from '@qodin-co/sol/devtools';
303
+
304
+ // Vite
305
+ {import.meta.env.DEV && <SolarDevTools />}
306
+
307
+ // Next.js
308
+ {process.env.NODE_ENV === 'development' && <SolarDevTools />}
309
+ ```
310
+
311
+ ### Full example
312
+
313
+ ```tsx
314
+ import '@qodin-co/sol/styles.css';
315
+ import { SolarThemeProvider, SolarWidget } from '@qodin-co/sol';
316
+ import { SolarDevTools } from '@qodin-co/sol/devtools';
317
+
318
+ export default function Demo() {
319
+ return (
320
+ <SolarThemeProvider initialDesign="foundry">
321
+ <SolarWidget showWeather showFlag />
322
+ {process.env.NODE_ENV === 'development' && (
323
+ <SolarDevTools position="bottom-center" />
324
+ )}
325
+ </SolarThemeProvider>
326
+ );
327
+ }
328
+ ```
329
+
330
+ ### Props
331
+
332
+ | Prop | Type | Default | Description |
333
+ |---|---|---|---|
334
+ | `defaultOpen` | `boolean` | `false` | Start expanded |
335
+ | `position` | `'bottom-left' \| 'bottom-center' \| 'bottom-right'` | `'bottom-center'` | Pill position |
336
+ | `enabled` | `boolean` | `true` | Programmatic enable/disable |
337
+
338
+ ---
339
+
340
+ ## useSolarTheme
341
+
342
+ ```tsx
343
+ import { useSolarTheme } from '@qodin-co/sol';
344
+
345
+ function DebugPanel() {
346
+ const { phase, timezone, latitude, longitude, design } = useSolarTheme();
347
+ return (
348
+ <pre>{JSON.stringify({ phase, timezone, latitude, longitude, design }, null, 2)}</pre>
349
+ );
350
+ }
351
+ ```
352
+
353
+ ### Return shape
354
+
355
+ | Property | Type | Description |
356
+ |---|---|---|
357
+ | `phase` | `SolarPhase` | Current active phase |
358
+ | `blend` | `SolarBlend` | Phase blend state (phase, nextPhase, t) |
359
+ | `isDaytime` | `boolean` | Whether the sun is above the horizon |
360
+ | `brightness` | `number` | 0–1 brightness value |
361
+ | `mode` | `'light' \| 'dim' \| 'dark'` | Current light mode |
362
+ | `accentColor` | `string` | Active accent hex |
363
+ | `timezone` | `string \| null` | Resolved timezone |
364
+ | `latitude` | `number \| null` | Resolved latitude |
365
+ | `longitude` | `number \| null` | Resolved longitude |
366
+ | `coordsReady` | `boolean` | Whether coordinates have resolved |
367
+ | `design` | `DesignMode` | Active skin name |
368
+ | `activeSkin` | `SkinDefinition` | Full skin definition object |
369
+ | `setOverridePhase` | `(phase \| null) => void` | Set/clear phase override |
370
+ | `setDesign` | `(skin: DesignMode) => void` | Change active skin |
371
+
372
+ ---
373
+
374
+ ## Multiple Widgets
375
+
376
+ ```tsx
377
+ <SolarThemeProvider initialDesign="foundry">
378
+ <SolarWidget showWeather />
379
+ <CompactWidget design="signal" />
380
+ <SolarWidget />
381
+ </SolarThemeProvider>
382
+ ```
383
+
384
+ Each widget can have its own design. The provider manages shared solar state.
385
+
386
+ ---
387
+
388
+ ## TypeScript
389
+
390
+ ```ts
391
+ import type {
392
+ DesignMode,
393
+ SolarPhase,
394
+ SolarBlend,
395
+ WeatherCategory,
396
+ ExpandDirection,
397
+ WidgetSize,
398
+ CompactSize,
399
+ SkinDefinition,
400
+ WidgetPalette,
401
+ SolarTheme,
402
+ } from '@qodin-co/sol';
403
+ ```
404
+
405
+ ---
406
+
407
+ ## SSR / Hydration Notes
408
+
409
+ Sol is client-aware and uses browser APIs for geolocation, timezone, and storage. The provider falls back safely when coordinates are not yet resolved. Use the `ClientOnly` wrapper if you encounter hydration mismatches in SSR frameworks.
410
+
411
+ ---
412
+
413
+ ## What's Included
414
+
415
+ | | |
416
+ |---|---|
417
+ | ✅ | Full widget + compact widget |
418
+ | ✅ | 10 skins with full + compact variants |
419
+ | ✅ | Solar math (NOAA equations, no external API) |
420
+ | ✅ | Timezone fallback logic |
421
+ | | Optional live weather (Open-Meteo) |
422
+ | ✅ | Skin-aware country flags |
423
+ | ✅ | Dev timeline scrubber |
424
+ | ✅ | Compiled CSS (no Tailwind required) |
425
+ | ❌ | No solar API key needed |
426
+ | | No weather API key needed |
427
+ | ❌ | No Tailwind in your app |
428
+ | | No geolocation permission required |
429
+
430
+ ---
431
+
432
+ ## Coming Soon
433
+
434
+ **SOL** website is launching soon — a dedicated site for Sol with full documentation, live skin previews, and a playground to explore every phase and skin combination.
435
+
436
+ Sol is actively being developed. Things in progress:
437
+
438
+ - **Seasonal theme system** 4 seasons (Summer, Autumn, Winter, Spring) that blend automatically with the existing 9-phase system, computed from date and location with no configuration required
439
+ - More skins
440
+ - Vue and Svelte adapters
441
+ - Deep token override system
442
+
443
+ Follow the repo or watch releases to stay updated.
444
+
445
+ ---
446
+
447
+ <div align="center">
448
+
449
+ MIT © [qodin](https://github.com/qodin-co)
450
+
470
451
  </div>