feat: optional provider icon on calendar event blocks

Adds a toggle in Calendar settings to show the provider icon
(Google/Apple/Outlook/Synology) in the bottom-right corner of
calendar event blocks. The recurring icon is grouped alongside
when both are visible.

v1.64.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
mARTin 2026-03-24 10:56:49 +01:00
parent 18c2fc1a92
commit e00834e0bb
6 changed files with 67 additions and 11 deletions

View File

@ -1,6 +1,6 @@
{
"name": "my-weekly-todo-list",
"version": "1.63.5",
"version": "1.64.0",
"description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view",
"main": "index.js",
"scripts": {

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<rect x="2" y="2" width="20" height="20" rx="4" fill="#fff" stroke="#FF3B30" stroke-width="1.5"/>
<rect x="2" y="2" width="20" height="7" rx="4" fill="#FF3B30"/>
<text x="12" y="18" font-family="Arial,sans-serif" font-size="9" font-weight="bold" fill="#333" text-anchor="middle">31</text>
</svg>

After

Width:  |  Height:  |  Size: 385 B

View File

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<rect x="2" y="2" width="20" height="20" rx="2" fill="#fff" stroke="#4285F4" stroke-width="1.5"/>
<rect x="2" y="2" width="20" height="6" rx="2" fill="#4285F4"/>
<circle cx="8" cy="14" r="1.5" fill="#EA4335"/>
<circle cx="12" cy="14" r="1.5" fill="#FBBC04"/>
<circle cx="16" cy="14" r="1.5" fill="#34A853"/>
<rect x="7" y="4" width="2" height="4" rx="1" fill="#fff"/>
<rect x="15" y="4" width="2" height="4" rx="1" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 533 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<rect x="2" y="2" width="20" height="20" rx="2" fill="#fff" stroke="#0078D4" stroke-width="1.5"/>
<rect x="2" y="2" width="20" height="6" rx="2" fill="#0078D4"/>
<text x="12" y="18" font-family="Arial,sans-serif" font-size="10" font-weight="bold" fill="#0078D4" text-anchor="middle">O</text>
</svg>

After

Width:  |  Height:  |  Size: 388 B

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<rect x="2" y="2" width="20" height="20" rx="2" fill="#fff" stroke="#F5A623" stroke-width="1.5"/>
<rect x="2" y="2" width="20" height="6" rx="2" fill="#F5A623"/>
<text x="12" y="18" font-family="Arial,sans-serif" font-size="10" font-weight="bold" fill="#F5A623" text-anchor="middle">S</text>
</svg>

After

Width:  |  Height:  |  Size: 388 B

View File

@ -326,6 +326,7 @@ const translations: Record<string, any> = {
localization: "Localization",
allDayEvents: "ALL-DAY EVENTS",
syncCalendar: "Sync Calendar",
showProviderIcon: "Show provider icon on events",
toggleDarkMode: "Toggle Dark Mode",
signOut: "Sign Out",
startHour: "Start of Day",
@ -543,6 +544,7 @@ const translations: Record<string, any> = {
localization: "Lokalisierung",
allDayEvents: "GANZTÄGIGE EREIGNISSE",
syncCalendar: "Kalender synchronisieren",
showProviderIcon: "Anbieter-Icon auf Terminen anzeigen",
toggleDarkMode: "Dunkelmodus umschalten",
signOut: "Abmelden",
startHour: "Tagesbeginn",
@ -759,6 +761,7 @@ const translations: Record<string, any> = {
localization: "Localisation",
allDayEvents: "ÉVÉNEMENTS JOURNÉE ENTIÈRE",
syncCalendar: "Synchroniser le calendrier",
showProviderIcon: "Afficher l'icône du fournisseur sur les événements",
toggleDarkMode: "Basculer le mode sombre",
signOut: "Se déconnecter",
startHour: "Début de journée",
@ -975,6 +978,7 @@ const translations: Record<string, any> = {
localization: "Localización",
allDayEvents: "EVENTOS DE TODO EL DÍA",
syncCalendar: "Sincronizar calendario",
showProviderIcon: "Mostrar icono del proveedor en eventos",
toggleDarkMode: "Alternar modo oscuro",
signOut: "Cerrar sesión",
startHour: "Inicio del día",
@ -1191,6 +1195,7 @@ const translations: Record<string, any> = {
localization: "Localizzazione",
allDayEvents: "EVENTI GIORNATA INTERA",
syncCalendar: "Sincronizza calendario",
showProviderIcon: "Mostra icona del provider sugli eventi",
toggleDarkMode: "Attiva/disattiva modalità scura",
signOut: "Esci",
startHour: "Inizio giornata",
@ -1955,6 +1960,7 @@ export default function WeeklyView() {
weatherLat: null,
weatherLon: null,
weatherLocation: "",
showCalendarProviderIcon: false,
});
const [motivationalQuote, setMotivationalQuote] = useState("");
const [showSummary, setShowSummary] = useState(false);
@ -7636,16 +7642,32 @@ export default function WeeklyView() {
>
{event.title}
</div>
{event.isRecurring && (
<Repeat
size={12}
style={{
position: "absolute",
bottom: 3,
right: 5,
opacity: 0.5,
}}
/>
{(event.isRecurring || profile.showCalendarProviderIcon) && (
<div style={{
position: "absolute",
bottom: 2,
right: 4,
display: "flex",
alignItems: "center",
gap: 3,
opacity: 0.5,
}}>
{event.isRecurring && <Repeat size={11} />}
{profile.showCalendarProviderIcon && (
<img
src={
event.source === "google" ? "/icons/google-calendar.svg"
: event.source === "apple" ? "/icons/apple-calendar.svg"
: event.source === "outlook" ? "/icons/outlook-calendar.svg"
: event.source === "synology" ? "/icons/synology-calendar.svg"
: undefined
}
alt={event.source}
style={{ width: 13, height: 13 }}
onError={(e) => { (e.target as HTMLImageElement).style.display = 'none'; }}
/>
)}
</div>
)}
</div>
);
@ -12267,6 +12289,16 @@ function SettingsSidebar({
{t.connectedCalendars}
</h3>
<div style={{ display: "flex", alignItems: "center", gap: "8px", marginBottom: "12px" }}>
<input type="checkbox" id="showCalendarProviderIcon"
checked={profile.showCalendarProviderIcon || false}
onChange={(e) => saveField("showCalendarProviderIcon", e.target.checked)}
style={{ width: "16px", height: "16px" }} />
<label htmlFor="showCalendarProviderIcon" style={{ fontSize: "0.9rem", fontWeight: 600 }}>
{t.showProviderIcon}
</label>
</div>
{connMsg && (
<div
style={{