This commit is contained in:
Timothy Jaeryang Baek 2026-05-14 00:07:55 +09:00
parent 32a417bbf6
commit ab0ee858b7
4 changed files with 100 additions and 12 deletions

View file

@ -653,6 +653,21 @@
}
};
const moveDirectoryHandler = async (dirId: string, targetParentId: string | null) => {
if (dirId === targetParentId) return;
const res = await updateKnowledgeDirectory(localStorage.token, knowledge.id, dirId, {
parent_id: targetParentId
}).catch((e) => {
toast.error(`${e}`);
return null;
});
if (res) {
toast.success($i18n.t('Directory moved.'));
getItemsPage();
}
};
const deleteFileHandler = async (fileId) => {
try {
console.log('Starting file deletion process for:', fileId);
@ -1092,7 +1107,7 @@
{#if currentDirectoryId !== null}
<div class="px-5 -mt-1 pb-2">
<KnowledgeBreadcrumbs rootLabel={knowledge.name} {breadcrumbs} onNavigate={(dirId) => navigateToDirectory(dirId)} />
<KnowledgeBreadcrumbs rootLabel={knowledge.name} {breadcrumbs} onNavigate={(dirId) => navigateToDirectory(dirId)} onMoveFile={(fileId, dirId) => moveFileToDirectoryHandler(fileId, dirId)} onMoveDir={(dirId, targetId) => moveDirectoryHandler(dirId, targetId)} />
</div>
{/if}
@ -1187,7 +1202,9 @@
onDeleteDirectory={(id) => confirmDeleteDirectory(id)}
onMoveFileToDirectory={(fileId, dirId) =>
moveFileToDirectoryHandler(fileId, dirId)}
/>
onMoveDirectoryToDirectory={(dirId, targetId) => moveDirectoryHandler(dirId, targetId)}
/>
</div>
{#if fileItemsTotal > 30}

View file

@ -28,7 +28,7 @@
export let onRename: (id: string, name: string) => void = () => {};
export let onDelete: (id: string) => void = () => {};
export let onFileDrop: (fileId: string, directoryId: string) => void = () => {};
export let onDirDrop: (dirId: string, targetDirectoryId: string) => void = () => {};
let editing = false;
let editName = '';
let editInput: HTMLInputElement;
@ -62,11 +62,20 @@
{dragOver
? 'bg-gray-100 dark:bg-gray-800 ring-1 ring-gray-300 dark:ring-gray-600'
: 'hover:bg-gray-100 dark:hover:bg-gray-850'}"
draggable="true"
on:dragstart={(e) => {
e.dataTransfer?.setData(
'application/x-kb-dir-move',
JSON.stringify({ dirId: directory.id })
);
}}
on:dblclick={() => {
if (writeAccess) startRename();
}}
on:dragover={(e) => {
if (!e.dataTransfer?.types.includes('application/x-kb-file-move')) return;
const hasFile = e.dataTransfer?.types.includes('application/x-kb-file-move');
const hasDir = e.dataTransfer?.types.includes('application/x-kb-dir-move');
if (!hasFile && !hasDir) return;
e.preventDefault();
e.stopPropagation();
dragOver = true;
@ -75,15 +84,26 @@
dragOver = false;
}}
on:drop={(e) => {
const raw = e.dataTransfer?.getData('application/x-kb-file-move');
if (!raw) return;
e.preventDefault();
e.stopPropagation();
dragOver = false;
try {
const data = JSON.parse(raw);
onFileDrop(data.fileId, directory.id);
} catch {}
const fileRaw = e.dataTransfer?.getData('application/x-kb-file-move');
if (fileRaw) {
try {
const data = JSON.parse(fileRaw);
onFileDrop(data.fileId, directory.id);
} catch {}
return;
}
const dirRaw = e.dataTransfer?.getData('application/x-kb-dir-move');
if (dirRaw) {
try {
const data = JSON.parse(dirRaw);
if (data.dirId !== directory.id) {
onDirDrop(data.dirId, directory.id);
}
} catch {}
}
}}
>
<div class="flex items-center">

View file

@ -33,6 +33,7 @@
export let onRenameDirectory = (id: string, name: string) => {};
export let onDeleteDirectory = (id: string) => {};
export let onMoveFileToDirectory = (fileId: string, directoryId: string) => {};
export let onMoveDirectoryToDirectory = (dirId: string, targetDirectoryId: string) => {};
</script>
<div class=" max-h-full flex flex-col w-full gap-[0.5px]">
@ -45,6 +46,7 @@
onRename={(id, name) => onRenameDirectory(id, name)}
onDelete={(id) => onDeleteDirectory(id)}
onFileDrop={(fileId, directoryId) => onMoveFileToDirectory(fileId, directoryId)}
onDirDrop={(dirId, targetId) => onMoveDirectoryToDirectory(dirId, targetId)}
/>
{/each}

View file

@ -7,12 +7,49 @@
export let rootLabel: string = 'Root';
export let breadcrumbs: { id: string; name: string }[] = [];
export let onNavigate: (directoryId: string | null) => void = () => {};
export let onMoveFile: (fileId: string, targetDirectoryId: string | null) => void = () => {};
export let onMoveDir: (dirId: string, targetDirectoryId: string | null) => void = () => {};
let breadcrumbEl: HTMLDivElement;
let dragOverCrumb: number | null = null;
afterUpdate(() => {
if (breadcrumbEl) breadcrumbEl.scrollLeft = breadcrumbEl.scrollWidth;
});
const handleDragOver = (e: DragEvent, index: number) => {
const hasFile = e.dataTransfer?.types.includes('application/x-kb-file-move');
const hasDir = e.dataTransfer?.types.includes('application/x-kb-dir-move');
if (!hasFile && !hasDir) return;
e.preventDefault();
e.stopPropagation();
dragOverCrumb = index;
};
const handleDragLeave = (index: number) => {
if (dragOverCrumb === index) dragOverCrumb = null;
};
const handleDrop = (e: DragEvent, targetDirId: string | null) => {
e.preventDefault();
e.stopPropagation();
dragOverCrumb = null;
const fileRaw = e.dataTransfer?.getData('application/x-kb-file-move');
if (fileRaw) {
try {
const data = JSON.parse(fileRaw);
if (data.fileId) onMoveFile(data.fileId, targetDirId);
} catch {}
return;
}
const dirRaw = e.dataTransfer?.getData('application/x-kb-dir-move');
if (dirRaw) {
try {
const data = JSON.parse(dirRaw);
if (data.dirId) onMoveDir(data.dirId, targetDirId);
} catch {}
}
};
</script>
<div
@ -23,8 +60,14 @@
class="text-xs shrink-0 py-0.5 hover:underline transition
{breadcrumbs.length === 0
? 'text-gray-700 dark:text-gray-300'
: 'text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-400'}"
: 'text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-400'}
{dragOverCrumb === -1
? 'bg-gray-100 dark:bg-gray-800 rounded-lg'
: ''}"
on:click={() => onNavigate(null)}
on:dragover={(e) => handleDragOver(e, -1)}
on:dragleave={() => handleDragLeave(-1)}
on:drop={(e) => handleDrop(e, null)}
>
{rootLabel}
</button>
@ -35,8 +78,14 @@
class="text-xs shrink-0 py-0.5 hover:underline transition
{i === breadcrumbs.length - 1
? 'text-gray-700 dark:text-gray-300'
: 'text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-400'}"
: 'text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-400'}
{dragOverCrumb === i
? 'bg-gray-100 dark:bg-gray-800 rounded-lg'
: ''}"
on:click={() => onNavigate(crumb.id)}
on:dragover={(e) => handleDragOver(e, i)}
on:dragleave={() => handleDragLeave(i)}
on:drop={(e) => handleDrop(e, crumb.id)}
>
{crumb.name}
</button>