Skip to content

Commit 5a7ae53

Browse files
committed
chore: add story for theme manager to render all overlays
1 parent 9d73cd8 commit 5a7ae53

File tree

3 files changed

+160
-92
lines changed

3 files changed

+160
-92
lines changed

src/frontend/App.tsx

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,10 @@ import {
88
useRunningState,
99
SessionProvider,
1010
} from '@irdashies/context';
11-
import { Input } from './components/Input';
12-
import { Standings } from './components/Standings/Standings';
1311
import { Settings } from './components/Settings/Settings';
14-
import { Relative } from './components/Standings/Relative';
15-
import { Weather } from './components/Weather';
16-
import { TrackMap } from './components/TrackMap/TrackMap';
17-
import { FasterCarsFromBehind } from './components/FasterCarsFromBehind/FasterCarsFromBehind';
1812
import { EditMode } from './components/EditMode/EditMode';
1913
import { ThemeManager } from './components/ThemeManager/ThemeManager';
20-
21-
// TODO: type this better, right now the config comes from settings
22-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
23-
const WIDGET_MAP: Record<string, (config: any) => React.JSX.Element> = {
24-
standings: Standings,
25-
input: Input,
26-
relative: Relative,
27-
settings: Settings,
28-
map: TrackMap,
29-
weather: Weather,
30-
fastercarsfrombehind: FasterCarsFromBehind,
31-
};
14+
import { WIDGET_MAP } from './WidgetIndex';
3215

3316
const AppRoutes = () => {
3417
const { currentDashboard } = useDashboard();

src/frontend/WidgetIndex.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Standings } from './components/Standings/Standings';
2+
import { Input } from './components/Input';
3+
import { Relative } from './components/Standings/Relative';
4+
import { TrackMap } from './components/TrackMap/TrackMap';
5+
import { Weather } from './components/Weather';
6+
import { FasterCarsFromBehind } from './components/FasterCarsFromBehind/FasterCarsFromBehind';
7+
8+
// TODO: type this better, right now the config comes from settings
9+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
10+
export const WIDGET_MAP: Record<string, (config: any) => React.JSX.Element> = {
11+
standings: Standings,
12+
input: Input,
13+
relative: Relative,
14+
map: TrackMap,
15+
weather: Weather,
16+
fastercarsfrombehind: FasterCarsFromBehind,
17+
};

src/frontend/components/ThemeManager/ThemeManager.stories.tsx

Lines changed: 142 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,116 @@ import { MemoryRouter, Route, Routes } from 'react-router-dom';
55
import { DashboardProvider } from '@irdashies/context';
66
import type { DashboardBridge, DashboardLayout } from '@irdashies/types';
77
import { useState } from 'react';
8+
import { WIDGET_MAP } from '../../WidgetIndex';
9+
import { defaultDashboard } from '../../../app/storage/defaultDashboard';
810

911
const meta: Meta<typeof ThemeManager> = {
1012
component: ThemeManager,
11-
decorators: [TelemetryDecorator()],
13+
decorators: [TelemetryDecorator('/test-data/1747384033336')],
1214
};
1315

1416
export default meta;
1517

