@getmicdrop/venue-calendar 3.3.0 → 3.3.1
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 +661 -661
- package/dist/{VenueCalendar-BMSfRl2d.js → VenueCalendar-Xppig0q_.js} +13 -10
- package/dist/VenueCalendar-Xppig0q_.js.map +1 -0
- package/dist/{index-CoJaem3n.js → index-BjErG0CG.js} +2 -2
- package/dist/{index-CoJaem3n.js.map → index-BjErG0CG.js.map} +1 -1
- package/dist/types/index.d.ts +395 -395
- package/dist/venue-calendar.css +1 -1
- package/dist/venue-calendar.es.js +1 -1
- package/dist/venue-calendar.iife.js +4 -4
- package/dist/venue-calendar.iife.js.map +1 -1
- package/dist/venue-calendar.umd.js +4 -4
- package/dist/venue-calendar.umd.js.map +1 -1
- package/package.json +2 -1
- package/src/lib/api/client.ts +210 -210
- package/src/lib/api/events.ts +358 -358
- package/src/lib/api/index.ts +182 -182
- package/src/lib/api/orders.ts +390 -390
- package/src/lib/api/promo.ts +164 -164
- package/src/lib/api/transformers/event.ts +248 -248
- package/src/lib/api/transformers/index.ts +29 -29
- package/src/lib/api/transformers/order.ts +207 -207
- package/src/lib/api/transformers/venue.ts +118 -118
- package/src/lib/api/types.ts +289 -289
- package/src/lib/api/venues.ts +100 -100
- package/src/lib/theme.js +209 -209
- package/src/lib/utils/api.js +790 -0
- package/src/lib/utils/api.test.js +1284 -0
- package/src/lib/utils/constants.js +8 -0
- package/src/lib/utils/constants.test.js +39 -0
- package/src/lib/utils/datetime.js +266 -0
- package/src/lib/utils/datetime.test.js +340 -0
- package/src/lib/utils/event-transform.js +464 -0
- package/src/lib/utils/event-transform.test.js +413 -0
- package/src/lib/utils/logger.js +105 -0
- package/src/lib/utils/timezone.js +109 -0
- package/src/lib/utils/timezone.test.js +222 -0
- package/src/lib/utils/utils.js +806 -0
- package/src/lib/utils/utils.test.js +959 -0
- package/dist/VenueCalendar-BMSfRl2d.js.map +0 -1
package/src/lib/api/venues.ts
CHANGED
|
@@ -1,100 +1,100 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Venues API
|
|
3
|
-
*
|
|
4
|
-
* Functions for fetching venue data including
|
|
5
|
-
* service fees and tax configuration.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { logger } from '../utils/logger.js';
|
|
9
|
-
import { getPublicBaseUrl, getLegacyPublicUrl, simpleFetch } from './client.js';
|
|
10
|
-
import type { Venue } from './types.js';
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Get venue details (public, no auth required)
|
|
14
|
-
*
|
|
15
|
-
* Fetches venue information including service fees and taxes
|
|
16
|
-
* needed for checkout calculations.
|
|
17
|
-
*
|
|
18
|
-
* @param venueId - The venue ID
|
|
19
|
-
* @returns Venue details or null on error
|
|
20
|
-
*/
|
|
21
|
-
export async function getVenue(venueId: string | number): Promise<Venue | null> {
|
|
22
|
-
try {
|
|
23
|
-
if (!venueId) {
|
|
24
|
-
logger.warn('getVenue called without venueId');
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Uses /api/public/getVenue/:id (same as micdrop-frontend)
|
|
29
|
-
const response = await fetch(`${getLegacyPublicUrl()}/getVenue/${venueId}`);
|
|
30
|
-
|
|
31
|
-
if (!response.ok) {
|
|
32
|
-
logger.error(`Failed to fetch venue: ${response.status}`);
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return response.json();
|
|
37
|
-
} catch (error) {
|
|
38
|
-
logger.error('Error fetching venue:', error);
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Get venue service fee configuration
|
|
45
|
-
*
|
|
46
|
-
* Returns just the fee-related fields for checkout calculations.
|
|
47
|
-
*
|
|
48
|
-
* @param venueId - The venue ID
|
|
49
|
-
* @returns Fee configuration or null on error
|
|
50
|
-
*/
|
|
51
|
-
export async function getVenueFees(
|
|
52
|
-
venueId: string | number
|
|
53
|
-
): Promise<{
|
|
54
|
-
serviceFeePercentage: number;
|
|
55
|
-
serviceFeeCents: number;
|
|
56
|
-
taxPercentage: number;
|
|
57
|
-
} | null> {
|
|
58
|
-
const venue = await getVenue(venueId);
|
|
59
|
-
|
|
60
|
-
if (!venue) {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
serviceFeePercentage: venue.serviceFeePercentage ?? 0,
|
|
66
|
-
serviceFeeCents: venue.serviceFeeCents ?? 0,
|
|
67
|
-
taxPercentage: venue.taxPercentage ?? 0,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Get venue by slug
|
|
73
|
-
*
|
|
74
|
-
* Fetches venue using its URL-friendly slug.
|
|
75
|
-
*
|
|
76
|
-
* @param slug - The venue slug
|
|
77
|
-
* @returns Venue details or null on error
|
|
78
|
-
*/
|
|
79
|
-
export async function getVenueBySlug(slug: string): Promise<Venue | null> {
|
|
80
|
-
try {
|
|
81
|
-
if (!slug) {
|
|
82
|
-
logger.warn('getVenueBySlug called without slug');
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const encodedSlug = encodeURIComponent(slug);
|
|
87
|
-
// Uses /api/public/venue/:slug (same as micdrop-frontend)
|
|
88
|
-
const response = await fetch(`${getLegacyPublicUrl()}/venue/${encodedSlug}`);
|
|
89
|
-
|
|
90
|
-
if (!response.ok) {
|
|
91
|
-
logger.error(`Failed to fetch venue by slug: ${response.status}`);
|
|
92
|
-
return null;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return response.json();
|
|
96
|
-
} catch (error) {
|
|
97
|
-
logger.error('Error fetching venue by slug:', error);
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Venues API
|
|
3
|
+
*
|
|
4
|
+
* Functions for fetching venue data including
|
|
5
|
+
* service fees and tax configuration.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { logger } from '../utils/logger.js';
|
|
9
|
+
import { getPublicBaseUrl, getLegacyPublicUrl, simpleFetch } from './client.js';
|
|
10
|
+
import type { Venue } from './types.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get venue details (public, no auth required)
|
|
14
|
+
*
|
|
15
|
+
* Fetches venue information including service fees and taxes
|
|
16
|
+
* needed for checkout calculations.
|
|
17
|
+
*
|
|
18
|
+
* @param venueId - The venue ID
|
|
19
|
+
* @returns Venue details or null on error
|
|
20
|
+
*/
|
|
21
|
+
export async function getVenue(venueId: string | number): Promise<Venue | null> {
|
|
22
|
+
try {
|
|
23
|
+
if (!venueId) {
|
|
24
|
+
logger.warn('getVenue called without venueId');
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Uses /api/public/getVenue/:id (same as micdrop-frontend)
|
|
29
|
+
const response = await fetch(`${getLegacyPublicUrl()}/getVenue/${venueId}`);
|
|
30
|
+
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
logger.error(`Failed to fetch venue: ${response.status}`);
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return response.json();
|
|
37
|
+
} catch (error) {
|
|
38
|
+
logger.error('Error fetching venue:', error);
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get venue service fee configuration
|
|
45
|
+
*
|
|
46
|
+
* Returns just the fee-related fields for checkout calculations.
|
|
47
|
+
*
|
|
48
|
+
* @param venueId - The venue ID
|
|
49
|
+
* @returns Fee configuration or null on error
|
|
50
|
+
*/
|
|
51
|
+
export async function getVenueFees(
|
|
52
|
+
venueId: string | number
|
|
53
|
+
): Promise<{
|
|
54
|
+
serviceFeePercentage: number;
|
|
55
|
+
serviceFeeCents: number;
|
|
56
|
+
taxPercentage: number;
|
|
57
|
+
} | null> {
|
|
58
|
+
const venue = await getVenue(venueId);
|
|
59
|
+
|
|
60
|
+
if (!venue) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
serviceFeePercentage: venue.serviceFeePercentage ?? 0,
|
|
66
|
+
serviceFeeCents: venue.serviceFeeCents ?? 0,
|
|
67
|
+
taxPercentage: venue.taxPercentage ?? 0,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get venue by slug
|
|
73
|
+
*
|
|
74
|
+
* Fetches venue using its URL-friendly slug.
|
|
75
|
+
*
|
|
76
|
+
* @param slug - The venue slug
|
|
77
|
+
* @returns Venue details or null on error
|
|
78
|
+
*/
|
|
79
|
+
export async function getVenueBySlug(slug: string): Promise<Venue | null> {
|
|
80
|
+
try {
|
|
81
|
+
if (!slug) {
|
|
82
|
+
logger.warn('getVenueBySlug called without slug');
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const encodedSlug = encodeURIComponent(slug);
|
|
87
|
+
// Uses /api/public/venue/:slug (same as micdrop-frontend)
|
|
88
|
+
const response = await fetch(`${getLegacyPublicUrl()}/venue/${encodedSlug}`);
|
|
89
|
+
|
|
90
|
+
if (!response.ok) {
|
|
91
|
+
logger.error(`Failed to fetch venue by slug: ${response.status}`);
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return response.json();
|
|
96
|
+
} catch (error) {
|
|
97
|
+
logger.error('Error fetching venue by slug:', error);
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
package/src/lib/theme.js
CHANGED
|
@@ -1,209 +1,209 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Theme Configuration for Embeddable Calendar Widget
|
|
3
|
-
*
|
|
4
|
-
* This module provides comprehensive theming options for the calendar widget.
|
|
5
|
-
* All colors use HSL format for easy manipulation.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* 1. Import and call applyTheme() with your custom theme
|
|
9
|
-
* 2. Or set CSS custom properties directly on the widget container
|
|
10
|
-
*
|
|
11
|
-
* Example:
|
|
12
|
-
* ```js
|
|
13
|
-
* import { applyTheme, themes } from '@getmicdrop/venue-calendar/theme';
|
|
14
|
-
* applyTheme(themes.dark);
|
|
15
|
-
*
|
|
16
|
-
* // Or custom theme:
|
|
17
|
-
* applyTheme({
|
|
18
|
-
* brandPrimary: '270 76% 60%', // Purple
|
|
19
|
-
* textPrimary: '0 0% 100%',
|
|
20
|
-
* bgPrimary: '0 0% 10%',
|
|
21
|
-
* });
|
|
22
|
-
* ```
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
// Default light theme
|
|
26
|
-
export const lightTheme = {
|
|
27
|
-
// Brand colors
|
|
28
|
-
brandPrimary: '217 91% 60%', // #2563EB - Blue
|
|
29
|
-
|
|
30
|
-
// Text colors
|
|
31
|
-
textPrimary: '0 0% 0%', // Black
|
|
32
|
-
textSecondary: '0 0% 40%', // Dark Gray
|
|
33
|
-
textTertiary: '0 0% 60%', // Gray
|
|
34
|
-
|
|
35
|
-
// Background colors
|
|
36
|
-
bgPrimary: '0 0% 100%', // White
|
|
37
|
-
bgSecondary: '0 0% 98%', // Light Gray
|
|
38
|
-
bgQuaternary: '0 0% 96%', // Very Light Gray
|
|
39
|
-
|
|
40
|
-
// Border/Stroke colors
|
|
41
|
-
strokePrimary: '0 0% 80%', // Medium Gray
|
|
42
|
-
strokeSecondary: '0 0% 90%', // Light Gray
|
|
43
|
-
|
|
44
|
-
// Status colors
|
|
45
|
-
statusOnSale: '217 91% 60%', // Blue
|
|
46
|
-
statusSellingFast: '38 92% 50%', // Orange
|
|
47
|
-
statusSoldOut: '0 84% 60%', // Red
|
|
48
|
-
|
|
49
|
-
// Calendar specific
|
|
50
|
-
todayBg: '217 91% 97%', // Light blue
|
|
51
|
-
todayText: '217 91% 50%', // Blue
|
|
52
|
-
eventDotOnSale: '217 91% 60%',
|
|
53
|
-
eventDotSellingFast: '38 92% 50%',
|
|
54
|
-
eventDotSoldOut: '0 84% 60%',
|
|
55
|
-
|
|
56
|
-
// Interaction states
|
|
57
|
-
hoverBg: '0 0% 96%',
|
|
58
|
-
focusRing: '217 91% 60%',
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
// Dark theme
|
|
62
|
-
export const darkTheme = {
|
|
63
|
-
// Brand colors
|
|
64
|
-
brandPrimary: '217 91% 65%', // Lighter blue for dark mode
|
|
65
|
-
|
|
66
|
-
// Text colors
|
|
67
|
-
textPrimary: '0 0% 98%', // Near white
|
|
68
|
-
textSecondary: '0 0% 70%', // Light gray
|
|
69
|
-
textTertiary: '0 0% 50%', // Gray
|
|
70
|
-
|
|
71
|
-
// Background colors
|
|
72
|
-
bgPrimary: '0 0% 9%', // Very dark gray
|
|
73
|
-
bgSecondary: '0 0% 13%', // Dark gray
|
|
74
|
-
bgQuaternary: '0 0% 17%', // Slightly lighter
|
|
75
|
-
|
|
76
|
-
// Border/Stroke colors
|
|
77
|
-
strokePrimary: '0 0% 30%',
|
|
78
|
-
strokeSecondary: '0 0% 20%',
|
|
79
|
-
|
|
80
|
-
// Status colors
|
|
81
|
-
statusOnSale: '217 91% 65%',
|
|
82
|
-
statusSellingFast: '38 92% 55%',
|
|
83
|
-
statusSoldOut: '0 84% 65%',
|
|
84
|
-
|
|
85
|
-
// Calendar specific
|
|
86
|
-
todayBg: '217 50% 20%',
|
|
87
|
-
todayText: '217 91% 70%',
|
|
88
|
-
eventDotOnSale: '217 91% 65%',
|
|
89
|
-
eventDotSellingFast: '38 92% 55%',
|
|
90
|
-
eventDotSoldOut: '0 84% 65%',
|
|
91
|
-
|
|
92
|
-
// Interaction states
|
|
93
|
-
hoverBg: '0 0% 20%',
|
|
94
|
-
focusRing: '217 91% 65%',
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
// High contrast theme for accessibility
|
|
98
|
-
export const highContrastTheme = {
|
|
99
|
-
brandPrimary: '217 100% 50%',
|
|
100
|
-
textPrimary: '0 0% 0%',
|
|
101
|
-
textSecondary: '0 0% 20%',
|
|
102
|
-
textTertiary: '0 0% 30%',
|
|
103
|
-
bgPrimary: '0 0% 100%',
|
|
104
|
-
bgSecondary: '0 0% 95%',
|
|
105
|
-
bgQuaternary: '0 0% 90%',
|
|
106
|
-
strokePrimary: '0 0% 0%',
|
|
107
|
-
strokeSecondary: '0 0% 30%',
|
|
108
|
-
statusOnSale: '217 100% 40%',
|
|
109
|
-
statusSellingFast: '30 100% 40%',
|
|
110
|
-
statusSoldOut: '0 100% 40%',
|
|
111
|
-
todayBg: '217 100% 90%',
|
|
112
|
-
todayText: '217 100% 30%',
|
|
113
|
-
eventDotOnSale: '217 100% 40%',
|
|
114
|
-
eventDotSellingFast: '30 100% 40%',
|
|
115
|
-
eventDotSoldOut: '0 100% 40%',
|
|
116
|
-
hoverBg: '217 100% 95%',
|
|
117
|
-
focusRing: '217 100% 40%',
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
// Preset themes collection
|
|
121
|
-
export const themes = {
|
|
122
|
-
light: lightTheme,
|
|
123
|
-
dark: darkTheme,
|
|
124
|
-
highContrast: highContrastTheme,
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Apply a theme to the calendar widget
|
|
129
|
-
* @param {Object} theme - Theme object with HSL color values
|
|
130
|
-
* @param {HTMLElement} container - Optional container element (defaults to :root)
|
|
131
|
-
*/
|
|
132
|
-
export function applyTheme(theme, container = document.documentElement) {
|
|
133
|
-
const cssVarMap = {
|
|
134
|
-
brandPrimary: '--Brand-Primary',
|
|
135
|
-
textPrimary: '--Text-Primary',
|
|
136
|
-
textSecondary: '--Text-Secondary',
|
|
137
|
-
textTertiary: '--Text-Tartiary', // Note: keeping original typo for compatibility
|
|
138
|
-
bgPrimary: '--BG-Primary',
|
|
139
|
-
bgSecondary: '--BG-Secondary',
|
|
140
|
-
bgQuaternary: '--BG-Quaternary',
|
|
141
|
-
strokePrimary: '--Stroke-Primary',
|
|
142
|
-
strokeSecondary: '--Stroke-Secondary',
|
|
143
|
-
statusOnSale: '--Status-OnSale',
|
|
144
|
-
statusSellingFast: '--Status-SellingFast',
|
|
145
|
-
statusSoldOut: '--Status-SoldOut',
|
|
146
|
-
todayBg: '--Today-BG',
|
|
147
|
-
todayText: '--Today-Text',
|
|
148
|
-
eventDotOnSale: '--EventDot-OnSale',
|
|
149
|
-
eventDotSellingFast: '--EventDot-SellingFast',
|
|
150
|
-
eventDotSoldOut: '--EventDot-SoldOut',
|
|
151
|
-
hoverBg: '--Hover-BG',
|
|
152
|
-
focusRing: '--Focus-Ring',
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
Object.entries(theme).forEach(([key, value]) => {
|
|
156
|
-
const cssVar = cssVarMap[key];
|
|
157
|
-
if (cssVar) {
|
|
158
|
-
container.style.setProperty(cssVar, value);
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Generate CSS string for embedding
|
|
165
|
-
* @param {Object} theme - Theme object
|
|
166
|
-
* @returns {string} CSS string
|
|
167
|
-
*/
|
|
168
|
-
export function generateThemeCSS(theme) {
|
|
169
|
-
const cssVarMap = {
|
|
170
|
-
brandPrimary: '--Brand-Primary',
|
|
171
|
-
textPrimary: '--Text-Primary',
|
|
172
|
-
textSecondary: '--Text-Secondary',
|
|
173
|
-
textTertiary: '--Text-Tartiary',
|
|
174
|
-
bgPrimary: '--BG-Primary',
|
|
175
|
-
bgSecondary: '--BG-Secondary',
|
|
176
|
-
bgQuaternary: '--BG-Quaternary',
|
|
177
|
-
strokePrimary: '--Stroke-Primary',
|
|
178
|
-
strokeSecondary: '--Stroke-Secondary',
|
|
179
|
-
statusOnSale: '--Status-OnSale',
|
|
180
|
-
statusSellingFast: '--Status-SellingFast',
|
|
181
|
-
statusSoldOut: '--Status-SoldOut',
|
|
182
|
-
todayBg: '--Today-BG',
|
|
183
|
-
todayText: '--Today-Text',
|
|
184
|
-
eventDotOnSale: '--EventDot-OnSale',
|
|
185
|
-
eventDotSellingFast: '--EventDot-SellingFast',
|
|
186
|
-
eventDotSoldOut: '--EventDot-SoldOut',
|
|
187
|
-
hoverBg: '--Hover-BG',
|
|
188
|
-
focusRing: '--Focus-Ring',
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
const vars = Object.entries(theme)
|
|
192
|
-
.map(([key, value]) => {
|
|
193
|
-
const cssVar = cssVarMap[key];
|
|
194
|
-
return cssVar ? ` ${cssVar}: ${value};` : null;
|
|
195
|
-
})
|
|
196
|
-
.filter(Boolean)
|
|
197
|
-
.join('\n');
|
|
198
|
-
|
|
199
|
-
return `:root {\n${vars}\n}`;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
export default {
|
|
203
|
-
themes,
|
|
204
|
-
lightTheme,
|
|
205
|
-
darkTheme,
|
|
206
|
-
highContrastTheme,
|
|
207
|
-
applyTheme,
|
|
208
|
-
generateThemeCSS,
|
|
209
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* Theme Configuration for Embeddable Calendar Widget
|
|
3
|
+
*
|
|
4
|
+
* This module provides comprehensive theming options for the calendar widget.
|
|
5
|
+
* All colors use HSL format for easy manipulation.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* 1. Import and call applyTheme() with your custom theme
|
|
9
|
+
* 2. Or set CSS custom properties directly on the widget container
|
|
10
|
+
*
|
|
11
|
+
* Example:
|
|
12
|
+
* ```js
|
|
13
|
+
* import { applyTheme, themes } from '@getmicdrop/venue-calendar/theme';
|
|
14
|
+
* applyTheme(themes.dark);
|
|
15
|
+
*
|
|
16
|
+
* // Or custom theme:
|
|
17
|
+
* applyTheme({
|
|
18
|
+
* brandPrimary: '270 76% 60%', // Purple
|
|
19
|
+
* textPrimary: '0 0% 100%',
|
|
20
|
+
* bgPrimary: '0 0% 10%',
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// Default light theme
|
|
26
|
+
export const lightTheme = {
|
|
27
|
+
// Brand colors
|
|
28
|
+
brandPrimary: '217 91% 60%', // #2563EB - Blue
|
|
29
|
+
|
|
30
|
+
// Text colors
|
|
31
|
+
textPrimary: '0 0% 0%', // Black
|
|
32
|
+
textSecondary: '0 0% 40%', // Dark Gray
|
|
33
|
+
textTertiary: '0 0% 60%', // Gray
|
|
34
|
+
|
|
35
|
+
// Background colors
|
|
36
|
+
bgPrimary: '0 0% 100%', // White
|
|
37
|
+
bgSecondary: '0 0% 98%', // Light Gray
|
|
38
|
+
bgQuaternary: '0 0% 96%', // Very Light Gray
|
|
39
|
+
|
|
40
|
+
// Border/Stroke colors
|
|
41
|
+
strokePrimary: '0 0% 80%', // Medium Gray
|
|
42
|
+
strokeSecondary: '0 0% 90%', // Light Gray
|
|
43
|
+
|
|
44
|
+
// Status colors
|
|
45
|
+
statusOnSale: '217 91% 60%', // Blue
|
|
46
|
+
statusSellingFast: '38 92% 50%', // Orange
|
|
47
|
+
statusSoldOut: '0 84% 60%', // Red
|
|
48
|
+
|
|
49
|
+
// Calendar specific
|
|
50
|
+
todayBg: '217 91% 97%', // Light blue
|
|
51
|
+
todayText: '217 91% 50%', // Blue
|
|
52
|
+
eventDotOnSale: '217 91% 60%',
|
|
53
|
+
eventDotSellingFast: '38 92% 50%',
|
|
54
|
+
eventDotSoldOut: '0 84% 60%',
|
|
55
|
+
|
|
56
|
+
// Interaction states
|
|
57
|
+
hoverBg: '0 0% 96%',
|
|
58
|
+
focusRing: '217 91% 60%',
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// Dark theme
|
|
62
|
+
export const darkTheme = {
|
|
63
|
+
// Brand colors
|
|
64
|
+
brandPrimary: '217 91% 65%', // Lighter blue for dark mode
|
|
65
|
+
|
|
66
|
+
// Text colors
|
|
67
|
+
textPrimary: '0 0% 98%', // Near white
|
|
68
|
+
textSecondary: '0 0% 70%', // Light gray
|
|
69
|
+
textTertiary: '0 0% 50%', // Gray
|
|
70
|
+
|
|
71
|
+
// Background colors
|
|
72
|
+
bgPrimary: '0 0% 9%', // Very dark gray
|
|
73
|
+
bgSecondary: '0 0% 13%', // Dark gray
|
|
74
|
+
bgQuaternary: '0 0% 17%', // Slightly lighter
|
|
75
|
+
|
|
76
|
+
// Border/Stroke colors
|
|
77
|
+
strokePrimary: '0 0% 30%',
|
|
78
|
+
strokeSecondary: '0 0% 20%',
|
|
79
|
+
|
|
80
|
+
// Status colors
|
|
81
|
+
statusOnSale: '217 91% 65%',
|
|
82
|
+
statusSellingFast: '38 92% 55%',
|
|
83
|
+
statusSoldOut: '0 84% 65%',
|
|
84
|
+
|
|
85
|
+
// Calendar specific
|
|
86
|
+
todayBg: '217 50% 20%',
|
|
87
|
+
todayText: '217 91% 70%',
|
|
88
|
+
eventDotOnSale: '217 91% 65%',
|
|
89
|
+
eventDotSellingFast: '38 92% 55%',
|
|
90
|
+
eventDotSoldOut: '0 84% 65%',
|
|
91
|
+
|
|
92
|
+
// Interaction states
|
|
93
|
+
hoverBg: '0 0% 20%',
|
|
94
|
+
focusRing: '217 91% 65%',
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// High contrast theme for accessibility
|
|
98
|
+
export const highContrastTheme = {
|
|
99
|
+
brandPrimary: '217 100% 50%',
|
|
100
|
+
textPrimary: '0 0% 0%',
|
|
101
|
+
textSecondary: '0 0% 20%',
|
|
102
|
+
textTertiary: '0 0% 30%',
|
|
103
|
+
bgPrimary: '0 0% 100%',
|
|
104
|
+
bgSecondary: '0 0% 95%',
|
|
105
|
+
bgQuaternary: '0 0% 90%',
|
|
106
|
+
strokePrimary: '0 0% 0%',
|
|
107
|
+
strokeSecondary: '0 0% 30%',
|
|
108
|
+
statusOnSale: '217 100% 40%',
|
|
109
|
+
statusSellingFast: '30 100% 40%',
|
|
110
|
+
statusSoldOut: '0 100% 40%',
|
|
111
|
+
todayBg: '217 100% 90%',
|
|
112
|
+
todayText: '217 100% 30%',
|
|
113
|
+
eventDotOnSale: '217 100% 40%',
|
|
114
|
+
eventDotSellingFast: '30 100% 40%',
|
|
115
|
+
eventDotSoldOut: '0 100% 40%',
|
|
116
|
+
hoverBg: '217 100% 95%',
|
|
117
|
+
focusRing: '217 100% 40%',
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// Preset themes collection
|
|
121
|
+
export const themes = {
|
|
122
|
+
light: lightTheme,
|
|
123
|
+
dark: darkTheme,
|
|
124
|
+
highContrast: highContrastTheme,
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Apply a theme to the calendar widget
|
|
129
|
+
* @param {Object} theme - Theme object with HSL color values
|
|
130
|
+
* @param {HTMLElement} container - Optional container element (defaults to :root)
|
|
131
|
+
*/
|
|
132
|
+
export function applyTheme(theme, container = document.documentElement) {
|
|
133
|
+
const cssVarMap = {
|
|
134
|
+
brandPrimary: '--Brand-Primary',
|
|
135
|
+
textPrimary: '--Text-Primary',
|
|
136
|
+
textSecondary: '--Text-Secondary',
|
|
137
|
+
textTertiary: '--Text-Tartiary', // Note: keeping original typo for compatibility
|
|
138
|
+
bgPrimary: '--BG-Primary',
|
|
139
|
+
bgSecondary: '--BG-Secondary',
|
|
140
|
+
bgQuaternary: '--BG-Quaternary',
|
|
141
|
+
strokePrimary: '--Stroke-Primary',
|
|
142
|
+
strokeSecondary: '--Stroke-Secondary',
|
|
143
|
+
statusOnSale: '--Status-OnSale',
|
|
144
|
+
statusSellingFast: '--Status-SellingFast',
|
|
145
|
+
statusSoldOut: '--Status-SoldOut',
|
|
146
|
+
todayBg: '--Today-BG',
|
|
147
|
+
todayText: '--Today-Text',
|
|
148
|
+
eventDotOnSale: '--EventDot-OnSale',
|
|
149
|
+
eventDotSellingFast: '--EventDot-SellingFast',
|
|
150
|
+
eventDotSoldOut: '--EventDot-SoldOut',
|
|
151
|
+
hoverBg: '--Hover-BG',
|
|
152
|
+
focusRing: '--Focus-Ring',
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
Object.entries(theme).forEach(([key, value]) => {
|
|
156
|
+
const cssVar = cssVarMap[key];
|
|
157
|
+
if (cssVar) {
|
|
158
|
+
container.style.setProperty(cssVar, value);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Generate CSS string for embedding
|
|
165
|
+
* @param {Object} theme - Theme object
|
|
166
|
+
* @returns {string} CSS string
|
|
167
|
+
*/
|
|
168
|
+
export function generateThemeCSS(theme) {
|
|
169
|
+
const cssVarMap = {
|
|
170
|
+
brandPrimary: '--Brand-Primary',
|
|
171
|
+
textPrimary: '--Text-Primary',
|
|
172
|
+
textSecondary: '--Text-Secondary',
|
|
173
|
+
textTertiary: '--Text-Tartiary',
|
|
174
|
+
bgPrimary: '--BG-Primary',
|
|
175
|
+
bgSecondary: '--BG-Secondary',
|
|
176
|
+
bgQuaternary: '--BG-Quaternary',
|
|
177
|
+
strokePrimary: '--Stroke-Primary',
|
|
178
|
+
strokeSecondary: '--Stroke-Secondary',
|
|
179
|
+
statusOnSale: '--Status-OnSale',
|
|
180
|
+
statusSellingFast: '--Status-SellingFast',
|
|
181
|
+
statusSoldOut: '--Status-SoldOut',
|
|
182
|
+
todayBg: '--Today-BG',
|
|
183
|
+
todayText: '--Today-Text',
|
|
184
|
+
eventDotOnSale: '--EventDot-OnSale',
|
|
185
|
+
eventDotSellingFast: '--EventDot-SellingFast',
|
|
186
|
+
eventDotSoldOut: '--EventDot-SoldOut',
|
|
187
|
+
hoverBg: '--Hover-BG',
|
|
188
|
+
focusRing: '--Focus-Ring',
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const vars = Object.entries(theme)
|
|
192
|
+
.map(([key, value]) => {
|
|
193
|
+
const cssVar = cssVarMap[key];
|
|
194
|
+
return cssVar ? ` ${cssVar}: ${value};` : null;
|
|
195
|
+
})
|
|
196
|
+
.filter(Boolean)
|
|
197
|
+
.join('\n');
|
|
198
|
+
|
|
199
|
+
return `:root {\n${vars}\n}`;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export default {
|
|
203
|
+
themes,
|
|
204
|
+
lightTheme,
|
|
205
|
+
darkTheme,
|
|
206
|
+
highContrastTheme,
|
|
207
|
+
applyTheme,
|
|
208
|
+
generateThemeCSS,
|
|
209
|
+
};
|