Files
controller-v2/client/src/components/DesktopAIShell.tsx
T
eafonyang f3961cc72a Update project dependencies and configurations; remove deprecated package settings and enhance legacy build support
- Upgrade package manager to pnpm@11.5.2 and remove patched dependencies from package.json.
- Update pnpm-lock.yaml to reflect new dependency versions and remove obsolete entries.
- Refactor Vite configuration to improve legacy build handling, including new plugins for legacy CSS management.
- Remove unused client/index.html file and adjust paths in Vite config for better project structure.
- Enhance DesktopAIShell and EQPage components to support legacy build conditions and improve loading states for raw curves.
2026-06-09 14:24:30 +08:00

135 lines
3.7 KiB
TypeScript

import PageSuspense from "@/components/PageSuspense";
import { useAIDrawer } from "@/contexts/AIDrawerContext";
import { useIsLgUp } from "@/hooks/useIsLgUp";
import { cn } from "@/lib/utils";
import { useLocation } from "wouter";
import {
useCallback,
useEffect,
useRef,
lazy,
type ReactNode,
type RefObject,
} from "react";
const AIPage = lazy(() => import("@/pages/AIPage"));
function SplitDivider({
containerRef,
onResize,
}: {
containerRef: RefObject<HTMLDivElement | null>;
onResize: (aiPercent: number) => void;
}) {
const dragging = useRef(false);
const onMove = useCallback(
(e: MouseEvent) => {
if (!dragging.current || !containerRef.current) return;
const r = containerRef.current.getBoundingClientRect();
const w = r.width;
if (w <= 0) return;
const aiPct = ((r.right - e.clientX) / w) * 100;
onResize(aiPct);
},
[containerRef, onResize],
);
useEffect(() => {
const onUp = () => {
dragging.current = false;
};
window.addEventListener("mouseup", onUp);
window.addEventListener("mousemove", onMove);
return () => {
window.removeEventListener("mouseup", onUp);
window.removeEventListener("mousemove", onMove);
};
}, [onMove]);
return (
<div
className={cn(
"group relative z-10 w-2 shrink-0 cursor-col-resize bg-transparent",
"hover:bg-[#00FFF6]/10",
)}
onMouseDown={() => {
dragging.current = true;
}}
role="separator"
aria-orientation="vertical"
aria-label="Resize panels"
>
<div className="absolute inset-y-0 left-1/2 w-px -translate-x-1/2 bg-white/15 transition-colors group-hover:bg-[#00FFF6]/45" />
</div>
);
}
const isLegacyBuild = import.meta.env.VITE_X8_LEGACY === "1";
/**
* lg+: optional side-by-side AI panel with draggable divider. Mobile unchanged (router only).
*/
export default function DesktopAIShell({ children }: { children: ReactNode }) {
const isLgUp = useIsLgUp();
const [location] = useLocation();
const { open, setOpen, splitPercent, setSplitPercent } = useAIDrawer();
const containerRef = useRef<HTMLDivElement>(null);
const showSplit = Boolean(isLgUp && open && location !== "/ai");
useEffect(() => {
if (location === "/ai" && isLgUp) setOpen(false);
}, [location, isLgUp, setOpen]);
return (
<div
ref={containerRef}
className={cn(
"w-full min-w-0",
showSplit
? "flex h-dvh max-h-dvh flex-row overflow-hidden"
: isLegacyBuild
? "min-h-0"
: "min-h-dvh",
)}
>
<div
className={cn(
"min-w-0",
showSplit
? "h-full min-h-0 overflow-y-auto overflow-x-hidden"
: isLgUp
? "min-h-dvh overflow-x-hidden"
: isLegacyBuild
? "w-full overflow-x-hidden"
: "min-h-dvh max-h-dvh overflow-x-hidden overflow-y-auto overscroll-y-contain [touch-action:pan-y]",
)}
style={
showSplit
? { flex: `${100 - splitPercent} 1 0%`, minWidth: 0 }
: { width: "100%" }
}
>
{children}
</div>
{showSplit && (
<>
<SplitDivider
containerRef={containerRef}
onResize={(aiPct) => setSplitPercent(aiPct)}
/>
<div
className="flex h-full min-h-0 min-w-0 flex-col overflow-hidden border-l border-white/[0.08] bg-[#0d1117]"
style={{ flex: `${splitPercent} 1 0%` }}
>
<PageSuspense>
<AIPage variant="split" onClose={() => setOpen(false)} />
</PageSuspense>
</div>
</>
)}
</div>
);
}