diff --git a/src/panels/calendar/ha-full-calendar.ts b/src/panels/calendar/ha-full-calendar.ts index 3682b848f5c5..e089f38dd3ae 100644 --- a/src/panels/calendar/ha-full-calendar.ts +++ b/src/panels/calendar/ha-full-calendar.ts @@ -4,9 +4,12 @@ import allLocales from "@fullcalendar/core/locales-all"; import dayGridPlugin from "@fullcalendar/daygrid"; import interactionPlugin from "@fullcalendar/interaction"; import listPlugin from "@fullcalendar/list"; +import timeGridPlugin from "@fullcalendar/timegrid"; import { ResizeController } from "@lit-labs/observers/resize-controller"; import { + mdiCalendarClock, mdiPlus, + mdiTimetable, mdiViewAgenda, mdiViewDay, mdiViewModule, @@ -56,12 +59,14 @@ declare global { const defaultFullCalendarConfig: CalendarOptions = { headerToolbar: false, - plugins: [dayGridPlugin, listPlugin, interactionPlugin], + plugins: [dayGridPlugin, listPlugin, interactionPlugin, timeGridPlugin], initialView: "dayGridMonth", dayMaxEventRows: true, height: "parent", handleWindowResize: false, locales: allLocales, + nowIndicator: true, + scrollTime: "06:00:00", views: { listWeek: { type: "list", @@ -86,6 +91,8 @@ export class HAFullCalendar extends LitElement { "dayGridMonth", "dayGridWeek", "dayGridDay", + "timeGridWeek", + "timeGridDay", "listWeek", ]; @@ -325,6 +332,8 @@ export class HAFullCalendar extends LitElement { selectedDate: this._activeView === "dayGridWeek" || this._activeView === "dayGridDay" || + this._activeView === "timeGridWeek" || + this._activeView === "timeGridDay" || (this._activeView === "dayGridMonth" && this.calendar!.view.currentStart.getMonth() !== new Date().getMonth()) ? this.calendar!.view.currentStart @@ -359,8 +368,11 @@ export class HAFullCalendar extends LitElement { if (info.view.type !== "dayGridMonth") { return; } - this._activeView = "dayGridDay"; - this.calendar!.changeView("dayGridDay"); + const dayView = this.views.includes("timeGridDay") + ? "timeGridDay" + : "dayGridDay"; + this._activeView = dayView; + this.calendar!.changeView(dayView); this.calendar!.gotoDate(info.dateStr); this._fireViewChanged(); } @@ -473,6 +485,16 @@ export class HAFullCalendar extends LitElement { value: "dayGridDay", iconPath: mdiViewDay, }, + { + label: localize("ui.components.calendar.views.timeGridWeek"), + value: "timeGridWeek", + iconPath: mdiTimetable, + }, + { + label: localize("ui.components.calendar.views.timeGridDay"), + value: "timeGridDay", + iconPath: mdiCalendarClock, + }, { label: localize("ui.components.calendar.views.listWeek"), value: "listWeek", @@ -767,6 +789,64 @@ export class HAFullCalendar extends LitElement { scrollbar-color: var(--scrollbar-thumb-color) transparent; scrollbar-width: thin; } + + /* timeGrid (week/day) view styles */ + .fc-timegrid-slot-label { + font-size: var(--ha-font-size-xs); + color: var(--secondary-text-color); + } + + .fc-timegrid-axis { + font-size: var(--ha-font-size-xs); + color: var(--secondary-text-color); + } + + .fc .fc-timegrid-col.fc-day-today { + background: var(--primary-color-alpha-10, rgba(0, 0, 0, 0.04)); + } + + .fc-timegrid-now-indicator-line { + border-color: var(--primary-color); + } + + .fc-timegrid-now-indicator-arrow { + border-top-color: var(--primary-color); + border-bottom-color: var(--primary-color); + } + + .fc-timegrid-event { + border-radius: var(--ha-border-radius-sm); + } + + .fc-timegrid-event .fc-event-main { + padding: 2px 4px; + } + + .fc-timegrid-event .fc-event-title-container { + order: -1; + } + + /* Compact styling for short events via container query */ + .fc-timegrid-event-harness { + container-type: size; + } + + @container (max-height: 30px) { + .fc-v-event { + border-top-width: 0; + border-bottom-width: 0; + } + .fc-v-event .fc-event-main { + padding-top: 0; + padding-bottom: 0; + } + .fc-v-event .fc-event-main .fc-event-main-frame { + line-height: 14px; + } + .fc-v-event .fc-event-time { + display: none; + } + } `, ]; } diff --git a/src/panels/lovelace/cards/hui-calendar-card.ts b/src/panels/lovelace/cards/hui-calendar-card.ts index 45d1d3926cfd..40aa8f5c361d 100644 --- a/src/panels/lovelace/cards/hui-calendar-card.ts +++ b/src/panels/lovelace/cards/hui-calendar-card.ts @@ -188,11 +188,11 @@ export class HuiCalendarCard const loading = !this._entityRegistry || !this._eventsLoaded; - const views: FullCalendarView[] = [ - "dayGridMonth", - "dayGridDay", - "listWeek", - ]; + const dayView: FullCalendarView = this._config.schedule_day_view + ? "timeGridDay" + : "dayGridDay"; + + const views: FullCalendarView[] = ["dayGridMonth", dayView, "listWeek"]; return html` diff --git a/src/panels/lovelace/cards/types.ts b/src/panels/lovelace/cards/types.ts index ac4a9bbe0c5e..31f817d4fe97 100644 --- a/src/panels/lovelace/cards/types.ts +++ b/src/panels/lovelace/cards/types.ts @@ -53,6 +53,7 @@ export interface AlarmPanelCardConfig extends LovelaceCardConfig { export interface CalendarCardConfig extends LovelaceCardConfig { entities: string[]; initial_view?: FullCalendarView; + schedule_day_view?: boolean; title?: string; theme?: string; } diff --git a/src/panels/lovelace/editor/config-elements/hui-calendar-card-editor.ts b/src/panels/lovelace/editor/config-elements/hui-calendar-card-editor.ts index 8d3de51c1b28..2249c563d49b 100644 --- a/src/panels/lovelace/editor/config-elements/hui-calendar-card-editor.ts +++ b/src/panels/lovelace/editor/config-elements/hui-calendar-card-editor.ts @@ -26,6 +26,7 @@ const cardConfigStruct = assign( object({ title: optional(union([string(), boolean()])), initial_view: optional(string()), + schedule_day_view: optional(boolean()), theme: optional(string()), entities: array(string()), }) @@ -69,6 +70,11 @@ export class HuiCalendarCardEditor }, }, }, + { + name: "schedule_day_view", + required: false, + selector: { boolean: {} }, + }, ], }, { name: "theme", required: false, selector: { theme: {} } }, diff --git a/src/translations/en.json b/src/translations/en.json index d95cedd9ee9f..34aef4dc439e 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1331,6 +1331,8 @@ "dayGridMonth": "[%key:ui::panel::lovelace::editor::card::calendar::views::dayGridMonth%]", "dayGridWeek": "[%key:ui::panel::lovelace::editor::card::calendar::views::dayGridWeek%]", "dayGridDay": "[%key:ui::panel::lovelace::editor::card::calendar::views::dayGridDay%]", + "timeGridWeek": "Schedule (week)", + "timeGridDay": "Schedule (day)", "listWeek": "[%key:ui::panel::lovelace::editor::card::calendar::views::listWeek%]" } }, @@ -8932,6 +8934,7 @@ "name": "Calendar", "description": "This card displays a calendar including day, week, and list views", "initial_view": "Initial view", + "schedule_day_view": "Use schedule for day view", "calendar_entities": "Calendar entities", "views": { "dayGridMonth": "Month", diff --git a/src/types.ts b/src/types.ts index 4cee05ac1f8c..20ebccaa55f4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -157,6 +157,8 @@ export type FullCalendarView = | "dayGridMonth" | "dayGridWeek" | "dayGridDay" + | "timeGridWeek" + | "timeGridDay" | "listWeek"; export const THEME_MODES = ["auto", "light", "dark"] as const;