diff --git a/frontend/src/app/settings/page.tsx b/frontend/src/app/settings/page.tsx
index 86e4b24c..5ee72ec6 100644
--- a/frontend/src/app/settings/page.tsx
+++ b/frontend/src/app/settings/page.tsx
@@ -17,6 +17,8 @@ import {
Mail,
Monitor,
Moon,
+ MousePointer2,
+ PanelLeftClose,
QrCode,
Save,
Smartphone,
@@ -28,6 +30,7 @@ import { AppShell } from "@/components/AppShell";
import NotificationDeliveryApps from "@/components/settings/NotificationDeliveryApps";
import { usePwa } from "@/contexts/PwaContext";
import { useMobileNavPlacement } from "@/contexts/MobileNavPlacementContext";
+import { useDesktopCompactPanelBehavior } from "@/hooks/useDesktopCompactPanelBehavior";
import {
formatSessionDateTime,
getSessionDeviceKind,
@@ -62,6 +65,21 @@ const mobileNavCards = [
},
] as const;
+const desktopCompactPanelCards = [
+ {
+ value: "hover",
+ title: "Раскрывать при наведении",
+ description: "Меню и календарь временно выезжают поверх страницы при наведении мыши.",
+ Icon: MousePointer2,
+ },
+ {
+ value: "compact",
+ title: "Всегда компактные",
+ description: "Меню и календарь остаются в виде узких панелей со значками.",
+ Icon: PanelLeftClose,
+ },
+] as const;
+
function getSessionDeviceIcon(deviceName?: string | null) {
return getSessionDeviceKind(deviceName) === "mobile" ? Smartphone : Monitor;
}
@@ -136,6 +154,7 @@ function SectionCard({
export default function SettingsPage() {
const { mobileNavPlacement, setMobileNavPlacement } = useMobileNavPlacement();
+ const [desktopCompactPanelBehavior, setDesktopCompactPanelBehavior] = useDesktopCompactPanelBehavior();
const { canInstall, install, isInstalled, isRegistrationReady } = usePwa();
const {
activeVerbCount,
@@ -416,6 +435,48 @@ export default function SettingsPage() {
})}
+
+
+
+
Боковые панели в расширенном режиме
+
+ Определяет поведение компактного меню и календаря на этом устройстве.
+
+
+
+
+ {desktopCompactPanelCards.map(({ value, title, description, Icon }) => {
+ const active = desktopCompactPanelBehavior === value;
+
+ return (
+
+ );
+ })}
+
+
{
+ if (compact && expandOnHover) setHoverExpanded(true);
+ }}
+ onMouseLeave={() => setHoverExpanded(false)}
+ onFocus={() => {
+ if (compact && expandOnHover) setHoverExpanded(true);
+ }}
+ onBlur={(event) => {
+ if (!event.currentTarget.contains(event.relatedTarget)) setHoverExpanded(false);
+ }}
>
-
+
);
@@ -605,6 +627,8 @@ export function AppShell({
}: AppShellProps) {
const { user, loading, status: authStatus, error: authError, retryAuthentication } = useUser();
const { mobileNavPlacement } = useMobileNavPlacement();
+ const [desktopCompactPanelBehavior] = useDesktopCompactPanelBehavior();
+ const expandCompactPanelsOnHover = desktopCompactPanelBehavior === "hover";
const router = useRouter();
const pathname = usePathname();
const [isMobileLeftNavOpen, setIsMobileLeftNavOpen] = useState(false);
@@ -708,7 +732,13 @@ export function AppShell({
/>
- {!desktopImmersiveMode && !standaloneAppMode ?
: null}
+ {!desktopImmersiveMode && !standaloneAppMode ? (
+
+ ) : null}
{!mobileFullscreen && !standaloneAppMode && !suppressPushOnboardingPrompt ? : null}
{children}
@@ -723,6 +753,7 @@ export function AppShell({
onCalendarChange={cal.handleCalendarChange}
fixedDesktop
compact={desktopWideMode}
+ expandOnHover={expandCompactPanelsOnHover}
onExpand={() => onDesktopWideModeChange?.(false)}
/> : null}
diff --git a/frontend/src/components/calendar/CalendarSidebar.tsx b/frontend/src/components/calendar/CalendarSidebar.tsx
index 3f56c868..e42adcde 100644
--- a/frontend/src/components/calendar/CalendarSidebar.tsx
+++ b/frontend/src/components/calendar/CalendarSidebar.tsx
@@ -1,7 +1,7 @@
"use client";
import { CalendarDays } from "lucide-react";
-import { memo } from "react";
+import { memo, useState } from "react";
import { CalendarCard } from "@/components/calendar/CalendarCard";
import { type CalendarParticipantsTarget } from "@/lib/calendar/ui";
import type { CalendarEvent, CalendarEventDraft } from "@/services/calendarService";
@@ -16,6 +16,7 @@ interface CalendarSidebarProps {
onCalendarChange: (calendarId: number | null) => void;
fixedDesktop?: boolean;
compact?: boolean;
+ expandOnHover?: boolean;
onExpand?: () => void;
}
@@ -26,31 +27,46 @@ export const CalendarSidebar = memo(function CalendarSidebar(props: CalendarSide
const {
fixedDesktop = false,
compact = false,
+ expandOnHover = true,
onExpand,
...calendarProps
} = props;
+ const [hoverExpanded, setHoverExpanded] = useState(false);
+ const [calendarActivated, setCalendarActivated] = useState(false);
+ const expanded = expandOnHover && hoverExpanded;
if (compact) {
return (