@sirsluginston/sharedui 2.0.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,130 @@
1
+ # @sirsluginston/sharedui
2
+
3
+ Server-Driven UI component library for SirSluginston Co.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @sirsluginston/sharedui
9
+ ```
10
+
11
+ **Peer Dependencies:**
12
+ ```bash
13
+ npm install react react-dom
14
+ ```
15
+
16
+ ## Quick Start
17
+
18
+ ```tsx
19
+ import { StatePage, applyTheme } from '@sirsluginston/sharedui';
20
+ import '@sirsluginston/sharedui/dist/style.css';
21
+
22
+ // Apply brand theme
23
+ applyTheme({
24
+ primaryColor: '#1a365d',
25
+ secondaryColor: '#2d3748',
26
+ accentColor: '#319795'
27
+ });
28
+
29
+ // Render a page
30
+ function App() {
31
+ return (
32
+ <StatePage
33
+ brand={brandConfig}
34
+ data={stateData}
35
+ />
36
+ );
37
+ }
38
+ ```
39
+
40
+ ## Exports
41
+
42
+ ### Page Templates (Primary)
43
+ Pre-composed pages for SDUI rendering:
44
+
45
+ | Template | Description |
46
+ |----------|-------------|
47
+ | `NationPage` | Nation-level overview with state directory |
48
+ | `StatePage` | State-level with cities directory + recent events |
49
+ | `CityPage` | City-level with companies directory + recent events |
50
+ | `CompanyPage` | Company profile with sites + event history |
51
+ | `SitePage` | Individual site (e.g., "Walmart #1234") |
52
+
53
+ ### Block Components
54
+ Composable sections for custom pages:
55
+
56
+ - `Hero` - Title, breadcrumbs, score badge
57
+ - `StatGrid` - Statistics cards grid
58
+ - `Directory` - Searchable entity list (cities, companies, etc.)
59
+ - `RecentEvents` - Event/incident feed
60
+ - `FilterSidebar` - Left sidebar with filters
61
+ - `InfoSidebar` - Right sidebar with metadata + ad slot
62
+ - `AdSlot` - Placeholder for advertisements
63
+ - `MobileAdBanner` - Sticky bottom banner for mobile
64
+
65
+ ### Layout Components
66
+ - `Shell` - Page wrapper (header, footer, theming)
67
+ - `Header` - Brand navigation header
68
+ - `Footer` - Copyright and links
69
+
70
+ ### Core UI Components
71
+ - `Button`, `Card`, `Badge`, `Input`
72
+ - `Table`, `Modal`, `Alert`, `Tabs`
73
+ - `Tooltip`, `Spinner`, `Skeleton`
74
+
75
+ ### Hooks & Utilities
76
+ - `useTheme()` - Dark mode toggle hook
77
+ - `applyTheme(config)` - Apply brand colors to CSS variables
78
+
79
+ ### Types
80
+ Full TypeScript definitions exported:
81
+ - `BrandConfig` - Brand configuration
82
+ - `NationPageData`, `StatePageData`, `CityPageData`, etc.
83
+ - `EntityStats`, `DirectoryItem`, `RecentEvent`
84
+
85
+ ## Theming
86
+
87
+ SharedUI uses CSS variables for theming. Override at runtime:
88
+
89
+ ```ts
90
+ import { applyTheme } from '@sirsluginston/sharedui';
91
+
92
+ applyTheme({
93
+ primaryColor: '#your-primary',
94
+ secondaryColor: '#your-secondary',
95
+ accentColor: '#your-accent'
96
+ });
97
+ ```
98
+
99
+ Or override in CSS:
100
+ ```css
101
+ :root {
102
+ --primary-color: #custom;
103
+ --accent-color: #custom;
104
+ }
105
+ ```
106
+
107
+ ## Responsive Layout
108
+
109
+ The `page-layout` CSS class provides:
110
+ - **Desktop (>1400px)**: 3-column grid (filters | main | info)
111
+ - **Tablet (992-1400px)**: 2-column (main | info)
112
+ - **Mobile (<992px)**: Single column + sticky ad banner
113
+
114
+ ## Development
115
+
116
+ ```bash
117
+ # Install dependencies
118
+ npm install
119
+
120
+ # Start dev server with demo
121
+ npm run dev
122
+
123
+ # Build library
124
+ npm run build
125
+ ```
126
+
127
+ ## License
128
+
129
+ MIT © SirSluginston Co
130
+
@@ -0,0 +1,444 @@
1
+ import { default as default_2 } from 'react';
2
+ import { JSX as JSX_2 } from 'react/jsx-runtime';
3
+
4
+ export declare const AdSlot: default_2.FC<AdSlotProps>;
5
+
6
+ declare interface AdSlotProps {
7
+ position: 'sidebar' | 'left-sidebar' | 'banner' | 'inline';
8
+ width?: number | string;
9
+ height?: number | string;
10
+ }
11
+
12
+ export declare const Alert: default_2.FC<AlertProps>;
13
+
14
+ declare interface AlertProps {
15
+ children: default_2.ReactNode;
16
+ variant?: 'info' | 'success' | 'warning' | 'danger';
17
+ title?: string;
18
+ dismissible?: boolean;
19
+ onDismiss?: () => void;
20
+ }
21
+
22
+ /**
23
+ * Apply theme colors to CSS variables
24
+ * Can be called standalone (e.g., from SSR/static shell) or via useTheme hook
25
+ */
26
+ export declare function applyTheme(theme: BrandTheme): void;
27
+
28
+ export declare const Badge: default_2.FC<BadgeProps>;
29
+
30
+ declare interface BadgeProps {
31
+ children: default_2.ReactNode;
32
+ variant?: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'outline';
33
+ size?: 'sm' | 'md';
34
+ }
35
+
36
+ /**
37
+ * Brand Configuration
38
+ *
39
+ * Stored in DynamoDB: VentureOS-Projects
40
+ * PK: BRAND#{slug}, SK: CONFIG
41
+ *
42
+ * Structure is IDENTICAL - no mapping/transformation.
43
+ * Frontend fetches and uses directly.
44
+ */
45
+ export declare interface BrandConfig {
46
+ slug: string;
47
+ name: string;
48
+ tagline?: string;
49
+ logoUrl?: string;
50
+ theme: BrandTheme;
51
+ scoreConfig?: ScoreConfig;
52
+ typography?: BrandTypography;
53
+ footer: {
54
+ copyrightBrand: string;
55
+ yearCreated: number;
56
+ poweredBy?: string;
57
+ links?: FooterLink[];
58
+ };
59
+ navItems: NavItem[];
60
+ }
61
+
62
+ export declare interface BrandTheme {
63
+ primaryColor: string;
64
+ secondaryColor: string;
65
+ accentColor: string;
66
+ surfaceLight?: string;
67
+ surfaceDark?: string;
68
+ textLight?: string;
69
+ textDark?: string;
70
+ defaultTheme?: 'light' | 'dark' | 'auto';
71
+ }
72
+
73
+ export declare interface BrandTypography {
74
+ fontSans?: string;
75
+ fontSerif?: string;
76
+ spaceUnit?: number;
77
+ radiusMaster?: number;
78
+ }
79
+
80
+ export declare const Button: default_2.FC<ButtonProps>;
81
+
82
+ declare interface ButtonProps extends default_2.ButtonHTMLAttributes<HTMLButtonElement> {
83
+ variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
84
+ size?: 'sm' | 'md' | 'lg';
85
+ loading?: boolean;
86
+ icon?: default_2.ReactNode;
87
+ children: default_2.ReactNode;
88
+ }
89
+
90
+ export declare const Card: default_2.FC<CardProps>;
91
+
92
+ declare interface CardProps {
93
+ title?: string;
94
+ subtitle?: string;
95
+ children: default_2.ReactNode;
96
+ hoverable?: boolean;
97
+ padding?: 'none' | 'sm' | 'md' | 'lg';
98
+ className?: string;
99
+ style?: default_2.CSSProperties;
100
+ onClick?: () => void;
101
+ }
102
+
103
+ export declare const CityPage: default_2.FC<CityPageProps>;
104
+
105
+ export declare interface CityPageData {
106
+ name: string;
107
+ slug: string;
108
+ state: string;
109
+ stateName: string;
110
+ stats: EntityStats;
111
+ directory: DirectoryItem[];
112
+ recentByAgency: Record<string, RecentEvent[]>;
113
+ meta?: EntityMeta;
114
+ }
115
+
116
+ declare interface CityPageProps {
117
+ brand: BrandConfig;
118
+ data: CityPageData;
119
+ onAccountClick?: () => void;
120
+ onNotificationClick?: () => void;
121
+ }
122
+
123
+ declare interface Column<T> {
124
+ key: keyof T | string;
125
+ header: string;
126
+ render?: (item: T) => default_2.ReactNode;
127
+ width?: string | number;
128
+ align?: 'left' | 'center' | 'right';
129
+ }
130
+
131
+ export declare const CompanyPage: default_2.FC<CompanyPageProps>;
132
+
133
+ export declare interface CompanyPageData {
134
+ name: string;
135
+ slug: string;
136
+ stats: EntityStats;
137
+ sites?: DirectoryItem[];
138
+ recentEvents: RecentEvent[];
139
+ meta?: EntityMeta;
140
+ }
141
+
142
+ declare interface CompanyPageProps {
143
+ brand: BrandConfig;
144
+ data: CompanyPageData;
145
+ onAccountClick?: () => void;
146
+ onNotificationClick?: () => void;
147
+ }
148
+
149
+ export declare const Directory: default_2.FC<DirectoryProps>;
150
+
151
+ export declare interface DirectoryItem {
152
+ slug: string;
153
+ name: string;
154
+ count: number;
155
+ subtitle?: string;
156
+ }
157
+
158
+ declare interface DirectoryProps {
159
+ title: string;
160
+ items: DirectoryItem[];
161
+ basePath: string;
162
+ emptyMessage?: string;
163
+ showSearch?: boolean;
164
+ initialLimit?: number;
165
+ }
166
+
167
+ export declare interface EntityMeta {
168
+ population?: number;
169
+ flagUrl?: string;
170
+ logoUrl?: string;
171
+ industry?: string;
172
+ founded?: number;
173
+ headquarters?: string;
174
+ [key: string]: unknown;
175
+ }
176
+
177
+ export declare interface EntityStats {
178
+ totalViolations: number;
179
+ totalInjuries?: number;
180
+ totalFatalities?: number;
181
+ totalFines?: number;
182
+ avgFines?: number;
183
+ score?: number;
184
+ scoreLabel?: string;
185
+ trend?: {
186
+ direction: 'up' | 'down' | 'flat';
187
+ percentage: number;
188
+ };
189
+ }
190
+
191
+ export declare const FilterSidebar: default_2.FC<FilterSidebarProps>;
192
+
193
+ declare interface FilterSidebarProps {
194
+ showAd?: boolean;
195
+ }
196
+
197
+ export declare const Footer: default_2.FC<FooterProps>;
198
+
199
+ export declare interface FooterLink {
200
+ label: string;
201
+ url: string;
202
+ }
203
+
204
+ declare interface FooterProps {
205
+ copyrightBrand: string;
206
+ yearCreated: number;
207
+ poweredBy?: string;
208
+ links?: FooterLink[];
209
+ }
210
+
211
+ export declare const Header: default_2.FC<HeaderProps>;
212
+
213
+ declare interface HeaderProps {
214
+ brand: BrandConfig;
215
+ darkMode: boolean;
216
+ onThemeToggle: () => void;
217
+ onAccountClick?: () => void;
218
+ onNotificationClick?: () => void;
219
+ }
220
+
221
+ export declare const Hero: default_2.FC<HeroProps>;
222
+
223
+ declare interface HeroProps {
224
+ title: string;
225
+ subtitle?: string;
226
+ breadcrumbs?: {
227
+ label: string;
228
+ path?: string;
229
+ }[];
230
+ score?: {
231
+ value: number;
232
+ label: string;
233
+ betaDisclaimer?: boolean;
234
+ };
235
+ }
236
+
237
+ export declare const InfoSidebar: default_2.FC<InfoSidebarProps>;
238
+
239
+ declare interface InfoSidebarProps {
240
+ meta?: EntityMeta;
241
+ showAd?: boolean;
242
+ }
243
+
244
+ export declare const Input: default_2.FC<InputProps>;
245
+
246
+ declare interface InputProps extends default_2.InputHTMLAttributes<HTMLInputElement> {
247
+ label?: string;
248
+ error?: string;
249
+ hint?: string;
250
+ icon?: default_2.ReactNode;
251
+ }
252
+
253
+ export declare const LoadingOverlay: default_2.FC<LoadingOverlayProps>;
254
+
255
+ declare interface LoadingOverlayProps {
256
+ message?: string;
257
+ }
258
+
259
+ export declare const MobileAdBanner: default_2.FC;
260
+
261
+ export declare const Modal: default_2.FC<ModalProps>;
262
+
263
+ declare interface ModalProps {
264
+ open: boolean;
265
+ onClose: () => void;
266
+ title?: string;
267
+ children: default_2.ReactNode;
268
+ size?: 'sm' | 'md' | 'lg';
269
+ showCloseButton?: boolean;
270
+ }
271
+
272
+ export declare const NationPage: default_2.FC<NationPageProps>;
273
+
274
+ export declare interface NationPageData {
275
+ name: string;
276
+ slug: string;
277
+ stats: EntityStats;
278
+ directory: DirectoryItem[];
279
+ meta?: EntityMeta;
280
+ }
281
+
282
+ declare interface NationPageProps {
283
+ brand: BrandConfig;
284
+ data: NationPageData;
285
+ onAccountClick?: () => void;
286
+ onNotificationClick?: () => void;
287
+ }
288
+
289
+ export declare interface NavItem {
290
+ label: string;
291
+ path?: string;
292
+ onClick?: () => void;
293
+ inNavbar?: boolean;
294
+ children?: NavItem[];
295
+ }
296
+
297
+ export declare interface RecentEvent {
298
+ eventId: string;
299
+ eventTitle: string;
300
+ eventDescription?: string;
301
+ eventDate?: string;
302
+ companySlug?: string;
303
+ companyName?: string;
304
+ citySlug?: string;
305
+ city?: string;
306
+ state?: string;
307
+ agency: string;
308
+ }
309
+
310
+ export declare const RecentEvents: default_2.FC<RecentEventsProps>;
311
+
312
+ declare interface RecentEventsProps {
313
+ title: string;
314
+ events: RecentEvent[];
315
+ viewMorePath?: string;
316
+ showAgencyBadge?: boolean;
317
+ }
318
+
319
+ export declare interface ScoreConfig {
320
+ name: string;
321
+ type: string;
322
+ icon?: string;
323
+ betaDisclaimer?: boolean;
324
+ }
325
+
326
+ export declare const Shell: default_2.FC<ShellProps>;
327
+
328
+ declare interface ShellProps {
329
+ brand: BrandConfig;
330
+ children: default_2.ReactNode;
331
+ onAccountClick?: () => void;
332
+ onNotificationClick?: () => void;
333
+ }
334
+
335
+ export declare const SitePage: default_2.FC<SitePageProps>;
336
+
337
+ export declare interface SitePageData {
338
+ name: string;
339
+ siteId: string;
340
+ companySlug: string;
341
+ companyName: string;
342
+ stats: EntityStats;
343
+ siblings?: DirectoryItem[];
344
+ recentEvents: RecentEvent[];
345
+ meta?: EntityMeta;
346
+ }
347
+
348
+ declare interface SitePageProps {
349
+ brand: BrandConfig;
350
+ data: SitePageData;
351
+ onAccountClick?: () => void;
352
+ onNotificationClick?: () => void;
353
+ }
354
+
355
+ export declare const Skeleton: default_2.FC<SkeletonProps>;
356
+
357
+ export declare const SkeletonCard: default_2.FC;
358
+
359
+ declare interface SkeletonProps {
360
+ width?: string | number;
361
+ height?: string | number;
362
+ variant?: 'text' | 'rect' | 'circle';
363
+ animation?: 'pulse' | 'wave' | 'none';
364
+ }
365
+
366
+ export declare const SkeletonText: default_2.FC<{
367
+ lines?: number;
368
+ }>;
369
+
370
+ export declare const Spinner: default_2.FC<SpinnerProps>;
371
+
372
+ declare interface SpinnerProps {
373
+ size?: 'sm' | 'md' | 'lg';
374
+ color?: string;
375
+ }
376
+
377
+ export declare const StatePage: default_2.FC<StatePageProps>;
378
+
379
+ export declare interface StatePageData {
380
+ name: string;
381
+ slug: string;
382
+ abbreviation: string;
383
+ stats: EntityStats;
384
+ directory: DirectoryItem[];
385
+ recentByAgency: Record<string, RecentEvent[]>;
386
+ meta?: EntityMeta;
387
+ }
388
+
389
+ declare interface StatePageProps {
390
+ brand: BrandConfig;
391
+ data: StatePageData;
392
+ onAccountClick?: () => void;
393
+ onNotificationClick?: () => void;
394
+ }
395
+
396
+ export declare const StatGrid: default_2.FC<StatGridProps>;
397
+
398
+ declare interface StatGridProps {
399
+ stats: EntityStats;
400
+ columns?: 2 | 3 | 4;
401
+ }
402
+
403
+ declare interface Tab {
404
+ id: string;
405
+ label: string;
406
+ content: default_2.ReactNode;
407
+ disabled?: boolean;
408
+ }
409
+
410
+ export declare function Table<T>({ columns, data, keyExtractor, onRowClick, emptyMessage, striped, }: TableProps<T>): JSX_2.Element;
411
+
412
+ declare interface TableProps<T> {
413
+ columns: Column<T>[];
414
+ data: T[];
415
+ keyExtractor: (item: T) => string;
416
+ onRowClick?: (item: T) => void;
417
+ emptyMessage?: string;
418
+ striped?: boolean;
419
+ }
420
+
421
+ export declare const Tabs: default_2.FC<TabsProps>;
422
+
423
+ declare interface TabsProps {
424
+ tabs: Tab[];
425
+ activeTab: string;
426
+ onTabChange: (tabId: string) => void;
427
+ variant?: 'underline' | 'pills';
428
+ }
429
+
430
+ export declare const Tooltip: default_2.FC<TooltipProps>;
431
+
432
+ declare interface TooltipProps {
433
+ content: default_2.ReactNode;
434
+ children: default_2.ReactNode;
435
+ position?: 'top' | 'bottom' | 'left' | 'right';
436
+ delay?: number;
437
+ }
438
+
439
+ export declare function useTheme(brandConfig: BrandConfig): {
440
+ darkMode: boolean;
441
+ toggleDarkMode: () => void;
442
+ };
443
+
444
+ export { }