Implement code highlighting, thumbnail retries, and pinned order fix
All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m29s

This commit is contained in:
Elijah 2026-05-23 08:42:30 -07:00
parent 745d959c9b
commit 2b49e90b81
5 changed files with 371 additions and 16 deletions

View file

@ -151,6 +151,40 @@ function Tooltip({ children, text }: { children: React.ReactNode; text: string }
);
}
function ThumbnailImage({ checksum, fallbackIcon }: { checksum: string; fallbackIcon: React.ReactNode }) {
const [errorCount, setErrorCount] = useState(0);
const [key, setKey] = useState(0);
const [showFallback, setShowFallback] = useState(false);
return (
<>
<img
key={key}
src={`${api.getThumbnailUrl(checksum)}${errorCount > 0 ? `?t=${key}` : ''}`}
alt=""
className="w-full h-full object-cover"
style={{ display: showFallback ? 'none' : 'block' }}
onError={(e) => {
if (errorCount < 5) {
e.currentTarget.style.display = 'none';
setTimeout(() => {
setErrorCount(c => c + 1);
setKey(Date.now());
}, 2000);
} else {
setShowFallback(true);
}
}}
onLoad={(e) => {
e.currentTarget.style.display = 'block';
setShowFallback(false);
}}
/>
{showFallback && fallbackIcon}
</>
);
}
export default function FileExplorer({ onLogout }: FileExplorerProps) {
const [currentPath, setCurrentPath] = useState(() => {
if (typeof window !== 'undefined') {
@ -202,6 +236,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
const [dragOverFolder, setDragOverFolder] = useState<string | null>(null);
const [pinnedExpanded, setPinnedExpanded] = useState(false);
const [pinnedOrder, setPinnedOrder] = useState<string[]>([]);
const [dragOverPinnedItem, setDragOverPinnedItem] = useState<string | null>(null);
const [selectionBox, setSelectionBox] = useState<{ startX: number; startY: number; currentX: number; currentY: number } | null>(null);
const [initialSelectedFiles, setInitialSelectedFiles] = useState<Set<string>>(new Set());
const searchTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined);
@ -806,17 +841,7 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
if (isMedia && file.checksum && viewMode === 'grid') {
return (
<div className="relative w-full h-full flex items-center justify-center overflow-hidden rounded-md">
<img
src={api.getThumbnailUrl(file.checksum)}
alt=""
className="w-full h-full object-cover"
onError={(e) => {
e.currentTarget.style.display = 'none';
const next = e.currentTarget.nextElementSibling as HTMLElement;
if (next) next.style.display = 'block';
}}
/>
<div style={{ display: 'none' }}>{fallbackIcon}</div>
<ThumbnailImage checksum={file.checksum} fallbackIcon={fallbackIcon} />
</div>
);
}
@ -977,16 +1002,24 @@ export default function FileExplorer({ onLogout }: FileExplorerProps) {
}}
onDragOver={(e) => {
e.preventDefault();
setDragOverPinnedItem(file.path);
}}
onDragLeave={() => {
setDragOverPinnedItem(null);
}}
onDrop={(e) => {
e.preventDefault();
setDragOverPinnedItem(null);
const source = e.dataTransfer.getData('text/plain');
if (source && source !== file.path) {
handlePinnedDragEnd(source, file.path);
}
}}
className="group flex items-center justify-between px-10 py-2 text-sm font-medium cursor-pointer rounded-lg transition-colors hover:bg-white/5 gap-3"
style={{ color: 'var(--color-text-secondary)' }}
style={{
color: 'var(--color-text-secondary)',
borderTop: dragOverPinnedItem === file.path ? '2px solid var(--color-accent)' : '2px solid transparent',
}}
onClick={() => { setActiveSection('files'); navigateTo(file.path); }}
>
<div className="w-4 h-4 flex items-center justify-center flex-shrink-0 [&>svg]:w-4 [&>svg]:h-4">