From 8eb6e66005aa12b9499c15c9a53c1767963c6c71 Mon Sep 17 00:00:00 2001 From: Jaime Idolpx Date: Sun, 7 Jun 2026 11:26:18 -0400 Subject: [PATCH] feat: add DirectoryListing component and integrate it into StatusPage; update fonts.css with new font definitions; enhance .gitignore to exclude files directory --- .gitignore | 1 + package.json | 3 +- src/app/components/DirectoryListing.tsx | 97 +++++++++++++++++++++++++ src/app/components/StatusPage.tsx | 72 ++++++++++++++++-- src/styles/fonts.css | 15 ++++ 5 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 src/app/components/DirectoryListing.tsx diff --git a/.gitignore b/.gitignore index abe9356..af69cae 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ ?archives/* dist/* +files/* node_modules/* package-lock.json diff --git a/package.json b/package.json index 92bf5a9..4efb4d3 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,8 @@ "sonner": "2.0.3", "tailwind-merge": "3.2.0", "tw-animate-css": "1.3.8", - "vaul": "1.1.2" + "vaul": "1.1.2", + "webdav": "^5.10.0" }, "devDependencies": { "@tailwindcss/vite": "4.1.12", diff --git a/src/app/components/DirectoryListing.tsx b/src/app/components/DirectoryListing.tsx new file mode 100644 index 0000000..a9c1f59 --- /dev/null +++ b/src/app/components/DirectoryListing.tsx @@ -0,0 +1,97 @@ +import { useState } from 'react'; +import { Type } from 'lucide-react'; + +export type DirectoryFont = 'C64_Pro_Mono' | 'CbmShift'; + +const FONTS: { id: DirectoryFont; label: string }[] = [ + { id: 'C64_Pro_Mono', label: 'C64 Pro' }, + { id: 'CbmShift', label: 'CBM Shift' }, +]; + +export interface DirectoryEntry { + blocks: number; + name: string; + type: string; +} + +interface DirectoryListingProps { + entries: DirectoryEntry[]; + footerNote?: string; +} + +const TYPE_BADGE: Record = { + PRG: 'bg-blue-100 text-blue-700', + SEQ: 'bg-green-100 text-green-700', + DEL: 'bg-neutral-200 text-neutral-500', + REL: 'bg-purple-100 text-purple-700', + USR: 'bg-orange-100 text-orange-700', +}; + +export default function DirectoryListing({ entries, footerNote }: DirectoryListingProps) { + const [font, setFont] = useState('C64_Pro_Mono'); + + return ( +
+ {/* Font toggle bar */} +
+ + Font: +
+ {FONTS.map((f, idx) => ( + + ))} +
+
+ + {/* Listing */} +
+ {entries.length === 0 ? ( +
+ Empty directory +
+ ) : ( + entries.map((entry, idx) => ( +
+ + {String(entry.blocks).padStart(3, ' ')} + + + {entry.name} + + + + {entry.type} + + +
+ )) + )} +
+ + {footerNote && ( +
+ {footerNote} +
+ )} +
+ ); +} diff --git a/src/app/components/StatusPage.tsx b/src/app/components/StatusPage.tsx index be010e4..3e072a8 100644 --- a/src/app/components/StatusPage.tsx +++ b/src/app/components/StatusPage.tsx @@ -3,7 +3,7 @@ import { HardDrive, Activity, Wifi, Signal, Clock, RefreshCw, FolderOpen, Map } import DeviceDetailOverlay from './DeviceDetailOverlay'; import { ImageWithFallback } from './figma/ImageWithFallback'; import { Dialog, DialogContent, DialogTitle, DialogDescription } from './ui/dialog'; -import FileBrowser from './FileBrowser'; +import DirectoryListing from './DirectoryListing'; interface StatusPageProps { config: any; @@ -74,7 +74,12 @@ export default function StatusPage({ config, setConfig }: StatusPageProps) { className="bg-white border border-neutral-200 rounded-lg p-4 relative" >
-
+
-
+
@@ -204,13 +209,66 @@ export default function StatusPage({ config, setConfig }: StatusPageProps) { {showDirectory && (
setShowDirectory(false)} /> -
+
e.stopPropagation()}>
-

Directory

+
+

Directory

+
+ Device #{activeDevice.number} • {activeDevice.url ? activeDevice.url.split('/').pop() : 'No file mounted'} +
+
-
- {}} onClose={() => setShowDirectory(false)} /> +
+ {(() => { + // Derive a directory listing for the currently mounted file. + // In a real device this would come from reading the disk's + // BAM/ directory sectors. Here we synthesize a plausible + // listing based on the mounted file's name. + const fileName = activeDevice.url ? activeDevice.url.split('/').pop() : ''; + if (!fileName) { + return ( +
+ No file mounted on this device. +
+ ); + } + + // Mock directory entries (C64-style: blocks, name, type) + const mockEntries = [ + { blocks: 42, name: 'PAC-MAN', type: 'PRG' }, + { blocks: 38, name: 'GALAGA', type: 'PRG' }, + { blocks: 21, name: 'HISCORE', type: 'SEQ' }, + { blocks: 12, name: 'LOADER', type: 'PRG' }, + { blocks: 5, name: 'TITLE-SCREEN', type: 'SEQ' }, + { blocks: 3, name: 'CONFIG', type: 'SEQ' }, + { blocks: 1, name: 'PARTICLES', type: 'PRG' }, + ]; + + const totalBlocks = 664; // standard D64 capacity + const usedBlocks = mockEntries.reduce((sum, e) => sum + e.blocks, 0); + const freeBlocks = totalBlocks - usedBlocks; + + return ( + <> +
+ BLOCKS + NAME + TYPE + {usedBlocks} BLOCKS USED · {freeBlocks} FREE +
+
+ +
+ + ); + })()}
diff --git a/src/styles/fonts.css b/src/styles/fonts.css index e69de29..91e42ed 100644 --- a/src/styles/fonts.css +++ b/src/styles/fonts.css @@ -0,0 +1,15 @@ +@font-face { + font-family: 'C64_Pro_Mono'; + src: url('/fonts/C64_Pro_Mono-STYLE.woff2') format('woff2'); + font-weight: normal; + font-style: normal; + font-display: swap; +} + +@font-face { + font-family: 'CbmShift'; + src: url('/fonts/CbmShift-STYLE.woff2') format('woff2'); + font-weight: normal; + font-style: normal; + font-display: swap; +}