@circadian/sol 0.2.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 +607 -0
- package/dist/devtools/index.d.ts +16 -0
- package/dist/devtools/index.d.ts.map +1 -0
- package/dist/devtools/index.js +384 -0
- package/dist/devtools/index.js.map +1 -0
- package/dist/index.d.ts +368 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +324 -0
- package/dist/index.js.map +1 -0
- package/dist/solar-theme-provider-c3NXcPU7.js +54220 -0
- package/dist/solar-theme-provider-c3NXcPU7.js.map +1 -0
- package/dist/styles-no-preflight.css +2 -0
- package/dist/styles.css +2 -0
- package/package.json +88 -0
package/README.md
ADDED
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src=".github/banner.png" alt="@circadian/sol — solar-aware React widgets" width="100%" />
|
|
4
|
+
|
|
5
|
+
<br />
|
|
6
|
+
<br />
|
|
7
|
+
|
|
8
|
+
<a href="https://www.npmjs.com/package/@circadian/sol">
|
|
9
|
+
<img src="https://img.shields.io/npm/v/@circadian/sol?style=flat-square&color=111&labelColor=111&logo=npm" alt="npm version" />
|
|
10
|
+
</a>
|
|
11
|
+
<a href="https://www.npmjs.com/package/@circadian/sol">
|
|
12
|
+
<img src="https://img.shields.io/npm/dm/@circadian/sol?style=flat-square&color=111&labelColor=111" alt="npm downloads" />
|
|
13
|
+
</a>
|
|
14
|
+
<a href="https://github.com/circadian-dev/sol/blob/main/LICENSE">
|
|
15
|
+
<img src="https://img.shields.io/npm/l/@circadian/sol?style=flat-square&color=111&labelColor=111" alt="license" />
|
|
16
|
+
</a>
|
|
17
|
+
<a href="https://github.com/circadian-dev/sol/actions/workflows/validate.yml">
|
|
18
|
+
<img src="https://img.shields.io/github/actions/workflow/status/circadian-dev/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/@circadian/sol) · [GitHub](https://github.com/circadian-dev/sol) · [circadian.dev](https://circadian.dev)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
> **Dark mode reacts to a preference. Sol reacts to place and time.**
|
|
33
|
+
|
|
34
|
+
Most apps treat theming as a binary choice — light or dark, on or off, a toggle buried in settings.
|
|
35
|
+
|
|
36
|
+
Sol replaces that with something alive. It computes the sun's real position from the user's location, timezone, and current time, then smoothly transitions the interface through **9 solar phases** — dawn, sunrise, morning, solar noon, afternoon, sunset, dusk, night, and midnight — with animated blends, optional weather layers, and 10 richly designed skins.
|
|
37
|
+
|
|
38
|
+
No API key. No manual toggle. Your UI just follows the sun.
|
|
39
|
+
|
|
40
|
+
Sol is the flagship package from [Circadian](https://circadian.dev) — a platform for ambient-aware UI.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
bun add @circadian/sol
|
|
46
|
+
# or
|
|
47
|
+
npm install @circadian/sol
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`@circadian/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`. Solar position is computed locally from latitude, longitude, timezone, and current time — no solar API required.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Features
|
|
55
|
+
|
|
56
|
+
- **2 widget variants** — `SolarWidget` (full card) and `CompactWidget` (slim pill/bar)
|
|
57
|
+
- **10 skins** — `foundry`, `paper`, `signal`, `meridian`, `mineral`, `aurora`, `tide`, `void`, `sundial`, `parchment`
|
|
58
|
+
- **9 solar phases** — `midnight`, `night`, `dawn`, `sunrise`, `morning`, `solar-noon`, `afternoon`, `sunset`, `dusk`
|
|
59
|
+
- **Built-in fallback strategy** — geolocation → browser timezone → timezone centroid
|
|
60
|
+
- **Optional live weather** — powered by Open-Meteo (no API key required)
|
|
61
|
+
- **Dev preview tooling** — `SolarDevTools` lets you scrub through the day and preview phase colors
|
|
62
|
+
- **SSR-safe** — works in Next.js, Remix, TanStack Start, Blade, and Vite
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Quick Start
|
|
67
|
+
|
|
68
|
+
Sol uses browser APIs for geolocation and solar computation. The exact setup depends on your framework — pick yours below.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
### Vite
|
|
73
|
+
|
|
74
|
+
No special setup needed. Wrap your app with the provider and use widgets directly.
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
// main.tsx
|
|
78
|
+
import { StrictMode } from 'react';
|
|
79
|
+
import { createRoot } from 'react-dom/client';
|
|
80
|
+
import { SolarThemeProvider } from '@circadian/sol';
|
|
81
|
+
import App from './App';
|
|
82
|
+
|
|
83
|
+
createRoot(document.getElementById('root')!).render(
|
|
84
|
+
<StrictMode>
|
|
85
|
+
<SolarThemeProvider initialDesign="foundry">
|
|
86
|
+
<App />
|
|
87
|
+
</SolarThemeProvider>
|
|
88
|
+
</StrictMode>,
|
|
89
|
+
);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
// App.tsx
|
|
94
|
+
import { SolarWidget } from '@circadian/sol';
|
|
95
|
+
|
|
96
|
+
export default function App() {
|
|
97
|
+
return <SolarWidget showWeather showFlag />;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### Next.js (App Router)
|
|
104
|
+
|
|
105
|
+
Add `'use client'` at the top of any file that uses Sol. This marks it as a client component and prevents it from running during server rendering.
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
// components/providers.tsx
|
|
109
|
+
'use client';
|
|
110
|
+
import { SolarThemeProvider } from '@circadian/sol';
|
|
111
|
+
|
|
112
|
+
export default function Providers({ children }: { children: React.ReactNode }) {
|
|
113
|
+
return (
|
|
114
|
+
<SolarThemeProvider initialDesign="foundry">
|
|
115
|
+
{children}
|
|
116
|
+
</SolarThemeProvider>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
// components/solar-widget.tsx
|
|
123
|
+
'use client';
|
|
124
|
+
import { SolarWidget } from '@circadian/sol';
|
|
125
|
+
|
|
126
|
+
export default function Solar() {
|
|
127
|
+
return <SolarWidget showWeather showFlag />;
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
// app/layout.tsx
|
|
133
|
+
import Providers from '../components/providers';
|
|
134
|
+
|
|
135
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
136
|
+
return (
|
|
137
|
+
<html lang="en">
|
|
138
|
+
<body>
|
|
139
|
+
<Providers>{children}</Providers>
|
|
140
|
+
</body>
|
|
141
|
+
</html>
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
```tsx
|
|
147
|
+
// app/page.tsx
|
|
148
|
+
import Solar from '../components/solar-widget';
|
|
149
|
+
|
|
150
|
+
export default function Page() {
|
|
151
|
+
return <Solar />;
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### Remix
|
|
158
|
+
|
|
159
|
+
Name any file that uses Sol with a `.client.tsx` extension. Remix excludes `.client` files from the server bundle automatically.
|
|
160
|
+
|
|
161
|
+
```tsx
|
|
162
|
+
// app/components/providers.client.tsx
|
|
163
|
+
import { SolarThemeProvider } from '@circadian/sol';
|
|
164
|
+
|
|
165
|
+
export default function Providers({ children }: { children: React.ReactNode }) {
|
|
166
|
+
return (
|
|
167
|
+
<SolarThemeProvider initialDesign="foundry">
|
|
168
|
+
{children}
|
|
169
|
+
</SolarThemeProvider>
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
// app/components/solar-widget.client.tsx
|
|
176
|
+
import { SolarWidget } from '@circadian/sol';
|
|
177
|
+
|
|
178
|
+
export default function Solar() {
|
|
179
|
+
return <SolarWidget showWeather showFlag />;
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
// app/root.tsx
|
|
185
|
+
import Providers from './components/providers.client';
|
|
186
|
+
|
|
187
|
+
export default function App() {
|
|
188
|
+
return (
|
|
189
|
+
<html lang="en">
|
|
190
|
+
<body>
|
|
191
|
+
<Providers>
|
|
192
|
+
<Outlet />
|
|
193
|
+
</Providers>
|
|
194
|
+
</body>
|
|
195
|
+
</html>
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
// app/routes/_index.tsx
|
|
202
|
+
import Solar from '../components/solar-widget.client';
|
|
203
|
+
|
|
204
|
+
export default function Index() {
|
|
205
|
+
return <Solar />;
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
### TanStack Start
|
|
212
|
+
|
|
213
|
+
Use the `ClientOnly` component from `@tanstack/react-router` to prevent Sol from rendering during SSR.
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
// app/components/solar-widget.tsx
|
|
217
|
+
import { ClientOnly } from '@tanstack/react-router';
|
|
218
|
+
import { SolarThemeProvider, SolarWidget } from '@circadian/sol';
|
|
219
|
+
|
|
220
|
+
export default function Solar() {
|
|
221
|
+
return (
|
|
222
|
+
<ClientOnly fallback={null}>
|
|
223
|
+
<SolarThemeProvider initialDesign="foundry">
|
|
224
|
+
<SolarWidget showWeather showFlag />
|
|
225
|
+
</SolarThemeProvider>
|
|
226
|
+
</ClientOnly>
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
// app/routes/index.tsx
|
|
233
|
+
import Solar from '../components/solar-widget';
|
|
234
|
+
|
|
235
|
+
export const Route = createFileRoute('/')({
|
|
236
|
+
component: () => <Solar />,
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
### Blade
|
|
243
|
+
|
|
244
|
+
Name any file that uses Sol with a `.client.tsx` extension. Blade runs pages server-side; component files run client-side.
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
// components/providers.client.tsx
|
|
248
|
+
import { SolarThemeProvider } from '@circadian/sol';
|
|
249
|
+
|
|
250
|
+
export default function Providers({ children }: { children: React.ReactNode }) {
|
|
251
|
+
return (
|
|
252
|
+
<SolarThemeProvider initialDesign="foundry">
|
|
253
|
+
{children}
|
|
254
|
+
</SolarThemeProvider>
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
// components/solar-widget.client.tsx
|
|
261
|
+
import { SolarWidget } from '@circadian/sol';
|
|
262
|
+
|
|
263
|
+
export default function Solar() {
|
|
264
|
+
return <SolarWidget showWeather showFlag />;
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
// pages/layout.tsx
|
|
270
|
+
import Providers from '../components/providers.client';
|
|
271
|
+
|
|
272
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
273
|
+
return <Providers>{children}</Providers>;
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
// pages/index.tsx
|
|
279
|
+
import Solar from '../components/solar-widget.client';
|
|
280
|
+
|
|
281
|
+
export default function Page() {
|
|
282
|
+
return <Solar />;
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Provider Props
|
|
289
|
+
|
|
290
|
+
`SolarThemeProvider` is the shared runtime for solar phase computation, timezone, coordinates, and skin selection.
|
|
291
|
+
|
|
292
|
+
| Prop | Type | Default | Description |
|
|
293
|
+
|---|---|---|---|
|
|
294
|
+
| `children` | `ReactNode` | — | Required |
|
|
295
|
+
| `initialDesign` | `DesignMode` | `'foundry'` | Starting skin |
|
|
296
|
+
| `isolated` | `boolean` | `false` | Scope CSS vars to wrapper div instead of `:root`. Useful when mounting multiple providers on a single page. |
|
|
297
|
+
|
|
298
|
+
### Location is automatic
|
|
299
|
+
|
|
300
|
+
`SolarThemeProvider` resolves the user's location using a 3-step fallback:
|
|
301
|
+
|
|
302
|
+
1. **Browser Geolocation API** — most accurate, requires user permission
|
|
303
|
+
2. **Browser timezone** (`Intl.DateTimeFormat`) — instant, no permission needed
|
|
304
|
+
3. **Timezone centroid lookup** — maps the IANA timezone to approximate coordinates
|
|
305
|
+
|
|
306
|
+
Solar phases are accurate to ~15–30 minutes from timezone alone, and refine to exact values when geolocation is granted.
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## SolarWidget
|
|
311
|
+
|
|
312
|
+
The full card widget. Reads its design from the nearest `SolarThemeProvider`.
|
|
313
|
+
|
|
314
|
+
```tsx
|
|
315
|
+
<SolarWidget
|
|
316
|
+
expandDirection="top-left"
|
|
317
|
+
size="lg"
|
|
318
|
+
showWeather
|
|
319
|
+
showFlag
|
|
320
|
+
hoverEffect
|
|
321
|
+
/>
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
### Props
|
|
325
|
+
|
|
326
|
+
| Prop | Type | Default | Description |
|
|
327
|
+
|---|---|---|---|
|
|
328
|
+
| `expandDirection` | `ExpandDirection` | `'bottom-right'` | Direction the card expands |
|
|
329
|
+
| `size` | `WidgetSize` | `'lg'` | Widget size |
|
|
330
|
+
| `showWeather` | `boolean` | `false` | Enable live weather display |
|
|
331
|
+
| `showFlag` | `boolean` | `false` | Show country flag |
|
|
332
|
+
| `hoverEffect` | `boolean` | `false` | Enable hover animation |
|
|
333
|
+
| `phaseOverride` | `SolarPhase` | — | Force a discrete phase |
|
|
334
|
+
| `simulatedDate` | `Date` | — | Simulate a specific time |
|
|
335
|
+
| `weatherCategoryOverride` | `WeatherCategory \| null` | — | Force weather condition |
|
|
336
|
+
| `customPalettes` | `CustomPalettes` | — | Override phase colors per phase |
|
|
337
|
+
| `forceExpanded` | `boolean` | — | Lock expanded or collapsed state |
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## CompactWidget
|
|
342
|
+
|
|
343
|
+
<div align="center">
|
|
344
|
+
<img src=".github/compact-banner.png" alt="CompactWidget skins - Tide at Drift, Paper at Morning, Meridian at Dawn" width="100%"/>
|
|
345
|
+
</div>
|
|
346
|
+
|
|
347
|
+
The slim pill/bar variant. Accepts an optional `design` prop to override the provider's active skin.
|
|
348
|
+
|
|
349
|
+
```tsx
|
|
350
|
+
<CompactWidget
|
|
351
|
+
design="signal"
|
|
352
|
+
size="md"
|
|
353
|
+
showWeather
|
|
354
|
+
showFlag
|
|
355
|
+
showTemperature
|
|
356
|
+
/>
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Props
|
|
360
|
+
|
|
361
|
+
| Prop | Type | Default | Description |
|
|
362
|
+
|---|---|---|---|
|
|
363
|
+
| `design` | `DesignMode` | provider design | Design/skin override for this widget |
|
|
364
|
+
| `size` | `CompactSize` | `'md'` | Compact size |
|
|
365
|
+
| `showWeather` | `boolean` | `false` | Show weather icon |
|
|
366
|
+
| `showFlag` | `boolean` | `false` | Show country flag |
|
|
367
|
+
| `showTemperature` | `boolean` | `true` | Show live temperature |
|
|
368
|
+
| `overridePhase` | `SolarPhase \| null` | — | Force a discrete phase |
|
|
369
|
+
| `customPalettes` | `CustomPalettes` | — | Override bg gradient per phase |
|
|
370
|
+
| `simulatedDate` | `Date` | — | Simulate a time |
|
|
371
|
+
| `className` | `string` | — | Wrapper CSS class |
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## Skins
|
|
376
|
+
|
|
377
|
+
10 designs, each with a full widget and compact variant. If `design` is omitted on `CompactWidget`, it uses the provider's active design. `SolarWidget` always uses the provider's active design.
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
type DesignMode =
|
|
381
|
+
| 'aurora' // luminous ethereal
|
|
382
|
+
| 'foundry' // warm volumetric industrial
|
|
383
|
+
| 'tide' // fluid organic wave
|
|
384
|
+
| 'void' // minimal negative space
|
|
385
|
+
| 'mineral' // faceted crystal gem
|
|
386
|
+
| 'meridian' // hairline geometric
|
|
387
|
+
| 'signal' // pixel/blocky lo-fi
|
|
388
|
+
| 'paper' // flat ink editorial
|
|
389
|
+
| 'sundial' // roman/classical carved
|
|
390
|
+
| 'parchment'; // document strokes
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
---
|
|
394
|
+
|
|
395
|
+
## Positioning
|
|
396
|
+
|
|
397
|
+
```tsx
|
|
398
|
+
<SolarWidget /> // inline (default)
|
|
399
|
+
<SolarWidget position="bottom-right" /> // fixed to viewport
|
|
400
|
+
<SolarWidget position="bottom-right" expandDirection="top-left" /> // with expand direction
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Supported positions: `top-left` `top-center` `top-right` `center-left` `center` `center-right` `bottom-left` `bottom-center` `bottom-right` `inline`
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## Weather
|
|
408
|
+
|
|
409
|
+
```tsx
|
|
410
|
+
<SolarWidget showWeather />
|
|
411
|
+
|
|
412
|
+
// Force a category for preview
|
|
413
|
+
<SolarWidget showWeather weatherCategoryOverride="thunder" />
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
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`
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
420
|
+
## Phase & Time Overrides
|
|
421
|
+
|
|
422
|
+
```tsx
|
|
423
|
+
// Force a discrete phase
|
|
424
|
+
<SolarWidget phaseOverride="sunset" />
|
|
425
|
+
|
|
426
|
+
// Simulate a specific time (with blend)
|
|
427
|
+
const preview = new Date();
|
|
428
|
+
preview.setHours(6, 45, 0, 0);
|
|
429
|
+
<SolarWidget simulatedDate={preview} />
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
Use `simulatedDate` for realistic continuous previews. Use `phaseOverride` for simple hard overrides.
|
|
433
|
+
|
|
434
|
+
---
|
|
435
|
+
|
|
436
|
+
## Custom Palettes
|
|
437
|
+
|
|
438
|
+
Override the background gradient for any phase on any skin. Works on both `SolarWidget` and `CompactWidget`.
|
|
439
|
+
|
|
440
|
+
```tsx
|
|
441
|
+
<SolarWidget
|
|
442
|
+
customPalettes={{
|
|
443
|
+
dawn: { bg: ['#20122a', '#7f3b5d', '#f5a66e'] },
|
|
444
|
+
sunset: { bg: ['#2e0f18', '#b84a3d', '#ffbe7a'] },
|
|
445
|
+
}}
|
|
446
|
+
/>
|
|
447
|
+
|
|
448
|
+
<CompactWidget
|
|
449
|
+
customPalettes={{
|
|
450
|
+
dawn: { bg: ['#20122a', '#7f3b5d', '#f5a66e'] },
|
|
451
|
+
sunset: { bg: ['#2e0f18', '#b84a3d', '#ffbe7a'] },
|
|
452
|
+
}}
|
|
453
|
+
/>
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
Each `bg` is a 3-stop gradient: `[top, middle, bottom]`. Only the phases you specify are overridden — the rest keep the skin's default colors. All skin-specific elements (orbs, glows, text, tracks) remain unchanged; only the background gradient is replaced.
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## SolarDevTools
|
|
461
|
+
|
|
462
|
+
When your interface depends on live solar time, manual testing breaks down fast — you can't wait until sunset to test sunset. `SolarDevTools` lets you scrub through the full day in seconds, preview every one of the **9 phases**, test every skin against every time of day, and catch phase-specific visual bugs before your users do.
|
|
463
|
+
|
|
464
|
+
Imported from a dedicated subpath — never included in production bundles unless explicitly imported.
|
|
465
|
+
|
|
466
|
+
```tsx
|
|
467
|
+
import { SolarDevTools } from '@circadian/sol/devtools';
|
|
468
|
+
|
|
469
|
+
// Vite
|
|
470
|
+
{import.meta.env.DEV && <SolarDevTools />}
|
|
471
|
+
|
|
472
|
+
// Next.js / Remix / TanStack Start / Blade
|
|
473
|
+
{process.env.NODE_ENV === 'development' && <SolarDevTools />}
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
### Full example
|
|
477
|
+
|
|
478
|
+
```tsx
|
|
479
|
+
import { SolarThemeProvider, SolarWidget } from '@circadian/sol';
|
|
480
|
+
import { SolarDevTools } from '@circadian/sol/devtools';
|
|
481
|
+
|
|
482
|
+
export default function Demo() {
|
|
483
|
+
return (
|
|
484
|
+
<SolarThemeProvider initialDesign="foundry">
|
|
485
|
+
<SolarWidget showWeather showFlag />
|
|
486
|
+
{process.env.NODE_ENV === 'development' && (
|
|
487
|
+
<SolarDevTools position="bottom-center" />
|
|
488
|
+
)}
|
|
489
|
+
</SolarThemeProvider>
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Props
|
|
495
|
+
|
|
496
|
+
| Prop | Type | Default | Description |
|
|
497
|
+
|---|---|---|---|
|
|
498
|
+
| `defaultOpen` | `boolean` | `false` | Start expanded |
|
|
499
|
+
| `position` | `'bottom-left' \| 'bottom-center' \| 'bottom-right'` | `'bottom-center'` | Pill position |
|
|
500
|
+
| `enabled` | `boolean` | `true` | Programmatic enable/disable |
|
|
501
|
+
|
|
502
|
+
---
|
|
503
|
+
|
|
504
|
+
## useSolarTheme
|
|
505
|
+
|
|
506
|
+
```tsx
|
|
507
|
+
import { useSolarTheme } from '@circadian/sol';
|
|
508
|
+
|
|
509
|
+
function DebugPanel() {
|
|
510
|
+
const { phase, timezone, latitude, longitude, design } = useSolarTheme();
|
|
511
|
+
return (
|
|
512
|
+
<pre>{JSON.stringify({ phase, timezone, latitude, longitude, design }, null, 2)}</pre>
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### Return shape
|
|
518
|
+
|
|
519
|
+
| Property | Type | Description |
|
|
520
|
+
|---|---|---|
|
|
521
|
+
| `phase` | `SolarPhase` | Current active phase |
|
|
522
|
+
| `blend` | `SolarBlend` | Phase blend state (phase, nextPhase, t) |
|
|
523
|
+
| `isDaytime` | `boolean` | Whether the sun is above the horizon |
|
|
524
|
+
| `brightness` | `number` | 0–1 brightness value |
|
|
525
|
+
| `mode` | `'light' \| 'dim' \| 'dark'` | Current light mode |
|
|
526
|
+
| `accentColor` | `string` | Active accent hex |
|
|
527
|
+
| `timezone` | `string \| null` | Resolved timezone |
|
|
528
|
+
| `latitude` | `number \| null` | Resolved latitude |
|
|
529
|
+
| `longitude` | `number \| null` | Resolved longitude |
|
|
530
|
+
| `coordsReady` | `boolean` | Whether coordinates have resolved |
|
|
531
|
+
| `design` | `DesignMode` | Active skin name |
|
|
532
|
+
| `activeSkin` | `SkinDefinition` | Full skin definition object |
|
|
533
|
+
| `setOverridePhase` | `(phase \| null) => void` | Set/clear phase override |
|
|
534
|
+
| `setDesign` | `(skin: DesignMode) => void` | Change active skin |
|
|
535
|
+
|
|
536
|
+
---
|
|
537
|
+
|
|
538
|
+
## Multiple Widgets
|
|
539
|
+
|
|
540
|
+
```tsx
|
|
541
|
+
<SolarThemeProvider initialDesign="foundry">
|
|
542
|
+
<SolarWidget showWeather />
|
|
543
|
+
<CompactWidget design="signal" />
|
|
544
|
+
<SolarWidget />
|
|
545
|
+
</SolarThemeProvider>
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
`CompactWidget` accepts a `design` prop to override per-instance. `SolarWidget` always follows the provider. The provider manages shared solar state — location, phase, and weather are computed once and shared across all children.
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## TypeScript
|
|
553
|
+
|
|
554
|
+
```ts
|
|
555
|
+
import type {
|
|
556
|
+
DesignMode,
|
|
557
|
+
SolarPhase,
|
|
558
|
+
SolarBlend,
|
|
559
|
+
WeatherCategory,
|
|
560
|
+
ExpandDirection,
|
|
561
|
+
WidgetSize,
|
|
562
|
+
CompactSize,
|
|
563
|
+
SkinDefinition,
|
|
564
|
+
WidgetPalette,
|
|
565
|
+
CustomPalettes,
|
|
566
|
+
SolarTheme,
|
|
567
|
+
} from '@circadian/sol';
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## What's Included
|
|
573
|
+
|
|
574
|
+
| | |
|
|
575
|
+
|---|---|
|
|
576
|
+
| ✅ | Full widget + compact widget |
|
|
577
|
+
| ✅ | 10 skins with full + compact variants |
|
|
578
|
+
| ✅ | Solar math (NOAA equations, no external API) |
|
|
579
|
+
| ✅ | Timezone fallback logic |
|
|
580
|
+
| ✅ | Optional live weather (Open-Meteo) |
|
|
581
|
+
| ✅ | Skin-aware country flags |
|
|
582
|
+
| ✅ | Dev timeline scrubber |
|
|
583
|
+
| ✅ | Self-contained CSS (no Tailwind required in host app) |
|
|
584
|
+
| ✅ | SSR-safe (Next.js, Remix, TanStack Start, Blade, Vite) |
|
|
585
|
+
| ❌ | No solar API key needed |
|
|
586
|
+
| ❌ | No weather API key needed |
|
|
587
|
+
| ❌ | No Tailwind needed in your app |
|
|
588
|
+
| ❌ | No geolocation permission required |
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
## Coming Soon
|
|
593
|
+
|
|
594
|
+
Sol is actively being developed. Things in progress:
|
|
595
|
+
|
|
596
|
+
- **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
|
|
597
|
+
- More skins
|
|
598
|
+
- Vue and Svelte adapters
|
|
599
|
+
- Deep token override system
|
|
600
|
+
|
|
601
|
+
---
|
|
602
|
+
|
|
603
|
+
<div align="center">
|
|
604
|
+
|
|
605
|
+
MIT © [Circadian] - website coming soon
|
|
606
|
+
|
|
607
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
|
|
3
|
+
//#region src/devtools/solar-devtools.d.ts
|
|
4
|
+
interface SolarDevToolsProps {
|
|
5
|
+
defaultOpen?: boolean;
|
|
6
|
+
position?: 'bottom-left' | 'bottom-center' | 'bottom-right';
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
declare function SolarDevTools({
|
|
10
|
+
defaultOpen,
|
|
11
|
+
position,
|
|
12
|
+
enabled
|
|
13
|
+
}: SolarDevToolsProps): React.ReactPortal | null;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { SolarDevTools, type SolarDevToolsProps };
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/devtools/solar-devtools.tsx"],"sourcesContent":[],"mappings":";;;UA6BiB,kBAAA;;EAAA,QAAA,CAAA,EAAA,aAAkB,GAAA,eAAA,GAAA,cAAA;EAqCnB,OAAA,CAAA,EAAA,OAAa;;AAE3B,iBAFc,aAAA,CAEd;EAAA,WAAA;EAAA,QAAA;EAAA;AAAA,CAAA,EAEC,kBAFD,CAAA,EAEmB,KAAA,CAAA,WAFnB,GAAA,IAAA"}
|