Shared utilities: - Add src/utils/formatters.js — formatDate, formatSize, providerColor, providerBg, providerLabel; all components import from here, no inline duplicates - Add src/components/ui/TreeItem.vue — generic expand/collapse tree node; FolderTreeItem, CloudFolderTreeItem, CloudProviderTreeItem now wrap it - Add src/components/storage/StorageBrowser.vue — unified file browser grid used by both FileManagerView and CloudFolderView View refactor (thin data-providers): - FileManagerView.vue: stripped to props + event wiring; all layout moved to StorageBrowser - CloudFolderView.vue: same treatment — feeds props into StorageBrowser - All tree sidebar components delegate expand/collapse to TreeItem.vue Dead code removed: - Delete HomeView.vue — no active route, replaced by FileManagerView - Delete FolderView.vue — no active route, logic merged into FileManagerView Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
78 lines
2.9 KiB
Vue
78 lines
2.9 KiB
Vue
<template>
|
|
<div class="flex flex-col h-full">
|
|
|
|
<!-- Toolbar -->
|
|
<div class="sticky top-0 z-10 bg-white border-b border-gray-100">
|
|
<div class="px-6 py-3 flex items-center gap-3">
|
|
<span class="text-sm font-medium text-gray-700">Cloud Storage</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Content -->
|
|
<div class="flex-1 overflow-y-auto px-6 py-5">
|
|
|
|
<!-- Column headers -->
|
|
<div class="px-4 py-2 grid grid-cols-[2rem_1fr_8rem] gap-3 items-center rounded-lg bg-gray-50 text-xs font-semibold text-gray-400 uppercase tracking-wider select-none mb-1">
|
|
<span></span>
|
|
<span>Name</span>
|
|
<span>Status</span>
|
|
</div>
|
|
|
|
<div v-if="loading" class="text-sm text-gray-400 py-8 text-center">Loading…</div>
|
|
|
|
<div v-else-if="connections.length === 0" class="text-center py-12 text-gray-400">
|
|
<p class="text-sm">No cloud storage connected.</p>
|
|
<router-link to="/settings" class="text-sm text-indigo-600 hover:underline mt-1 inline-block">
|
|
Add a connection in Settings
|
|
</router-link>
|
|
</div>
|
|
|
|
<div v-else class="flex flex-col divide-y divide-gray-100 border border-gray-100 rounded-xl overflow-hidden">
|
|
<div
|
|
v-for="conn in connections"
|
|
:key="conn.id"
|
|
class="px-4 py-2.5 grid grid-cols-[2rem_1fr_8rem] gap-3 items-center hover:bg-gray-50 group cursor-pointer transition-colors"
|
|
@click="openProvider(conn)"
|
|
>
|
|
<!-- Provider icon -->
|
|
<div class="w-7 h-7 rounded-lg flex items-center justify-center shrink-0" :class="providerBg(conn.provider)">
|
|
<svg class="w-4 h-4" :class="providerColor(conn.provider)" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
|
d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 10-9.78 2.096A4.001 4.001 0 003 15z" />
|
|
</svg>
|
|
</div>
|
|
|
|
<span class="text-sm font-medium text-gray-900 truncate">{{ conn.display_name }}</span>
|
|
|
|
<span class="text-xs" :class="conn.status === 'ACTIVE' ? 'text-green-600' : 'text-amber-500'">
|
|
{{ conn.status === 'ACTIVE' ? 'Connected' : 'Needs reauth' }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<p v-if="connections.length > 0" class="mt-4 text-xs text-gray-400 text-center">
|
|
To upload files, navigate into a cloud folder first.
|
|
</p>
|
|
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
import { useCloudConnectionsStore } from '../stores/cloudConnections.js'
|
|
import { providerColor, providerBg } from '../utils/formatters.js'
|
|
|
|
const router = useRouter()
|
|
const cloudStore = useCloudConnectionsStore()
|
|
|
|
const loading = computed(() => cloudStore.loading)
|
|
const connections = computed(() => cloudStore.connections)
|
|
|
|
function openProvider(conn) {
|
|
router.push(`/cloud/${conn.provider}/root`)
|
|
}
|
|
|
|
</script>
|