feat: add calendar event stacking configuration options (#1257, #1064)

Add user-configurable options for controlling how events display and
stack in the calendar view:
- slotEventOverlap: toggle visual overlap of timed events
- eventMaxStack: limit stacked events in week/day view
- dayMaxEvents: limit events per day in month view
- dayMaxEventRows: limit event rows per day in month view

Also includes dark mode styling fixes for the timeGrid more-link element
and translations for all supported locales.
This commit is contained in:
callumalpass 2025-11-30 18:45:53 +11:00
parent fa357a69f5
commit 00cc503384
17 changed files with 315 additions and 6 deletions

View file

@ -68,6 +68,7 @@ Example:
- Search existing tasks or type natural language to create new tasks (e.g., "Buy groceries tomorrow #shopping")
- Press Enter to select an existing task, Shift+Enter to create a new task
- Real-time preview shows parsed title, due date, priority, tags, and other metadata
- Can be used when adding sub-tasks to create sub-tasks on-the-fly
- Thanks to @luciolebrillante for the feature request
- (#1044), (#1222) Added unsaved changes confirmation when closing task edit modal
@ -87,6 +88,14 @@ Example:
- Example: `if(priority=="high",0,if(priority=="normal",1,if(priority=="low",2,999)))`
- Thanks to @jhedlund for the suggestion
- (#1257), (#1064) Added configurable event stacking options for Bases Calendar view
- **Allow events to overlap**: Toggle whether timed events visually overlap or display side-by-side in week/day views
- **Max stacked events**: Limit horizontal event stacking in week/day views (0 = unlimited)
- **Max events per day**: Limit events shown per day cell in month view (0 = auto based on cell height)
- **Max event rows per day**: Limit event rows per day cell in month view (0 = unlimited)
- Configure per-view in the Bases Calendar view settings under Layout
- Thanks to @3zra47 and @hasanyilmaz for the feature requests
## Changed
- Improved inline task conversion to merge TasksPlugin and NLP parsing results

View file

@ -18,6 +18,18 @@ You can also configure the **Calendar Locale** to change the calendar's language
You can control which types of events are shown by default in the calendar views, including scheduled tasks, tasks with due dates, recurring tasks, time entries, and events from external calendars.
## Event Display and Stacking
These settings control how events are displayed when multiple events occur at the same time or on the same day.
**Allow events to overlap** - When enabled, timed events in week and day views can visually overlap each other. When disabled, events are displayed side-by-side with no overlapping.
**Max stacked events (week/day view)** - Limits how many events can stack horizontally in the week and day views. When exceeded, a "+X more" link appears. Set to 0 for unlimited stacking.
**Max events per day (month view)** - Limits how many events are shown per day cell in month view. When exceeded, a "+X more" link appears. Set to 0 for automatic limiting based on cell height.
**Max event rows per day (month view)** - Limits how many rows of events are shown per day cell in month view. Set to 0 for unlimited rows.
## Timeblocking Features
You can enable or disable the **Timeblocking** feature in the Features tab, which allows you to create and manage timeblocks in the calendar views. When enabled, dragging on a time slot in the calendar view will display a context menu that includes the "Create timeblock" option.

View file

@ -167,6 +167,11 @@
"views.basesCalendar.settings.layout.initialScrollTime": "57489455a18c7f3f66048b39c934497b1a858b6b",
"views.basesCalendar.settings.layout.initialScrollTimePlaceholder": "76b7b3219aac0cf237e1aa634f4d4034665565d0",
"views.basesCalendar.settings.layout.minimumEventHeight": "0c7471e72296e1a9ba5487514e4c96c819b4e53a",
"views.basesCalendar.settings.layout.slotEventOverlap": "4f268fa7ce2545e141181e81a09d907c293505b7",
"views.basesCalendar.settings.layout.enableSearch": "c814e198f0848e59affefac11f1186ff95464085",
"views.basesCalendar.settings.layout.eventMaxStack": "33531c6baf7200666603776e293d9d6ef507fcec",
"views.basesCalendar.settings.layout.dayMaxEvents": "13a7bf6c528f5d52ea1f45a9a37059305351d609",
"views.basesCalendar.settings.layout.dayMaxEventRows": "c36df6fb674736e1999726e4446702c5ab4938fa",
"views.basesCalendar.settings.propertyBasedEvents.startDateProperty": "05c65e1fc55d32dc8aab0c001a11218e4ee4119c",
"views.basesCalendar.settings.propertyBasedEvents.startDatePropertyPlaceholder": "f46d1039527ed2dab5f0d0f1218cc0f45b2f6c42",
"views.basesCalendar.settings.propertyBasedEvents.endDateProperty": "5bd23d448ccda903b2388615927c2d497117466f",

View file

@ -672,6 +672,26 @@
"source": "0c7471e72296e1a9ba5487514e4c96c819b4e53a",
"translation": "9899569d7041013b13d8870aef0d224eac9c84cf"
},
"views.basesCalendar.settings.layout.slotEventOverlap": {
"source": "4f268fa7ce2545e141181e81a09d907c293505b7",
"translation": "16084bef7221db4e74746881ce7877a90b361ac8"
},
"views.basesCalendar.settings.layout.enableSearch": {
"source": "c814e198f0848e59affefac11f1186ff95464085",
"translation": "9752015595a2dbdf8c6dd41b606df87221908e6e"
},
"views.basesCalendar.settings.layout.eventMaxStack": {
"source": "33531c6baf7200666603776e293d9d6ef507fcec",
"translation": "d2b82746821b4464282c92cdb153536a75ba4819"
},
"views.basesCalendar.settings.layout.dayMaxEvents": {
"source": "13a7bf6c528f5d52ea1f45a9a37059305351d609",
"translation": "029ae1ea3a02b3917a10410bf2f3f7c2d4dbe2a4"
},
"views.basesCalendar.settings.layout.dayMaxEventRows": {
"source": "c36df6fb674736e1999726e4446702c5ab4938fa",
"translation": "444746b8d379be2e1a9a6632a99e6acd4c1f7d05"
},
"views.basesCalendar.settings.propertyBasedEvents.startDateProperty": {
"source": "05c65e1fc55d32dc8aab0c001a11218e4ee4119c",
"translation": "14ffc61439bc59829f7f6f92e7422158c370036a"
@ -7846,6 +7866,26 @@
"source": "0c7471e72296e1a9ba5487514e4c96c819b4e53a",
"translation": "7d970abc24a1ea8ff9f516cbe6010c6d7fb9e325"
},
"views.basesCalendar.settings.layout.slotEventOverlap": {
"source": "4f268fa7ce2545e141181e81a09d907c293505b7",
"translation": "a7d46bd7e90b4fdfedb596ffc4bfd56fe677a2c1"
},
"views.basesCalendar.settings.layout.enableSearch": {
"source": "c814e198f0848e59affefac11f1186ff95464085",
"translation": "389d3ee2dc8b82b244cbc1fc61c68b0e0ae193dd"
},
"views.basesCalendar.settings.layout.eventMaxStack": {
"source": "33531c6baf7200666603776e293d9d6ef507fcec",
"translation": "0e125a289ed0a3ac5dc3a8264a5bf11042977b84"
},
"views.basesCalendar.settings.layout.dayMaxEvents": {
"source": "13a7bf6c528f5d52ea1f45a9a37059305351d609",
"translation": "246098bff6e068a8f4f7abefedf2e90a10b6266e"
},
"views.basesCalendar.settings.layout.dayMaxEventRows": {
"source": "c36df6fb674736e1999726e4446702c5ab4938fa",
"translation": "7807b7c9ab99851eb47727fd6dff0a272e86438c"
},
"views.basesCalendar.settings.propertyBasedEvents.startDateProperty": {
"source": "05c65e1fc55d32dc8aab0c001a11218e4ee4119c",
"translation": "e1595c21e6dff6aa736d8e689f6414b130ccc13f"
@ -15020,6 +15060,26 @@
"source": "0c7471e72296e1a9ba5487514e4c96c819b4e53a",
"translation": "69932caff3a7e60d94199f6ab571fa8ac0288e11"
},
"views.basesCalendar.settings.layout.slotEventOverlap": {
"source": "4f268fa7ce2545e141181e81a09d907c293505b7",
"translation": "5ba447b7b44c99705e62ca37c1b7991892c070bf"
},
"views.basesCalendar.settings.layout.enableSearch": {
"source": "c814e198f0848e59affefac11f1186ff95464085",
"translation": "6fad57d0aa365ee05281094b72db7d33be7dc2a4"
},
"views.basesCalendar.settings.layout.eventMaxStack": {
"source": "33531c6baf7200666603776e293d9d6ef507fcec",
"translation": "15143c97661ca69add35026a99a0d40b2d374b26"
},
"views.basesCalendar.settings.layout.dayMaxEvents": {
"source": "13a7bf6c528f5d52ea1f45a9a37059305351d609",
"translation": "c55ea7bc1fbe2121fe8b0cf757e9e6f41f7e5a8d"
},
"views.basesCalendar.settings.layout.dayMaxEventRows": {
"source": "c36df6fb674736e1999726e4446702c5ab4938fa",
"translation": "c682d3eb1fab2c9548adfdea706775950fcf6779"
},
"views.basesCalendar.settings.propertyBasedEvents.startDateProperty": {
"source": "05c65e1fc55d32dc8aab0c001a11218e4ee4119c",
"translation": "203d111e33f69228908d5681133ccbe72f17dd99"
@ -22194,6 +22254,26 @@
"source": "0c7471e72296e1a9ba5487514e4c96c819b4e53a",
"translation": "b29e0df7212084d973911cd7651a9e42e74f2007"
},
"views.basesCalendar.settings.layout.slotEventOverlap": {
"source": "4f268fa7ce2545e141181e81a09d907c293505b7",
"translation": "4183339a41f281e72fe3769a25f619d31fbdca54"
},
"views.basesCalendar.settings.layout.enableSearch": {
"source": "c814e198f0848e59affefac11f1186ff95464085",
"translation": "79e90c4b5f88e93106da0901176fb530584e30fe"
},
"views.basesCalendar.settings.layout.eventMaxStack": {
"source": "33531c6baf7200666603776e293d9d6ef507fcec",
"translation": "130981bc3723501d489432756e1c8c77435c7386"
},
"views.basesCalendar.settings.layout.dayMaxEvents": {
"source": "13a7bf6c528f5d52ea1f45a9a37059305351d609",
"translation": "0e8800ad75bb44487ab035267e0c47178b0e0de0"
},
"views.basesCalendar.settings.layout.dayMaxEventRows": {
"source": "c36df6fb674736e1999726e4446702c5ab4938fa",
"translation": "1f2e0b32ea67b7bc88bff9979581689412b069ec"
},
"views.basesCalendar.settings.propertyBasedEvents.startDateProperty": {
"source": "05c65e1fc55d32dc8aab0c001a11218e4ee4119c",
"translation": "a563266dbf5e822216ebb842629702644bb73636"
@ -29368,6 +29448,26 @@
"source": "0c7471e72296e1a9ba5487514e4c96c819b4e53a",
"translation": "a9e578ac4f64ae08610c9545feb2e9cad0e936dc"
},
"views.basesCalendar.settings.layout.slotEventOverlap": {
"source": "4f268fa7ce2545e141181e81a09d907c293505b7",
"translation": "9e4092b46fcb4ce354809fdfe597b5ca1a86119d"
},
"views.basesCalendar.settings.layout.enableSearch": {
"source": "c814e198f0848e59affefac11f1186ff95464085",
"translation": "36deb7ea2780ffacb186a28284c51666b69e8911"
},
"views.basesCalendar.settings.layout.eventMaxStack": {
"source": "33531c6baf7200666603776e293d9d6ef507fcec",
"translation": "51527c04be75e348e2cd9f5b2d62ebb4330878d7"
},
"views.basesCalendar.settings.layout.dayMaxEvents": {
"source": "13a7bf6c528f5d52ea1f45a9a37059305351d609",
"translation": "fa0411414300e1604ea0be730d99e522b5738100"
},
"views.basesCalendar.settings.layout.dayMaxEventRows": {
"source": "c36df6fb674736e1999726e4446702c5ab4938fa",
"translation": "1aaa140c24f041e9b8584d986efc902a7b80d6ec"
},
"views.basesCalendar.settings.propertyBasedEvents.startDateProperty": {
"source": "05c65e1fc55d32dc8aab0c001a11218e4ee4119c",
"translation": "2efd3012d6e8d4c8d8d5e17e010ccbf10c7c4b1a"
@ -36542,6 +36642,26 @@
"source": "0c7471e72296e1a9ba5487514e4c96c819b4e53a",
"translation": "50663327fc5ba67975e8e5fa08adab8449d8d43e"
},
"views.basesCalendar.settings.layout.slotEventOverlap": {
"source": "4f268fa7ce2545e141181e81a09d907c293505b7",
"translation": "794384386430a0bfbb8aeb13765e26e3470067ef"
},
"views.basesCalendar.settings.layout.enableSearch": {
"source": "c814e198f0848e59affefac11f1186ff95464085",
"translation": "04ad3b19e9cda738f16f899f80a056222bb7df78"
},
"views.basesCalendar.settings.layout.eventMaxStack": {
"source": "33531c6baf7200666603776e293d9d6ef507fcec",
"translation": "32831b47fd4ae9a90d4486e87c37f77909b574a5"
},
"views.basesCalendar.settings.layout.dayMaxEvents": {
"source": "13a7bf6c528f5d52ea1f45a9a37059305351d609",
"translation": "df38ee14c9f43048db482aa2d2dac096e0636108"
},
"views.basesCalendar.settings.layout.dayMaxEventRows": {
"source": "c36df6fb674736e1999726e4446702c5ab4938fa",
"translation": "5bce529be6bbe9de882971c455d651564f72ffd2"
},
"views.basesCalendar.settings.propertyBasedEvents.startDateProperty": {
"source": "05c65e1fc55d32dc8aab0c001a11218e4ee4119c",
"translation": "76ca7e2d4d189ade6e69c3bbde68bf280ab93da1"
@ -43716,6 +43836,26 @@
"source": "0c7471e72296e1a9ba5487514e4c96c819b4e53a",
"translation": "1dc77fabfa7166ff86c4d70720c99e1a21d6a072"
},
"views.basesCalendar.settings.layout.slotEventOverlap": {
"source": "4f268fa7ce2545e141181e81a09d907c293505b7",
"translation": "c6ac2feea0c7290d03c8171d85d48f877dee9be3"
},
"views.basesCalendar.settings.layout.enableSearch": {
"source": "c814e198f0848e59affefac11f1186ff95464085",
"translation": "657b6f387cbe9adf6e84063e19ab492890ff57d0"
},
"views.basesCalendar.settings.layout.eventMaxStack": {
"source": "33531c6baf7200666603776e293d9d6ef507fcec",
"translation": "457dfbcd888b94be03d9e3282e8480d943dfd3b6"
},
"views.basesCalendar.settings.layout.dayMaxEvents": {
"source": "13a7bf6c528f5d52ea1f45a9a37059305351d609",
"translation": "fbe10e475d188602de8ce62a86574101beb0f24a"
},
"views.basesCalendar.settings.layout.dayMaxEventRows": {
"source": "c36df6fb674736e1999726e4446702c5ab4938fa",
"translation": "e1e19ae69d25c529a01b733ba69e1c68dbdc2d84"
},
"views.basesCalendar.settings.propertyBasedEvents.startDateProperty": {
"source": "05c65e1fc55d32dc8aab0c001a11218e4ee4119c",
"translation": "c1a169c76040d5baa529dee7a2edc6550ef02ca9"

View file

@ -125,6 +125,10 @@ export class CalendarView extends BasesViewBase {
timeFormat: string;
scrollTime: string;
eventMinHeight: number;
slotEventOverlap: boolean;
eventMaxStack: number | null;
dayMaxEvents: number | boolean;
dayMaxEventRows: number | boolean;
// Locale (non-configurable per view)
locale: string;
@ -181,6 +185,10 @@ export class CalendarView extends BasesViewBase {
selectMirror: calendarSettings.selectMirror,
timeFormat: calendarSettings.timeFormat,
eventMinHeight: calendarSettings.eventMinHeight,
slotEventOverlap: calendarSettings.slotEventOverlap,
eventMaxStack: calendarSettings.eventMaxStack,
dayMaxEvents: calendarSettings.dayMaxEvents,
dayMaxEventRows: calendarSettings.dayMaxEventRows,
locale: calendarSettings.locale,
// Property-based events
@ -365,6 +373,25 @@ export class CalendarView extends BasesViewBase {
this.viewOptions.selectMirror = this.config.get('selectMirror') ?? this.viewOptions.selectMirror;
this.viewOptions.timeFormat = this.config.get('timeFormat') ?? this.viewOptions.timeFormat;
this.viewOptions.eventMinHeight = this.config.get('eventMinHeight') ?? this.viewOptions.eventMinHeight;
this.viewOptions.slotEventOverlap = this.config.get('slotEventOverlap') ?? this.viewOptions.slotEventOverlap;
// Convert slider values: 0 means special behavior (null/true/false)
const eventMaxStackValue = this.config.get('eventMaxStack');
if (eventMaxStackValue !== undefined) {
this.viewOptions.eventMaxStack = eventMaxStackValue === 0 ? null : eventMaxStackValue;
}
const dayMaxEventsValue = this.config.get('dayMaxEvents');
if (dayMaxEventsValue !== undefined) {
// 0 = auto (true), positive number = limit
this.viewOptions.dayMaxEvents = dayMaxEventsValue === 0 ? true : dayMaxEventsValue;
}
const dayMaxEventRowsValue = this.config.get('dayMaxEventRows');
if (dayMaxEventRowsValue !== undefined) {
// 0 = unlimited (false), positive number = limit
this.viewOptions.dayMaxEventRows = dayMaxEventRowsValue === 0 ? false : dayMaxEventRowsValue;
}
// Property-based events
this.viewOptions.startDateProperty = this.config.get('startDateProperty') ?? this.viewOptions.startDateProperty;
@ -531,7 +558,9 @@ export class CalendarView extends BasesViewBase {
nowIndicator: this.viewOptions.nowIndicator,
weekends: this.viewOptions.showWeekends,
allDaySlot: this.viewOptions.showAllDaySlot,
dayMaxEvents: true,
dayMaxEvents: this.viewOptions.dayMaxEvents,
dayMaxEventRows: this.viewOptions.dayMaxEventRows,
eventMaxStack: this.viewOptions.eventMaxStack ?? undefined,
navLinks: true,
navLinkDayClick: (date: Date) => handleDateTitleClick(date, this.plugin),
editable: true,
@ -549,6 +578,7 @@ export class CalendarView extends BasesViewBase {
},
scrollTime: this.viewOptions.scrollTime,
eventMinHeight: this.viewOptions.eventMinHeight,
slotEventOverlap: this.viewOptions.slotEventOverlap,
eventAllow: () => true, // Allow all drops to proceed visually
events: (fetchInfo, successCallback, failureCallback) => {
this.fetchEvents(fetchInfo, successCallback, failureCallback);

View file

@ -299,6 +299,18 @@ export async function registerBasesTaskList(plugin: TaskNotesPlugin): Promise<vo
displayName: t("layout.showSelectionPreview"),
default: calendarSettings.selectMirror,
},
{
type: "toggle",
key: "slotEventOverlap",
displayName: t("layout.slotEventOverlap"),
default: calendarSettings.slotEventOverlap,
},
{
type: "toggle",
key: "enableSearch",
displayName: t("layout.enableSearch"),
default: false,
},
{
type: "dropdown",
key: "timeFormat",
@ -326,10 +338,31 @@ export async function registerBasesTaskList(plugin: TaskNotesPlugin): Promise<vo
step: 5,
},
{
type: "toggle",
key: "enableSearch",
displayName: "Enable search box",
default: false,
type: "slider",
key: "eventMaxStack",
displayName: t("layout.eventMaxStack"),
default: calendarSettings.eventMaxStack ?? 0,
min: 0,
max: 10,
step: 1,
},
{
type: "slider",
key: "dayMaxEvents",
displayName: t("layout.dayMaxEvents"),
default: typeof calendarSettings.dayMaxEvents === 'number' ? calendarSettings.dayMaxEvents : 0,
min: 0,
max: 20,
step: 1,
},
{
type: "slider",
key: "dayMaxEventRows",
displayName: t("layout.dayMaxEventRows"),
default: typeof calendarSettings.dayMaxEventRows === 'number' ? calendarSettings.dayMaxEventRows : 0,
min: 0,
max: 10,
step: 1,
},
],
},

View file

@ -229,6 +229,11 @@ export const de: TranslationTree = {
initialScrollTime: "Anfangsscrollzeit",
initialScrollTimePlaceholder: "HH:mm:ss (z.B. 08:00:00)",
minimumEventHeight: "Minimale Ereignishöhe (px)",
slotEventOverlap: "Ereignisüberlappung zulassen",
enableSearch: "Suchfeld aktivieren",
eventMaxStack: "Max. gestapelte Ereignisse (Wochen-/Tagesansicht, 0 = unbegrenzt)",
dayMaxEvents: "Max. Ereignisse pro Tag (Monatsansicht, 0 = automatisch)",
dayMaxEventRows: "Max. Ereigniszeilen pro Tag (Monatsansicht, 0 = unbegrenzt)",
},
propertyBasedEvents: {
startDateProperty: "Startdatumseigenschaft",

View file

@ -231,6 +231,11 @@ export const en: TranslationTree = {
initialScrollTime: "Initial scroll time",
initialScrollTimePlaceholder: "HH:mm:ss (e.g., 08:00:00)",
minimumEventHeight: "Minimum event height (px)",
slotEventOverlap: "Allow events to overlap",
enableSearch: "Enable search box",
eventMaxStack: "Max stacked events (week/day view, 0 = unlimited)",
dayMaxEvents: "Max events per day (month view, 0 = auto)",
dayMaxEventRows: "Max event rows per day (month view, 0 = unlimited)",
},
propertyBasedEvents: {
startDateProperty: "Start date property",

View file

@ -229,6 +229,11 @@ export const es: TranslationTree = {
initialScrollTime: "Hora de desplazamiento inicial",
initialScrollTimePlaceholder: "HH:mm:ss (ej. 08:00:00)",
minimumEventHeight: "Altura mínima del evento (px)",
slotEventOverlap: "Permitir superposición de eventos",
enableSearch: "Habilitar cuadro de búsqueda",
eventMaxStack: "Máx. eventos apilados (vista semana/día, 0 = ilimitado)",
dayMaxEvents: "Máx. eventos por día (vista mes, 0 = automático)",
dayMaxEventRows: "Máx. filas de eventos por día (vista mes, 0 = ilimitado)",
},
propertyBasedEvents: {
startDateProperty: "Propiedad de fecha de inicio",

View file

@ -229,6 +229,11 @@ export const fr: TranslationTree = {
initialScrollTime: "Heure de défilement initial",
initialScrollTimePlaceholder: "HH:mm:ss (ex. 08:00:00)",
minimumEventHeight: "Hauteur minimale de l'événement (px)",
slotEventOverlap: "Autoriser le chevauchement des événements",
enableSearch: "Activer la zone de recherche",
eventMaxStack: "Max. événements empilés (vue semaine/jour, 0 = illimité)",
dayMaxEvents: "Max. événements par jour (vue mois, 0 = automatique)",
dayMaxEventRows: "Max. lignes d'événements par jour (vue mois, 0 = illimité)",
},
propertyBasedEvents: {
startDateProperty: "Propriété de date de début",

View file

@ -229,6 +229,11 @@ export const ja: TranslationTree = {
initialScrollTime: "初期スクロール時刻",
initialScrollTimePlaceholder: "HH:mm:ss08:00:00",
minimumEventHeight: "最小イベント高さpx",
slotEventOverlap: "イベントの重なりを許可",
enableSearch: "検索ボックスを有効化",
eventMaxStack: "最大スタックイベント数(週/日表示、0 = 無制限)",
dayMaxEvents: "1日あたりの最大イベント数月表示、0 = 自動)",
dayMaxEventRows: "1日あたりの最大イベント行数月表示、0 = 無制限)",
},
propertyBasedEvents: {
startDateProperty: "開始日プロパティ",

View file

@ -228,7 +228,12 @@ export const pt: TranslationTree = {
timeFormat24: "24 horas",
initialScrollTime: "Hora inicial de rolagem",
initialScrollTimePlaceholder: "HH:mm:ss (ex: 08:00:00)",
minimumEventHeight: "Altura mínima do evento (px)"
minimumEventHeight: "Altura mínima do evento (px)",
slotEventOverlap: "Permitir sobreposição de eventos",
enableSearch: "Habilitar caixa de pesquisa",
eventMaxStack: "Máx. eventos empilhados (vista semana/dia, 0 = ilimitado)",
dayMaxEvents: "Máx. eventos por dia (vista mês, 0 = automático)",
dayMaxEventRows: "Máx. linhas de eventos por dia (vista mês, 0 = ilimitado)"
},
propertyBasedEvents: {
startDateProperty: "Propriedade da data de início",

View file

@ -229,6 +229,11 @@ export const ru: TranslationTree = {
initialScrollTime: "Начальное время прокрутки",
initialScrollTimePlaceholder: "ЧЧ:мм:сс (например, 08:00:00)",
minimumEventHeight: "Минимальная высота события (px)",
slotEventOverlap: "Разрешить наложение событий",
enableSearch: "Включить поле поиска",
eventMaxStack: "Макс. наложенных событий (неделя/день, 0 = без ограничений)",
dayMaxEvents: "Макс. событий в день (месяц, 0 = авто)",
dayMaxEventRows: "Макс. строк событий в день (месяц, 0 = без ограничений)",
},
propertyBasedEvents: {
startDateProperty: "Свойство даты начала",

View file

@ -223,6 +223,11 @@ export const zh: TranslationTree = {
showAllDaySlot: "显示全天时段",
showTodayHighlight: "突出显示今天",
showSelectionPreview: "显示选择预览",
slotEventOverlap: "允许事件重叠",
enableSearch: "启用搜索框",
eventMaxStack: "最大堆叠事件数(周/日视图0 = 无限制)",
dayMaxEvents: "每天最大事件数月视图0 = 自动)",
dayMaxEventRows: "每天最大事件行数月视图0 = 无限制)",
timeFormat: "时间格式",
timeFormat12: "12小时制AM/PM",
timeFormat24: "24小时制",

View file

@ -172,6 +172,11 @@ export const DEFAULT_CALENDAR_VIEW_SETTINGS: CalendarViewSettings = {
showTodayHighlight: true,
// Event display
eventMinHeight: 15, // FullCalendar default
// Event overlap and stacking behavior
slotEventOverlap: true, // FullCalendar default - events can visually overlap
eventMaxStack: null, // No limit on stacked events in timeGrid (null = unlimited)
dayMaxEvents: true, // Auto-limit based on cell height in dayGrid
dayMaxEventRows: false, // No row limit in dayGrid (false = unlimited)
};
export const DEFAULT_ICS_INTEGRATION_SETTINGS: ICSIntegrationSettings = {

View file

@ -317,4 +317,9 @@ export interface CalendarViewSettings {
showTodayHighlight: boolean;
// Event display
eventMinHeight: number; // Minimum height for events (FullCalendar eventMinHeight)
// Event overlap and stacking behavior
slotEventOverlap: boolean; // Whether timed events should visually overlap (false = side-by-side)
eventMaxStack: number | null; // Max events stacked in timeGrid view (null = unlimited)
dayMaxEvents: number | boolean; // Max events per day in dayGrid view (true = auto, number = limit, false = unlimited)
dayMaxEventRows: number | boolean; // Max event rows per day in dayGrid view (true = auto, number = limit, false = unlimited)
}

View file

@ -1288,3 +1288,33 @@
background: var(--background-primary) !important;
color: var(--text-normal) !important;
}
/* Dark mode fixes for timeGrid more link (eventMaxStack) */
.advanced-calendar-view .fc-timegrid-more-link {
color: var(--text-normal);
background: var(--background-secondary);
border: 1px solid var(--background-modifier-border);
border-radius: 4px;
padding: 2px 6px;
font-size: 0.75rem;
font-weight: 500;
text-decoration: none;
display: inline-block;
margin-top: 2px;
}
.advanced-calendar-view .fc-timegrid-more-link:hover {
background: var(--background-modifier-hover);
color: var(--text-normal);
}
.theme-dark .advanced-calendar-view .fc-timegrid-more-link {
background: var(--background-secondary);
color: var(--text-normal);
border-color: var(--background-modifier-border);
}
.theme-dark .advanced-calendar-view .fc-timegrid-more-link:hover {
background: var(--background-modifier-hover);
color: var(--text-normal);
}