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": "下一项",