feat(10-06): update StorageBrowser — skeleton rows, EmptyState, BreadcrumbBar swap
- Replace FolderBreadcrumb import with BreadcrumbBar + EmptyState imports - Replace <FolderBreadcrumb> with <BreadcrumbBar :root-label="mode === 'cloud' ? 'Cloud' : 'Home'"> - Replace Loading… div with 5 animated skeleton rows (animate-pulse, grid-cols-[2rem_1fr_6rem_8rem_6rem]) - Replace inline empty-state divs with three <EmptyState> blocks (search/in-folder/root) - UX-02 skeleton tests green (4/4)
This commit is contained in:
@@ -4,8 +4,9 @@
|
|||||||
<!-- ── Sticky toolbar ──────────────────────────────────────────────── -->
|
<!-- ── Sticky toolbar ──────────────────────────────────────────────── -->
|
||||||
<div class="sticky top-0 z-10 bg-white border-b border-gray-100">
|
<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 flex-wrap">
|
<div class="px-6 py-3 flex items-center gap-3 flex-wrap">
|
||||||
<FolderBreadcrumb
|
<BreadcrumbBar
|
||||||
:segments="breadcrumb"
|
:segments="breadcrumb"
|
||||||
|
:root-label="mode === 'cloud' ? 'Cloud' : 'Home'"
|
||||||
@navigate="$emit('breadcrumb-navigate', $event)"
|
@navigate="$emit('breadcrumb-navigate', $event)"
|
||||||
/>
|
/>
|
||||||
<div class="ml-auto flex items-center gap-2 shrink-0">
|
<div class="ml-auto flex items-center gap-2 shrink-0">
|
||||||
@@ -223,25 +224,46 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Empty state -->
|
<template v-if="loading">
|
||||||
<div
|
<div
|
||||||
v-if="!loading && folders.length === 0 && files.length === 0 && !showNewFolderInput"
|
v-for="n in 5"
|
||||||
class="px-4 py-10 text-center text-gray-300"
|
:key="`sk-${n}`"
|
||||||
>
|
class="px-4 py-2.5 grid grid-cols-[2rem_1fr_6rem_8rem_6rem] gap-3 items-center border-b border-gray-100"
|
||||||
<p class="text-gray-400 text-sm">{{ emptyMessage }}</p>
|
>
|
||||||
<p class="text-xs mt-1">{{ emptyHint }}</p>
|
<div class="w-7 h-7 bg-gray-100 rounded-lg animate-pulse"></div>
|
||||||
</div>
|
<div class="h-4 bg-gray-100 rounded animate-pulse w-2/3"></div>
|
||||||
|
<div class="h-3 bg-gray-100 rounded animate-pulse hidden md:block"></div>
|
||||||
|
<div class="h-3 bg-gray-100 rounded animate-pulse hidden sm:block"></div>
|
||||||
|
<div class="w-14 h-3 bg-gray-100 rounded animate-pulse"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<!-- Search no-results -->
|
<EmptyState
|
||||||
<div
|
v-else-if="searchQuery && folders.length === 0 && files.length === 0"
|
||||||
v-else-if="searchQuery && files.length === 0 && folders.length === 0"
|
icon="search"
|
||||||
class="px-4 py-10 text-center text-sm text-gray-400"
|
:headline="`No results for "${searchQuery}"`"
|
||||||
|
subtext="Try a different search term or clear the filter."
|
||||||
>
|
>
|
||||||
No items match "{{ searchQuery }}".
|
<template #cta>
|
||||||
</div>
|
<button @click="$emit('search-change', '')" class="mt-3 text-sm text-indigo-600 hover:underline">
|
||||||
|
Clear search
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</EmptyState>
|
||||||
|
|
||||||
<!-- Loading -->
|
<EmptyState
|
||||||
<div v-if="loading" class="py-6 text-center text-sm text-gray-400">Loading…</div>
|
v-else-if="breadcrumb.length > 0 && folders.length === 0 && files.length === 0 && !showNewFolderInput"
|
||||||
|
icon="document"
|
||||||
|
:headline="emptyMessage"
|
||||||
|
:subtext="emptyHint"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<EmptyState
|
||||||
|
v-else-if="folders.length === 0 && files.length === 0 && !showNewFolderInput"
|
||||||
|
icon="folder"
|
||||||
|
:headline="emptyMessage"
|
||||||
|
:subtext="emptyHint"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -249,7 +271,8 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, nextTick, onMounted, onUnmounted } from 'vue'
|
import { ref, computed, nextTick, onMounted, onUnmounted } from 'vue'
|
||||||
import FolderBreadcrumb from '../folders/FolderBreadcrumb.vue'
|
import BreadcrumbBar from '../ui/BreadcrumbBar.vue'
|
||||||
|
import EmptyState from '../ui/EmptyState.vue'
|
||||||
import SearchBar from '../documents/SearchBar.vue'
|
import SearchBar from '../documents/SearchBar.vue'
|
||||||
import SortControls from '../documents/SortControls.vue'
|
import SortControls from '../documents/SortControls.vue'
|
||||||
import DropZone from '../upload/DropZone.vue'
|
import DropZone from '../upload/DropZone.vue'
|
||||||
|
|||||||
Reference in New Issue
Block a user