98 lines
3.2 KiB
TypeScript
98 lines
3.2 KiB
TypeScript
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<string, string> = {
|
|
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<DirectoryFont>('C64_Pro_Mono');
|
|
|
|
return (
|
|
<div className="flex flex-col h-full" style={{ fontFamily: `'${font}', monospace` }}>
|
|
{/* Font toggle bar */}
|
|
<div className="flex items-center justify-end gap-2 px-4 py-2 border-b border-neutral-200 bg-neutral-50">
|
|
<Type className="w-4 h-4 text-neutral-500" />
|
|
<span className="text-xs text-neutral-500">Font:</span>
|
|
<div className="inline-flex rounded-md border border-neutral-300 bg-white overflow-hidden">
|
|
{FONTS.map((f, idx) => (
|
|
<button
|
|
key={f.id}
|
|
onClick={() => setFont(f.id)}
|
|
className={`px-3 py-1 text-xs ${
|
|
font === f.id
|
|
? 'bg-blue-600 text-white'
|
|
: 'bg-white text-neutral-700 hover:bg-neutral-100'
|
|
} ${idx > 0 ? 'border-l border-neutral-300' : ''}`}
|
|
aria-pressed={font === f.id}
|
|
>
|
|
{f.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Listing */}
|
|
<div className="flex-1 overflow-auto text-sm">
|
|
{entries.length === 0 ? (
|
|
<div className="p-8 text-center text-neutral-500">
|
|
Empty directory
|
|
</div>
|
|
) : (
|
|
entries.map((entry, idx) => (
|
|
<div
|
|
key={idx}
|
|
className="px-4 py-2 border-b border-neutral-100 flex items-center hover:bg-neutral-50"
|
|
>
|
|
<span className="inline-block w-16 text-neutral-700 flex-shrink-0">
|
|
{String(entry.blocks).padStart(3, ' ')}
|
|
</span>
|
|
<span className="inline-block w-40 truncate text-neutral-900 flex-shrink-0">
|
|
{entry.name}
|
|
</span>
|
|
<span className="inline-block w-16 flex-shrink-0">
|
|
<span
|
|
className={`px-1.5 py-0.5 rounded text-xs font-medium ${
|
|
TYPE_BADGE[entry.type] || 'bg-neutral-200 text-neutral-700'
|
|
}`}
|
|
style={{ fontFamily: 'system-ui, sans-serif' }}
|
|
>
|
|
{entry.type}
|
|
</span>
|
|
</span>
|
|
</div>
|
|
))
|
|
)}
|
|
</div>
|
|
|
|
{footerNote && (
|
|
<div className="px-4 py-3 text-xs text-neutral-500 border-t border-neutral-200">
|
|
{footerNote}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|