feat: P2.2 Create Appointment from Email + P2.4 Calendar Dashlet + P2.12 Action Wheel + P2.14 Share Files
- P2.2: 'Create Appointment' button in email viewer → pre-fills event modal with subject, body, participants, date. calendar-store newEventPrefill state. - P2.4: MiniCalendarDashlet in sidebar bottom — month grid with event dots, day click navigates to calendar. Collapsible, respect firstDayOfWeek. - P2.12: Custom radial menu (components/ui/radial-menu.tsx) — circular SVG menu with keyboard nav, animations. Wired into email-list, contact-list, file-browser, calendar-month-view right-click handlers. - P2.14: 'Send as Attachment' button in file browser — opens compose tab with selected files pre-attached via Pro tab store.
This commit is contained in:
@@ -4,6 +4,7 @@ import { useState, useEffect, useMemo, ReactNode } from "react";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { useRouter } from "@/i18n/navigation";
|
||||
import { PluginSlot } from "@/components/plugins/plugin-slot";
|
||||
import { MiniCalendarDashlet } from "@/components/calendar/mini-calendar-dashlet";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Inbox,
|
||||
@@ -62,6 +63,7 @@ import { useUIStore } from "@/stores/ui-store";
|
||||
import { useAuthStore } from "@/stores/auth-store";
|
||||
import { useVacationStore } from "@/stores/vacation-store";
|
||||
import { useSettingsStore, getKeywordVisibility } from "@/stores/settings-store";
|
||||
import { usePolicyStore } from "@/stores/policy-store";
|
||||
import { useEmailStore } from "@/stores/email-store";
|
||||
import { toast } from "@/stores/toast-store";
|
||||
import { debug } from "@/lib/debug";
|
||||
@@ -808,6 +810,12 @@ export function Sidebar({
|
||||
return stored !== null ? JSON.parse(stored) : true;
|
||||
} catch { return true; }
|
||||
});
|
||||
const [calendarDashletExpanded, setCalendarDashletExpanded] = useState(() => {
|
||||
try {
|
||||
const stored = localStorage.getItem('sidebarCalendarDashletExpanded');
|
||||
return stored !== null ? JSON.parse(stored) : true;
|
||||
} catch { return true; }
|
||||
});
|
||||
const [unifiedExpanded, setUnifiedExpanded] = useState(() => {
|
||||
try {
|
||||
const stored = localStorage.getItem('sidebarUnifiedExpanded');
|
||||
@@ -840,6 +848,7 @@ export function Sidebar({
|
||||
const emailKeywords = useSettingsStore(s => s.emailKeywords);
|
||||
const nestedTags = useSettingsStore(s => s.nestedTags);
|
||||
const isEmbedded = useIsEmbedded();
|
||||
const calendarEnabled = usePolicyStore((s) => s.isFeatureEnabled('calendarEnabled'));
|
||||
// The Pro shell owns the global chrome (rail + tab bar), so the sidebar's
|
||||
// own AccountSwitcher would be a redundant second account UI in the same
|
||||
// pane.
|
||||
@@ -1054,6 +1063,13 @@ export function Sidebar({
|
||||
return next;
|
||||
});
|
||||
};
|
||||
const toggleCalendarDashlet = () => {
|
||||
setCalendarDashletExpanded((prev: boolean) => {
|
||||
const next = !prev;
|
||||
try { localStorage.setItem('sidebarCalendarDashletExpanded', JSON.stringify(next)); } catch { /* */ }
|
||||
return next;
|
||||
});
|
||||
};
|
||||
const toggleShared = () => {
|
||||
setSharedExpanded((prev: boolean) => {
|
||||
const next = !prev;
|
||||
@@ -1405,6 +1421,18 @@ export function Sidebar({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isCollapsed && calendarEnabled && (
|
||||
<div>
|
||||
<SidebarSectionHeader
|
||||
label={t("calendar")}
|
||||
expanded={calendarDashletExpanded}
|
||||
onToggle={toggleCalendarDashlet}
|
||||
isCollapsed={isCollapsed}
|
||||
/>
|
||||
{calendarDashletExpanded && <MiniCalendarDashlet />}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!isCollapsed && <PluginSlot name="sidebar-widget" className="border-t border-border" />}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user