feat(MediaManager): add VMS creation functionality and UI enhancements
This commit is contained in:
parent
e4a5eac676
commit
243a134a9c
|
|
@ -21,6 +21,7 @@ import {
|
||||||
Hash,
|
Hash,
|
||||||
Home,
|
Home,
|
||||||
Image as ImageIcon,
|
Image as ImageIcon,
|
||||||
|
Layers,
|
||||||
Loader2,
|
Loader2,
|
||||||
MoreVertical,
|
MoreVertical,
|
||||||
Move,
|
Move,
|
||||||
|
|
@ -370,9 +371,11 @@ export default function MediaManager({ initialPath, rootPath, title, config, set
|
||||||
const [viewHexData, setViewHexData] = useState<Uint8Array | null>(null);
|
const [viewHexData, setViewHexData] = useState<Uint8Array | null>(null);
|
||||||
const [viewLoading, setViewLoading] = useState(false);
|
const [viewLoading, setViewLoading] = useState(false);
|
||||||
|
|
||||||
// Rename / folder
|
// Rename / folder / VMS
|
||||||
const [showNewFolder, setShowNewFolder] = useState(false);
|
const [showNewFolder, setShowNewFolder] = useState(false);
|
||||||
const [newFolderName, setNewFolderName] = useState('');
|
const [newFolderName, setNewFolderName] = useState('');
|
||||||
|
const [showCreateVms, setShowCreateVms] = useState(false);
|
||||||
|
const [vmsName, setVmsName] = useState('');
|
||||||
const [renameEntry, setRenameEntry] = useState<EntryInfo | null>(null);
|
const [renameEntry, setRenameEntry] = useState<EntryInfo | null>(null);
|
||||||
const [renameName, setRenameName] = useState('');
|
const [renameName, setRenameName] = useState('');
|
||||||
const [mountEntry, setMountEntry] = useState<EntryInfo | null>(null);
|
const [mountEntry, setMountEntry] = useState<EntryInfo | null>(null);
|
||||||
|
|
@ -781,6 +784,36 @@ export default function MediaManager({ initialPath, rootPath, title, config, set
|
||||||
void openEntry(entry, 'config');
|
void openEntry(entry, 'config');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// ── Create VMS ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
const openCreateVms = () => {
|
||||||
|
const folderName = path.split('/').filter(Boolean).pop() ?? 'playlist';
|
||||||
|
setVmsName(folderName + '.vms');
|
||||||
|
setShowNewFolder(false);
|
||||||
|
setShowCreateVms(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCreateVms = async () => {
|
||||||
|
const name = vmsName.trim();
|
||||||
|
if (!name) return;
|
||||||
|
const filename = name.endsWith('.vms') ? name : name + '.vms';
|
||||||
|
const selectedFiles = entries.filter(e => selected.has(e.path) && e.type === 'file');
|
||||||
|
const content = selectedFiles
|
||||||
|
.map(e => {
|
||||||
|
const stem = e.name.includes('.') ? e.name.slice(0, e.name.lastIndexOf('.')) : e.name;
|
||||||
|
return `${e.name},${stem}`;
|
||||||
|
})
|
||||||
|
.join('\n') + '\n';
|
||||||
|
try {
|
||||||
|
await putFileContents(joinPath(path, filename), content);
|
||||||
|
toast.success(`Created "${filename}"`);
|
||||||
|
setShowCreateVms(false);
|
||||||
|
setVmsName('');
|
||||||
|
setSelected(new Set());
|
||||||
|
void load(path);
|
||||||
|
} catch (e: any) { toast.error(`Failed to create VMS: ${e?.message ?? e}`); }
|
||||||
|
};
|
||||||
|
|
||||||
// ── New folder ───────────────────────────────────────────────────────────
|
// ── New folder ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
const handleCreateFolder = async () => {
|
const handleCreateFolder = async () => {
|
||||||
|
|
@ -972,6 +1005,28 @@ export default function MediaManager({ initialPath, rootPath, title, config, set
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{showCreateVms && (
|
||||||
|
<div className="mt-2 flex items-center gap-2">
|
||||||
|
<Layers className="w-4 h-4 text-indigo-500 flex-shrink-0" />
|
||||||
|
<input
|
||||||
|
value={vmsName}
|
||||||
|
onChange={e => setVmsName(e.target.value)}
|
||||||
|
onKeyDown={e => {
|
||||||
|
if (e.key === 'Enter') void handleCreateVms();
|
||||||
|
if (e.key === 'Escape') { setShowCreateVms(false); setVmsName(''); }
|
||||||
|
}}
|
||||||
|
placeholder="playlist.vms"
|
||||||
|
className="flex-1 px-2 py-1 text-sm border border-neutral-300 rounded"
|
||||||
|
autoFocus
|
||||||
|
/>
|
||||||
|
<button onClick={() => void handleCreateVms()} className="px-3 py-1 text-sm bg-indigo-600 text-white rounded">
|
||||||
|
Create
|
||||||
|
</button>
|
||||||
|
<button onClick={() => { setShowCreateVms(false); setVmsName(''); }} className="p-1 rounded hover:bg-neutral-200">
|
||||||
|
<X className="w-4 h-4 text-neutral-500" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ── Filter + sort bar ── */}
|
{/* ── Filter + sort bar ── */}
|
||||||
|
|
@ -1017,6 +1072,11 @@ export default function MediaManager({ initialPath, rootPath, title, config, set
|
||||||
<button onClick={moveSelected} className="px-2 py-0.5 rounded border border-blue-300 bg-white text-blue-700 hover:bg-blue-100 inline-flex items-center gap-1">
|
<button onClick={moveSelected} className="px-2 py-0.5 rounded border border-blue-300 bg-white text-blue-700 hover:bg-blue-100 inline-flex items-center gap-1">
|
||||||
<Move className="w-3.5 h-3.5" /> Move
|
<Move className="w-3.5 h-3.5" /> Move
|
||||||
</button>
|
</button>
|
||||||
|
{selCount > 1 && (
|
||||||
|
<button onClick={openCreateVms} className="px-2 py-0.5 rounded border border-blue-300 bg-white text-blue-700 hover:bg-blue-100 inline-flex items-center gap-1">
|
||||||
|
<Layers className="w-3.5 h-3.5" /> Create VMS
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<button onClick={() => void deleteSelected()} className="px-2 py-0.5 rounded border border-red-300 bg-white text-red-700 hover:bg-red-50 inline-flex items-center gap-1">
|
<button onClick={() => void deleteSelected()} className="px-2 py-0.5 rounded border border-red-300 bg-white text-red-700 hover:bg-red-50 inline-flex items-center gap-1">
|
||||||
<Trash2 className="w-3.5 h-3.5" /> Delete
|
<Trash2 className="w-3.5 h-3.5" /> Delete
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user