Feature: Added agenda view for calendar, calendar improvements (#2216)
* Feature: Added agenda view for calendar, calendar improvements * Fix duplicate event keys * Additional hover on title, not date * Show date once in list * Rename monthly view for consistency * Remove unneeded key props * CSS cleanup, dont slice title to arbitrary 42 chars which can break column layouts * Simplify agenda components * Fix show date once in list --------- Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
This commit is contained in:
parent
792f768a7f
commit
6898faa3de
11 changed files with 219 additions and 68 deletions
|
@ -3,6 +3,8 @@ title: Calendar
|
||||||
description: Calendar widget
|
description: Calendar widget
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Monthly view
|
||||||
|
|
||||||
<img alt="calendar" src="https://user-images.githubusercontent.com/5442891/271131282-6767a3ea-573e-4005-aeb9-6e14ee01e845.png">
|
<img alt="calendar" src="https://user-images.githubusercontent.com/5442891/271131282-6767a3ea-573e-4005-aeb9-6e14ee01e845.png">
|
||||||
|
|
||||||
This widget shows monthly calendar, with optional integrations to show events from supported widgets.
|
This widget shows monthly calendar, with optional integrations to show events from supported widgets.
|
||||||
|
@ -11,6 +13,8 @@ This widget shows monthly calendar, with optional integrations to show events fr
|
||||||
widget:
|
widget:
|
||||||
type: calendar
|
type: calendar
|
||||||
firstDayInWeek: sunday # optional - defaults to monday
|
firstDayInWeek: sunday # optional - defaults to monday
|
||||||
|
view: monthly # optional - possible values monthly, agenda
|
||||||
|
maxEvents: 10 # optional - defaults to 10
|
||||||
integrations: # optional
|
integrations: # optional
|
||||||
- type: sonarr # active widget type that is currently enabled on homepage - possible values: radarr, sonarr, lidarr, readarr
|
- type: sonarr # active widget type that is currently enabled on homepage - possible values: radarr, sonarr, lidarr, readarr
|
||||||
service_group: Media # group name where widget exists
|
service_group: Media # group name where widget exists
|
||||||
|
@ -20,6 +24,20 @@ widget:
|
||||||
unmonitored: true # optional - defaults to false, used with *arr stack
|
unmonitored: true # optional - defaults to false, used with *arr stack
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Agenda
|
||||||
|
|
||||||
|
This view shows only list of events from configured integrations
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
widget:
|
||||||
|
type: calendar
|
||||||
|
view: agenda
|
||||||
|
maxEvents: 10 # optional - defaults to 10
|
||||||
|
integrations: # same as in Monthly view example
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integrations
|
||||||
|
|
||||||
Currently integrated widgets are [sonarr](sonarr.md), [radarr](radarr.md), [lidarr](lidarr.md) and [readarr](readarr.md).
|
Currently integrated widgets are [sonarr](sonarr.md), [radarr](radarr.md), [lidarr](lidarr.md) and [readarr](readarr.md).
|
||||||
|
|
||||||
Supported colors can be found on [color palette](../../configs/settings.md#color-palette).
|
Supported colors can be found on [color palette](../../configs/settings.md#color-palette).
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { ColorProvider } from "utils/contexts/color";
|
||||||
import { ThemeProvider } from "utils/contexts/theme";
|
import { ThemeProvider } from "utils/contexts/theme";
|
||||||
import { SettingsProvider } from "utils/contexts/settings";
|
import { SettingsProvider } from "utils/contexts/settings";
|
||||||
import { TabProvider } from "utils/contexts/tab";
|
import { TabProvider } from "utils/contexts/tab";
|
||||||
import { EventProvider, ShowDateProvider } from "utils/contexts/calendar";
|
import { EventProvider } from "utils/contexts/calendar";
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }) {
|
function MyApp({ Component, pageProps }) {
|
||||||
return (
|
return (
|
||||||
|
@ -33,9 +33,7 @@ function MyApp({ Component, pageProps }) {
|
||||||
<SettingsProvider>
|
<SettingsProvider>
|
||||||
<TabProvider>
|
<TabProvider>
|
||||||
<EventProvider>
|
<EventProvider>
|
||||||
<ShowDateProvider>
|
<Component {...pageProps} />
|
||||||
<Component {...pageProps} />
|
|
||||||
</ShowDateProvider>
|
|
||||||
</EventProvider>
|
</EventProvider>
|
||||||
</TabProvider>
|
</TabProvider>
|
||||||
</SettingsProvider>
|
</SettingsProvider>
|
||||||
|
|
|
@ -364,6 +364,8 @@ export function cleanServiceGroups(groups) {
|
||||||
refreshInterval,
|
refreshInterval,
|
||||||
integrations, // calendar widget
|
integrations, // calendar widget
|
||||||
firstDayInWeek,
|
firstDayInWeek,
|
||||||
|
view,
|
||||||
|
maxEvents,
|
||||||
} = cleanedService.widget;
|
} = cleanedService.widget;
|
||||||
|
|
||||||
let fieldsList = fields;
|
let fieldsList = fields;
|
||||||
|
@ -450,6 +452,8 @@ export function cleanServiceGroups(groups) {
|
||||||
if (type === "calendar") {
|
if (type === "calendar") {
|
||||||
if (integrations) cleanedService.widget.integrations = integrations;
|
if (integrations) cleanedService.widget.integrations = integrations;
|
||||||
if (firstDayInWeek) cleanedService.widget.firstDayInWeek = firstDayInWeek;
|
if (firstDayInWeek) cleanedService.widget.firstDayInWeek = firstDayInWeek;
|
||||||
|
if (view) cleanedService.widget.view = view;
|
||||||
|
if (maxEvents) cleanedService.widget.maxEvents = maxEvents;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import { createContext, useState, useMemo } from "react";
|
import { createContext, useState, useMemo } from "react";
|
||||||
|
|
||||||
export const EventContext = createContext();
|
export const EventContext = createContext();
|
||||||
export const ShowDateContext = createContext();
|
|
||||||
|
|
||||||
export function EventProvider({ initialEvent, children }) {
|
export function EventProvider({ initialEvent, children }) {
|
||||||
const [events, setEvents] = useState({});
|
const [events, setEvents] = useState({});
|
||||||
|
@ -14,15 +13,3 @@ export function EventProvider({ initialEvent, children }) {
|
||||||
|
|
||||||
return <EventContext.Provider value={value}>{children}</EventContext.Provider>;
|
return <EventContext.Provider value={value}>{children}</EventContext.Provider>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ShowDateProvider({ initialDate, children }) {
|
|
||||||
const [showDate, setShowDate] = useState(null);
|
|
||||||
|
|
||||||
if (initialDate) {
|
|
||||||
setShowDate(initialDate);
|
|
||||||
}
|
|
||||||
|
|
||||||
const value = useMemo(() => ({ showDate, setShowDate }), [showDate]);
|
|
||||||
|
|
||||||
return <ShowDateContext.Provider value={value}>{children}</ShowDateContext.Provider>;
|
|
||||||
}
|
|
||||||
|
|
101
src/widgets/calendar/agenda.jsx
Normal file
101
src/widgets/calendar/agenda.jsx
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
import { useContext, useState } from "react";
|
||||||
|
import { DateTime } from "luxon";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import { useTranslation } from "next-i18next";
|
||||||
|
import { IoMdCheckmarkCircleOutline } from "react-icons/io";
|
||||||
|
|
||||||
|
import { EventContext } from "../../utils/contexts/calendar";
|
||||||
|
|
||||||
|
export function Event({ event, colorVariants, showDate = false }) {
|
||||||
|
const [hover, setHover] = useState(false);
|
||||||
|
const { i18n } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex flex-row text-theme-700 dark:text-theme-200 items-center text-xs text-left h-5 rounded-md bg-theme-200/50 dark:bg-theme-900/20 mt-1"
|
||||||
|
onMouseEnter={() => setHover(!hover)}
|
||||||
|
onMouseLeave={() => setHover(!hover)}
|
||||||
|
>
|
||||||
|
<span className="ml-2 w-10">
|
||||||
|
<span>
|
||||||
|
{showDate &&
|
||||||
|
event.date.setLocale(i18n.language).startOf("day").toLocaleString({ month: "short", day: "numeric" })}
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<span className="ml-2 h-2 w-2">
|
||||||
|
<span className={classNames("block w-2 h-2 rounded", colorVariants[event.color] ?? "gray")} />
|
||||||
|
</span>
|
||||||
|
<div className="ml-2 h-5 text-left relative truncate" style={{ width: "70%" }}>
|
||||||
|
<div className="absolute mt-0.5 text-xs">{hover && event.additional ? event.additional : event.title}</div>
|
||||||
|
</div>
|
||||||
|
{event.isCompleted && (
|
||||||
|
<span className="text-xs mr-1 ml-auto z-10">
|
||||||
|
<IoMdCheckmarkCircleOutline />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Agenda({ service, colorVariants, showDate }) {
|
||||||
|
const { widget } = service;
|
||||||
|
const { events } = useContext(EventContext);
|
||||||
|
const { i18n } = useTranslation();
|
||||||
|
|
||||||
|
if (!showDate) {
|
||||||
|
return <div className=" text-center" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventsArray = Object.keys(events)
|
||||||
|
.filter(
|
||||||
|
(eventKey) => showDate.startOf("day").toUnixInteger() <= events[eventKey].date?.startOf("day").toUnixInteger(),
|
||||||
|
)
|
||||||
|
.map((eventKey) => events[eventKey])
|
||||||
|
.sort((a, b) => a.date - b.date)
|
||||||
|
.slice(0, widget?.maxEvents ?? 10);
|
||||||
|
|
||||||
|
if (!eventsArray.length) {
|
||||||
|
return (
|
||||||
|
<div className="text-center">
|
||||||
|
<div className="p-2 ">
|
||||||
|
<div
|
||||||
|
className={classNames("flex flex-col pt-1 pb-1", !eventsArray.length && !events.length && "animate-pulse")}
|
||||||
|
>
|
||||||
|
<Event
|
||||||
|
key="no-event"
|
||||||
|
event={{
|
||||||
|
title: `No events for today!`,
|
||||||
|
date: DateTime.now(),
|
||||||
|
color: "gray",
|
||||||
|
}}
|
||||||
|
colorVariants={colorVariants}
|
||||||
|
i18n={i18n}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const days = Array.from(new Set(eventsArray.map((e) => e.date.startOf("day").ts)));
|
||||||
|
const eventsByDay = days.map((d) => eventsArray.filter((e) => e.date.startOf("day").ts === d));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="p-2">
|
||||||
|
<div className={classNames("flex flex-col pt-1 pb-1", !eventsArray.length && !events.length && "animate-pulse")}>
|
||||||
|
{eventsByDay.map((eventsDay, i) => (
|
||||||
|
<div key={days[i]}>
|
||||||
|
{eventsDay.map((event, j) => (
|
||||||
|
<Event
|
||||||
|
key={`event${event.title}-${event.date}`}
|
||||||
|
event={event}
|
||||||
|
colorVariants={colorVariants}
|
||||||
|
showDate={j === 0}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,15 +1,51 @@
|
||||||
import { useContext, useMemo } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
|
import { DateTime } from "luxon";
|
||||||
|
import { useTranslation } from "next-i18next";
|
||||||
|
|
||||||
import { ShowDateContext } from "../../utils/contexts/calendar";
|
import Monthly from "./monthly";
|
||||||
|
import Agenda from "./agenda";
|
||||||
import MonthlyView from "./monthly-view";
|
|
||||||
|
|
||||||
import Container from "components/services/widget/container";
|
import Container from "components/services/widget/container";
|
||||||
|
|
||||||
|
const colorVariants = {
|
||||||
|
// https://tailwindcss.com/docs/content-configuration#dynamic-class-names
|
||||||
|
amber: "bg-amber-500",
|
||||||
|
blue: "bg-blue-500",
|
||||||
|
cyan: "bg-cyan-500",
|
||||||
|
emerald: "bg-emerald-500",
|
||||||
|
fuchsia: "bg-fuchsia-500",
|
||||||
|
gray: "bg-gray-500",
|
||||||
|
green: "bg-green-500",
|
||||||
|
indigo: "bg-indigo-500",
|
||||||
|
lime: "bg-lime-500",
|
||||||
|
neutral: "bg-neutral-500",
|
||||||
|
orange: "bg-orange-500",
|
||||||
|
pink: "bg-pink-500",
|
||||||
|
purple: "bg-purple-500",
|
||||||
|
red: "bg-red-500",
|
||||||
|
rose: "bg-rose-500",
|
||||||
|
sky: "bg-sky-500",
|
||||||
|
slate: "bg-slate-500",
|
||||||
|
stone: "bg-stone-500",
|
||||||
|
teal: "bg-teal-500",
|
||||||
|
violet: "bg-violet-500",
|
||||||
|
white: "bg-white-500",
|
||||||
|
yellow: "bg-yellow-500",
|
||||||
|
zinc: "bg-zinc-500",
|
||||||
|
};
|
||||||
|
|
||||||
export default function Component({ service }) {
|
export default function Component({ service }) {
|
||||||
const { widget } = service;
|
const { widget } = service;
|
||||||
const { showDate } = useContext(ShowDateContext);
|
const { i18n } = useTranslation();
|
||||||
|
const [showDate, setShowDate] = useState(null);
|
||||||
|
const currentDate = DateTime.now().setLocale(i18n.language).startOf("day");
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!showDate) {
|
||||||
|
setShowDate(currentDate);
|
||||||
|
}
|
||||||
|
}, [showDate, currentDate]);
|
||||||
|
|
||||||
// params for API fetch
|
// params for API fetch
|
||||||
const params = useMemo(() => {
|
const params = useMemo(() => {
|
||||||
|
@ -27,10 +63,12 @@ export default function Component({ service }) {
|
||||||
// Load active integrations
|
// Load active integrations
|
||||||
const integrations = useMemo(
|
const integrations = useMemo(
|
||||||
() =>
|
() =>
|
||||||
widget.integrations?.map((integration) => ({
|
widget.integrations
|
||||||
service: dynamic(() => import(`./integrations/${integration?.type}`)),
|
?.filter((integration) => integration?.type)
|
||||||
widget: integration,
|
.map((integration) => ({
|
||||||
})) ?? [],
|
service: dynamic(() => import(`./integrations/${integration.type}`)),
|
||||||
|
widget: integration,
|
||||||
|
})) ?? [],
|
||||||
[widget.integrations],
|
[widget.integrations],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -52,7 +90,24 @@ export default function Component({ service }) {
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<MonthlyView service={service} className="flex" />
|
{(!widget?.view || widget?.view === "monthly") && (
|
||||||
|
<Monthly
|
||||||
|
service={service}
|
||||||
|
colorVariants={colorVariants}
|
||||||
|
showDate={showDate}
|
||||||
|
setShowDate={setShowDate}
|
||||||
|
className="flex"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{widget?.view === "agenda" && (
|
||||||
|
<Agenda
|
||||||
|
service={service}
|
||||||
|
colorVariants={colorVariants}
|
||||||
|
showDate={showDate}
|
||||||
|
setShowDate={setShowDate}
|
||||||
|
className="flex"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
|
|
@ -27,6 +27,8 @@ export default function Integration({ config, params }) {
|
||||||
title,
|
title,
|
||||||
date: DateTime.fromISO(event.releaseDate),
|
date: DateTime.fromISO(event.releaseDate),
|
||||||
color: config?.color ?? "green",
|
color: config?.color ?? "green",
|
||||||
|
isCompleted: event.grabbed,
|
||||||
|
additional: "",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -29,16 +29,22 @@ export default function Integration({ config, params }) {
|
||||||
title: cinemaTitle,
|
title: cinemaTitle,
|
||||||
date: DateTime.fromISO(event.inCinemas),
|
date: DateTime.fromISO(event.inCinemas),
|
||||||
color: config?.color ?? "amber",
|
color: config?.color ?? "amber",
|
||||||
|
isCompleted: event.isAvailable,
|
||||||
|
additional: "",
|
||||||
};
|
};
|
||||||
eventsToAdd[physicalTitle] = {
|
eventsToAdd[physicalTitle] = {
|
||||||
title: physicalTitle,
|
title: physicalTitle,
|
||||||
date: DateTime.fromISO(event.physicalRelease),
|
date: DateTime.fromISO(event.physicalRelease),
|
||||||
color: config?.color ?? "cyan",
|
color: config?.color ?? "cyan",
|
||||||
|
isCompleted: event.isAvailable,
|
||||||
|
additional: "",
|
||||||
};
|
};
|
||||||
eventsToAdd[digitalTitle] = {
|
eventsToAdd[digitalTitle] = {
|
||||||
title: digitalTitle,
|
title: digitalTitle,
|
||||||
date: DateTime.fromISO(event.digitalRelease),
|
date: DateTime.fromISO(event.digitalRelease),
|
||||||
color: config?.color ?? "emerald",
|
color: config?.color ?? "emerald",
|
||||||
|
isCompleted: event.isAvailable,
|
||||||
|
additional: "",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,8 @@ export default function Integration({ config, params }) {
|
||||||
title,
|
title,
|
||||||
date: DateTime.fromISO(event.releaseDate),
|
date: DateTime.fromISO(event.releaseDate),
|
||||||
color: config?.color ?? "rose",
|
color: config?.color ?? "rose",
|
||||||
|
isCompleted: event.grabbed,
|
||||||
|
additional: "",
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -26,9 +26,11 @@ export default function Integration({ config, params }) {
|
||||||
const title = `${event.series.title ?? event.title} - S${event.seasonNumber}E${event.episodeNumber}`;
|
const title = `${event.series.title ?? event.title} - S${event.seasonNumber}E${event.episodeNumber}`;
|
||||||
|
|
||||||
eventsToAdd[title] = {
|
eventsToAdd[title] = {
|
||||||
title,
|
title: `${event.series.title ?? event.title}`,
|
||||||
date: DateTime.fromISO(event.airDateUtc),
|
date: DateTime.fromISO(event.airDateUtc),
|
||||||
color: config?.color ?? "teal",
|
color: config?.color ?? "teal",
|
||||||
|
isCompleted: event.hasFile,
|
||||||
|
additional: `S${event.seasonNumber} E${event.episodeNumber}`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,43 +1,16 @@
|
||||||
import { useContext, useEffect, useMemo } from "react";
|
import { useContext, useMemo } from "react";
|
||||||
import { DateTime, Info } from "luxon";
|
import { DateTime, Info } from "luxon";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { useTranslation } from "next-i18next";
|
import { useTranslation } from "next-i18next";
|
||||||
|
import { IoMdCheckmarkCircleOutline } from "react-icons/io";
|
||||||
|
|
||||||
import { EventContext, ShowDateContext } from "../../utils/contexts/calendar";
|
import { EventContext } from "../../utils/contexts/calendar";
|
||||||
|
|
||||||
const colorVariants = {
|
|
||||||
// https://tailwindcss.com/docs/content-configuration#dynamic-class-names
|
|
||||||
amber: "bg-amber-500",
|
|
||||||
blue: "bg-blue-500",
|
|
||||||
cyan: "bg-cyan-500",
|
|
||||||
emerald: "bg-emerald-500",
|
|
||||||
fuchsia: "bg-fuchsia-500",
|
|
||||||
gray: "bg-gray-500",
|
|
||||||
green: "bg-green-500",
|
|
||||||
indigo: "bg-indigo-500",
|
|
||||||
lime: "bg-lime-500",
|
|
||||||
neutral: "bg-neutral-500",
|
|
||||||
orange: "bg-orange-500",
|
|
||||||
pink: "bg-pink-500",
|
|
||||||
purple: "bg-purple-500",
|
|
||||||
red: "bg-red-500",
|
|
||||||
rose: "bg-rose-500",
|
|
||||||
sky: "bg-sky-500",
|
|
||||||
slate: "bg-slate-500",
|
|
||||||
stone: "bg-stone-500",
|
|
||||||
teal: "bg-teal-500",
|
|
||||||
violet: "bg-violet-500",
|
|
||||||
white: "bg-white-500",
|
|
||||||
yellow: "bg-yellow-500",
|
|
||||||
zinc: "bg-zinc-500",
|
|
||||||
};
|
|
||||||
|
|
||||||
const cellStyle = "relative w-10 flex items-center justify-center flex-col";
|
const cellStyle = "relative w-10 flex items-center justify-center flex-col";
|
||||||
const monthButton = "pl-6 pr-6 ml-2 mr-2 hover:bg-theme-100/20 dark:hover:bg-white/5 rounded-md cursor-pointer";
|
const monthButton = "pl-6 pr-6 ml-2 mr-2 hover:bg-theme-100/20 dark:hover:bg-white/5 rounded-md cursor-pointer";
|
||||||
|
|
||||||
export function Day({ weekNumber, weekday, events }) {
|
export function Day({ weekNumber, weekday, events, colorVariants, showDate, setShowDate }) {
|
||||||
const currentDate = DateTime.now();
|
const currentDate = DateTime.now();
|
||||||
const { showDate, setShowDate } = useContext(ShowDateContext);
|
|
||||||
|
|
||||||
const cellDate = showDate.set({ weekday, weekNumber }).startOf("day");
|
const cellDate = showDate.set({ weekday, weekNumber }).startOf("day");
|
||||||
const filteredEvents = events?.filter(
|
const filteredEvents = events?.filter(
|
||||||
|
@ -105,7 +78,13 @@ export function Event({ event }) {
|
||||||
>
|
>
|
||||||
<span className="absolute left-2 text-left text-xs mt-[2px] truncate text-ellipsis" style={{ width: "96%" }}>
|
<span className="absolute left-2 text-left text-xs mt-[2px] truncate text-ellipsis" style={{ width: "96%" }}>
|
||||||
{event.title}
|
{event.title}
|
||||||
|
{event.additional ? ` - ${event.additional}` : ""}
|
||||||
</span>
|
</span>
|
||||||
|
{event.isCompleted && (
|
||||||
|
<span className="text-right text-xs flex justify-end mr-1 mt-1 z-10 ">
|
||||||
|
<IoMdCheckmarkCircleOutline />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -120,19 +99,12 @@ const dayInWeekId = {
|
||||||
sunday: 7,
|
sunday: 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function MonthlyView({ service }) {
|
export default function Monthly({ service, colorVariants, showDate, setShowDate }) {
|
||||||
const { widget } = service;
|
const { widget } = service;
|
||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
const { showDate, setShowDate } = useContext(ShowDateContext);
|
|
||||||
const { events } = useContext(EventContext);
|
const { events } = useContext(EventContext);
|
||||||
const currentDate = DateTime.now().setLocale(i18n.language).startOf("day");
|
const currentDate = DateTime.now().setLocale(i18n.language).startOf("day");
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!showDate) {
|
|
||||||
setShowDate(currentDate);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const dayNames = Info.weekdays("short", { locale: i18n.language });
|
const dayNames = Info.weekdays("short", { locale: i18n.language });
|
||||||
|
|
||||||
const firstDayInWeekCalendar = widget?.firstDayInWeek ? widget?.firstDayInWeek?.toLowerCase() : "monday";
|
const firstDayInWeekCalendar = widget?.firstDayInWeek ? widget?.firstDayInWeek?.toLowerCase() : "monday";
|
||||||
|
@ -211,6 +183,9 @@ export default function MonthlyView({ service }) {
|
||||||
weekNumber={weekNumber}
|
weekNumber={weekNumber}
|
||||||
weekday={dayInWeek}
|
weekday={dayInWeek}
|
||||||
events={eventsArray}
|
events={eventsArray}
|
||||||
|
colorVariants={colorVariants}
|
||||||
|
showDate={showDate}
|
||||||
|
setShowDate={setShowDate}
|
||||||
/>
|
/>
|
||||||
)),
|
)),
|
||||||
)}
|
)}
|
||||||
|
@ -219,8 +194,9 @@ export default function MonthlyView({ service }) {
|
||||||
<div className="flex flex-col pt-1 pb-1">
|
<div className="flex flex-col pt-1 pb-1">
|
||||||
{eventsArray
|
{eventsArray
|
||||||
?.filter((event) => showDate.startOf("day").toUnixInteger() === event.date?.startOf("day").toUnixInteger())
|
?.filter((event) => showDate.startOf("day").toUnixInteger() === event.date?.startOf("day").toUnixInteger())
|
||||||
|
.slice(0, widget?.maxEvents ?? 10)
|
||||||
.map((event) => (
|
.map((event) => (
|
||||||
<Event key={`event${event.title}`} event={event} />
|
<Event key={`event${event.title}-${event.additional}`} event={event} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
Loading…
Add table
Reference in a new issue