@getdashfy/ui 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,461 @@
1
+ # `@getdashfy/ui`
2
+
3
+ > Dashfy UI component library for building Dashfy dashboards.
4
+
5
+ ## Introduction
6
+
7
+ `@getdashfy/ui` is the frontend runtime for Dashfy dashboards. It provides a complete React component library for rendering dashboards, managing WebSocket connections, handling real-time data subscriptions, and providing an extensible widget system.
8
+
9
+ The UI library acts as the client-side orchestrator that:
10
+
11
+ - Connects to the Dashfy server via WebSockets
12
+ - Renders dashboard layouts and widgets
13
+ - Manages real-time data subscriptions
14
+ - Provides theme support and customization
15
+ - Handles user interactions and keyboard shortcuts
16
+ - Manages application state with Zustand
17
+
18
+ ## Install
19
+
20
+ Install with your favorite package manager:
21
+
22
+ #### `npm`
23
+
24
+ ```bash
25
+ npm install @getdashfy/ui
26
+ ```
27
+
28
+ #### `pnpm`
29
+
30
+ ```bash
31
+ pnpm add @getdashfy/ui
32
+ ```
33
+
34
+ #### `yarn`
35
+
36
+ ```bash
37
+ yarn add @getdashfy/ui
38
+ ```
39
+
40
+ #### `bun`
41
+
42
+ ```bash
43
+ bun add @getdashfy/ui
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ Create a Dashfy client and register extension widgets:
49
+
50
+ ```tsx
51
+ import { CustomJson, JsonKeys, JsonStatus } from '@getdashfy/ext-json'
52
+ import {
53
+ Branches,
54
+ CommitActivityLine,
55
+ ContributorsStats,
56
+ Gitmap,
57
+ OrgBadge,
58
+ PullRequests,
59
+ RepoBadge,
60
+ Status,
61
+ UserBadge,
62
+ } from '@getdashfy/ext-github'
63
+ import { Dashfy, WidgetRegistry } from '@getdashfy/ui'
64
+
65
+ // Register GitHub extension widgets
66
+ WidgetRegistry.addExtension('github', {
67
+ Branches,
68
+ CommitActivityLine,
69
+ ContributorsStats,
70
+ Gitmap,
71
+ OrgBadge,
72
+ PullRequests,
73
+ RepoBadge,
74
+ Status,
75
+ UserBadge,
76
+ })
77
+
78
+ // Register JSON extension widgets
79
+ WidgetRegistry.addExtension('json', {
80
+ CustomJson,
81
+ JsonKeys,
82
+ JsonStatus,
83
+ })
84
+
85
+ export const App = () => {
86
+ return <Dashfy serverUrl="http://localhost:5001" />
87
+ }
88
+ ```
89
+
90
+ ## Core Features
91
+
92
+ #### » Widget System
93
+
94
+ Extensible widget registry for registering and managing dashboard widgets:
95
+
96
+ ```tsx
97
+ import { WidgetRegistry } from '@getdashfy/ui'
98
+ import { MyCustomWidget, AnotherWidget } from './widgets'
99
+
100
+ // Register a single widget
101
+ WidgetRegistry.register('myextension:CustomWidget', MyCustomWidget)
102
+
103
+ // Register multiple widgets from an extension
104
+ WidgetRegistry.addExtension('myextension', {
105
+ CustomWidget: MyCustomWidget,
106
+ AnotherWidget,
107
+ })
108
+
109
+ // Get a registered widget
110
+ const Widget = WidgetRegistry.getComponent('myextension', 'CustomWidget')
111
+ ```
112
+
113
+ **Widget Lifecycle:**
114
+
115
+ 1. Widgets are registered via `WidgetRegistry`
116
+ 2. Dashboard configuration references widgets by `extension:widget` name
117
+ 3. Dashfy component dynamically loads and renders widgets
118
+ 4. Widgets subscribe to API data via `useApiSubscription` hook
119
+ 5. Real-time updates flow through WebSocket to widget components
120
+
121
+ #### » Real-time Data Subscriptions
122
+
123
+ Built-in hooks for subscribing to API data from the server:
124
+
125
+ ```tsx
126
+ import {
127
+ useApiSubscription,
128
+ Widget,
129
+ WidgetHeader,
130
+ WidgetBody,
131
+ WidgetLoader,
132
+ WidgetError,
133
+ } from '@getdashfy/ui'
134
+
135
+ export const MyWidget = ({ repository }: { repository: string }) => {
136
+ const { data, error, loading } = useApiSubscription<RepoData>({
137
+ api: 'github',
138
+ endpoint: 'repo',
139
+ params: { repository },
140
+ })
141
+
142
+ if (loading) return <WidgetLoader />
143
+ if (error) return <WidgetError error={error} />
144
+
145
+ return (
146
+ <Widget>
147
+ <WidgetHeader title="GitHub Repository" />
148
+ <WidgetBody>
149
+ <pre>{JSON.stringify(data, null, 2)}</pre>
150
+ </WidgetBody>
151
+ </Widget>
152
+ )
153
+ }
154
+ ```
155
+
156
+ **Subscription Features:**
157
+
158
+ - Automatic subscription on mount
159
+ - Automatic unsubscription on unmount
160
+ - Loading and error states
161
+ - Type-safe data handling
162
+ - Shared subscriptions (multiple widgets can subscribe to same data)
163
+
164
+ #### » WebSocket Connection
165
+
166
+ Managed [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) connection with automatic reconnection:
167
+
168
+ ```tsx
169
+ import { useWebSocket } from '@getdashfy/ui'
170
+
171
+ const socket = useWebSocket({
172
+ url: 'http://localhost:5001', // Server URL
173
+ autoConnect: true,
174
+ reconnect: true,
175
+ })
176
+
177
+ if (!socket) {
178
+ return <div>Connecting...</div>
179
+ }
180
+
181
+ // Socket is ready to use
182
+ ```
183
+
184
+ **Connection Features:**
185
+
186
+ - Automatic reconnection with configurable attempts and delays
187
+ - Connection status tracking (via store)
188
+ - Automatic resubscription of API endpoints on reconnect
189
+ - Integration with notification system
190
+ - Graceful error handling and cleanup
191
+
192
+ #### » Theme System
193
+
194
+ Built-in theme support with light/dark mode:
195
+
196
+ ```tsx
197
+ import { ThemeRegistry } from '@getdashfy/ui'
198
+ import { defaultTheme, nordTheme } from '@getdashfy/themes'
199
+ import { myCustomTheme } from './themes/custom'
200
+
201
+ // Load all built-in themes from @getdashfy/themes
202
+ ThemeRegistry.loadAllThemes()
203
+
204
+ // Or register themes individually
205
+ ThemeRegistry.add(myCustomTheme)
206
+
207
+ // Or register multiple themes at once
208
+ ThemeRegistry.addAll([defaultTheme, nordTheme])
209
+
210
+ // Set default theme
211
+ ThemeRegistry.defaultTheme = 'nord'
212
+
213
+ // Get all theme IDs
214
+ const themeIds = ThemeRegistry.list()
215
+
216
+ // Get a specific theme
217
+ const theme = ThemeRegistry.get('nord')
218
+ ```
219
+
220
+ **Theme Features:**
221
+
222
+ - Built-in themes from `@getdashfy/themes` package
223
+ - Light/dark mode support
224
+ - CSS variable-based theming
225
+ - LocalStorage persistence
226
+ - Theme switching via settings panel
227
+
228
+ #### » Keyboard Shortcuts
229
+
230
+ Built-in keyboard shortcuts for dashboard control:
231
+
232
+ | Shortcut | Action |
233
+ | --------------------- | ------------------------ |
234
+ | `Space` | Start/Pause rotation |
235
+ | `←` / `→` | Navigate dashboards |
236
+ | `F` | Toggle fullscreen |
237
+ | `S` or `Cmd/Ctrl + ,` | Open settings |
238
+ | `Esc` | Close settings/exit full |
239
+ | `Cmd/Ctrl + P` | Open bottom panel |
240
+
241
+ #### » Bottom Panel
242
+
243
+ Tabbed bottom panel with built-in tabs:
244
+
245
+ - **Connection:** WebSocket connection status and server info
246
+ - **Console:** Real-time logs and API events
247
+ - **Notifications:** System notifications and alerts
248
+
249
+ #### » State Management
250
+
251
+ Centralized state management with [Zustand](https://github.com/pmndrs/zustand):
252
+
253
+ ```tsx
254
+ import { useDashfyStore } from '@getdashfy/ui'
255
+
256
+ // Access store slices
257
+ const config = useDashfyStore((state) => state.config)
258
+ const dashboards = useDashfyStore((state) => state.dashboards)
259
+ const currentTheme = useDashfyStore((state) => state.currentTheme)
260
+
261
+ // Dispatch actions
262
+ const setTheme = useDashfyStore((state) => state.setTheme)
263
+ const nextDashboard = useDashfyStore((state) => state.nextDashboard)
264
+ ```
265
+
266
+ ## Widget Architecture
267
+
268
+ #### » Widget Props
269
+
270
+ Widgets receive props from dashboard configuration. The `WidgetConfig` interface defines the standard properties:
271
+
272
+ ```tsx
273
+ interface WidgetConfig {
274
+ extension: string
275
+ widget: string
276
+ title?: string
277
+ columns: number
278
+ rows: number
279
+ x: number
280
+ y: number
281
+ // Custom props defined in configuration
282
+ [key: string]: unknown
283
+ }
284
+ ```
285
+
286
+ When creating widgets, you can define your own prop interface that extends the configuration properties you need.
287
+
288
+ #### » Widget Structure
289
+
290
+ Recommended widget structure:
291
+
292
+ ```tsx
293
+ import {
294
+ useApiSubscription,
295
+ Widget,
296
+ WidgetHeader,
297
+ WidgetBody,
298
+ WidgetLoader,
299
+ WidgetError,
300
+ WidgetEmpty,
301
+ } from '@getdashfy/ui'
302
+
303
+ interface MyWidgetProps {
304
+ title?: string
305
+ repository: string
306
+ }
307
+
308
+ export const MyWidget = ({ title, repository }: MyWidgetProps) => {
309
+ const { data, error, loading } = useApiSubscription<RepoData>({
310
+ api: 'github',
311
+ endpoint: 'repo',
312
+ params: { repository },
313
+ })
314
+
315
+ if (loading) return <WidgetLoader />
316
+ if (error) return <WidgetError error={error} />
317
+ if (!data) return <WidgetEmpty message="No data available" />
318
+
319
+ return (
320
+ <Widget>
321
+ <WidgetHeader title={title || data.name} />
322
+ <WidgetBody>
323
+ <div className="space-y-2">
324
+ <p>{data.description}</p>
325
+ <div className="flex gap-4">
326
+ <span>⭐ {data.stars}</span>
327
+ <span>🍴 {data.forks}</span>
328
+ </div>
329
+ </div>
330
+ </WidgetBody>
331
+ </Widget>
332
+ )
333
+ }
334
+ ```
335
+
336
+ **Widget Best Practices:**
337
+
338
+ - Use `useApiSubscription` for data fetching
339
+ - Handle loading, error, and empty states
340
+ - Use base widget components for consistent styling
341
+ - Keep widgets focused and composable
342
+ - Provide TypeScript types for props
343
+ - Use error boundaries for resilience
344
+
345
+ #### » Widget Registration
346
+
347
+ Register widgets before rendering the Dashfy component:
348
+
349
+ ```tsx
350
+ import { WidgetRegistry } from '@getdashfy/ui'
351
+ import { MyWidget } from './widgets/MyWidget'
352
+
353
+ // Register extension with multiple widgets
354
+ WidgetRegistry.addExtension('myextension', {
355
+ MyWidget,
356
+ AnotherWidget,
357
+ ThirdWidget,
358
+ })
359
+ ```
360
+
361
+ #### » Widget Configuration
362
+
363
+ Reference widgets in dashboard configuration:
364
+
365
+ ```json
366
+ {
367
+ "dashboards": [
368
+ {
369
+ "title": "My Dashboard",
370
+ "columns": 3,
371
+ "rows": 2,
372
+ "widgets": [
373
+ {
374
+ "extension": "myextension",
375
+ "widget": "MyWidget",
376
+ "x": 0,
377
+ "y": 0,
378
+ "columns": 1,
379
+ "rows": 1,
380
+ "title": "Custom Title",
381
+ "repository": "facebook/react"
382
+ }
383
+ ]
384
+ }
385
+ ]
386
+ }
387
+ ```
388
+
389
+ ## Styling
390
+
391
+ The UI library uses [Tailwind CSS](https://tailwindcss.com) with custom theme tokens:
392
+
393
+ ```tsx
394
+ // Use Tailwind utility classes
395
+ <div className="bg-background text-foreground p-4 rounded-lg border">
396
+ Content
397
+ </div>
398
+
399
+ // Use theme CSS variables
400
+ <div style={{ color: 'hsl(var(--primary))' }}>
401
+ Themed text
402
+ </div>
403
+ ```
404
+
405
+ **Theme Variables:**
406
+
407
+ - `--background`, `--foreground`
408
+ - `--primary`, `--primary-foreground`
409
+ - `--secondary`, `--secondary-foreground`
410
+ - `--muted`, `--muted-foreground`
411
+ - `--accent`, `--accent-foreground`
412
+ - `--destructive`, `--destructive-foreground`
413
+ - `--border`, `--input`, `--ring`
414
+ - `--card`, `--card-foreground`
415
+ - `--popover`, `--popover-foreground`
416
+
417
+ ## TypeScript Support
418
+
419
+ Fully typed with TypeScript:
420
+
421
+ ```tsx
422
+ import type { DashfyConfig, DashboardConfig, WidgetConfig } from '@getdashfy/ui'
423
+
424
+ const dashfyConfig: DashfyConfig = {
425
+ dashboards: [
426
+ /* ... */
427
+ ],
428
+ }
429
+ ```
430
+
431
+ ## Development
432
+
433
+ ```bash
434
+ # Install dependencies
435
+ pnpm install
436
+
437
+ # Build
438
+ pnpm build
439
+
440
+ # Watch mode
441
+ pnpm dev
442
+
443
+ # Run Storybook
444
+ pnpm storybook
445
+
446
+ # Run tests
447
+ pnpm test
448
+
449
+ # Type check
450
+ pnpm typecheck
451
+ ```
452
+
453
+ ## Community
454
+
455
+ Join the community on [Dashfy's Discord server](https://dashfy.dev/discord) to discuss the project, ask questions, or get help.
456
+
457
+ Join the conversation on X (Twitter) and follow [@dashfydev](https://x.com/dashfydev) for updates and announcements.
458
+
459
+ ## License
460
+
461
+ This project is licensed under the AGPL-3.0 License - see the [LICENSE](./LICENSE) file for details.