diff --git a/core/src/domain/file.rs b/core/src/domain/file.rs index cd29b920b..217f95419 100644 --- a/core/src/domain/file.rs +++ b/core/src/domain/file.rs @@ -182,8 +182,9 @@ impl crate::domain::resource::Identifiable for File { })?; // Find entries with matching content_identity UUID + // Note: content_identity.uuid is Option, must wrap in Some() let ci_opt = content_identity::Entity::find() - .filter(content_identity::Column::Uuid.eq(sc.content_uuid)) + .filter(content_identity::Column::Uuid.eq(Some(sc.content_uuid))) .one(db) .await?; diff --git a/packages/interface/src/Explorer.tsx b/packages/interface/src/Explorer.tsx index 1527ec1d0..f4f1340c7 100644 --- a/packages/interface/src/Explorer.tsx +++ b/packages/interface/src/Explorer.tsx @@ -19,7 +19,7 @@ import { import { KeyboardHandler } from "./components/Explorer/KeyboardHandler"; import { TagAssignmentMode } from "./components/Explorer/TagAssignmentMode"; import { SpacesSidebar } from "./components/SpacesSidebar"; -import { QuickPreviewModal } from "./components/QuickPreview"; +import { QuickPreviewFullscreen, PREVIEW_LAYER_ID } from "./components/QuickPreview"; import { createExplorerRouter } from "./router"; import { useNormalizedCache } from "./context"; import { usePlatform } from "./platform"; @@ -110,11 +110,20 @@ export function ExplorerLayout() { } }; + const isPreviewActive = !!quickPreviewFileId; + return (
+ {/* Preview layer - portal target for fullscreen preview, sits between content and sidebar/inspector */} +
+ @@ -124,15 +133,14 @@ export function ExplorerLayout() { animate={{ x: 0, width: 220 }} exit={{ x: -220, width: 0 }} transition={{ duration: 0.3, ease: [0.25, 1, 0.5, 1] }} - className="overflow-hidden" + className="relative z-50 overflow-hidden" > - - {/**/} + )} -
+
{/* Router content renders here */}
@@ -154,21 +162,22 @@ export function ExplorerLayout() { animate={{ width: 280 }} exit={{ width: 0 }} transition={{ duration: 0.3, ease: [0.25, 1, 0.5, 1] }} - className="overflow-hidden" + className="relative z-50 overflow-hidden" > -
+
)} - {/* Quick Preview Modal - TODO: Fix files reference */} + {/* Quick Preview - renders via portal into preview layer */} {quickPreviewFileId && ( - goToPreviousPreview([])} hasPrevious={false} hasNext={false} + sidebarWidth={sidebarVisible ? 220 : 0} + inspectorWidth={inspectorVisible && !isOverview && !isKnowledgeView ? 280 : 0} /> )}
diff --git a/packages/interface/src/Inspector.tsx b/packages/interface/src/Inspector.tsx index bcfa685f5..f485b0257 100644 --- a/packages/interface/src/Inspector.tsx +++ b/packages/interface/src/Inspector.tsx @@ -7,6 +7,7 @@ import { usePlatform } from "./platform"; import { useSelection } from "./components/Explorer/SelectionContext"; import { FileInspector } from "./inspectors/FileInspector"; import { LocationInspector } from "./inspectors/LocationInspector"; +import clsx from "clsx"; export type InspectorVariant = | { type: "file"; file: File } @@ -18,12 +19,14 @@ interface InspectorProps { onPopOut?: () => void; showPopOutButton?: boolean; currentLocation?: LocationInfo | null; + isPreviewActive?: boolean; } export function Inspector({ onPopOut, showPopOutButton = true, currentLocation, + isPreviewActive = false, }: InspectorProps) { const { selectedFiles } = useSelection(); @@ -41,7 +44,12 @@ export function Inspector({ // No need for interface package to call platform-specific commands return ( -
+
{/* Variant-specific content */} {!variant || variant.type === "empty" ? ( diff --git a/packages/interface/src/TopBar/TopBar.tsx b/packages/interface/src/TopBar/TopBar.tsx index 01a1ebde8..e2914fa53 100644 --- a/packages/interface/src/TopBar/TopBar.tsx +++ b/packages/interface/src/TopBar/TopBar.tsx @@ -5,9 +5,10 @@ import clsx from "clsx"; interface TopBarProps { sidebarWidth?: number; inspectorWidth?: number; + isPreviewActive?: boolean; } -export const TopBar = memo(function TopBar({ sidebarWidth = 0, inspectorWidth = 0 }: TopBarProps) { +export const TopBar = memo(function TopBar({ sidebarWidth = 0, inspectorWidth = 0, isPreviewActive = false }: TopBarProps) { const { setLeftRef, setCenterRef, setRightRef } = useTopBar(); const leftRef = useRef(null); const centerRef = useRef(null); @@ -21,7 +22,7 @@ export const TopBar = memo(function TopBar({ sidebarWidth = 0, inspectorWidth = return (
- {/* Right fade mask */} -
+ {/* Right fade mask - hide when preview active */} + {!isPreviewActive && ( +
+ )}
); diff --git a/packages/interface/src/components/Explorer/ExplorerView.tsx b/packages/interface/src/components/Explorer/ExplorerView.tsx index a18a44ec3..8071f0577 100644 --- a/packages/interface/src/components/Explorer/ExplorerView.tsx +++ b/packages/interface/src/components/Explorer/ExplorerView.tsx @@ -44,8 +44,11 @@ export function ExplorerView() { currentPath, setCurrentPath, devices, + quickPreviewFileId, } = useExplorer(); + const isPreviewActive = !!quickPreviewFileId; + // Fetch locations to get the SdPath for this locationId const locationsQuery = useNormalizedCache({ wireMethod: "query:locations.list", @@ -99,59 +102,61 @@ export function ExplorerView() { return ( <> - - setSidebarVisible(!sidebarVisible)} - active={sidebarVisible} - /> - + {!isPreviewActive && ( + setSidebarVisible(!sidebarVisible)} + active={sidebarVisible} + /> + + + + + {currentPath && ( + + )} +
+ } + right={ +
+ + setTagModeActive(!tagModeActive)} + active={tagModeActive} + tooltip="Tag Mode (T)" + /> + + + setInspectorVisible(!inspectorVisible)} + active={inspectorVisible} /> - - {currentPath && ( - - )} -
- } - right={ -
- - setTagModeActive(!tagModeActive)} - active={tagModeActive} - tooltip="Tag Mode (T)" - /> - - - - setInspectorVisible(!inspectorVisible)} - active={inspectorVisible} - /> -
- } - /> +
+ } + /> + )}
diff --git a/packages/interface/src/components/QuickPreview/AudioPlayer.tsx b/packages/interface/src/components/QuickPreview/AudioPlayer.tsx index 7a178a9f3..42fc43533 100644 --- a/packages/interface/src/components/QuickPreview/AudioPlayer.tsx +++ b/packages/interface/src/components/QuickPreview/AudioPlayer.tsx @@ -7,10 +7,8 @@ import { SkipBack, SkipForward, } from "@phosphor-icons/react"; -import { motion, AnimatePresence } from "framer-motion"; +import { motion } from "framer-motion"; import type { File } from "@sd/ts-client"; -import { File as FileComponent } from "../Explorer/File"; -import { formatBytes } from "../Explorer/utils"; interface SubtitleCue { index: number; @@ -240,7 +238,7 @@ export function AudioPlayer({ src, file }: AudioPlayerProps) { }; return ( -
+
{/* Hidden audio element */}