Перейти к основному содержимому

Дерево файлов в Worker

Как устроен пример

Ссылка на заголовок

Эта страница показывает вложенное worker-based дерево файлов без моков. Docs-страница держит host DOM и pointer hit-testing, а remote Vue-приложение хранит структуру дерева, inline-редактирование и drag-логику внутри выделенного Web Worker.

Пример состоит из трех частей:

  • host runtime, который монтирует HostedTree в область preview;
  • remote Worker, который рендерит папки, файлы, inline-действия и обрабатывает RemoteSortableEvent;
  • live snapshot под деревом, который показывает текущее вложенное remote-state после редактирования и drop.

Как взаимодействовать

Ссылка на заголовок
  • Перетаскивайте узлы за handle, чтобы менять порядок соседей или переносить их в другую папку.
  • Переименовывайте элементы inline, добавляйте файлы и папки, удаляйте узлы из текущего дерева.
  • Используйте Сбросить дерево, чтобы вернуть исходную структуру workspace.

Сортируемое и редактируемое дерево файлов в выделенном Worker

Перетаскивайте файлы и папки за handle, переносите узлы между папками, переименовывайте элементы inline, создавайте новые записи и при необходимости сбрасывайте дерево к исходному состоянию.

Запускаю выделенный Worker runtime...

Это дерево подключено через тот же host/worker transport, который используется публичными runtime API библиотеки.

import type { Channel } from '@omnicajs/vue-remote/host'
import { createEndpoint, fromWebWorker } from '@remote-ui/rpc'
import {
createApp,
h,
} from 'vue'
import {
HostedTree,
createProvider,
createReceiver,
} from '@omnicajs/vue-remote/host'
interface SandboxWorkerApi {
release (): void;
run (channel: Channel, labels: SortableFileTreeSandboxLabels): Promise<void>;
}
export interface SortableFileTreeSandboxLabels {
addFileLabel: string;
addFolderLabel: string;
booting: string;
cancelLabel: string;
collapseLabel: string;
deleteLabel: string;
dragCanceledAction: string;
draggingAction: string;
emptyFolderLabel: string;
expandLabel: string;
failed: string;
fileAddedAction: string;
fileKindLabel: string;
folderAddedAction: string;
folderKindLabel: string;
initialAction: string;
movedAction: string;
newFileName: string;
newFolderName: string;
ready: string;
removedAction: string;
renameLabel: string;
renamedAction: string;
resetLabel: string;
rootEyebrow: string;
saveLabel: string;
snapshotLabel: string;
snapshotUnavailable?: string;
unsupported: string;
}
export interface SortableFileTreeSandboxElements {
rootElement: HTMLElement;
}
export interface SortableFileTreeSandboxHandle {
destroy (): Promise<void>;
}
export const mountSortableFileTreeSandbox = async (
elements: SortableFileTreeSandboxElements,
labels: SortableFileTreeSandboxLabels
): Promise<SortableFileTreeSandboxHandle> => {
const { rootElement } = elements
if (typeof Worker === 'undefined') {
rootElement.textContent = labels.unsupported
return {
async destroy () {},
}
}
rootElement.textContent = labels.booting
const receiver = createReceiver()
const provider = createProvider()
const host = createApp({
render: () => h(HostedTree, { provider, receiver }),
})
const worker = new Worker(new URL('./remote.worker.ts', import.meta.url), {
type: 'module',
})
const endpoint = createEndpoint<SandboxWorkerApi>(fromWebWorker(worker))
let destroyed = false
const destroy = async () => {
if (destroyed) {
return
}
destroyed = true
try {
await endpoint.call.release()
} catch {
// Worker teardown should not block page cleanup.
} finally {
endpoint.terminate()
worker.terminate()
host.unmount()
rootElement.innerHTML = ''
}
}
try {
host.mount(rootElement)
await endpoint.call.run(receiver.receive, labels)
} catch (error) {
await destroy()
rootElement.textContent = `${labels.failed}: ${error instanceof Error ? error.message : String(error)}`
}
return {
destroy,
}
}

Связанные страницы

Ссылка на заголовок