diff --git a/components/calendar/calendar-app.tsx b/components/calendar/calendar-app.tsx
index e7f982bab..8edb59548 100644
--- a/components/calendar/calendar-app.tsx
+++ b/components/calendar/calendar-app.tsx
@@ -75,6 +75,7 @@ import { ConfirmDialog } from "@/components/ui/confirm-dialog";
import { useConfirmDialog } from "@/hooks/use-confirm-dialog";
import { SchedulingDeniedError } from "@/lib/jmap/scheduling-error";
import { CreateCalendarModal } from "@/components/calendar/create-calendar-modal";
+import { CalendarSidebarHeader } from "@/components/calendar/calendar-sidebar-header";
import { getUserParticipantId, collectUserCalendarAddresses } from "@/lib/calendar-participants";
import { generateBirthdayEvents, createBirthdayCalendar, BIRTHDAY_CALENDAR_ID } from "@/lib/birthday-calendar";
import { sharedCalendarColorKey, pickUnusedCalendarColor } from "@/lib/shared-calendar-colors";
@@ -1774,15 +1775,13 @@ export function CalendarApp({ linkSegments: routeSegments }: CalendarAppProps =
{!inlineApp && (
- {/* Desktop: the bar spans the sidebar and the grid, as in Google Calendar. */}
- {!isMobile && calendarToolbar}
{/* Sidebar - in-flow when desktop pane, overlay when narrow */}
{(isNarrow || !sidebarCollapsed) && (
<>
- {!isMobile && (
-
{ setNarrowSidebarOpen(false); openCreateModal(); }}
- data-tour={isNarrow ? undefined : "create-event-button"}
- className="w-full h-8 mb-3"
- >
-
- {t("events.create")}
-
- )}
+
{ setNarrowSidebarOpen(false); openCreateModal(); }}
+ tourTarget={!isNarrow}
+ />
+
{!isNarrow && (
- {isMobile && calendarToolbar}
+ {calendarToolbar}
{/* isolate keeps the views' sticky headers (z-50) below the toolbar's
import dropdown, which overlaps this area (#1049). */}
diff --git a/components/calendar/calendar-sidebar-header.tsx b/components/calendar/calendar-sidebar-header.tsx
new file mode 100644
index 000000000..79272d9aa
--- /dev/null
+++ b/components/calendar/calendar-sidebar-header.tsx
@@ -0,0 +1,39 @@
+"use client";
+
+import { useTranslations } from "next-intl";
+import { Button } from "@/components/ui/button";
+import { Plus } from "@/components/icons";
+
+interface CalendarSidebarHeaderProps {
+ onCreateEvent: () => void;
+ /** Mark the button for the guided tour; off while the toolbar's own "+" is the visible one. */
+ tourTarget?: boolean;
+}
+
+/**
+ * Title row at the top of the calendar sidebar, the same shape as the
+ * contacts sidebar header: the app name on the left and "+" on the right.
+ */
+export function CalendarSidebarHeader({ onCreateEvent, tourTarget = true }: CalendarSidebarHeaderProps) {
+ const t = useTranslations("calendar");
+
+ return (
+
+ );
+}
diff --git a/components/calendar/calendar-sidebar-panel.tsx b/components/calendar/calendar-sidebar-panel.tsx
index 37b6f6abc..e6b798f45 100644
--- a/components/calendar/calendar-sidebar-panel.tsx
+++ b/components/calendar/calendar-sidebar-panel.tsx
@@ -255,10 +255,11 @@ export function CalendarSidebarPanel({
data-account={cal.accountName ?? ''}
data-visible={isVisible}
className={cn(
- "flex items-center gap-2 w-full px-1.5 py-1 rounded-md text-sm transition-colors duration-150",
+ "flex items-center gap-2 w-full ps-5 pe-3 text-sm text-foreground/80 transition-colors duration-150",
"hover:bg-muted",
- hasMenu && "pe-7"
+ hasMenu && "pe-9"
)}
+ style={{ paddingBlock: 'var(--density-sidebar-py, 4px)', minHeight: '32px' }}
>
{/* A checkbox filled in the calendar colour, empty when hidden. */}
openContextMenu(e, cal)}
className={cn(
- "absolute end-1 top-1/2 -translate-y-1/2 p-0.5 rounded text-muted-foreground hover:text-foreground hover:bg-accent transition-opacity",
+ "absolute end-2 top-1/2 -translate-y-1/2 p-0.5 rounded text-muted-foreground hover:text-foreground hover:bg-accent transition-opacity",
"opacity-0 group-hover/cal:opacity-100 focus-visible:opacity-100",
contextMenu.isOpen && contextMenu.data?.id === cal.id && "opacity-100"
)}
@@ -424,19 +425,19 @@ export function CalendarSidebarPanel({
const renderSectionHeader = (key: string, label: string, onAdd?: () => void) => {
const expanded = !collapsedAccountGroups.has(key);
return (
-
+
toggleAccountGroup(key)}
aria-expanded={expanded}
- className="flex-1 min-w-0 flex items-center gap-1 px-1 py-1 rounded-sm text-xs font-medium text-muted-foreground uppercase tracking-wider hover:text-foreground transition-colors"
+ className="flex-1 min-w-0 flex items-center gap-1 ps-3 py-1 text-start"
>
- {label}
{expanded ? (
-
+
) : (
-
+
)}
+ {label}
{onAdd && (
{renderSectionHeader(key, label, onAdd)}
{!collapsedAccountGroups.has(key) && (
-
+
{list.map(renderCalendarItem)}
)}
@@ -469,7 +470,8 @@ export function CalendarSidebarPanel({
{enableCalendarTasks && (
setViewMode('tasks')}
- className="flex items-center gap-2 w-full px-1.5 py-1.5 mb-3 rounded-md text-sm hover:bg-muted transition-colors"
+ className="flex items-center gap-2 w-full px-3 mb-2 text-sm text-foreground/80 hover:bg-muted transition-colors"
+ style={{ paddingBlock: 'var(--density-sidebar-py, 4px)', minHeight: '32px' }}
>
{t('tasks.label')}
@@ -491,7 +493,7 @@ export function CalendarSidebarPanel({
toggleAccountGroup(group.key)}
- className="group w-full flex items-center gap-1.5 px-1 py-1 rounded-sm hover:bg-muted/40 transition-colors"
+ className="group w-full flex items-center gap-1.5 px-3 py-1 hover:bg-muted/40 transition-colors"
>
{expanded ? (
@@ -522,24 +524,24 @@ export function CalendarSidebarPanel({
)}
{expanded && (
-
+
{owned.length > 0 && (
-
+
{t('my_calendars')}
-
+
{owned.map(renderCalendarItem)}
)}
{sharedGroups.map((sg) => (
-
+
{sg.label}
-
+
{sg.calendars.map(renderCalendarItem)}
@@ -560,15 +562,15 @@ export function CalendarSidebarPanel({
)}
{sharedAccountGroups.length > 0 && (
-
+
{renderSectionHeader('__others__', t('other_calendars'))}
{!collapsedAccountGroups.has('__others__') && sharedAccountGroups.map((group) => (
-
+
{group.accountName}
-
+
{group.calendars.map(renderCalendarItem)}
diff --git a/components/calendar/calendar-toolbar.tsx b/components/calendar/calendar-toolbar.tsx
index 197a4ebc7..99eba0c23 100644
--- a/components/calendar/calendar-toolbar.tsx
+++ b/components/calendar/calendar-toolbar.tsx
@@ -332,7 +332,7 @@ export function CalendarToolbar({
const currentViewLabel = t(`views.${viewMode}`);
return (
-