18+
// Helper function to create a mock dashboard bridge
19+
const createMockBridge = (
20+
fontSize: 'xs' | 'sm' | 'lg' | 'xl',
21+
setFontSize: (size: 'xs' | 'sm' | 'lg' | 'xl') => void,
22+
widgets: DashboardLayout['widgets'] = []
23+
): DashboardBridge => ({
24+
reloadDashboard: () => {
25+
// noop
26+
},
27+
saveDashboard: (dashboard: DashboardLayout) => {
28+
// Update the font size in the dashboard
29+
setFontSize(dashboard.generalSettings?.fontSize || 'sm');
30+
},
31+
dashboardUpdated: (callback) => {
32+
// Initialize with current font size
33+
callback({
34+
widgets,
35+
generalSettings: { fontSize },
36+
});
37+
return () => {
38+
// noop
39+
};
40+
},
41+
onEditModeToggled: (callback) => {
42+
callback(false);
43+
return () => {
44+
// noop
45+
};
46+
},
47+
toggleLockOverlays: () => Promise.resolve(true),
48+
getAppVersion: () => Promise.resolve('0.0.7+mock'),
49+
resetDashboard: () =>
50+
Promise.resolve({
51+
widgets: [],
52+
generalSettings: { fontSize },
53+
}),
54+
});
55+
56+
// Helper function to create font size buttons
57+
const createFontSizeButtons = (
58+
fontSize: 'xs' | 'sm' | 'lg' | 'xl',
59+
mockBridge: DashboardBridge
60+
) => {
61+
const getButtonClass = (size: 'xs' | 'sm' | 'lg' | 'xl') => {
62+
const baseClass = 'px-2 py-1 rounded transition-colors';
63+
return size === fontSize
64+
? `${baseClass} bg-blue-700 text-white`
65+
: `${baseClass} bg-blue-500 text-white hover:bg-blue-600`;
66+
};
67+
68+
return (
69+
<div className="flex gap-2">
70+
<button
71+
className={getButtonClass('xs')}
72+
onClick={() =>
73+
mockBridge.saveDashboard({
74+
widgets: [],
75+
generalSettings: { fontSize: 'xs' },
76+
})
77+
}
78+
>
79+
Extra Small
80+
</button>
81+
<button
82+
className={getButtonClass('sm')}
83+
onClick={() =>
84+
mockBridge.saveDashboard({
85+
widgets: [],
86+
generalSettings: { fontSize: 'sm' },
87+
})
88+
}
89+
>
90+
Small
91+
</button>
92+
<button
93+
className={getButtonClass('lg')}
94+
onClick={() =>
95+
mockBridge.saveDashboard({
96+
widgets: [],
97+
generalSettings: { fontSize: 'lg' },
98+
})
99+
}
100+
>
101+
Large
102+
</button>
103+
<button
104+
className={getButtonClass('xl')}
105+
onClick={() =>
106+
mockBridge.saveDashboard({
107+
widgets: [],
108+
generalSettings: { fontSize: 'xl' },
109+
})
110+
}
111+
>
112+
Extra Large
113+
</button>
114+
</div>
115+
);
116+
};
117+
16118
export const Primary = {
17119
render: () => {
18120
return (
@@ -41,85 +143,14 @@ export const Primary = {
41143
export const WithFontSizeControls = {
42144
render: () => {
43145
const [fontSize, setFontSize] = useState<'xs' | 'sm' | 'lg' | 'xl'>('sm');
44-
45-
const mockBridge: DashboardBridge = {
46-
reloadDashboard: () => {
47-
// noop
48-
},
49-
saveDashboard: (dashboard: DashboardLayout) => {
50-
// Update the font size in the dashboard
51-
setFontSize(dashboard.generalSettings?.fontSize || 'sm');
52-
},
53-
dashboardUpdated: (callback) => {
54-
// Initialize with current font size
55-
callback({
56-
widgets: [],
57-
generalSettings: { fontSize }
58-
});
59-
return () => {
60-
// noop
61-
};
62-
},
63-
onEditModeToggled: (callback) => {
64-
callback(false);
65-
return () => {
66-
// noop
67-
};
68-
},
69-
toggleLockOverlays: () => Promise.resolve(true),
70-
getAppVersion: () => Promise.resolve('0.0.7+mock'),
71-
};
72-
73-
const getButtonClass = (size: 'xs' | 'sm' | 'lg' | 'xl') => {
74-
const baseClass = "px-2 py-1 rounded transition-colors";
75-
return size === fontSize
76-
? `${baseClass} bg-blue-700 text-white`
77-
: `${baseClass} bg-blue-500 text-white hover:bg-blue-600`;
78-
};
146+
const mockBridge = createMockBridge(fontSize, setFontSize);
79147

80148
return (
81149
<DashboardProvider bridge={mockBridge}>
82150
<MemoryRouter initialEntries={['/']}>
83151
<ThemeManager>
84152
<div className="p-4 space-y-4">
85-
<div className="flex gap-2">
86-
<button
87-
className={getButtonClass('xs')}
88-
onClick={() => mockBridge.saveDashboard({
89-
widgets: [],
90-
generalSettings: { fontSize: 'xs' }
91-
})}
92-
>
93-
Extra Small
94-
</button>
95-
<button
96-
className={getButtonClass('sm')}
97-
onClick={() => mockBridge.saveDashboard({
98-
widgets: [],
99-
generalSettings: { fontSize: 'sm' }
100-
})}
101-
>
102-
Small
103-
</button>
104-
<button
105-
className={getButtonClass('lg')}
106-
onClick={() => mockBridge.saveDashboard({
107-
widgets: [],
108-
generalSettings: { fontSize: 'lg' }
109-
})}
110-
>
111-
Large
112-
</button>
113-
<button
114-
className={getButtonClass('xl')}
115-
onClick={() => mockBridge.saveDashboard({
116-
widgets: [],
117-
generalSettings: { fontSize: 'xl' }
118-
})}
119-
>
120-
Extra Large
121-
</button>
122-
</div>
153+
{createFontSizeButtons(fontSize, mockBridge)}
123154
<div className="space-y-2">
124155
<div className="text-xs">This is extra small text</div>
125156
<div className="text-sm">This is small text</div>
@@ -134,3 +165,40 @@ export const WithFontSizeControls = {
134165
);
135166
},
136167
};
168+
169+
export const WithAllAvailableWidgets = {
170+
render: () => {
171+
const [fontSize, setFontSize] = useState<'xs' | 'sm' | 'lg' | 'xl'>('sm');
172+
const mockBridge = createMockBridge(fontSize, setFontSize, defaultDashboard.widgets);
173+
174+
return (
175+
<DashboardProvider bridge={mockBridge}>
176+
<MemoryRouter initialEntries={['/']}>
177+
<ThemeManager>
178+
<div className="p-4 space-y-4">
179+
{createFontSizeButtons(fontSize, mockBridge)}
180+
</div>
181+
<hr className="my-4" />
182+
<Routes>
183+
<Route
184+
path="/"
185+
element={
186+
<div>
187+
{Object.entries(WIDGET_MAP).map(([key, Widget]) => (
188+
<div key={key}>
189+
<h2 className="text-md font-bold m-2 uppercase">{key}</h2>
190+
<div className="min-h-24 pb-12">
191+
<Widget />
192+
</div>
193+
</div>
194+
))}
195+
</div>
196+
}
197+
/>
198+
</Routes>
199+
</ThemeManager>
200+
</MemoryRouter>
201+
</DashboardProvider>
202+
);
203+
},
204+
};

0 commit comments

Comments
 (0)