refac
This commit is contained in:
1 parent
5caa91a493
commit
2dadc5435a
7 files changed
+101
-38
No files matched your search
@@ -7,6 +7,7 @@
|
||||
|
||||
export let count: number = 0;
|
||||
export let hasFiles: boolean = false;
|
||||
export let canDelete = true;
|
||||
|
||||
export let onDelete: () => void = () => {};
|
||||
export let onDownload: () => void = () => {};
|
||||
@@ -64,8 +65,9 @@
|
||||
|
||||
<Tooltip content={$i18n.t('Delete')}>
|
||||
<button
|
||||
class="p-1 rounded transition text-gray-400 dark:text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-gray-600 dark:hover:text-gray-400"
|
||||
class="p-1 rounded transition text-gray-400 dark:text-gray-500 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-gray-600 dark:hover:text-gray-400 disabled:opacity-30 disabled:hover:bg-transparent"
|
||||
on:click={onDelete}
|
||||
disabled={!canDelete}
|
||||
aria-label={$i18n.t('Delete')}
|
||||
>
|
||||
<GarbageBin className="size-3.5" />
|
||||
|
||||
@@ -32,6 +32,10 @@
|
||||
export let onSelect: (entry: FileEntry, event: MouseEvent) => void = () => {};
|
||||
export let onLongPress: () => void = () => {};
|
||||
export let showDate: boolean = false;
|
||||
export let parentWritable = true;
|
||||
|
||||
$: writable = entry.writable !== false;
|
||||
$: canMutate = parentWritable && writable;
|
||||
|
||||
const formatRelativeTime = (epoch: number): string => {
|
||||
const diff = Math.floor(Date.now() / 1000) - epoch;
|
||||
@@ -143,6 +147,7 @@
|
||||
role={entry.type === 'directory' ? 'button' : undefined}
|
||||
on:dragover={(e) => {
|
||||
if (entry.type !== 'directory') return;
|
||||
if (!writable) return;
|
||||
if (!e.dataTransfer?.types.includes('application/x-terminal-file-move')) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -155,6 +160,7 @@
|
||||
}}
|
||||
on:drop={(e) => {
|
||||
if (entry.type !== 'directory') return;
|
||||
if (!writable) return;
|
||||
const raw = e.dataTransfer?.getData('application/x-terminal-file-move');
|
||||
if (!raw) return;
|
||||
e.preventDefault();
|
||||
@@ -173,8 +179,12 @@
|
||||
>
|
||||
<button
|
||||
class="flex-1 flex items-center gap-2 px-3 py-1.5 text-left min-w-0"
|
||||
draggable={true}
|
||||
draggable={canMutate}
|
||||
on:dragstart={(e) => {
|
||||
if (!canMutate) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
const filePath = `${currentPath}${entry.name}`;
|
||||
// If dragging a selected item, drag all selected
|
||||
if (selected && selectedPaths.size > 1) {
|
||||
@@ -282,6 +292,9 @@
|
||||
{entry.name}
|
||||
</span>
|
||||
{/if}
|
||||
{#if !writable && !renaming}
|
||||
<span class="text-[10px] text-gray-400 shrink-0">Read-only</span>
|
||||
{/if}
|
||||
{#if entry.type === 'file' && entry.size !== undefined && !renaming}
|
||||
{#if showDate && entry.modified}
|
||||
<span class="text-[10px] text-gray-400 shrink-0"
|
||||
@@ -354,9 +367,11 @@
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] hover:bg-gray-50/40 dark:hover:bg-gray-800/40 transition"
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] hover:bg-gray-50/40 dark:hover:bg-gray-800/40 transition disabled:opacity-40 disabled:hover:bg-transparent"
|
||||
disabled={!canMutate}
|
||||
on:click={(e) => {
|
||||
e.stopPropagation();
|
||||
if (!canMutate) return;
|
||||
startRename();
|
||||
}}
|
||||
>
|
||||
@@ -366,9 +381,11 @@
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] hover:bg-gray-50/40 dark:hover:bg-gray-800/40 transition"
|
||||
class="select-none flex h-[1.6875rem] w-full items-center gap-2 rounded-xl px-2 text-[13px] hover:bg-gray-50/40 dark:hover:bg-gray-800/40 transition disabled:opacity-40 disabled:hover:bg-transparent"
|
||||
disabled={!canMutate}
|
||||
on:click={(e) => {
|
||||
e.stopPropagation();
|
||||
if (!canMutate) return;
|
||||
onDelete(`${currentPath}${entry.name}`, entry.name);
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
export let breadcrumbs: { label: string; path: string }[] = [];
|
||||
export let selectedFile: string | null = null;
|
||||
export let loading = false;
|
||||
export let writable = true;
|
||||
|
||||
export let onNavigate: (path: string) => void = () => {};
|
||||
export let onRefresh: () => void = () => {};
|
||||
@@ -114,6 +115,7 @@
|
||||
: ''}"
|
||||
on:click={() => onNavigate(crumb.path)}
|
||||
on:dragover={(e) => {
|
||||
if (!writable) return;
|
||||
if (!e.dataTransfer?.types.includes('application/x-terminal-file-move')) return;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
@@ -123,6 +125,7 @@
|
||||
if (dragOverCrumb === i) dragOverCrumb = null;
|
||||
}}
|
||||
on:drop={(e) => {
|
||||
if (!writable) return;
|
||||
const raw = e.dataTransfer?.getData('application/x-terminal-file-move');
|
||||
if (!raw) return;
|
||||
e.preventDefault();
|
||||
@@ -145,6 +148,11 @@
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
{#if !writable}
|
||||
<span class="text-[10px] text-gray-400 dark:text-gray-500 shrink-0">
|
||||
Read-only
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
<Tooltip content={$i18n.t('Refresh')}>
|
||||
<button
|
||||
@@ -240,8 +248,9 @@
|
||||
</Dropdown>
|
||||
<Tooltip content={$i18n.t('New Folder')}>
|
||||
<button
|
||||
class="shrink-0 p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-400"
|
||||
class="shrink-0 p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-400 disabled:opacity-30 disabled:hover:bg-transparent"
|
||||
on:click={onNewFolder}
|
||||
disabled={!writable}
|
||||
aria-label={$i18n.t('New Folder')}
|
||||
>
|
||||
<NewFolderAlt className="size-3.5" />
|
||||
@@ -249,8 +258,9 @@
|
||||
</Tooltip>
|
||||
<Tooltip content={$i18n.t('New File')}>
|
||||
<button
|
||||
class="shrink-0 p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-400"
|
||||
class="shrink-0 p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-400 disabled:opacity-30 disabled:hover:bg-transparent"
|
||||
on:click={onNewFile}
|
||||
disabled={!writable}
|
||||
aria-label={$i18n.t('New File')}
|
||||
>
|
||||
<FilePlusAlt className="size-3.5" />
|
||||
@@ -279,8 +289,9 @@
|
||||
</Tooltip>
|
||||
<Tooltip content={$i18n.t('Upload')}>
|
||||
<button
|
||||
class="shrink-0 p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-400"
|
||||
class="shrink-0 p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800 transition text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-400 disabled:opacity-30 disabled:hover:bg-transparent"
|
||||
on:click={() => uploadInput?.click()}
|
||||
disabled={!writable}
|
||||
aria-label={$i18n.t('Upload')}
|
||||
>
|
||||
<svg
|
||||
@@ -305,7 +316,7 @@
|
||||
multiple
|
||||
hidden
|
||||
on:change={async () => {
|
||||
if (!uploadInput?.files?.length) return;
|
||||
if (!writable || !uploadInput?.files?.length) return;
|
||||
onUploadFiles(Array.from(uploadInput.files));
|
||||
uploadInput.value = '';
|
||||
}}
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
export let onSheetChange: ((sheet: string) => void) | null = null;
|
||||
|
||||
export let overlay = false;
|
||||
export let readOnly = false;
|
||||
|
||||
export let onSave: ((content: string) => Promise<void>) | null = null;
|
||||
|
||||
@@ -59,6 +60,7 @@
|
||||
};
|
||||
|
||||
export const startEdit = async () => {
|
||||
if (readOnly) return;
|
||||
editContent = fileContent ?? '';
|
||||
editing = true;
|
||||
showRaw = true;
|
||||
@@ -67,7 +69,7 @@
|
||||
};
|
||||
|
||||
export const saveEdit = async () => {
|
||||
if (!onSave) return;
|
||||
if (!onSave || readOnly) return;
|
||||
saving = true;
|
||||
await onSave(editContent);
|
||||
saving = false;
|
||||
@@ -81,7 +83,7 @@
|
||||
|
||||
/** Save code file directly from CodeMirror */
|
||||
export const saveCodeFile = async () => {
|
||||
if (!onSave) return;
|
||||
if (!onSave || readOnly) return;
|
||||
saving = true;
|
||||
const content = fileCodeEditorRef?.getValue() ?? '';
|
||||
await onSave(content);
|
||||
@@ -426,7 +428,7 @@
|
||||
bind:this={fileCodeEditorRef}
|
||||
value={fileContent ?? ''}
|
||||
filePath={selectedFile}
|
||||
{onSave}
|
||||
onSave={readOnly ? null : onSave}
|
||||
/>
|
||||
</div>
|
||||
{:else if isMarkdown && !showRaw}
|
||||
@@ -439,7 +441,7 @@
|
||||
bind:this={fileCodeEditorRef}
|
||||
value={fileContent ?? ''}
|
||||
filePath={selectedFile}
|
||||
{onSave}
|
||||
onSave={readOnly ? null : onSave}
|
||||
/>
|
||||
</div>
|
||||
{:else if isCsv && !showRaw && csvRows.length > 0}
|
||||
@@ -496,7 +498,7 @@
|
||||
bind:this={fileCodeEditorRef}
|
||||
value={fileContent ?? ''}
|
||||
filePath={selectedFile}
|
||||
{onSave}
|
||||
onSave={readOnly ? null : onSave}
|
||||
/>
|
||||
</div>
|
||||
{:else if isSvg && highlightedHtml && !showRaw}
|
||||
|
||||
Reference in new issue
Block a user