EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
themes.ts
Go to the documentation of this file.
1/**
2 * EverydayPOS Theme System
3 * Defines color palettes and styling for different themes
4 */
5
6export interface Theme {
7 id: string;
8 name: string;
9 description: string;
10 colors: {
11 bg: string;
12 surface: string;
13 surface2: string;
14 text: string;
15 muted: string;
16 border: string;
17 brand: string;
18 brand2: string;
19 warn: string;
20 danger: string;
21 success?: string;
22 info?: string;
23 };
24 shadows: {
25 shadow: string;
26 shadowSm: string;
27 };
28 radius: {
29 radius: string;
30 radiusSm: string;
31 };
32 focus: string;
33}
34
35export const themes: Record<string, Theme> = {
36 fieldpine: {
37 id: 'fieldpine',
38 name: 'Fieldpine',
39 description: 'Classic teal and mint - the original EverydayPOS look',
40 colors: {
41 bg: '#f8fafc',
42 surface: '#ffffff',
43 surface2: '#f1f5f9',
44 text: '#0f172a',
45 muted: '#64748b',
46 border: '#e2e8f0',
47 brand: '#00483d',
48 brand2: '#00946b',
49 warn: '#f59e0b',
50 danger: '#ef4444',
51 success: '#10b981',
52 info: '#3b82f6',
53 },
54 shadows: {
55 shadow: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
56 shadowSm: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
57 },
58 radius: {
59 radius: '0.75rem',
60 radiusSm: '0.5rem',
61 },
62 focus: '0 0 0 3px rgba(16, 185, 129, 0.2)',
63 },
64
65 midnight: {
66 id: 'midnight',
67 name: 'Midnight',
68 description: 'Deep blues and purples for a sophisticated dark aesthetic',
69 colors: {
70 bg: '#0f172a',
71 surface: '#1e293b',
72 surface2: '#283548',
73 text: '#f1f5f9',
74 muted: '#94a3b8',
75 border: '#334155',
76 brand: '#8b5cf6',
77 brand2: '#a78bfa',
78 warn: '#fbbf24',
79 danger: '#ef4444',
80 success: '#10b981',
81 info: '#3b82f6',
82 },
83 shadows: {
84 shadow: '0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 10px 10px -5px rgba(0, 0, 0, 0.3)',
85 shadowSm: '0 4px 6px -1px rgba(0, 0, 0, 0.3), 0 2px 4px -1px rgba(0, 0, 0, 0.2)',
86 },
87 radius: {
88 radius: '0.75rem',
89 radiusSm: '0.5rem',
90 },
91 focus: '0 0 0 3px rgba(139, 92, 246, 0.4)',
92 },
93
94 sunset: {
95 id: 'sunset',
96 name: 'Miami Sunset',
97 description: 'Vibrant coral, magenta and gold - tropical energy',
98 colors: {
99 bg: '#fff5f7',
100 surface: '#ffffff',
101 surface2: '#ffe4ec',
102 text: '#4a1c2e',
103 muted: '#a8546b',
104 border: '#ffc9db',
105 brand: '#ff6b9d',
106 brand2: '#ff8fab',
107 warn: '#ffb347',
108 danger: '#ff4757',
109 success: '#1dd1a1',
110 info: '#5f27cd',
111 },
112 shadows: {
113 shadow: '0 18px 48px rgba(255,107,157,0.25)',
114 shadowSm: '0 8px 20px rgba(255,107,157,0.15)',
115 },
116 radius: {
117 radius: '16px',
118 radiusSm: '10px',
119 },
120 focus: '0 0 0 4px rgba(255,107,157,0.3)',
121 },
122
123 forest: {
124 id: 'forest',
125 name: 'Emerald Forest',
126 description: 'Vibrant emerald and lime - fresh and energizing',
127 colors: {
128 bg: '#ecfdf5',
129 surface: '#ffffff',
130 surface2: '#d1fae5',
131 text: '#064e3b',
132 muted: '#047857',
133 border: '#a7f3d0',
134 brand: '#10b981',
135 brand2: '#34d399',
136 warn: '#f59e0b',
137 danger: '#ef4444',
138 success: '#22c55e',
139 info: '#3b82f6',
140 },
141 shadows: {
142 shadow: '0 18px 48px rgba(16,185,129,0.25)',
143 shadowSm: '0 8px 20px rgba(16,185,129,0.15)',
144 },
145 radius: {
146 radius: '14px',
147 radiusSm: '9px',
148 },
149 focus: '0 0 0 4px rgba(16,185,129,0.3)',
150 },
151
152 ocean: {
153 id: 'ocean',
154 name: 'Electric Ocean',
155 description: 'Bright turquoise and aqua - refreshing and modern',
156 colors: {
157 bg: '#e0f7ff',
158 surface: '#ffffff',
159 surface2: '#b3e5fc',
160 text: '#01579b',
161 muted: '#0277bd',
162 border: '#81d4fa',
163 brand: '#00bcd4',
164 brand2: '#00e5ff',
165 warn: '#ffc107',
166 danger: '#e91e63',
167 success: '#00e676',
168 info: '#2196f3',
169 },
170 shadows: {
171 shadow: '0 18px 48px rgba(0,188,212,0.3)',
172 shadowSm: '0 8px 20px rgba(0,188,212,0.2)',
173 },
174 radius: {
175 radius: '16px',
176 radiusSm: '10px',
177 },
178 focus: '0 0 0 4px rgba(0,188,212,0.35)',
179 },
180
181 rose: {
182 id: 'rose',
183 name: 'Hot Pink',
184 description: 'Bold fuchsia and magenta - confident and energetic',
185 colors: {
186 bg: '#fff0f9',
187 surface: '#ffffff',
188 surface2: '#fce4ec',
189 text: '#880e4f',
190 muted: '#ad1457',
191 border: '#f8bbd0',
192 brand: '#e91e63',
193 brand2: '#ff4081',
194 warn: '#ff9800',
195 danger: '#f44336',
196 success: '#4caf50',
197 info: '#9c27b0',
198 },
199 shadows: {
200 shadow: '0 18px 48px rgba(233,30,99,0.25)',
201 shadowSm: '0 8px 20px rgba(233,30,99,0.15)',
202 },
203 radius: {
204 radius: '16px',
205 radiusSm: '10px',
206 },
207 focus: '0 0 0 4px rgba(233,30,99,0.3)',
208 },
209
210 retro: {
211 id: 'retro',
212 name: 'Retro Wave',
213 description: '80s inspired with electric purple, hot pink and cyan',
214 colors: {
215 bg: '#fff5ff',
216 surface: '#ffffff',
217 surface2: '#f3e5f5',
218 text: '#4a148c',
219 muted: '#7b1fa2',
220 border: '#e1bee7',
221 brand: '#9c27b0',
222 brand2: '#ba68c8',
223 warn: '#ff6f00',
224 danger: '#d50000',
225 success: '#00e676',
226 info: '#00b0ff',
227 },
228 shadows: {
229 shadow: '0 18px 48px rgba(156,39,176,0.25)',
230 shadowSm: '0 8px 20px rgba(156,39,176,0.15)',
231 },
232 radius: {
233 radius: '12px',
234 radiusSm: '8px',
235 },
236 focus: '0 0 0 4px rgba(156,39,176,0.3)',
237 },
238
239 cosmic: {
240 id: 'cosmic',
241 name: 'Cosmic Purple',
242 description: 'Vivid violet and electric purple - otherworldly',
243 colors: {
244 bg: '#f3e5f5',
245 surface: '#ffffff',
246 surface2: '#e1bee7',
247 text: '#4a148c',
248 muted: '#6a1b9a',
249 border: '#ce93d8',
250 brand: '#8e24aa',
251 brand2: '#ab47bc',
252 warn: '#ff6f00',
253 danger: '#c62828',
254 success: '#00c853',
255 info: '#2979ff',
256 },
257 shadows: {
258 shadow: '0 18px 48px rgba(142,36,170,0.3)',
259 shadowSm: '0 8px 20px rgba(142,36,170,0.2)',
260 },
261 radius: {
262 radius: '14px',
263 radiusSm: '9px',
264 },
265 focus: '0 0 0 4px rgba(142,36,170,0.35)',
266 },
267
268 sunshine: {
269 id: 'sunshine',
270 name: 'Sunshine',
271 description: 'Bright yellow and orange - cheerful and optimistic',
272 colors: {
273 bg: '#fffde7',
274 surface: '#ffffff',
275 surface2: '#fff9c4',
276 text: '#f57f17',
277 muted: '#f9a825',
278 border: '#fff59d',
279 brand: '#ffc107',
280 brand2: '#ffeb3b',
281 warn: '#ff9800',
282 danger: '#f44336',
283 success: '#8bc34a',
284 info: '#03a9f4',
285 },
286 shadows: {
287 shadow: '0 18px 48px rgba(255,193,7,0.3)',
288 shadowSm: '0 8px 20px rgba(255,193,7,0.2)',
289 },
290 radius: {
291 radius: '14px',
292 radiusSm: '9px',
293 },
294 focus: '0 0 0 4px rgba(255,193,7,0.3)',
295 },
296
297 neon: {
298 id: 'neon',
299 name: 'Neon Nights',
300 description: 'Vibrant cyans and magentas for a bold, modern look',
301 colors: {
302 bg: '#18181b',
303 surface: '#27272a',
304 surface2: '#3f3f46',
305 text: '#fafafa',
306 muted: '#a1a1aa',
307 border: '#52525b',
308 brand: '#06b6d4',
309 brand2: '#22d3ee',
310 warn: '#fbbf24',
311 danger: '#f43f5e',
312 success: '#22c55e',
313 info: '#a78bfa',
314 },
315 shadows: {
316 shadow: '0 18px 48px rgba(6,182,212,0.4)',
317 shadowSm: '0 8px 20px rgba(6,182,212,0.3)',
318 },
319 radius: {
320 radius: '8px',
321 radiusSm: '6px',
322 },
323 focus: '0 0 0 4px rgba(6,182,212,0.4)',
324 },
325
326 web3: {
327 id: 'web3',
328 name: 'Web3',
329 description: 'Futuristic gradients and neon accents for the decentralized era',
330 colors: {
331 bg: '#0a0b0d',
332 surface: '#13151a',
333 surface2: '#1c1f26',
334 text: '#e8e9ed',
335 muted: '#9ca3af',
336 border: '#2d3139',
337 brand: '#7c3aed',
338 brand2: '#a78bfa',
339 warn: '#fbbf24',
340 danger: '#f87171',
341 success: '#34d399',
342 info: '#60a5fa',
343 },
344 shadows: {
345 shadow: '0 18px 48px rgba(124,58,237,0.5), 0 0 80px rgba(124,58,237,0.15)',
346 shadowSm: '0 8px 20px rgba(124,58,237,0.3), 0 0 40px rgba(124,58,237,0.1)',
347 },
348 radius: {
349 radius: '10px',
350 radiusSm: '7px',
351 },
352 focus: '0 0 0 4px rgba(124,58,237,0.4), 0 0 20px rgba(124,58,237,0.2)',
353 },
354
355 cartridge: {
356 id: 'cartridge',
357 name: 'Cartridge World',
358 description: 'Bold orange and red - powered by Cartridge World',
359 colors: {
360 bg: '#fff8f0',
361 surface: '#ffffff',
362 surface2: '#ffe8d6',
363 text: '#1a1a1a',
364 muted: '#666666',
365 border: '#ffc299',
366 brand: '#ff6600',
367 brand2: '#ff8533',
368 warn: '#ffa500',
369 danger: '#cc0000',
370 success: '#00a650',
371 info: '#0066cc',
372 },
373 shadows: {
374 shadow: '0 18px 48px rgba(255,102,0,0.25)',
375 shadowSm: '0 8px 20px rgba(255,102,0,0.15)',
376 },
377 radius: {
378 radius: '12px',
379 radiusSm: '8px',
380 },
381 focus: '0 0 0 4px rgba(255,102,0,0.3)',
382 },
383
384 monochrome: {
385 id: 'monochrome',
386 name: 'Monochrome',
387 description: 'Pure black and white for maximum contrast and focus',
388 colors: {
389 bg: '#ffffff',
390 surface: '#ffffff',
391 surface2: '#f5f5f5',
392 text: '#000000',
393 muted: '#666666',
394 border: '#e0e0e0',
395 brand: '#000000',
396 brand2: '#333333',
397 warn: '#666666',
398 danger: '#000000',
399 success: '#000000',
400 info: '#333333',
401 },
402 shadows: {
403 shadow: '0 18px 48px rgba(0,0,0,0.15)',
404 shadowSm: '0 8px 20px rgba(0,0,0,0.1)',
405 },
406 radius: {
407 radius: '4px',
408 radiusSm: '2px',
409 },
410 focus: '0 0 0 3px rgba(0,0,0,0.2)',
411 },
412};
413
414export const defaultTheme = 'fieldpine';
415
416const CUSTOM_THEMES_KEY = 'everydaypos_custom_themes';
417
418// Load custom themes from localStorage
419export function loadCustomThemes(): Record<string, Theme> {
420 if (typeof window === 'undefined') return {};
421
422 try {
423 const stored = localStorage.getItem(CUSTOM_THEMES_KEY);
424 if (stored) {
425 return JSON.parse(stored);
426 }
427 } catch (error) {
428 console.error('Error loading custom themes:', error);
429 }
430 return {};
431}
432
433// Save custom theme to localStorage
434export function saveCustomTheme(theme: Theme): void {
435 if (typeof window === 'undefined') return;
436
437 try {
438 const customThemes = loadCustomThemes();
439 customThemes[theme.id] = theme;
440 localStorage.setItem(CUSTOM_THEMES_KEY, JSON.stringify(customThemes));
441 } catch (error) {
442 console.error('Error saving custom theme:', error);
443 }
444}
445
446// Delete custom theme from localStorage
447export function deleteCustomTheme(themeId: string): void {
448 if (typeof window === 'undefined') return;
449
450 try {
451 const customThemes = loadCustomThemes();
452 delete customThemes[themeId];
453 localStorage.setItem(CUSTOM_THEMES_KEY, JSON.stringify(customThemes));
454 } catch (error) {
455 console.error('Error deleting custom theme:', error);
456 }
457}
458
459// Get all themes (built-in + custom)
460export function getAllThemes(): Record<string, Theme> {
461 return { ...themes, ...loadCustomThemes() };
462}
463
464export function getTheme(themeId: string): Theme {
465 const allThemes = getAllThemes();
466 return allThemes[themeId] || themes[defaultTheme];
467}
468
469export function getThemeList(): { id: string; name: string; description: string; isCustom?: boolean }[] {
470 const allThemes = getAllThemes();
471 return Object.values(allThemes).map(theme => ({
472 id: theme.id,
473 name: theme.name,
474 description: theme.description,
475 isCustom: !themes[theme.id],
476 }));
477}