mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-25 18:26:35 +00:00
Calendar Card: New Card (#5813)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
06a25284e8
commit
dae42b1bd9
@ -23,8 +23,11 @@
|
|||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formatjs/intl-pluralrules": "^1.5.8",
|
"@formatjs/intl-pluralrules": "^1.5.8",
|
||||||
"@fullcalendar/core": "^5.0.0-beta.2",
|
"@fullcalendar/common": "5.1.0",
|
||||||
"@fullcalendar/daygrid": "^5.0.0-beta.2",
|
"@fullcalendar/core": "5.1.0",
|
||||||
|
"@fullcalendar/daygrid": "5.1.0",
|
||||||
|
"@fullcalendar/interaction": "5.1.0",
|
||||||
|
"@fullcalendar/list": "5.1.0",
|
||||||
"@material/chips": "=8.0.0-canary.096a7a066.0",
|
"@material/chips": "=8.0.0-canary.096a7a066.0",
|
||||||
"@material/circular-progress": "=8.0.0-canary.a78ceb112.0",
|
"@material/circular-progress": "=8.0.0-canary.a78ceb112.0",
|
||||||
"@material/mwc-button": "^0.18.0",
|
"@material/mwc-button": "^0.18.0",
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import "@material/mwc-icon-button/mwc-icon-button";
|
||||||
import {
|
import {
|
||||||
customElement,
|
customElement,
|
||||||
html,
|
html,
|
||||||
@ -8,14 +9,14 @@ import {
|
|||||||
css,
|
css,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
|
|
||||||
import "./ha-icon-button";
|
|
||||||
|
|
||||||
import { fireEvent } from "../common/dom/fire_event";
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
import type { ToggleButton } from "../types";
|
import type { ToggleButton } from "../types";
|
||||||
|
|
||||||
|
import "./ha-svg-icon";
|
||||||
|
|
||||||
@customElement("ha-button-toggle-group")
|
@customElement("ha-button-toggle-group")
|
||||||
export class HaButtonToggleGroup extends LitElement {
|
export class HaButtonToggleGroup extends LitElement {
|
||||||
@property() public buttons!: ToggleButton[];
|
@property({ attribute: false }) public buttons!: ToggleButton[];
|
||||||
|
|
||||||
@property() public active?: string;
|
@property() public active?: string;
|
||||||
|
|
||||||
@ -23,14 +24,16 @@ export class HaButtonToggleGroup extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<div>
|
<div>
|
||||||
${this.buttons.map(
|
${this.buttons.map(
|
||||||
(button) => html` <ha-icon-button
|
(button) => html`
|
||||||
.label=${button.label}
|
<mwc-icon-button
|
||||||
.icon=${button.icon}
|
.label=${button.label}
|
||||||
.value=${button.value}
|
.value=${button.value}
|
||||||
?active=${this.active === button.value}
|
?active=${this.active === button.value}
|
||||||
@click=${this._handleClick}
|
@click=${this._handleClick}
|
||||||
>
|
>
|
||||||
</ha-icon-button>`
|
<ha-svg-icon .path=${button.iconPath}></ha-svg-icon>
|
||||||
|
</mwc-icon-button>
|
||||||
|
`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@ -48,12 +51,13 @@ export class HaButtonToggleGroup extends LitElement {
|
|||||||
--mdc-icon-button-size: var(--button-toggle-size, 36px);
|
--mdc-icon-button-size: var(--button-toggle-size, 36px);
|
||||||
--mdc-icon-size: var(--button-toggle-icon-size, 20px);
|
--mdc-icon-size: var(--button-toggle-icon-size, 20px);
|
||||||
}
|
}
|
||||||
ha-icon-button {
|
mwc-icon-button {
|
||||||
border: 1px solid var(--primary-color);
|
border: 1px solid var(--primary-color);
|
||||||
border-right-width: 0px;
|
border-right-width: 0px;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
ha-icon-button::before {
|
mwc-icon-button::before {
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -65,22 +69,26 @@ export class HaButtonToggleGroup extends LitElement {
|
|||||||
content: "";
|
content: "";
|
||||||
transition: opacity 15ms linear, background-color 15ms linear;
|
transition: opacity 15ms linear, background-color 15ms linear;
|
||||||
}
|
}
|
||||||
ha-icon-button[active]::before {
|
mwc-icon-button[active]::before {
|
||||||
opacity: var(--mdc-icon-button-ripple-opacity, 0.12);
|
opacity: var(--mdc-icon-button-ripple-opacity, 0.12);
|
||||||
}
|
}
|
||||||
ha-icon-button:first-child {
|
mwc-icon-button:first-child {
|
||||||
border-radius: 4px 0 0 4px;
|
border-radius: 4px 0 0 4px;
|
||||||
}
|
}
|
||||||
ha-icon-button:last-child {
|
mwc-icon-button:last-child {
|
||||||
border-radius: 0 4px 4px 0;
|
border-radius: 0 4px 4px 0;
|
||||||
border-right-width: 1px;
|
border-right-width: 1px;
|
||||||
}
|
}
|
||||||
|
mwc-icon-button:only-child {
|
||||||
|
border-radius: 4px;
|
||||||
|
border-right-width: 1px;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"ha-button-toggle-button": HaButtonToggleGroup;
|
"ha-button-toggle-group": HaButtonToggleGroup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import "@material/mwc-button";
|
||||||
import {
|
import {
|
||||||
property,
|
property,
|
||||||
internalProperty,
|
internalProperty,
|
||||||
@ -9,13 +10,19 @@ import {
|
|||||||
unsafeCSS,
|
unsafeCSS,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
|
import { mdiViewModule, mdiViewWeek, mdiViewDay, mdiViewAgenda } from "@mdi/js";
|
||||||
import { Calendar } from "@fullcalendar/core";
|
import { Calendar } from "@fullcalendar/core";
|
||||||
|
import type { CalendarOptions } from "@fullcalendar/core";
|
||||||
import dayGridPlugin from "@fullcalendar/daygrid";
|
import dayGridPlugin from "@fullcalendar/daygrid";
|
||||||
|
import listPlugin from "@fullcalendar/list";
|
||||||
|
import interactionPlugin from "@fullcalendar/interaction";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import fullcalendarStyle from "@fullcalendar/core/main.css";
|
import fullcalendarStyle from "@fullcalendar/common/main.css";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import daygridStyle from "@fullcalendar/daygrid/main.css";
|
import daygridStyle from "@fullcalendar/daygrid/main.css";
|
||||||
import "@material/mwc-button";
|
// @ts-ignore
|
||||||
|
import listStyle from "@fullcalendar/list/main.css";
|
||||||
|
import memoize from "memoize-one";
|
||||||
|
|
||||||
import "../../components/ha-icon-button";
|
import "../../components/ha-icon-button";
|
||||||
import "../../components/ha-button-toggle-group";
|
import "../../components/ha-button-toggle-group";
|
||||||
@ -25,43 +32,56 @@ import type {
|
|||||||
CalendarEvent,
|
CalendarEvent,
|
||||||
ToggleButton,
|
ToggleButton,
|
||||||
HomeAssistant,
|
HomeAssistant,
|
||||||
|
FullCalendarView,
|
||||||
} from "../../types";
|
} from "../../types";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { haStyle } from "../../resources/styles";
|
import { haStyle } from "../../resources/styles";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"ha-full-calendar": HAFullCalendar;
|
||||||
|
}
|
||||||
interface HASSDomEvents {
|
interface HASSDomEvents {
|
||||||
"view-changed": CalendarViewChanged;
|
"view-changed": CalendarViewChanged;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const fullCalendarConfig = {
|
const defaultFullCalendarConfig: CalendarOptions = {
|
||||||
headerToolbar: false,
|
headerToolbar: false,
|
||||||
plugins: [dayGridPlugin],
|
plugins: [dayGridPlugin, listPlugin, interactionPlugin],
|
||||||
initialView: "dayGridMonth",
|
initialView: "dayGridMonth",
|
||||||
dayMaxEventRows: true,
|
dayMaxEventRows: true,
|
||||||
height: "parent",
|
height: "parent",
|
||||||
|
eventDisplay: "list-item",
|
||||||
};
|
};
|
||||||
|
|
||||||
const viewButtons: ToggleButton[] = [
|
const viewButtons: ToggleButton[] = [
|
||||||
{ label: "Month View", value: "dayGridMonth", icon: "hass:view-module" },
|
{ label: "Month View", value: "dayGridMonth", iconPath: mdiViewModule },
|
||||||
{ label: "Week View", value: "dayGridWeek", icon: "hass:view-week" },
|
{ label: "Week View", value: "dayGridWeek", iconPath: mdiViewWeek },
|
||||||
{ label: "Day View", value: "dayGridDay", icon: "hass:view-day" },
|
{ label: "Day View", value: "dayGridDay", iconPath: mdiViewDay },
|
||||||
|
{ label: "List View", value: "listWeek", iconPath: mdiViewAgenda },
|
||||||
];
|
];
|
||||||
|
|
||||||
class HAFullCalendar extends LitElement {
|
class HAFullCalendar extends LitElement {
|
||||||
public hass!: HomeAssistant;
|
public hass!: HomeAssistant;
|
||||||
|
|
||||||
@property() public events: CalendarEvent[] = [];
|
@property({ type: Boolean, reflect: true }) public narrow = false;
|
||||||
|
|
||||||
@property({ type: Boolean, reflect: true })
|
@property({ attribute: false }) public events: CalendarEvent[] = [];
|
||||||
public narrow!: boolean;
|
|
||||||
|
@property({ attribute: false }) public views: FullCalendarView[] = [
|
||||||
|
"dayGridMonth",
|
||||||
|
"dayGridWeek",
|
||||||
|
"dayGridDay",
|
||||||
|
];
|
||||||
|
|
||||||
@internalProperty() private calendar?: Calendar;
|
@internalProperty() private calendar?: Calendar;
|
||||||
|
|
||||||
@internalProperty() private _activeView = "dayGridMonth";
|
@internalProperty() private _activeView: FullCalendarView = "dayGridMonth";
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
|
const viewToggleButtons = this._viewToggleButtons(this.views);
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
${this.calendar
|
${this.calendar
|
||||||
? html`
|
? html`
|
||||||
@ -96,27 +116,12 @@ class HAFullCalendar extends LitElement {
|
|||||||
${this.calendar.view.title}
|
${this.calendar.view.title}
|
||||||
</h1>
|
</h1>
|
||||||
<ha-button-toggle-group
|
<ha-button-toggle-group
|
||||||
.buttons=${viewButtons}
|
.buttons=${viewToggleButtons}
|
||||||
.active=${this._activeView}
|
.active=${this._activeView}
|
||||||
@value-changed=${this._handleView}
|
@value-changed=${this._handleView}
|
||||||
></ha-button-toggle-group>
|
></ha-button-toggle-group>
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<div class="controls">
|
|
||||||
<mwc-button
|
|
||||||
outlined
|
|
||||||
class="today"
|
|
||||||
@click=${this._handleToday}
|
|
||||||
>${this.hass.localize(
|
|
||||||
"ui.panel.calendar.today"
|
|
||||||
)}</mwc-button
|
|
||||||
>
|
|
||||||
<ha-button-toggle-group
|
|
||||||
.buttons=${viewButtons}
|
|
||||||
.active=${this._activeView}
|
|
||||||
@value-changed=${this._handleView}
|
|
||||||
></ha-button-toggle-group>
|
|
||||||
</div>
|
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<h1>
|
<h1>
|
||||||
${this.calendar.view.title}
|
${this.calendar.view.title}
|
||||||
@ -138,6 +143,21 @@ class HAFullCalendar extends LitElement {
|
|||||||
</ha-icon-button>
|
</ha-icon-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<mwc-button
|
||||||
|
outlined
|
||||||
|
class="today"
|
||||||
|
@click=${this._handleToday}
|
||||||
|
>${this.hass.localize(
|
||||||
|
"ui.panel.calendar.today"
|
||||||
|
)}</mwc-button
|
||||||
|
>
|
||||||
|
<ha-button-toggle-group
|
||||||
|
.buttons=${viewToggleButtons}
|
||||||
|
.active=${this._activeView}
|
||||||
|
@value-changed=${this._handleView}
|
||||||
|
></ha-button-toggle-group>
|
||||||
|
</div>
|
||||||
`}
|
`}
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@ -157,14 +177,25 @@ class HAFullCalendar extends LitElement {
|
|||||||
this.calendar.removeAllEventSources();
|
this.calendar.removeAllEventSources();
|
||||||
this.calendar.addEventSource(this.events);
|
this.calendar.addEventSource(this.events);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (changedProps.has("views") && !this.views.includes(this._activeView)) {
|
||||||
|
this._activeView = this.views[0];
|
||||||
|
this.calendar!.changeView(this._activeView);
|
||||||
|
this._fireViewChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected firstUpdated(): void {
|
protected firstUpdated(): void {
|
||||||
const config = { ...fullCalendarConfig, locale: this.hass.language };
|
const config: CalendarOptions = {
|
||||||
|
...defaultFullCalendarConfig,
|
||||||
|
locale: this.hass.language,
|
||||||
|
};
|
||||||
|
|
||||||
|
config.dateClick = this._handleDateClick;
|
||||||
|
config.eventClick = this._handleEventClick;
|
||||||
|
|
||||||
this.calendar = new Calendar(
|
this.calendar = new Calendar(
|
||||||
this.shadowRoot!.getElementById("calendar")!,
|
this.shadowRoot!.getElementById("calendar")!,
|
||||||
// @ts-ignore
|
|
||||||
config
|
config
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -172,6 +203,25 @@ class HAFullCalendar extends LitElement {
|
|||||||
this._fireViewChanged();
|
this._fireViewChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _handleEventClick(info): void {
|
||||||
|
if (info.view.type !== "dayGridMonth") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._activeView = "dayGridDay";
|
||||||
|
this.calendar!.changeView("dayGridDay");
|
||||||
|
this.calendar!.gotoDate(info.event.startStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleDateClick(info): void {
|
||||||
|
if (info.view.type !== "dayGridMonth") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._activeView = "dayGridDay";
|
||||||
|
this.calendar!.changeView("dayGridDay");
|
||||||
|
this.calendar!.gotoDate(info.dateStr);
|
||||||
|
}
|
||||||
|
|
||||||
private _handleNext(): void {
|
private _handleNext(): void {
|
||||||
this.calendar!.next();
|
this.calendar!.next();
|
||||||
this._fireViewChanged();
|
this._fireViewChanged();
|
||||||
@ -201,14 +251,21 @@ class HAFullCalendar extends LitElement {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _viewToggleButtons = memoize((views) =>
|
||||||
|
viewButtons.filter((button) =>
|
||||||
|
views.includes(button.value as FullCalendarView)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
static get styles(): CSSResult[] {
|
static get styles(): CSSResult[] {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
${unsafeCSS(fullcalendarStyle)}
|
${unsafeCSS(fullcalendarStyle)}
|
||||||
${unsafeCSS(daygridStyle)}
|
${unsafeCSS(daygridStyle)}
|
||||||
|
${unsafeCSS(listStyle)}
|
||||||
:host {
|
|
||||||
|
:host {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
--fc-theme-standard-border-color: var(--divider-color);
|
--fc-theme-standard-border-color: var(--divider-color);
|
||||||
@ -262,6 +319,15 @@ class HAFullCalendar extends LitElement {
|
|||||||
#calendar {
|
#calendar {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
background-color: var(--card-background-color);
|
background-color: var(--card-background-color);
|
||||||
|
min-height: 400px;
|
||||||
|
--fc-neutral-bg-color: var(--card-background-color);
|
||||||
|
--fc-list-event-hover-bg-color: var(--card-background-color);
|
||||||
|
--fc-theme-standard-border-color: var(--divider-color);
|
||||||
|
--fc-border-color: var(--divider-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: inherit !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fc-theme-standard .fc-scrollgrid {
|
.fc-theme-standard .fc-scrollgrid {
|
||||||
@ -273,15 +339,20 @@ class HAFullCalendar extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
th.fc-col-header-cell.fc-day {
|
th.fc-col-header-cell.fc-day {
|
||||||
color: #70757a;
|
color: var(--secondary-text-color);
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fc-daygrid-dot-event:hover {
|
||||||
|
background-color: inherit
|
||||||
|
}
|
||||||
|
|
||||||
.fc-daygrid-day-top {
|
.fc-daygrid-day-top {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-top: 8px;
|
padding-top: 5px;
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.fc-scrollgrid-sync-table
|
table.fc-scrollgrid-sync-table
|
||||||
@ -296,13 +367,21 @@ class HAFullCalendar extends LitElement {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
td.fc-day-today {
|
.fc .fc-daygrid-day-number {
|
||||||
|
padding: 3px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc .fc-daygrid-day.fc-day-today {
|
||||||
background: inherit;
|
background: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
td.fc-day-today .fc-daygrid-day-top {
|
||||||
|
padding-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
td.fc-day-today .fc-daygrid-day-number {
|
td.fc-day-today .fc-daygrid-day-number {
|
||||||
height: 24px;
|
height: 24px;
|
||||||
color: var(--text-primary-color);
|
color: var(--text-primary-color) !important;
|
||||||
background-color: var(--primary-color);
|
background-color: var(--primary-color);
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@ -342,6 +421,66 @@ class HAFullCalendar extends LitElement {
|
|||||||
.fc-popover-header {
|
.fc-popover-header {
|
||||||
background-color: var(--secondary-background-color) !important;
|
background-color: var(--secondary-background-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fc-theme-standard .fc-list-day-frame {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-list.fc-view,
|
||||||
|
.fc-list-event.fc-event td {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-list-day.fc-day th {
|
||||||
|
border-bottom: none;
|
||||||
|
border-top: 1px solid var(--fc-theme-standard-border-color, #ddd) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-list-day-text {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-list-day-side-text {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 16px;
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.fc-list-table td,
|
||||||
|
.fc-list-day-frame {
|
||||||
|
padding-top: 12px;
|
||||||
|
padding-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([narrow]) .fc-dayGridMonth-view
|
||||||
|
.fc-daygrid-dot-event
|
||||||
|
.fc-event-time,
|
||||||
|
:host([narrow]) .fc-dayGridMonth-view
|
||||||
|
.fc-daygrid-dot-event
|
||||||
|
.fc-event-title,
|
||||||
|
:host([narrow]) .fc-dayGridMonth-view .fc-daygrid-day-bottom {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([narrow]) .fc .fc-dayGridMonth-view .fc-daygrid-event-harness-abs {
|
||||||
|
visibility: visible !important;
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([narrow]) .fc-dayGridMonth-view .fc-daygrid-day-events {
|
||||||
|
display: flex;
|
||||||
|
min-height: 2em !important;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
max-height: 2em;
|
||||||
|
height: 2em;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host([narrow]) .fc-dayGridMonth-view .fc-scrollgrid-sync-table {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -53,12 +53,6 @@ class PanelCalendar extends LitElement {
|
|||||||
selected: true,
|
selected: true,
|
||||||
calendar,
|
calendar,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (!this._start || !this._end) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._fetchEvents(this._start, this._end, this._selectedCalendars);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
@ -88,8 +82,8 @@ class PanelCalendar extends LitElement {
|
|||||||
<mwc-formfield .label=${selCal.calendar.name}>
|
<mwc-formfield .label=${selCal.calendar.name}>
|
||||||
<mwc-checkbox
|
<mwc-checkbox
|
||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
"--mdc-theme-secondary":
|
"--mdc-theme-secondary": selCal.calendar
|
||||||
selCal.calendar.backgroundColor,
|
.backgroundColor!,
|
||||||
})}
|
})}
|
||||||
.value=${selCal.calendar.entity_id}
|
.value=${selCal.calendar.entity_id}
|
||||||
.checked=${selCal.selected}
|
.checked=${selCal.selected}
|
||||||
|
213
src/panels/lovelace/cards/hui-calendar-card.ts
Normal file
213
src/panels/lovelace/cards/hui-calendar-card.ts
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
PropertyValues,
|
||||||
|
TemplateResult,
|
||||||
|
internalProperty,
|
||||||
|
} from "lit-element";
|
||||||
|
|
||||||
|
import "../../../components/ha-card";
|
||||||
|
import "../../../components/ha-icon";
|
||||||
|
import "../../calendar/ha-full-calendar";
|
||||||
|
|
||||||
|
import type {
|
||||||
|
HomeAssistant,
|
||||||
|
CalendarEvent,
|
||||||
|
Calendar,
|
||||||
|
CalendarViewChanged,
|
||||||
|
FullCalendarView,
|
||||||
|
} from "../../../types";
|
||||||
|
import type { LovelaceCard, LovelaceCardEditor } from "../types";
|
||||||
|
import type { CalendarCardConfig } from "./types";
|
||||||
|
import { findEntities } from "../common/find-entites";
|
||||||
|
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
|
||||||
|
import "../components/hui-warning";
|
||||||
|
import { fetchCalendarEvents } from "../../../data/calendar";
|
||||||
|
import { HASSDomEvent } from "../../../common/dom/fire_event";
|
||||||
|
import { HA_COLOR_PALETTE } from "../../../common/const";
|
||||||
|
import { debounce } from "../../../common/util/debounce";
|
||||||
|
import { installResizeObserver } from "../common/install-resize-observer";
|
||||||
|
|
||||||
|
@customElement("hui-calendar-card")
|
||||||
|
export class HuiCalendarCard extends LitElement implements LovelaceCard {
|
||||||
|
public static async getConfigElement(): Promise<LovelaceCardEditor> {
|
||||||
|
await import(
|
||||||
|
/* webpackChunkName: "hui-calendar-card-editor" */ "../editor/config-elements/hui-calendar-card-editor"
|
||||||
|
);
|
||||||
|
return document.createElement("hui-calendar-card-editor");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static getStubConfig(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entities: string[],
|
||||||
|
entitiesFill: string[]
|
||||||
|
) {
|
||||||
|
const includeDomains = ["calendar"];
|
||||||
|
const maxEntities = 2;
|
||||||
|
const foundEntities = findEntities(
|
||||||
|
hass,
|
||||||
|
maxEntities,
|
||||||
|
entities,
|
||||||
|
entitiesFill,
|
||||||
|
includeDomains
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
entities: foundEntities,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) public _events: CalendarEvent[] = [];
|
||||||
|
|
||||||
|
@internalProperty() private _config?: CalendarCardConfig;
|
||||||
|
|
||||||
|
@internalProperty() private _calendars: Calendar[] = [];
|
||||||
|
|
||||||
|
@internalProperty() private _narrow = false;
|
||||||
|
|
||||||
|
@internalProperty() private _veryNarrow = false;
|
||||||
|
|
||||||
|
private _resizeObserver?: ResizeObserver;
|
||||||
|
|
||||||
|
public setConfig(config: CalendarCardConfig): void {
|
||||||
|
if (!config.entities) {
|
||||||
|
throw new Error("Entities must be defined");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.entities && !Array.isArray(config.entities)) {
|
||||||
|
throw new Error("Entities need to be an array");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._calendars = config!.entities.map((entity, idx) => {
|
||||||
|
return {
|
||||||
|
entity_id: entity,
|
||||||
|
backgroundColor: `#${HA_COLOR_PALETTE[idx % HA_COLOR_PALETTE.length]}`,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
this._config = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getCardSize(): number {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public connectedCallback(): void {
|
||||||
|
super.connectedCallback();
|
||||||
|
this.updateComplete.then(() => this._attachObserver());
|
||||||
|
}
|
||||||
|
|
||||||
|
public disconnectedCallback(): void {
|
||||||
|
if (this._resizeObserver) {
|
||||||
|
this._resizeObserver.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this._config || !this.hass || !this._calendars.length) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
const views: FullCalendarView[] = this._veryNarrow
|
||||||
|
? ["listWeek"]
|
||||||
|
: ["listWeek", "dayGridMonth", "dayGridDay"];
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<ha-card>
|
||||||
|
<div class="header">${this._config.title}</div>
|
||||||
|
<ha-full-calendar
|
||||||
|
.narrow=${this._narrow}
|
||||||
|
.events=${this._events}
|
||||||
|
.hass=${this.hass}
|
||||||
|
.views=${views}
|
||||||
|
@view-changed=${this._handleViewChanged}
|
||||||
|
></ha-full-calendar>
|
||||||
|
</ha-card>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected updated(changedProps: PropertyValues) {
|
||||||
|
super.updated(changedProps);
|
||||||
|
if (!this._config || !this.hass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||||
|
const oldConfig = changedProps.get("_config") as
|
||||||
|
| CalendarCardConfig
|
||||||
|
| undefined;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!oldHass ||
|
||||||
|
!oldConfig ||
|
||||||
|
(changedProps.has("hass") && oldHass.themes !== this.hass.themes) ||
|
||||||
|
(changedProps.has("_config") && oldConfig.theme !== this._config.theme)
|
||||||
|
) {
|
||||||
|
applyThemesOnElement(this, this.hass.themes, this._config!.theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _handleViewChanged(
|
||||||
|
ev: HASSDomEvent<CalendarViewChanged>
|
||||||
|
): Promise<void> {
|
||||||
|
this._events = await fetchCalendarEvents(
|
||||||
|
this.hass!,
|
||||||
|
ev.detail.start,
|
||||||
|
ev.detail.end,
|
||||||
|
this._calendars
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _measureCard() {
|
||||||
|
const card = this.shadowRoot!.querySelector("ha-card");
|
||||||
|
if (!card) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._narrow = card.offsetWidth < 870;
|
||||||
|
this._veryNarrow = card.offsetWidth < 350;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _attachObserver(): Promise<void> {
|
||||||
|
if (!this._resizeObserver) {
|
||||||
|
await installResizeObserver();
|
||||||
|
this._resizeObserver = new ResizeObserver(
|
||||||
|
debounce(() => this._measureCard(), 250, false)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const card = this.shadowRoot!.querySelector("ha-card");
|
||||||
|
// If we show an error or warning there is no ha-card
|
||||||
|
if (!card) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._resizeObserver.observe(card);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
ha-card {
|
||||||
|
position: relative;
|
||||||
|
padding: 0 8px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
color: var(--ha-card-header-color, --primary-text-color);
|
||||||
|
font-size: var(--ha-card-header-font-size, 24px);
|
||||||
|
line-height: 1.2;
|
||||||
|
padding-top: 16px;
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-calendar-card": HuiCalendarCard;
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,12 @@ export interface AlarmPanelCardConfig extends LovelaceCardConfig {
|
|||||||
theme?: string;
|
theme?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CalendarCardConfig extends LovelaceCardConfig {
|
||||||
|
entities: string[];
|
||||||
|
title?: string;
|
||||||
|
theme?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ConditionalCardConfig extends LovelaceCardConfig {
|
export interface ConditionalCardConfig extends LovelaceCardConfig {
|
||||||
card: LovelaceCardConfig;
|
card: LovelaceCardConfig;
|
||||||
conditions: Condition[];
|
conditions: Condition[];
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { LovelaceCardConfig } from "../../../data/lovelace";
|
import { LovelaceCardConfig } from "../../../data/lovelace";
|
||||||
import "../cards/hui-button-card";
|
import "../cards/hui-button-card";
|
||||||
|
import "../cards/hui-calendar-card";
|
||||||
import "../cards/hui-entities-card";
|
import "../cards/hui-entities-card";
|
||||||
import "../cards/hui-entity-button-card";
|
import "../cards/hui-entity-button-card";
|
||||||
import "../cards/hui-entity-card";
|
import "../cards/hui-entity-card";
|
||||||
@ -52,6 +53,7 @@ const LAZY_LOAD_TYPES = {
|
|||||||
map: () => import("../cards/hui-map-card"),
|
map: () => import("../cards/hui-map-card"),
|
||||||
markdown: () => import("../cards/hui-markdown-card"),
|
markdown: () => import("../cards/hui-markdown-card"),
|
||||||
picture: () => import("../cards/hui-picture-card"),
|
picture: () => import("../cards/hui-picture-card"),
|
||||||
|
calendar: () => import("../cards/hui-calendar-card"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// This will not return an error card but will throw the error
|
// This will not return an error card but will throw the error
|
||||||
|
@ -0,0 +1,133 @@
|
|||||||
|
import {
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
TemplateResult,
|
||||||
|
internalProperty,
|
||||||
|
} from "lit-element";
|
||||||
|
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||||
|
import type { HomeAssistant } from "../../../../types";
|
||||||
|
import type { CalendarCardConfig } from "../../cards/types";
|
||||||
|
import "../../components/hui-entity-editor";
|
||||||
|
import "../../../../components/entity/ha-entities-picker";
|
||||||
|
import "../../components/hui-theme-select-editor";
|
||||||
|
import type { LovelaceCardEditor } from "../../types";
|
||||||
|
import type { EditorTarget, EntitiesEditorEvent } from "../types";
|
||||||
|
import { configElementStyle } from "./config-elements-style";
|
||||||
|
import {
|
||||||
|
string,
|
||||||
|
optional,
|
||||||
|
object,
|
||||||
|
boolean,
|
||||||
|
array,
|
||||||
|
union,
|
||||||
|
assert,
|
||||||
|
} from "superstruct";
|
||||||
|
|
||||||
|
const cardConfigStruct = object({
|
||||||
|
type: string(),
|
||||||
|
title: optional(union([string(), boolean()])),
|
||||||
|
theme: optional(string()),
|
||||||
|
entities: array(string()),
|
||||||
|
});
|
||||||
|
|
||||||
|
@customElement("hui-calendar-card-editor")
|
||||||
|
export class HuiCalendarCardEditor extends LitElement
|
||||||
|
implements LovelaceCardEditor {
|
||||||
|
@property({ attribute: false }) public hass?: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ attribute: false }) private _config?: CalendarCardConfig;
|
||||||
|
|
||||||
|
@internalProperty() private _configEntities?: string[];
|
||||||
|
|
||||||
|
public setConfig(config: CalendarCardConfig): void {
|
||||||
|
assert(config, cardConfigStruct);
|
||||||
|
this._config = config;
|
||||||
|
this._configEntities = config.entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
get _title(): string {
|
||||||
|
return this._config!.title || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
get _theme(): string {
|
||||||
|
return this._config!.theme || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected render(): TemplateResult {
|
||||||
|
if (!this.hass || !this._config) {
|
||||||
|
return html``;
|
||||||
|
}
|
||||||
|
|
||||||
|
return html`
|
||||||
|
${configElementStyle}
|
||||||
|
<div class="card-config">
|
||||||
|
<div class="side-by-side">
|
||||||
|
<paper-input
|
||||||
|
.label="${this.hass.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.generic.title"
|
||||||
|
)} (${this.hass.localize(
|
||||||
|
"ui.panel.lovelace.editor.card.config.optional"
|
||||||
|
)})"
|
||||||
|
.value=${this._title}
|
||||||
|
.configValue=${"title"}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
></paper-input>
|
||||||
|
<hui-theme-select-editor
|
||||||
|
.hass=${this.hass}
|
||||||
|
.value=${this._theme}
|
||||||
|
.configValue=${"theme"}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
></hui-theme-select-editor>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h3>
|
||||||
|
${"Calendar Entities" +
|
||||||
|
" (" +
|
||||||
|
this.hass!.localize("ui.panel.lovelace.editor.card.config.required") +
|
||||||
|
")"}
|
||||||
|
</h3>
|
||||||
|
<ha-entities-picker
|
||||||
|
.hass=${this.hass!}
|
||||||
|
.value=${this._configEntities}
|
||||||
|
.includeDomains=${["calendar"]}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
>
|
||||||
|
</ha-entities-picker>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _valueChanged(ev: EntitiesEditorEvent | CustomEvent): void {
|
||||||
|
if (!this._config || !this.hass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = ev.target! as EditorTarget;
|
||||||
|
|
||||||
|
if (this[`_${target.configValue}`] === target.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev.detail && ev.detail.value && Array.isArray(ev.detail.value)) {
|
||||||
|
this._config = { ...this._config, entities: ev.detail.value };
|
||||||
|
} else if (target.configValue) {
|
||||||
|
if (target.value === "") {
|
||||||
|
delete this._config[target.configValue!];
|
||||||
|
} else {
|
||||||
|
this._config = {
|
||||||
|
...this._config,
|
||||||
|
[target.configValue]: target.value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fireEvent(this, "config-changed", { config: this._config });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
"hui-calendar-card-editor": HuiCalendarCardEditor;
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,10 @@ export const coreCards: Card[] = [
|
|||||||
type: "button",
|
type: "button",
|
||||||
showElement: true,
|
showElement: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: "calendar",
|
||||||
|
showElement: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: "entities",
|
type: "entities",
|
||||||
showElement: true,
|
showElement: true,
|
||||||
|
@ -2134,6 +2134,10 @@
|
|||||||
"available_states": "Available States",
|
"available_states": "Available States",
|
||||||
"description": "The Alarm Panel card allows you to Arm and Disarm your alarm control panel integrations."
|
"description": "The Alarm Panel card allows you to Arm and Disarm your alarm control panel integrations."
|
||||||
},
|
},
|
||||||
|
"calendar": {
|
||||||
|
"name": "Calendar",
|
||||||
|
"description": "The Calendar card displays a calendar including day, week and list views"
|
||||||
|
},
|
||||||
"conditional": {
|
"conditional": {
|
||||||
"name": "Conditional",
|
"name": "Conditional",
|
||||||
"description": "The Conditional card displays another card based on entity states.",
|
"description": "The Conditional card displays another card based on entity states.",
|
||||||
|
14
src/types.ts
14
src/types.ts
@ -118,8 +118,8 @@ export interface Panels {
|
|||||||
|
|
||||||
export interface Calendar {
|
export interface Calendar {
|
||||||
entity_id: string;
|
entity_id: string;
|
||||||
name: string;
|
name?: string;
|
||||||
backgroundColor: string;
|
backgroundColor?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectedCalendar {
|
export interface SelectedCalendar {
|
||||||
@ -144,9 +144,15 @@ export interface CalendarViewChanged {
|
|||||||
view: string;
|
view: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type FullCalendarView =
|
||||||
|
| "dayGridMonth"
|
||||||
|
| "dayGridWeek"
|
||||||
|
| "dayGridDay"
|
||||||
|
| "listWeek";
|
||||||
|
|
||||||
export interface ToggleButton {
|
export interface ToggleButton {
|
||||||
label?: string;
|
label: string;
|
||||||
icon: string;
|
iconPath: string;
|
||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
52
yarn.lock
52
yarn.lock
@ -1184,20 +1184,45 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@formatjs/intl-utils/-/intl-utils-2.2.5.tgz#eaafd94df3d102ee13e54e80f992a33868a6b1e8"
|
resolved "https://registry.yarnpkg.com/@formatjs/intl-utils/-/intl-utils-2.2.5.tgz#eaafd94df3d102ee13e54e80f992a33868a6b1e8"
|
||||||
integrity sha512-p7gcmazKROteL4IECCp03Qrs790fZ8tbemUAjQu0+K0AaAlK49rI1SIFFq3LzDUAqXIshV95JJhRe/yXxkal5g==
|
integrity sha512-p7gcmazKROteL4IECCp03Qrs790fZ8tbemUAjQu0+K0AaAlK49rI1SIFFq3LzDUAqXIshV95JJhRe/yXxkal5g==
|
||||||
|
|
||||||
"@fullcalendar/core@^5.0.0-beta.2":
|
"@fullcalendar/common@5.1.0", "@fullcalendar/common@~5.1.0":
|
||||||
version "5.0.0-beta.2"
|
version "5.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@fullcalendar/core/-/core-5.0.0-beta.2.tgz#30a9cbbbf2d6476568f53cfa1c0746d06daa9660"
|
resolved "https://registry.yarnpkg.com/@fullcalendar/common/-/common-5.1.0.tgz#a45e01ebdcf00654f4d45f0457926cf2f5909820"
|
||||||
integrity sha512-9U/kk8Y4ackY1XZ1PHvX8rG1olixoKveStXdDsX3FCtKATR8fA/O+4Pd5qyH7nGcih8TrgreUjZ+dB+DEaomqQ==
|
integrity sha512-ubwf9T0BDocGLh0AK8achrmc0siQdrp3Wn6Rmg/Ht4/WnwBtjc5gumzJ0ezG/xHE0GWG+Pz6Tm0IJF/jE7NJHw==
|
||||||
dependencies:
|
dependencies:
|
||||||
preact "^10.0.5"
|
tslib "^2.0.0"
|
||||||
tslib "^1.9.3"
|
|
||||||
|
|
||||||
"@fullcalendar/daygrid@^5.0.0-beta.2":
|
"@fullcalendar/core@5.1.0":
|
||||||
version "5.0.0-beta.2"
|
version "5.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@fullcalendar/daygrid/-/daygrid-5.0.0-beta.2.tgz#fae2a7cba8a6afc23c9d6faaa88150d820e59a73"
|
resolved "https://registry.yarnpkg.com/@fullcalendar/core/-/core-5.1.0.tgz#0d9813b0564f24fe6285e31f8313d9366c6db411"
|
||||||
integrity sha512-Dd2VLsMPWPH1W1HQ+K1iftHVXF1MYOM/lo33FUdFKM8jc0MHnF620TVyOgPojAC26u2hApbURKIY2eY87vFulg==
|
integrity sha512-C9OA9LHD1zgfcMABQ17TaxvAO/iubYFLDrgTIRCe77LatC0G36UBafthevUlMRqCR6rt5SBcw0oBt23HqSJO3A==
|
||||||
dependencies:
|
dependencies:
|
||||||
tslib "^1.9.3"
|
"@fullcalendar/common" "~5.1.0"
|
||||||
|
preact "^10.0.5"
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
|
"@fullcalendar/daygrid@5.1.0":
|
||||||
|
version "5.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fullcalendar/daygrid/-/daygrid-5.1.0.tgz#4f8cb30e99ff00600f064645942d21e8f668c946"
|
||||||
|
integrity sha512-zdO/EFer8wWrr+kvkMfyizPi/F7yvOCpGOb6Arz6QqyOgFl1ffNUQoRf1iQf7h2PnIEvZWZdZs+3wuMwwmhb3g==
|
||||||
|
dependencies:
|
||||||
|
"@fullcalendar/common" "~5.1.0"
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
|
"@fullcalendar/interaction@5.1.0":
|
||||||
|
version "5.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fullcalendar/interaction/-/interaction-5.1.0.tgz#0e7c6fe17bf8532de2c994bde5fc6e9220c71a89"
|
||||||
|
integrity sha512-RuCtsVFXvGYk4vYz3Aq9+G8SMOG6iX+xNJmHELdmPfAatHTVyUSCD4GznxR1/fzUu74mb98X01DVkLwSB+78oA==
|
||||||
|
dependencies:
|
||||||
|
"@fullcalendar/common" "~5.1.0"
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
|
"@fullcalendar/list@5.1.0":
|
||||||
|
version "5.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@fullcalendar/list/-/list-5.1.0.tgz#e08b011cce8259fdee46ef8737bf98b31e6eac1a"
|
||||||
|
integrity sha512-FDLsInaLv0H/BwpoJ4RbC69M8yoJ3xoRnkulChAzhIBrwXAKOHJth5P+iNFJVVYI7DaPgSi0BzEwiu0dJdStHQ==
|
||||||
|
dependencies:
|
||||||
|
"@fullcalendar/common" "~5.1.0"
|
||||||
|
tslib "^2.0.0"
|
||||||
|
|
||||||
"@gfx/zopfli@^1.0.9":
|
"@gfx/zopfli@^1.0.9":
|
||||||
version "1.0.11"
|
version "1.0.11"
|
||||||
@ -11747,6 +11772,11 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
|
|||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
|
||||||
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
|
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
|
||||||
|
|
||||||
|
tslib@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.0.tgz#18d13fc2dce04051e20f074cc8387fd8089ce4f3"
|
||||||
|
integrity sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g==
|
||||||
|
|
||||||
tsutils@^3.17.1:
|
tsutils@^3.17.1:
|
||||||
version "3.17.1"
|
version "3.17.1"
|
||||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
|
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user