fix(DeviceDetailOverlay): notify parent on browsing state changes and improve portal usage in DeviceCard

This commit is contained in:
Jaime Idolpx 2026-06-13 22:25:37 -04:00
parent 3088f1801c
commit 7c25680091
2 changed files with 18 additions and 5 deletions

View File

@ -1,4 +1,5 @@
import { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { SettingsInput } from './ui/settings-input';
import { X, Printer, HardDrive, Network, Box, FolderOpen, MoreVertical, RotateCcw } from 'lucide-react';
import { motion, AnimatePresence } from 'motion/react';
@ -48,13 +49,19 @@ interface DeviceCardProps {
config: any;
setConfig: (c: any) => void;
isActive: boolean;
onBrowsingChange?: (browsing: boolean) => void;
}
function DeviceCard({ device, config, setConfig, isActive }: DeviceCardProps) {
function DeviceCard({ device, config, setConfig, isActive, onBrowsingChange }: DeviceCardProps) {
const [browsingField, setBrowsingField] = useState<'url' | 'base_url' | 'cache' | null>(null);
const [mediaSetFiles, setMediaSetFiles] = useState<MediaSetEntry[] | null>(null);
const detectTokenRef = useRef(0);
// Notify parent when browser opens/closes so it can lock slide scroll.
useEffect(() => {
onBrowsingChange?.(browsingField !== null);
}, [browsingField, onBrowsingChange]);
// Close any open browser when swiped away.
useEffect(() => {
if (!isActive) setBrowsingField(null);
@ -332,7 +339,7 @@ function DeviceCard({ device, config, setConfig, isActive }: DeviceCardProps) {
</div>
</div>
{browsingField && (
{browsingField && createPortal(
<MediaBrowser
currentPath={
browsingField === 'cache' ? (deviceData.cache || '/') :
@ -348,7 +355,8 @@ function DeviceCard({ device, config, setConfig, isActive }: DeviceCardProps) {
setBrowsingField(null);
}}
onClose={() => setBrowsingField(null)}
/>
/>,
document.body
)}
</>
);
@ -366,6 +374,7 @@ export default function DeviceDetailOverlay({
}: DeviceDetailOverlayProps) {
const [activeIndex, setActiveIndex] = useState(initialIndex);
const [showCommandMenu, setShowCommandMenu] = useState(false);
const [isBrowsing, setIsBrowsing] = useState(false);
const swiperRef = useRef<SwiperType | null>(null);
const activeDevice = devices[activeIndex] ?? devices[0];
@ -461,12 +470,13 @@ export default function DeviceDetailOverlay({
style={{ height: '100%' }}
>
{devices.map((device, i) => (
<SwiperSlide key={device.id} style={{ overflowY: 'auto', height: '100%' }}>
<SwiperSlide key={device.id} style={{ overflowY: isBrowsing && i === activeIndex ? 'hidden' : 'auto', height: '100%' }}>
<DeviceCard
device={device}
config={config}
setConfig={setConfig}
isActive={i === activeIndex}
onBrowsingChange={i === activeIndex ? setIsBrowsing : undefined}
/>
</SwiperSlide>
))}

View File

@ -136,6 +136,7 @@ export default function MediaBrowser({ currentPath, onSelect, onClose }: MediaBr
const pathParts = (path ?? '').split('/').filter(Boolean);
return (
<>
<div className="fixed inset-0 bg-black/50 z-50 flex items-end" onClick={onClose}>
<div className="bg-white w-full max-h-[80vh] rounded-t-xl flex flex-col" onClick={e => e.stopPropagation()}>
<div className="sticky top-0 bg-white border-b border-neutral-200 p-4">
@ -219,6 +220,8 @@ export default function MediaBrowser({ currentPath, onSelect, onClose }: MediaBr
</div>
</div>
</div>
<ConfirmDialog
open={confirm !== null}
{...(confirm ?? { title: '', onConfirm: () => {} })}
@ -254,6 +257,6 @@ export default function MediaBrowser({ currentPath, onSelect, onClose }: MediaBr
</div>
</DialogContent>
</Dialog>
</div>
</>
);
}