Add cloud breadcrumbs and even out cloud cards

This commit is contained in:
2026-07-18 19:40:42 -04:00
parent 470d8c3d25
commit 5cb37ff80d
2 changed files with 61 additions and 7 deletions
+42 -7
View File
@@ -6,6 +6,7 @@
app, app,
breadcrumbs, breadcrumbs,
browseTo, browseTo,
cloudBreadcrumbs,
linkedDocument, linkedDocument,
linkedSpace, linkedSpace,
openCloudFolder, openCloudFolder,
@@ -53,6 +54,7 @@
let menuAt = $state({ x: 0, y: 0 }); let menuAt = $state({ x: 0, y: 0 });
const trail = $derived(breadcrumbs()); const trail = $derived(breadcrumbs());
const cloudTrail = $derived(cloudBreadcrumbs());
$effect(() => { $effect(() => {
if (app.scope === "cloud" && app.account) { if (app.scope === "cloud" && app.account) {
@@ -200,10 +202,10 @@
<div <div
class="group flex flex-col overflow-hidden rounded-lg border border-[var(--color-line)] bg-[var(--color-surface)] transition hover:border-[var(--color-accent)] hover:shadow-sm" class="group flex flex-col overflow-hidden rounded-lg border border-[var(--color-line)] bg-[var(--color-surface)] transition hover:border-[var(--color-accent)] hover:shadow-sm"
> >
{#if link && cloudThumbs[link.path]} <div
<div class="flex h-24 items-center justify-center overflow-hidden border-b border-[var(--color-line)] bg-[var(--color-surface-muted)]"
class="flex h-24 items-center justify-center overflow-hidden border-b border-[var(--color-line)] bg-[var(--color-surface-muted)]" >
> {#if link && cloudThumbs[link.path]}
{#if cloudThumbs[link.path].kind === "svg"} {#if cloudThumbs[link.path].kind === "svg"}
<span <span
class="flex w-full items-start justify-center bg-white p-1 [&_svg]:h-auto [&_svg]:w-full" class="flex w-full items-start justify-center bg-white p-1 [&_svg]:h-auto [&_svg]:w-full"
@@ -217,12 +219,18 @@
class="h-full w-full object-contain" class="h-full w-full object-contain"
/> />
{/if} {/if}
</div> {:else}
{/if} <Icon
{icon}
class="text-3xl {link
? 'text-[var(--color-accent)]'
: 'text-[var(--color-ink-muted)]'}"
/>
{/if}
</div>
<div class="flex flex-col gap-2.5 p-3"> <div class="flex flex-col gap-2.5 p-3">
<div class="flex items-start gap-2"> <div class="flex items-start gap-2">
<Icon {icon} class="shrink-0 text-xl text-[var(--color-accent)]" />
<div class="min-w-0 flex-1"> <div class="min-w-0 flex-1">
<p class="truncate text-xs font-medium" {title}>{title}</p> <p class="truncate text-xs font-medium" {title}>{title}</p>
<p class="truncate text-[10px] text-[var(--color-ink-muted)]">{meta}</p> <p class="truncate text-[10px] text-[var(--color-ink-muted)]">{meta}</p>
@@ -676,6 +684,33 @@
{/if} {/if}
</div> </div>
{#if cloudTrail.length > 0}
<div class="mb-3 flex flex-wrap items-center gap-1 text-xs">
<button
class="rounded px-2 py-1 text-[var(--color-ink-muted)] transition hover:bg-[var(--color-surface)] hover:text-[var(--color-ink)]"
onclick={() => openCloudFolder(null)}
>
My Drive
</button>
{#each cloudTrail as folder, index}
<Icon
icon="ph:caret-right"
class="text-[10px] text-[var(--color-ink-muted)]"
/>
<button
class="rounded px-2 py-1 transition hover:bg-[var(--color-surface)]
{index === cloudTrail.length - 1
? 'font-medium'
: 'text-[var(--color-ink-muted)] hover:text-[var(--color-ink)]'}"
onclick={() => openCloudFolder(folder.id)}
>
{folder.name}
</button>
{/each}
</div>
{/if}
{#if app.cloudFolders.length > 0} {#if app.cloudFolders.length > 0}
<div <div
class="mb-4 grid grid-cols-[repeat(auto-fill,minmax(210px,1fr))] gap-2" class="mb-4 grid grid-cols-[repeat(auto-fill,minmax(210px,1fr))] gap-2"
+19
View File
@@ -31,6 +31,7 @@ interface AppState {
spaces: SpaceSummary[]; spaces: SpaceSummary[];
cloudFolder: string | null | "shared"; cloudFolder: string | null | "shared";
cloudFolders: CloudFolder[]; cloudFolders: CloudFolder[];
cloudFolderTree: CloudFolder[];
cloudDocuments: CloudDocument[]; cloudDocuments: CloudDocument[];
cloudFiles: CloudFile[]; cloudFiles: CloudFile[];
cloudLoading: boolean; cloudLoading: boolean;
@@ -65,6 +66,7 @@ export const app = $state<AppState>({
spaces: [], spaces: [],
cloudFolder: null, cloudFolder: null,
cloudFolders: [], cloudFolders: [],
cloudFolderTree: [],
cloudDocuments: [], cloudDocuments: [],
cloudFiles: [], cloudFiles: [],
cloudLoading: false, cloudLoading: false,
@@ -188,6 +190,7 @@ export async function refreshCloud() {
api.cloudListSpaces(), api.cloudListSpaces(),
api.cloudListFiles(app.cloudFolder), api.cloudListFiles(app.cloudFolder),
]); ]);
app.cloudFolderTree = folders;
app.cloudFolders = folders.filter( app.cloudFolders = folders.filter(
(folder) => (folder.parent_id ?? null) === app.cloudFolder, (folder) => (folder.parent_id ?? null) === app.cloudFolder,
); );
@@ -202,6 +205,22 @@ export async function refreshCloud() {
} }
} }
/** Trail from the drive root down to the folder being viewed. */
export function cloudBreadcrumbs(): CloudFolder[] {
if (app.cloudFolder === "shared" || app.cloudFolder === null) return [];
const byId = new Map(app.cloudFolderTree.map((folder) => [folder.id, folder]));
const trail: CloudFolder[] = [];
let current = byId.get(app.cloudFolder);
while (current) {
trail.unshift(current);
current = current.parent_id ? byId.get(current.parent_id) : undefined;
}
return trail;
}
export async function openCloudFolder(id: string | null | "shared") { export async function openCloudFolder(id: string | null | "shared") {
app.cloudFolder = id; app.cloudFolder = id;
await refreshCloud(); await refreshCloud();