botserver/ui/desktop/drive/drive.html

586 lines
25 KiB
HTML

<div class="drive-container" x-data="driveApp()" x-cloak>
<!-- Header -->
<div class="drive-header">
<div class="header-content">
<h1 class="drive-title">
<span class="drive-icon">📁</span>
General Bots Drive
</h1>
<div class="header-actions">
<button class="button-primary" @click="showUploadDialog = true">
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"
></path>
<polyline points="17 8 12 3 7 8"></polyline>
<line x1="12" y1="3" x2="12" y2="15"></line>
</svg>
Upload
</button>
<button class="button-secondary" @click="createFolder()">
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"
></path>
<line x1="12" y1="11" x2="12" y2="17"></line>
<line x1="9" y1="14" x2="15" y2="14"></line>
</svg>
New Folder
</button>
</div>
</div>
<div class="search-bar">
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.35-4.35"></path>
</svg>
<input
type="text"
x-model="searchQuery"
placeholder="Search files and folders..."
class="search-input"
/>
</div>
</div>
<!-- Main Content -->
<div class="drive-layout">
<!-- Sidebar Navigation -->
<aside class="drive-sidebar">
<div class="sidebar-section">
<h3 class="sidebar-heading">Quick Access</h3>
<template x-for="item in quickAccess" :key="item.id">
<button
class="nav-item"
:class="{ active: currentView === item.id }"
@click="currentView = item.id"
>
<span class="nav-icon" x-text="item.icon"></span>
<span class="nav-label" x-text="item.label"></span>
<span
class="nav-badge"
x-show="item.count"
x-text="item.count"
></span>
</button>
</template>
</div>
<div class="sidebar-section">
<h3 class="sidebar-heading">Storage</h3>
<div class="storage-info">
<div class="storage-bar">
<div
class="storage-used"
:style="`width: ${storagePercent}%`"
></div>
</div>
<p class="storage-text">
<span x-text="storageUsed"></span> of
<span x-text="storageTotal"></span> used
</p>
</div>
</div>
</aside>
<!-- File Tree and List -->
<main class="drive-main">
<!-- Breadcrumb -->
<div class="breadcrumb">
<template x-for="(crumb, index) in breadcrumbs" :key="index">
<span class="breadcrumb-item">
<button
@click="navigateToPath(crumb.path)"
x-text="crumb.name"
></button>
<span
class="breadcrumb-separator"
x-show="index < breadcrumbs.length - 1"
>/</span
>
</span>
</template>
</div>
<!-- View Toggle -->
<div class="view-controls">
<div class="view-toggle">
<button
class="view-button"
:class="{ active: viewMode === 'tree' }"
@click="viewMode = 'tree'"
title="Tree View"
>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="8" y1="6" x2="21" y2="6"></line>
<line x1="8" y1="12" x2="21" y2="12"></line>
<line x1="8" y1="18" x2="21" y2="18"></line>
<line x1="3" y1="6" x2="3.01" y2="6"></line>
<line x1="3" y1="12" x2="3.01" y2="12"></line>
<line x1="3" y1="18" x2="3.01" y2="18"></line>
</svg>
</button>
<button
class="view-button"
:class="{ active: viewMode === 'grid' }"
@click="viewMode = 'grid'"
title="Grid View"
>
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<rect x="3" y="3" width="7" height="7"></rect>
<rect x="14" y="3" width="7" height="7"></rect>
<rect x="14" y="14" width="7" height="7"></rect>
<rect x="3" y="14" width="7" height="7"></rect>
</svg>
</button>
</div>
<select class="sort-select" x-model="sortBy">
<option value="name">Name</option>
<option value="modified">Modified</option>
<option value="size">Size</option>
<option value="type">Type</option>
</select>
</div>
<!-- Tree View -->
<div class="file-tree" x-show="viewMode === 'tree'">
<template x-for="item in filteredItems" :key="item.id">
<div>
<div
class="tree-item"
:class="{
selected: selectedItem?.id === item.id,
folder: item.type === 'folder'
}"
:style="`padding-left: ${item.depth * 24 + 12}px`"
@click="selectItem(item)"
@dblclick="item.type === 'folder' && toggleFolder(item)"
>
<button
class="tree-toggle"
x-show="item.type === 'folder'"
@click.stop="toggleFolder(item)"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<polyline
:points="item.expanded ? '6 9 12 15 18 9' : '9 18 15 12 9 6'"
></polyline>
</svg>
</button>
<span
class="tree-icon"
x-text="getFileIcon(item)"
></span>
<span class="tree-label" x-text="item.name"></span>
<span class="tree-meta">
<span
class="tree-size"
x-show="item.type !== 'folder'"
x-text="item.size"
></span>
<span
class="tree-date"
x-text="item.modified"
></span>
</span>
<div class="tree-actions">
<button
class="action-button"
x-show="isEditableFile(item)"
@click.stop="editFile(item)"
title="Edit"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"
></path>
<path
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
></path>
</svg>
</button>
<button
class="action-button"
@click.stop="downloadItem(item)"
title="Download"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"
></path>
<polyline
points="7 10 12 15 17 10"
></polyline>
<line
x1="12"
y1="15"
x2="12"
y2="3"
></line>
</svg>
</button>
<button
class="action-button"
@click.stop="shareItem(item)"
title="Share"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<circle cx="18" cy="5" r="3"></circle>
<circle cx="6" cy="12" r="3"></circle>
<circle cx="18" cy="19" r="3"></circle>
<line
x1="8.59"
y1="13.51"
x2="15.42"
y2="17.49"
></line>
<line
x1="15.41"
y1="6.51"
x2="8.59"
y2="10.49"
></line>
</svg>
</button>
<button
class="action-button danger"
@click.stop="deleteItem(item)"
title="Delete"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<polyline
points="3 6 5 6 21 6"
></polyline>
<path
d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"
></path>
</svg>
</button>
</div>
</div>
<template
x-if="item.type === 'folder' && item.expanded"
>
<div x-html="renderChildren(item)"></div>
</template>
</div>
</template>
</div>
<!-- Grid View -->
<div class="file-grid" x-show="viewMode === 'grid'">
<template x-for="item in filteredItems" :key="item.id">
<div
class="grid-item"
:class="{ selected: selectedItem?.id === item.id }"
@click="selectItem(item)"
@dblclick="item.type === 'folder' && openFolder(item)"
>
<div class="grid-icon" x-text="getFileIcon(item)"></div>
<div class="grid-name" x-text="item.name"></div>
<div class="grid-meta">
<span
x-show="item.type !== 'folder'"
x-text="item.size"
></span>
<span x-text="item.modified"></span>
</div>
</div>
</template>
</div>
<!-- Empty State -->
<div class="empty-state" x-show="filteredItems.length === 0">
<svg
width="80"
height="80"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1"
>
<path
d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"
></path>
</svg>
<h3>No files found</h3>
<p>Upload files or create a new folder to get started</p>
</div>
</main>
<!-- Details Panel -->
<aside class="drive-details" x-show="selectedItem">
<div class="details-header">
<h3>Details</h3>
<button class="close-button" @click="selectedItem = null">
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
<template x-if="selectedItem">
<div class="details-content">
<div class="details-preview">
<div
class="preview-icon"
x-text="getFileIcon(selectedItem)"
></div>
</div>
<div class="details-info">
<h4 x-text="selectedItem.name"></h4>
<div class="info-row">
<span class="info-label">Type</span>
<span
class="info-value"
x-text="selectedItem.type"
></span>
</div>
<div
class="info-row"
x-show="selectedItem.type !== 'folder'"
>
<span class="info-label">Size</span>
<span
class="info-value"
x-text="selectedItem.size"
></span>
</div>
<div class="info-row">
<span class="info-label">Modified</span>
<span
class="info-value"
x-text="selectedItem.modified"
></span>
</div>
<div class="info-row">
<span class="info-label">Created</span>
<span
class="info-value"
x-text="selectedItem.created"
></span>
</div>
</div>
<div class="details-actions">
<button
class="button-primary"
x-show="isEditableFile(selectedItem)"
@click="editFile(selectedItem)"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"
></path>
<path
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
></path>
</svg>
Edit
</button>
<button
class="button-secondary"
@click="downloadItem(selectedItem)"
>
Download
</button>
<button
class="button-secondary"
@click="shareItem(selectedItem)"
>
Share
</button>
<button
class="button-secondary danger"
@click="deleteItem(selectedItem)"
>
Delete
</button>
</div>
</div>
</template>
</aside>
</div>
<!-- Text Editor Modal -->
<div
class="editor-modal"
x-show="showEditor"
x-cloak
@click.self="closeEditor()"
>
<div class="editor-container">
<!-- Editor Header -->
<div class="editor-header">
<div class="editor-title">
<svg
width="20"
height="20"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"
></path>
<path
d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"
></path>
</svg>
<span x-text="editorFileName"></span>
</div>
<div class="editor-actions">
<button
class="button-primary"
@click="saveFile()"
:disabled="editorSaving"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<path
d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"
></path>
<polyline points="17 21 17 13 7 13 7 21"></polyline>
<polyline points="7 3 7 8 15 8"></polyline>
</svg>
<span
x-text="editorSaving ? 'Saving...' : 'Save'"
></span>
</button>
<button class="button-secondary" @click="closeEditor()">
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
>
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
Close
</button>
</div>
</div>
<!-- Editor Content -->
<div class="editor-content">
<template x-if="editorLoading">
<div class="editor-loading">
<div class="loading-spinner"></div>
<p>Loading file...</p>
</div>
</template>
<template x-if="!editorLoading">
<textarea
class="editor-textarea"
x-model="editorContent"
placeholder="Start typing..."
spellcheck="false"
></textarea>
</template>
</div>
<!-- Editor Footer -->
<div class="editor-footer">
<span class="editor-info">
<span x-text="editorContent.length"></span> characters ·
<span x-text="editorContent.split('\\n').length"></span>
lines
</span>
<span class="editor-path" x-text="editorFilePath"></span>
</div>
</div>
</div>
</div>