tangled
alpha
login
or
join now
timtinkers.online
/
lemoncalendar
0
fork
atom
this repo has no description
0
fork
atom
overview
issues
pulls
pipelines
Added icons
timtinkers.online
1 year ago
ba724bab
25e820a1
+154
-61
1 changed file
expand all
collapse all
unified
split
components
WeeklySchedule.tsx
+154
-61
components/WeeklySchedule.tsx
···
8
8
headerColor: string;
9
9
dateRangeColor: string;
10
10
dayColor: string;
11
11
-
eventBgColor: string;
11
11
+
eventBgColors: {
12
12
+
default: string;
13
13
+
twitch: string;
14
14
+
discord: string;
15
15
+
};
12
16
eventTextColor: string;
13
17
noEventColor: string;
14
18
backgroundImagePath: string; // Path to background image
15
15
-
eventIconPath?: string; // Path to event SVG icon (optional)
19
19
+
iconPaths: {
20
20
+
discord: string;
21
21
+
twitch: string;
22
22
+
};
16
23
}
17
24
18
25
// Default theme
···
21
28
headerColor: "#ffffff",
22
29
dateRangeColor: "#ffffff",
23
30
dayColor: "#ffffff",
24
24
-
eventBgColor: "#e6d195", //twitch: eebd37 discord: f3af52
31
31
+
eventBgColors: {
32
32
+
default: "#e6d195",
33
33
+
twitch: "#eebd37",
34
34
+
discord: "#f3af52",
35
35
+
},
25
36
eventTextColor: "#ffffff",
26
37
noEventColor: "#ffffff",
27
38
backgroundImagePath: "./static/background.png",
28
28
-
eventIconPath: "./static/discord-icon.svg",
39
39
+
iconPaths: {
40
40
+
discord: "./static/discord-icon.svg",
41
41
+
twitch: "./static/twitch-icon.svg",
42
42
+
},
29
43
};
30
44
31
45
// Theme collection - can be expanded as needed
···
36
50
headerColor: "#ffffff",
37
51
dateRangeColor: "#cccccc",
38
52
dayColor: "#ffffff",
39
39
-
eventBgColor: "#333333",
53
53
+
eventBgColors: {
54
54
+
default: "#333333",
55
55
+
twitch: "#333333",
56
56
+
discord: "#333333",
57
57
+
},
40
58
eventTextColor: "#ffffff",
41
59
noEventColor: "#777777",
42
60
backgroundImagePath: "./static/background.png",
43
43
-
eventIconPath: "./static/discord-icon.svg",
61
61
+
iconPaths: {
62
62
+
discord: "./static/discord-icon.svg",
63
63
+
twitch: "./static/twitch-icon.svg",
64
64
+
},
44
65
},
45
66
// Add more themes as needed
46
67
};
···
50
71
startDate: Date,
51
72
endDate: Date,
52
73
backgroundImageBase64?: string,
74
74
+
iconBase64Map?: Record<string, string>,
53
75
theme: Theme = defaultTheme,
54
76
) {
55
77
const days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
···
58
80
const displayHeight = displayWidth / aspectRatio;
59
81
60
82
// Calculate relative positions
61
61
-
const headerPosition = 0.10;
62
62
-
const dateRangePosition = 0.15;
63
63
-
const scheduleStartPosition = 0.21;
83
83
+
const headerPosition = 0.08;
84
84
+
const scheduleStartPosition = 0.212;
64
85
const scheduleHeight = 0.73;
65
86
66
87
// Format the date range
···
68
89
const endDateFormatted = format(endDate, "dd.MM.", []);
69
90
const dateRangeText = `${startDateFormatted} - ${endDateFormatted}`;
70
91
92
92
+
// Helper function to get event background color based on location
93
93
+
const getEventBgColor = (event: Event | undefined) => {
94
94
+
if (!event || !event.location) return theme.eventBgColors.default;
95
95
+
96
96
+
const location = event.location.toLowerCase();
97
97
+
if (location === "twitch") return theme.eventBgColors.twitch;
98
98
+
if (location === "discord") return theme.eventBgColors.discord;
99
99
+
100
100
+
return theme.eventBgColors.default;
101
101
+
};
102
102
+
103
103
+
// Helper function to get icon based on location
104
104
+
const getEventIcon = (event: Event | undefined) => {
105
105
+
if (!event || !event.location || !iconBase64Map) return null;
106
106
+
107
107
+
const location = event.location.toLowerCase();
108
108
+
if (location === "twitch" && iconBase64Map.twitch) {
109
109
+
return iconBase64Map.twitch;
110
110
+
}
111
111
+
if (location === "discord" && iconBase64Map.discord) {
112
112
+
return iconBase64Map.discord;
113
113
+
}
114
114
+
115
115
+
return null;
116
116
+
};
117
117
+
71
118
return (
72
119
<div
73
120
style={{
···
95
142
/>
96
143
)}
97
144
98
98
-
{/* Header Title */}
145
145
+
{/* Header */}
99
146
<div
147
147
+
className="header"
100
148
style={{
101
149
position: "absolute",
102
150
top: `${headerPosition * 100}%`,
103
103
-
width: "79%",
104
104
-
textAlign: "center",
105
105
-
fontFamily: theme.fontFamily,
106
106
-
fontSize: "24px",
107
107
-
fontWeight: "bold",
108
108
-
color: theme.headerColor,
151
151
+
width: "100%",
152
152
+
display: "flex",
153
153
+
flexDirection: "column",
154
154
+
alignItems: "center",
155
155
+
justifyContent: "center",
109
156
}}
110
157
>
111
111
-
Stream Schedule
112
112
-
</div>
158
158
+
{/* Title */}
159
159
+
<div
160
160
+
className="title"
161
161
+
style={{
162
162
+
fontFamily: theme.fontFamily,
163
163
+
fontSize: "32px",
164
164
+
fontWeight: "bold",
165
165
+
color: theme.headerColor,
166
166
+
justifyContent: "center",
167
167
+
width: "100%",
168
168
+
marginBottom: "8px",
169
169
+
}}
170
170
+
>
171
171
+
Stream Schedule
172
172
+
</div>
113
173
114
114
-
{/* Date Range */}
115
115
-
<div
116
116
-
style={{
117
117
-
position: "absolute",
118
118
-
top: `${dateRangePosition * 100}%`,
119
119
-
width: "79%",
120
120
-
textAlign: "center",
121
121
-
fontFamily: theme.fontFamily,
122
122
-
fontSize: "18px",
123
123
-
color: theme.dateRangeColor,
124
124
-
}}
125
125
-
>
126
126
-
{dateRangeText}
174
174
+
{/* Date Range */}
175
175
+
<div
176
176
+
className="week-range"
177
177
+
style={{
178
178
+
fontFamily: theme.fontFamily,
179
179
+
fontSize: "20px",
180
180
+
color: theme.dateRangeColor,
181
181
+
justifyContent: "center",
182
182
+
width: "100%",
183
183
+
}}
184
184
+
>
185
185
+
{dateRangeText}
186
186
+
</div>
127
187
</div>
128
188
129
189
{/* Weekly Schedule */}
130
190
<div
191
191
+
className="schedule"
131
192
style={{
132
193
position: "absolute",
133
194
top: `${scheduleStartPosition * 100}%`,
134
134
-
width: "79%",
195
195
+
width: "80%",
135
196
height: `${scheduleHeight * 100}%`,
136
197
display: "flex",
137
198
flexDirection: "column",
···
142
203
const event = events.find((e) =>
143
204
format(e.start, "eee", []) === day
144
205
);
206
206
+
const hasEvent = !!event;
207
207
+
const eventBgColor = getEventBgColor(event);
208
208
+
const eventIcon = getEventIcon(event);
209
209
+
145
210
return (
146
211
<div
147
212
key={index}
213
213
+
className="event-box"
148
214
style={{
149
215
display: "flex",
150
216
flexDirection: "row",
···
152
218
justifyContent: "space-between",
153
219
width: "100%",
154
220
height: `${100 / days.length - 2}%`,
155
155
-
backgroundColor: theme.eventBgColor,
221
221
+
backgroundColor: eventBgColor,
156
222
padding: "10px",
157
157
-
borderRadius: "10px",
223
223
+
borderRadius: "15px",
158
224
marginBottom: "8px",
225
225
+
fontSize: "1.3em",
159
226
fontFamily: theme.fontFamily,
227
227
+
position: "relative",
160
228
}}
161
229
>
230
230
+
{/* Location icon overlay */}
231
231
+
{eventIcon && (
232
232
+
<img
233
233
+
src={`data:image/svg+xml;base64,${eventIcon}`}
234
234
+
style={{
235
235
+
position: "absolute",
236
236
+
top: "-12px",
237
237
+
left: "-12px",
238
238
+
width: "30px",
239
239
+
height: "30px",
240
240
+
zIndex: 10,
241
241
+
}}
242
242
+
/>
243
243
+
)}
244
244
+
162
245
<div
246
246
+
className="weekday"
163
247
style={{
164
248
fontWeight: "bold",
165
249
marginRight: "12px",
166
166
-
textAlign: "left",
250
250
+
justifyContent: "flex-start",
167
251
flex: "1",
168
168
-
fontSize: "1.2em",
169
252
color: theme.dayColor,
170
253
}}
171
254
>
172
255
{day}
173
256
</div>
174
257
175
175
-
{event && (
176
176
-
<>
177
177
-
<div
178
178
-
style={{
179
179
-
display: "flex",
180
180
-
flexDirection: "column",
181
181
-
textAlign: "center",
182
182
-
flex: 2,
183
183
-
marginRight: "12px",
184
184
-
wordWrap: "break-word",
185
185
-
fontSize: "1.2em",
186
186
-
color: theme.eventTextColor,
187
187
-
}}
188
188
-
>
189
189
-
<div>{event.summary}</div>
190
190
-
</div>
191
191
-
</>
192
192
-
)}
258
258
+
<div
259
259
+
className="summary"
260
260
+
style={{
261
261
+
display: "flex",
262
262
+
flexDirection: "column",
263
263
+
justifyContent: "center",
264
264
+
flex: 2,
265
265
+
marginRight: "12px",
266
266
+
wordWrap: "break-word",
267
267
+
color: theme.eventTextColor,
268
268
+
}}
269
269
+
>
270
270
+
{hasEvent ? event.summary : "-"}
271
271
+
</div>
193
272
194
273
<div
274
274
+
className="time"
195
275
style={{
196
276
display: "flex",
197
197
-
textAlign: "right",
277
277
+
justifyContent: "flex-end",
198
278
flex: "1",
199
279
whiteSpace: "nowrap",
200
200
-
color: event
201
201
-
? theme.eventTextColor
202
202
-
: theme.noEventColor,
203
203
-
fontSize: "1.2em",
280
280
+
color: theme.eventTextColor,
204
281
}}
205
282
>
206
206
-
{event && format(event.start, "ha", [])}
207
207
-
{!event && "No event"}
283
283
+
{hasEvent ? format(event.start, "ha", []) : ""}
208
284
</div>
209
285
</div>
210
286
);
···
239
315
);
240
316
}
241
317
318
318
+
// Load icon images
319
319
+
const iconBase64Map: Record<string, string> = {};
320
320
+
try {
321
321
+
// Load Discord icon
322
322
+
const discordIconData = await Deno.readFile(theme.iconPaths.discord);
323
323
+
iconBase64Map.discord = encodeBase64(discordIconData);
324
324
+
325
325
+
// Load Twitch icon
326
326
+
const twitchIconData = await Deno.readFile(theme.iconPaths.twitch);
327
327
+
iconBase64Map.twitch = encodeBase64(twitchIconData);
328
328
+
} catch (error) {
329
329
+
console.error(
330
330
+
`Error loading icon images: ${(error as Error).message}`,
331
331
+
);
332
332
+
}
333
333
+
242
334
const svg = await satori(
243
335
WeeklySchedule(
244
336
events,
245
337
startDate,
246
338
endDate,
247
339
backgroundImageBase64,
340
340
+
iconBase64Map,
248
341
theme,
249
342
// deno-lint-ignore no-explicit-any
250
343
) as any,