refac
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
type FileEntry
|
||||
} from '$lib/apis/terminal';
|
||||
import Folder from '../icons/Folder.svelte';
|
||||
import Document from '../icons/Document.svelte';
|
||||
import Spinner from '../common/Spinner.svelte';
|
||||
import ConfirmDialog from '../common/ConfirmDialog.svelte';
|
||||
|
||||
@@ -50,6 +51,9 @@
|
||||
let creatingFolder = false;
|
||||
let newFolderName = '';
|
||||
let newFolderInput: HTMLInputElement;
|
||||
let creatingFile = false;
|
||||
let newFileName = '';
|
||||
let newFileInput: HTMLInputElement;
|
||||
|
||||
// ── Delete confirmation ──────────────────────────────────────────────
|
||||
let deleteTarget: { path: string; name: string } | null = null;
|
||||
@@ -257,6 +261,31 @@
|
||||
await loadDir(currentPath);
|
||||
};
|
||||
|
||||
// ── File creation ────────────────────────────────────────────────────
|
||||
const startNewFile = async () => {
|
||||
creatingFile = true;
|
||||
newFileName = '';
|
||||
await tick();
|
||||
newFileInput?.focus();
|
||||
};
|
||||
|
||||
const submitNewFile = async () => {
|
||||
const name = newFileName.trim();
|
||||
creatingFile = false;
|
||||
newFileName = '';
|
||||
if (!name) return;
|
||||
|
||||
const terminal = selectedTerminal;
|
||||
if (!terminal) return;
|
||||
|
||||
const emptyFile = new File([''], name, { type: 'application/octet-stream' });
|
||||
const result = await uploadToTerminal(terminal.url, terminal.key, currentPath, emptyFile);
|
||||
toast[result ? 'success' : 'error'](
|
||||
$i18n.t(result ? 'File created' : 'Failed to create file')
|
||||
);
|
||||
await loadDir(currentPath);
|
||||
};
|
||||
|
||||
// ── Delete ───────────────────────────────────────────────────────────
|
||||
const handleDelete = async (path: string, name: string) => {
|
||||
const terminal = selectedTerminal;
|
||||
@@ -397,6 +426,7 @@
|
||||
onNavigate={loadDir}
|
||||
onRefresh={() => loadDir(currentPath)}
|
||||
onNewFolder={startNewFolder}
|
||||
onNewFile={startNewFile}
|
||||
onUploadFiles={handleUploadFiles}
|
||||
/>
|
||||
|
||||
@@ -422,7 +452,7 @@
|
||||
<div class="flex justify-center pt-8"><Spinner className="size-4" /></div>
|
||||
{:else if error}
|
||||
<div class="p-4 text-xs">{error}</div>
|
||||
{:else if entries.length === 0 && !creatingFolder}
|
||||
{:else if entries.length === 0 && !creatingFolder && !creatingFile}
|
||||
<div class="flex flex-col items-center justify-center gap-1.5 py-12 text-center">
|
||||
<Folder className="size-6 text-gray-200 dark:text-gray-700" />
|
||||
<div class="text-xs text-gray-400 dark:text-gray-500">
|
||||
@@ -454,8 +484,27 @@
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if creatingFile}
|
||||
<div class="flex items-center gap-2 px-3 py-1.5">
|
||||
<Document className="size-4 shrink-0 text-gray-400 dark:text-gray-500" />
|
||||
<input
|
||||
bind:this={newFileInput}
|
||||
bind:value={newFileName}
|
||||
class="flex-1 text-xs bg-transparent border border-gray-200 dark:border-gray-700 rounded px-1.5 py-0.5 outline-none focus:border-blue-400 dark:focus:border-blue-500"
|
||||
placeholder={$i18n.t('File name')}
|
||||
on:keydown={(e) => {
|
||||
if (e.key === 'Enter') submitNewFile();
|
||||
if (e.key === 'Escape') {
|
||||
creatingFile = false;
|
||||
newFileName = '';
|
||||
}
|
||||
}}
|
||||
on:blur={submitNewFile}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if entries.length > 0 || creatingFolder}
|
||||
{#if entries.length > 0 || creatingFolder || creatingFile}
|
||||
<ul>
|
||||
{#each entries as entry}
|
||||
<FileEntryRow
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { tick } from 'svelte';
|
||||
import Folder from '../../icons/Folder.svelte';
|
||||
import NewFolderAlt from '../../icons/NewFolderAlt.svelte';
|
||||
import FilePlusAlt from '../../icons/FilePlusAlt.svelte';
|
||||
import Spinner from '../../common/Spinner.svelte';
|
||||
import Tooltip from '../../common/Tooltip.svelte';
|
||||
|
||||
@@ -15,6 +16,7 @@
|
||||
export let onNavigate: (path: string) => void = () => {};
|
||||
export let onRefresh: () => void = () => {};
|
||||
export let onNewFolder: () => void = () => {};
|
||||
export let onNewFile: () => void = () => {};
|
||||
export let onUploadFiles: (files: File[]) => void = () => {};
|
||||
|
||||
let uploadInput: HTMLInputElement;
|
||||
@@ -83,6 +85,15 @@
|
||||
<NewFolderAlt className="size-3.5" />
|
||||
</button>
|
||||
</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"
|
||||
on:click={onNewFile}
|
||||
aria-label={$i18n.t('New File')}
|
||||
>
|
||||
<FilePlusAlt className="size-3.5" />
|
||||
</button>
|
||||
</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"
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<script lang="ts">
|
||||
export let className = 'size-4';
|
||||
</script>
|
||||
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.5"
|
||||
class={className}
|
||||
>
|
||||
<path
|
||||
d="M4 12V2.6C4 2.26863 4.26863 2 4.6 2H16.2515C16.4106 2 16.5632 2.06321 16.6757 2.17574L19.8243 5.32426C19.9368 5.43679 20 5.5894 20 5.74853V21.4C20 21.7314 19.7314 22 19.4 22H11"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M16 2V5.4C16 5.73137 16.2686 6 16.6 6H20"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
<path
|
||||
d="M1.99219 19H4.99219M7.99219 19H4.99219M4.99219 19V16M4.99219 19V22"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
Reference in New Issue
Block a user