From d5ce67e1675bbc41fc7ccc26ab61fc170c195318 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Sat, 10 Oct 2026 22:57:37 +0200 Subject: [PATCH] feat(calendar): create events from a quick editor next to the clicked slot Clicking or dragging over empty time in the week or day view used to open the full event panel. On wide screens it now draws the new event at that spot as a "(No title)" block and opens a small editor beside it with a title field, the picked time, a calendar picker, Save and "More options". More options carries the title, time and calendar over into the full editor. Enter saves, Escape or a click elsewhere discards. Phones keep opening the full editor. The placeholder for an event being created is now drawn like a saved event, in the calendar's colour, instead of a dashed outline. --- components/calendar/calendar-app.tsx | 111 +++++++++- components/calendar/calendar-day-view.tsx | 16 +- components/calendar/calendar-week-view.tsx | 16 +- components/calendar/event-modal.tsx | 5 +- components/calendar/quick-create-popover.tsx | 209 +++++++++++++++++++ locales/ar/common.json | 4 +- locales/ca/common.json | 4 +- locales/cs/common.json | 4 +- locales/da/common.json | 4 +- locales/de/common.json | 4 +- locales/en/common.json | 4 +- locales/es/common.json | 4 +- locales/fa/common.json | 4 +- locales/fr/common.json | 4 +- locales/he/common.json | 4 +- locales/hu/common.json | 4 +- locales/it/common.json | 4 +- locales/ja/common.json | 4 +- locales/ko/common.json | 4 +- locales/lv/common.json | 4 +- locales/mn/common.json | 4 +- locales/nb/common.json | 4 +- locales/nl/common.json | 4 +- locales/pl/common.json | 4 +- locales/pt/common.json | 4 +- locales/ro/common.json | 4 +- locales/ru/common.json | 4 +- locales/sk/common.json | 4 +- locales/tr/common.json | 4 +- locales/uk/common.json | 4 +- locales/zh-TW/common.json | 4 +- locales/zh/common.json | 4 +- 32 files changed, 419 insertions(+), 46 deletions(-) create mode 100644 components/calendar/quick-create-popover.tsx diff --git a/components/calendar/calendar-app.tsx b/components/calendar/calendar-app.tsx index 53aa4d2b8..84380754d 100644 --- a/components/calendar/calendar-app.tsx +++ b/components/calendar/calendar-app.tsx @@ -63,10 +63,12 @@ import { } from "@/lib/recurrence-instances"; import { getClientByLocalAccountId } from "@/stores/client-registry"; import { getEventStartDate } from "@/lib/calendar-utils"; -import { displayNow } from "@/lib/timezone"; +import { displayNow, getEffectiveTimeZone } from "@/lib/timezone"; +import { canCreateEventsIn } from "@/lib/calendar-editability"; +import { QuickCreatePopover, type QuickCreateDraft } from "@/components/calendar/quick-create-popover"; import { useTaskStore } from "@/stores/task-store"; import { useContactStore } from "@/stores/contact-store"; -import { cn } from "@/lib/utils"; +import { cn, generateUUID } from "@/lib/utils"; import type { Calendar, CalendarEvent, CalendarParticipant, CalendarRights, CalendarTask } from "@/lib/jmap/types"; import { ShareCollectionDialog } from "@/components/settings/share-collection-dialog"; import { ConfirmDialog } from "@/components/ui/confirm-dialog"; @@ -188,6 +190,10 @@ export function CalendarApp({ linkSegments: routeSegments }: CalendarAppProps = const [detailEvent, setDetailEvent] = useState(null); const [detailAnchorRect, setDetailAnchorRect] = useState(null); const [pendingPreview, setPendingPreview] = useState(null); + // Quick create (#calendar redesign): an empty slot clicked in the week or + // day view opens a small editor beside a placeholder block. + const [quickDraft, setQuickDraft] = useState(null); + const [defaultModalTitle, setDefaultModalTitle] = useState(); const [showTaskModal, setShowTaskModal] = useState(false); const [editTask, setEditTask] = useState(null); const [mobileReturnToMonth, setMobileReturnToMonth] = useState(false); @@ -599,6 +605,8 @@ export function CalendarApp({ linkSegments: routeSegments }: CalendarAppProps = }, [jumpTo]); const openCreateModal = useCallback((date?: Date, endDate?: Date, allDay?: boolean) => { + setQuickDraft(null); + setDefaultModalTitle(undefined); setEditEvent(null); const d = date || selectedDate; setDefaultModalDate(d); @@ -956,6 +964,83 @@ export function CalendarApp({ linkSegments: routeSegments }: CalendarAppProps = await save(requestedScheduling); }, [client, editEvent, createEvent, updateEvent, focusCalendarOnEvent, confirmAction, t]); + // Calendars a new event can go into: never a subscription or read-only one (#762). + const writableCalendars = useMemo( + () => calendars.filter((c) => !c.isTasksOnly && canCreateEventsIn(c, isSubscriptionCalendar)), + [calendars, isSubscriptionCalendar], + ); + + // A click or drag on empty grid space. On wide screens it opens the quick + // editor at that spot; on phones the full editor, as before. + const handleGridCreate = useCallback((start: Date, end?: Date) => { + if (isMobile) { + openCreateModal(start, end); + return; + } + const finalEnd = end ?? new Date(start.getTime() + 60 * 60 * 1000); + const preferred = writableCalendars.find((c) => c.isDefault) ?? writableCalendars[0]; + setShowEventModal(false); + setEditEvent(null); + setShowTaskModal(false); + setEditTask(null); + setDetailEvent(null); + setDetailAnchorRect(null); + setQuickDraft((prev) => ({ + start, + end: finalEnd, + title: "", + calendarId: prev && writableCalendars.some((c) => c.id === prev.calendarId) + ? prev.calendarId + : preferred?.id ?? "", + })); + }, [isMobile, openCreateModal, writableCalendars]); + + const closeQuickCreate = useCallback(() => setQuickDraft(null), []); + + const handleQuickCreateMoreOptions = useCallback(() => { + if (!quickDraft) return; + const draft = quickDraft; + openCreateModal(draft.start, draft.end); + setDefaultCalendarIdForCreate(draft.calendarId || undefined); + setDefaultModalTitle(draft.title || undefined); + }, [quickDraft, openCreateModal]); + + const handleQuickCreateSave = useCallback(async () => { + if (!quickDraft) return; + const { start, end, title, calendarId } = quickDraft; + const minutes = Math.max(15, Math.round((end.getTime() - start.getTime()) / 60000)); + const hours = Math.floor(minutes / 60); + const rest = minutes % 60; + const duration = `PT${hours > 0 ? `${hours}H` : ""}${rest > 0 ? `${rest}M` : ""}`; + setQuickDraft(null); + // Grid dates are wall-clock times in the user's zone (#755), the same + // as the full editor's fields, so they are labelled with that zone. + await handleSaveEvent({ + uid: generateUUID(), + title: title.trim(), + start: format(start, "yyyy-MM-dd'T'HH:mm:ss"), + duration, + timeZone: getEffectiveTimeZone(), + showWithoutTime: false, + calendarIds: { [calendarId]: true }, + status: "confirmed", + freeBusyStatus: "busy", + privacy: "public", + }); + }, [quickDraft, handleSaveEvent]); + + // While the quick editor is open its placeholder takes the preview slot. + const gridPreview = useMemo(() => { + if (!quickDraft) return pendingPreview; + return { + start: quickDraft.start, + end: quickDraft.end, + title: quickDraft.title.trim() || t("events.no_title"), + allDay: false, + calendarId: quickDraft.calendarId, + }; + }, [quickDraft, pendingPreview, t]); + const handleDuplicateEvent = useCallback(async (data: Partial) => { if (!client) { toast.error(t("notifications.event_error")); return; } try { @@ -1502,11 +1587,11 @@ export function CalendarApp({ linkSegments: routeSegments }: CalendarAppProps = onHoverLeave={handleHoverLeave} onContextMenuEvent={handleContextMenuEvent} onContextMenuEmpty={handleContextMenuEmpty} - onCreateAtTime={openCreateModal} + onCreateAtTime={handleGridCreate} firstDayOfWeek={firstDayOfWeek} timeFormat={timeFormat} isMobile={isMobile} - pendingPreview={pendingPreview} + pendingPreview={gridPreview} tasks={calendarTasks} onToggleTaskComplete={handleToggleTaskComplete} onSelectTask={openEditTaskModal} @@ -1525,10 +1610,10 @@ export function CalendarApp({ linkSegments: routeSegments }: CalendarAppProps = onHoverLeave={handleHoverLeave} onContextMenuEvent={handleContextMenuEvent} onContextMenuEmpty={handleContextMenuEmpty} - onCreateAtTime={openCreateModal} + onCreateAtTime={handleGridCreate} timeFormat={timeFormat} isMobile={isMobile} - pendingPreview={pendingPreview} + pendingPreview={gridPreview} tasks={calendarTasks} onToggleTaskComplete={handleToggleTaskComplete} onSelectTask={openEditTaskModal} @@ -1804,6 +1889,7 @@ export function CalendarApp({ linkSegments: routeSegments }: CalendarAppProps = defaultDate={defaultModalDate} defaultEndDate={defaultModalEndDate} defaultAllDay={defaultModalAllDay} + defaultTitle={defaultModalTitle} defaultCalendarId={defaultCalendarIdForCreate} onSave={handleSaveEvent} onDelete={handleDeleteEvent} @@ -1912,6 +1998,18 @@ export function CalendarApp({ linkSegments: routeSegments }: CalendarAppProps = ); })()} + {quickDraft && !isMobile && ( + + )} + {detailEvent && detailAnchorRect && ( = hours.endMinutes) return null; const clip = clipToDisplayHours(startMin, startMin + durationMin, hours); const cal = calendars.find(c => c.id === pendingPreview.calendarId); - const color = cal?.color || "hsl(var(--primary))"; + const color = cal?.color || "#3b82f6"; + // Drawn like a saved event, so the new event shows where + // it will land while it is being created. return (
-
+
{pendingPreview.title}
-
+
{formatSnapTime(startMin, timeFormat)} – {formatSnapTime(startMin + durationMin, timeFormat)}
diff --git a/components/calendar/calendar-week-view.tsx b/components/calendar/calendar-week-view.tsx index 44f4c7a18..2a342a034 100644 --- a/components/calendar/calendar-week-view.tsx +++ b/components/calendar/calendar-week-view.tsx @@ -22,6 +22,7 @@ import { useTimeGridInteractions } from "@/hooks/use-time-grid-interactions"; import { useScrollWindow, getScrollStart, setScrollStart, scrollToStart } from "@/hooks/use-scroll-window"; import { dayKey, type ScrollWindowViewProps } from "@/lib/calendar-scroll-window"; import type { PendingEventPreview } from "./event-modal"; +import { readableTextOn } from "@/lib/color-transform"; interface CalendarWeekViewProps extends ScrollWindowViewProps { selectedDate: Date; @@ -738,21 +739,24 @@ export function CalendarWeekView({ if (startMin + durationMin <= hours.startMinutes || startMin >= hours.endMinutes) return null; const clip = clipToDisplayHours(startMin, startMin + durationMin, hours); const cal = calendars.find(c => c.id === pendingPreview.calendarId); - const color = cal?.color || "hsl(var(--primary))"; + const color = cal?.color || "#3b82f6"; + // Drawn like a saved event, so the new event shows where + // it will land while it is being created. return (
-
+
{pendingPreview.title}
-
+
{formatSnapTime(startMin, timeFormat)} – {formatSnapTime(startMin + durationMin, timeFormat)}
diff --git a/components/calendar/event-modal.tsx b/components/calendar/event-modal.tsx index e2eccfe67..f15e2fae8 100644 --- a/components/calendar/event-modal.tsx +++ b/components/calendar/event-modal.tsx @@ -49,6 +49,8 @@ interface EventModalProps { defaultDate?: Date; defaultEndDate?: Date; defaultAllDay?: boolean; + /** Title to start a new event with (from the quick editor's "More options"). */ + defaultTitle?: string; defaultCalendarId?: string; onSave: (data: Partial, sendSchedulingMessages?: boolean) => void | Promise; onDelete?: (id: string, sendSchedulingMessages?: boolean) => void; @@ -192,6 +194,7 @@ export function EventModal({ defaultDate, defaultEndDate, defaultAllDay, + defaultTitle, defaultCalendarId, onSave, onDelete, @@ -299,7 +302,7 @@ export function EventModal({ return addHours(getInitialStart(), 1); }; - const [title, setTitle] = useState(event?.title || ""); + const [title, setTitle] = useState(event?.title || defaultTitle || ""); const [description, setDescription] = useState(event?.description || ""); const [location, setLocation] = useState( event?.locations ? Object.values(event.locations)[0]?.name || "" : "" diff --git a/components/calendar/quick-create-popover.tsx b/components/calendar/quick-create-popover.tsx new file mode 100644 index 000000000..960f49a75 --- /dev/null +++ b/components/calendar/quick-create-popover.tsx @@ -0,0 +1,209 @@ +"use client"; + +import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react"; +import { createPortal } from "react-dom"; +import { useTranslations } from "next-intl"; +import { format } from "date-fns"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Clock, X } from "@/components/icons"; +import type { Calendar } from "@/lib/jmap/types"; +import { useDisplayDateFormatter } from "@/hooks/use-display-date-formatter"; + +export interface QuickCreateDraft { + start: Date; + end: Date; + title: string; + calendarId: string; +} + +interface QuickCreatePopoverProps { + draft: QuickCreateDraft; + /** Calendars new events can go into. */ + calendars: Calendar[]; + timeFormat?: "12h" | "24h"; + onChange: (draft: QuickCreateDraft) => void; + onSave: () => void; + onMoreOptions: () => void; + onClose: () => void; +} + +const WIDTH = 340; +const GAP = 8; +const MARGIN = 12; + +// The views draw the new event's placeholder block with this attribute; the +// popover sits beside it, or under it when neither side has room. +const PLACEHOLDER_SELECTOR = "[data-pending-preview]"; + +function computePosition(anchor: DOMRect | null, height: number): { top: number; left: number } { + const vw = window.innerWidth; + const vh = window.innerHeight; + if (!anchor) return { top: Math.max(MARGIN, (vh - height) / 2), left: Math.max(MARGIN, (vw - WIDTH) / 2) }; + const clampTop = (top: number) => Math.min(Math.max(MARGIN, top), vh - height - MARGIN); + const clampLeft = (left: number) => Math.min(Math.max(MARGIN, left), vw - WIDTH - MARGIN); + if (anchor.right + GAP + WIDTH + MARGIN <= vw) return { top: clampTop(anchor.top), left: anchor.right + GAP }; + if (anchor.left - GAP - WIDTH >= MARGIN) return { top: clampTop(anchor.top), left: anchor.left - GAP - WIDTH }; + if (anchor.bottom + GAP + height + MARGIN <= vh) return { top: anchor.bottom + GAP, left: clampLeft(anchor.left) }; + return { top: Math.max(MARGIN, anchor.top - GAP - height), left: clampLeft(anchor.left) }; +} + +/** + * Compact editor that opens next to an empty slot clicked in the week or + * day view: a title, the time that was picked, the calendar, and a way into + * the full editor. Enter saves, Escape or a click elsewhere discards. + */ +export function QuickCreatePopover({ + draft, + calendars, + timeFormat = "24h", + onChange, + onSave, + onMoreOptions, + onClose, +}: QuickCreatePopoverProps) { + const t = useTranslations("calendar"); + const intlFormatter = useDisplayDateFormatter(); + const ref = useRef(null); + const inputRef = useRef(null); + const [position, setPosition] = useState<{ top: number; left: number } | null>(null); + + // Re-anchor when the draft moves (a new slot) and once the placeholder + // block has been drawn by the view. + const startKey = draft.start.getTime(); + const endKey = draft.end.getTime(); + useLayoutEffect(() => { + const place = () => { + const node = ref.current; + if (!node) return; + const anchor = document.querySelector(PLACEHOLDER_SELECTOR)?.getBoundingClientRect() ?? null; + setPosition(computePosition(anchor, node.offsetHeight)); + }; + place(); + const frame = requestAnimationFrame(place); + return () => cancelAnimationFrame(frame); + }, [startKey, endKey]); + + // Focus once placed. Chrome sometimes refuses the first focus() right + // after the slot click that opened the popover, so try again briefly. + const placed = position !== null; + useEffect(() => { + if (!placed) return; + let attempts = 0; + let timer: ReturnType | null = null; + const tryFocus = () => { + const el = inputRef.current; + if (!el) return; + el.focus(); + if (document.activeElement !== el && ++attempts < 5) timer = setTimeout(tryFocus, 50); + }; + const frame = requestAnimationFrame(tryFocus); + return () => { + cancelAnimationFrame(frame); + if (timer) clearTimeout(timer); + }; + }, [startKey, placed]); + + useEffect(() => { + const handleMouseDown = (e: MouseEvent) => { + if (ref.current && !ref.current.contains(e.target as Node)) onClose(); + }; + const handleKey = (e: KeyboardEvent) => { + if (e.key === "Escape") { + e.preventDefault(); + onClose(); + } + }; + const timer = setTimeout(() => document.addEventListener("mousedown", handleMouseDown), 0); + document.addEventListener("keydown", handleKey); + return () => { + clearTimeout(timer); + document.removeEventListener("mousedown", handleMouseDown); + document.removeEventListener("keydown", handleKey); + }; + }, [onClose]); + + const canSave = draft.title.trim().length > 0 && !!draft.calendarId; + const handleSubmit = useCallback((e: React.FormEvent) => { + e.preventDefault(); + if (canSave) onSave(); + }, [canSave, onSave]); + + const timeFmt = timeFormat === "12h" ? "h:mm a" : "HH:mm"; + const dateLabel = intlFormatter.dateTime(draft.start, { weekday: "long", month: "long", day: "numeric" }); + const timeLabel = `${format(draft.start, timeFmt)} – ${format(draft.end, timeFmt)}`; + + return createPortal( +
+
+
+ +
+
+ onChange({ ...draft, title: e.target.value })} + placeholder={t("quick_create.add_title")} + aria-label={t("form.title")} + maxLength={500} + className="text-base" + /> +
+ +
+
{dateLabel}
+
{timeLabel}
+
+
+ {calendars.length > 0 && ( +
+ c.id === draft.calendarId)?.color || "#3b82f6" }} + aria-hidden="true" + /> + +
+ )} +
+
+ + +
+
+
, + document.body, + ); +} diff --git a/locales/ar/common.json b/locales/ar/common.json index 34fba01c3..f2586706c 100644 --- a/locales/ar/common.json +++ b/locales/ar/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "عنوان الحدث الجديد", - "aria_label": "إنشاء حدث سريع" + "aria_label": "إنشاء حدث سريع", + "add_title": "أضف عنوانًا", + "more_options": "خيارات أخرى" }, "nav_prev": "السابق", "nav_next": "التالي", diff --git a/locales/ca/common.json b/locales/ca/common.json index 46eb9d5ca..d9f976d63 100644 --- a/locales/ca/common.json +++ b/locales/ca/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "Títol del nou esdeveniment", - "aria_label": "Crea un esdeveniment ràpidament" + "aria_label": "Crea un esdeveniment ràpidament", + "add_title": "Afegeix un títol", + "more_options": "Més opcions" }, "nav_prev": "Anterior", "nav_next": "Següent", diff --git a/locales/cs/common.json b/locales/cs/common.json index aedc165aa..527bd1df3 100644 --- a/locales/cs/common.json +++ b/locales/cs/common.json @@ -3251,7 +3251,9 @@ }, "quick_create": { "placeholder": "Název nové události", - "aria_label": "Rychlé vytvoření události" + "aria_label": "Rychlé vytvoření události", + "add_title": "Přidat název", + "more_options": "Další možnosti" }, "nav_prev": "Předchozí", "nav_next": "Další", diff --git a/locales/da/common.json b/locales/da/common.json index 6a849c45b..6d37c690b 100644 --- a/locales/da/common.json +++ b/locales/da/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "Ny begivenhedstitel", - "aria_label": "Hurtig oprettelse af begivenhed" + "aria_label": "Hurtig oprettelse af begivenhed", + "add_title": "Tilføj titel", + "more_options": "Flere indstillinger" }, "nav_prev": "Forrige", "nav_next": "Næste", diff --git a/locales/de/common.json b/locales/de/common.json index a120bd650..287aa0ab7 100644 --- a/locales/de/common.json +++ b/locales/de/common.json @@ -3251,7 +3251,9 @@ }, "quick_create": { "placeholder": "Titel des neuen Termins", - "aria_label": "Schnellerstellung eines Termins" + "aria_label": "Schnellerstellung eines Termins", + "add_title": "Titel hinzufügen", + "more_options": "Weitere Optionen" }, "nav_prev": "Zurück", "nav_next": "Weiter", diff --git a/locales/en/common.json b/locales/en/common.json index a1df65771..70225708c 100644 --- a/locales/en/common.json +++ b/locales/en/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "New event title", - "aria_label": "Quick create event" + "aria_label": "Quick create event", + "add_title": "Add title", + "more_options": "More options" }, "nav_prev": "Previous", "nav_next": "Next", diff --git a/locales/es/common.json b/locales/es/common.json index 72553e8b6..62cd252d4 100644 --- a/locales/es/common.json +++ b/locales/es/common.json @@ -3251,7 +3251,9 @@ }, "quick_create": { "placeholder": "Título del nuevo evento", - "aria_label": "Creación rápida de evento" + "aria_label": "Creación rápida de evento", + "add_title": "Añadir título", + "more_options": "Más opciones" }, "nav_prev": "Anterior", "nav_next": "Siguiente", diff --git a/locales/fa/common.json b/locales/fa/common.json index ddf0a589c..63da0628a 100644 --- a/locales/fa/common.json +++ b/locales/fa/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "عنوان رویداد جدید", - "aria_label": "ایجاد سریع رویداد" + "aria_label": "ایجاد سریع رویداد", + "add_title": "افزودن عنوان", + "more_options": "گزینه‌های بیشتر" }, "nav_prev": "قبلی", "nav_next": "بعدی", diff --git a/locales/fr/common.json b/locales/fr/common.json index 02b2d946d..b7a3b4a60 100644 --- a/locales/fr/common.json +++ b/locales/fr/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "Titre du nouvel événement", - "aria_label": "Création rapide d'événement" + "aria_label": "Création rapide d'événement", + "add_title": "Ajouter un titre", + "more_options": "Plus d'options" }, "nav_prev": "Précédent", "nav_next": "Suivant", diff --git a/locales/he/common.json b/locales/he/common.json index 0714241fe..b9cd6cc05 100644 --- a/locales/he/common.json +++ b/locales/he/common.json @@ -3175,7 +3175,9 @@ }, "quick_create": { "placeholder": "כותרת אירוע חדשה", - "aria_label": "אירוע יצירה מהיר" + "aria_label": "אירוע יצירה מהיר", + "add_title": "הוספת כותרת", + "more_options": "אפשרויות נוספות" }, "nav_prev": "הקודם", "nav_next": "הבא", diff --git a/locales/hu/common.json b/locales/hu/common.json index 381144f0b..d1457a8a3 100644 --- a/locales/hu/common.json +++ b/locales/hu/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "Új esemény címe", - "aria_label": "Gyors esemény létrehozása" + "aria_label": "Gyors esemény létrehozása", + "add_title": "Cím hozzáadása", + "more_options": "További beállítások" }, "nav_prev": "Előző", "nav_next": "Következő", diff --git a/locales/it/common.json b/locales/it/common.json index 08b1c25e9..03b20823f 100644 --- a/locales/it/common.json +++ b/locales/it/common.json @@ -3251,7 +3251,9 @@ }, "quick_create": { "placeholder": "Titolo del nuovo evento", - "aria_label": "Creazione rapida evento" + "aria_label": "Creazione rapida evento", + "add_title": "Aggiungi titolo", + "more_options": "Altre opzioni" }, "nav_prev": "Precedente", "nav_next": "Successivo", diff --git a/locales/ja/common.json b/locales/ja/common.json index d24a27366..ce7fd21ca 100644 --- a/locales/ja/common.json +++ b/locales/ja/common.json @@ -3251,7 +3251,9 @@ }, "quick_create": { "placeholder": "新しい予定のタイトル", - "aria_label": "予定をすばやく作成" + "aria_label": "予定をすばやく作成", + "add_title": "タイトルを追加", + "more_options": "その他のオプション" }, "nav_prev": "前へ", "nav_next": "次へ", diff --git a/locales/ko/common.json b/locales/ko/common.json index 25aba3272..771bc3bbe 100644 --- a/locales/ko/common.json +++ b/locales/ko/common.json @@ -3251,7 +3251,9 @@ }, "quick_create": { "placeholder": "새 일정 제목", - "aria_label": "빠른 일정 만들기" + "aria_label": "빠른 일정 만들기", + "add_title": "제목 추가", + "more_options": "추가 옵션" }, "nav_prev": "이전", "nav_next": "다음", diff --git a/locales/lv/common.json b/locales/lv/common.json index b70805b68..f60133c10 100644 --- a/locales/lv/common.json +++ b/locales/lv/common.json @@ -3250,7 +3250,9 @@ }, "quick_create": { "placeholder": "Jauna pasākuma nosaukums", - "aria_label": "Ātra pasākuma izveide" + "aria_label": "Ātra pasākuma izveide", + "add_title": "Pievienot nosaukumu", + "more_options": "Vairāk opciju" }, "nav_prev": "Iepriekšējais", "nav_next": "Nākamais", diff --git a/locales/mn/common.json b/locales/mn/common.json index 699a2439e..7ad7592fd 100644 --- a/locales/mn/common.json +++ b/locales/mn/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "Шинэ үйл явдлын гарчиг", - "aria_label": "Түргэн үүсгэх арга хэмжээ" + "aria_label": "Түргэн үүсгэх арга хэмжээ", + "add_title": "Гарчиг нэмэх", + "more_options": "Бусад тохиргоо" }, "nav_prev": "Өмнөх", "nav_next": "Дараагийн", diff --git a/locales/nb/common.json b/locales/nb/common.json index 7dae98835..1ba76a36b 100644 --- a/locales/nb/common.json +++ b/locales/nb/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "Tittel på ny hendelse", - "aria_label": "Opprett en hendelse raskt" + "aria_label": "Opprett en hendelse raskt", + "add_title": "Legg til tittel", + "more_options": "Flere alternativer" }, "nav_prev": "Forrige", "nav_next": "Neste", diff --git a/locales/nl/common.json b/locales/nl/common.json index f3d731e36..eecd73200 100644 --- a/locales/nl/common.json +++ b/locales/nl/common.json @@ -3251,7 +3251,9 @@ }, "quick_create": { "placeholder": "Titel nieuw evenement", - "aria_label": "Snel evenement aanmaken" + "aria_label": "Snel evenement aanmaken", + "add_title": "Titel toevoegen", + "more_options": "Meer opties" }, "nav_prev": "Vorige", "nav_next": "Volgende", diff --git a/locales/pl/common.json b/locales/pl/common.json index 7a6635aa7..14e9a415e 100644 --- a/locales/pl/common.json +++ b/locales/pl/common.json @@ -3251,7 +3251,9 @@ }, "quick_create": { "placeholder": "Tytuł nowego wydarzenia", - "aria_label": "Szybkie tworzenie wydarzenia" + "aria_label": "Szybkie tworzenie wydarzenia", + "add_title": "Dodaj tytuł", + "more_options": "Więcej opcji" }, "nav_prev": "Poprzedni", "nav_next": "Następny", diff --git a/locales/pt/common.json b/locales/pt/common.json index 8b43bbc6e..4aa5f964e 100644 --- a/locales/pt/common.json +++ b/locales/pt/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "Título do novo evento", - "aria_label": "Criação rápida de evento" + "aria_label": "Criação rápida de evento", + "add_title": "Adicionar título", + "more_options": "Mais opções" }, "nav_prev": "Anterior", "nav_next": "Próximo", diff --git a/locales/ro/common.json b/locales/ro/common.json index 039fbc0e9..ff9c710cf 100644 --- a/locales/ro/common.json +++ b/locales/ro/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "Titlul unui eveniment nou", - "aria_label": "Creare rapidă a unui eveniment" + "aria_label": "Creare rapidă a unui eveniment", + "add_title": "Adaugă titlu", + "more_options": "Mai multe opțiuni" }, "nav_prev": "Anterior", "nav_next": "Următorul", diff --git a/locales/ru/common.json b/locales/ru/common.json index 96a589c67..a5c46b3cf 100644 --- a/locales/ru/common.json +++ b/locales/ru/common.json @@ -3251,7 +3251,9 @@ }, "quick_create": { "placeholder": "Название нового события", - "aria_label": "Быстрое создание события" + "aria_label": "Быстрое создание события", + "add_title": "Добавьте название", + "more_options": "Другие параметры" }, "nav_prev": "Предыдущий", "nav_next": "Следующий", diff --git a/locales/sk/common.json b/locales/sk/common.json index 312e62dd5..9070f53bc 100644 --- a/locales/sk/common.json +++ b/locales/sk/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "Názov novej udalosti", - "aria_label": "Rýchle vytvorenie udalosti" + "aria_label": "Rýchle vytvorenie udalosti", + "add_title": "Pridať názov", + "more_options": "Ďalšie možnosti" }, "nav_prev": "Predchádzajúci", "nav_next": "Ďalší", diff --git a/locales/tr/common.json b/locales/tr/common.json index 1c6b8ba9e..f512dc9d3 100644 --- a/locales/tr/common.json +++ b/locales/tr/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "Yeni etkinlik başlığı", - "aria_label": "Hızlı etkinlik oluştur" + "aria_label": "Hızlı etkinlik oluştur", + "add_title": "Başlık ekle", + "more_options": "Diğer seçenekler" }, "nav_prev": "Önceki", "nav_next": "Sonraki", diff --git a/locales/uk/common.json b/locales/uk/common.json index c414e9d06..03197ce6e 100644 --- a/locales/uk/common.json +++ b/locales/uk/common.json @@ -3251,7 +3251,9 @@ }, "quick_create": { "placeholder": "Нова назва події", - "aria_label": "Швидке створення події" + "aria_label": "Швидке створення події", + "add_title": "Додайте назву", + "more_options": "Більше параметрів" }, "nav_prev": "Попередній", "nav_next": "Далі", diff --git a/locales/zh-TW/common.json b/locales/zh-TW/common.json index 0165a7eee..5873062cf 100644 --- a/locales/zh-TW/common.json +++ b/locales/zh-TW/common.json @@ -3277,7 +3277,9 @@ }, "quick_create": { "placeholder": "新活動標題", - "aria_label": "快速建立活動" + "aria_label": "快速建立活動", + "add_title": "新增標題", + "more_options": "更多選項" }, "nav_prev": "上一項", "nav_next": "下一項", diff --git a/locales/zh/common.json b/locales/zh/common.json index 350d13dcc..73fd781fe 100644 --- a/locales/zh/common.json +++ b/locales/zh/common.json @@ -3251,7 +3251,9 @@ }, "quick_create": { "placeholder": "新活动标题", - "aria_label": "快速创建事件" + "aria_label": "快速创建事件", + "add_title": "添加标题", + "more_options": "更多选项" }, "nav_prev": "上一项", "nav_next": "下一项",