diff --git a/web/src/lib/components/folder-tree/folder-tree.svelte b/web/src/lib/components/folder-tree/folder-tree.svelte
deleted file mode 100644
index 7f8289ce74..0000000000
--- a/web/src/lib/components/folder-tree/folder-tree.svelte
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-{#if isExpanded}
-
- {#each Object.entries(content) as [subFolderName, subContent], index (index)}
- -
-
-
- {/each}
-
-{/if}
diff --git a/web/src/lib/components/layouts/user-page-layout.svelte b/web/src/lib/components/layouts/user-page-layout.svelte
index 495c1aae30..8222007d57 100644
--- a/web/src/lib/components/layouts/user-page-layout.svelte
+++ b/web/src/lib/components/layouts/user-page-layout.svelte
@@ -3,7 +3,6 @@
import NavigationBar from '../shared-components/navigation-bar/navigation-bar.svelte';
import SideBar from '../shared-components/side-bar/side-bar.svelte';
import AdminSideBar from '../shared-components/side-bar/admin-side-bar.svelte';
- import FolderSideBar from '$lib/components/shared-components/side-bar/folder-side-bar.svelte';
export let hideNavbar = false;
export let showUploadButton = false;
@@ -11,7 +10,6 @@
export let description: string | undefined = undefined;
export let scrollbar = true;
export let admin = false;
- export let isFolderView = false;
$: scrollbarClass = scrollbar ? 'immich-scrollbar p-2 pb-8' : 'scrollbar-hidden';
$: hasTitleClass = title ? 'top-16 h-[calc(100%-theme(spacing.16))]' : 'top-0 h-full';
@@ -31,8 +29,6 @@
{#if admin}
- {:else if isFolderView}
-
{:else}
{/if}
diff --git a/web/src/lib/components/shared-components/side-bar/folder-browser-sidebar.svelte b/web/src/lib/components/shared-components/side-bar/folder-browser-sidebar.svelte
deleted file mode 100644
index 8e744c23aa..0000000000
--- a/web/src/lib/components/shared-components/side-bar/folder-browser-sidebar.svelte
+++ /dev/null
@@ -1,32 +0,0 @@
-
-
-
diff --git a/web/src/lib/components/shared-components/side-bar/folder-side-bar.svelte b/web/src/lib/components/shared-components/side-bar/folder-side-bar.svelte
deleted file mode 100644
index ff1cd514e6..0000000000
--- a/web/src/lib/components/shared-components/side-bar/folder-side-bar.svelte
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
diff --git a/web/src/lib/components/shared-components/tree/tree-item-thumbnails.svelte b/web/src/lib/components/shared-components/tree/tree-item-thumbnails.svelte
new file mode 100644
index 0000000000..759a3e5e65
--- /dev/null
+++ b/web/src/lib/components/shared-components/tree/tree-item-thumbnails.svelte
@@ -0,0 +1,25 @@
+
+
+{#if items.length > 0}
+
+{/if}
diff --git a/web/src/lib/components/shared-components/tree/tree-items.svelte b/web/src/lib/components/shared-components/tree/tree-items.svelte
new file mode 100644
index 0000000000..bf04e6ae1f
--- /dev/null
+++ b/web/src/lib/components/shared-components/tree/tree-items.svelte
@@ -0,0 +1,17 @@
+
+
+
+ {#each Object.entries(items) as [path, tree], index (index)}
+ -
+
+
+ {/each}
+
diff --git a/web/src/lib/components/shared-components/tree/tree.svelte b/web/src/lib/components/shared-components/tree/tree.svelte
new file mode 100644
index 0000000000..7975825c5e
--- /dev/null
+++ b/web/src/lib/components/shared-components/tree/tree.svelte
@@ -0,0 +1,39 @@
+
+
+
+ (isOpen = !isOpen)}>
+
+
+
+
+
+ {value}
+
+
+{#if isOpen}
+
+{/if}
diff --git a/web/src/lib/constants.ts b/web/src/lib/constants.ts
index 184e913d9e..34d6409848 100644
--- a/web/src/lib/constants.ts
+++ b/web/src/lib/constants.ts
@@ -80,6 +80,7 @@ export enum QueryParameter {
SEARCHED_PEOPLE = 'searchedPeople',
SMART_SEARCH = 'smartSearch',
PAGE = 'page',
+ PATH = 'path',
}
export enum OpenSettingQueryParameterValue {
diff --git a/web/src/lib/utils/folder-utils.ts b/web/src/lib/utils/tree-utils.ts
similarity index 71%
rename from web/src/lib/utils/folder-utils.ts
rename to web/src/lib/utils/tree-utils.ts
index 0305f89672..cc17784eb6 100644
--- a/web/src/lib/utils/folder-utils.ts
+++ b/web/src/lib/utils/tree-utils.ts
@@ -2,7 +2,9 @@ export interface RecursiveObject {
[key: string]: RecursiveObject;
}
-export function buildFolderTree(paths: string[]) {
+export const normalizeTreePath = (path: string) => path.replace(/^\//, '').replace(/\/$/, '');
+
+export function buildTree(paths: string[]) {
const root: RecursiveObject = {};
for (const path of paths) {
const parts = path.split('/');
diff --git a/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte b/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte
index bf914ff8f9..b530184342 100644
--- a/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte
+++ b/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.svelte
@@ -1,14 +1,22 @@
-
+
+
+
+ {$t('explorer').toUpperCase()}
+
+
+
+
+
+
{#if data.path}
@@ -71,42 +93,20 @@
-
-
- {#if data.currentFolders.length > 0}
-
- {/if}
+
+
- 0}
- >
- {#if data.pathAssets && data.pathAssets.length > 0}
+ {#if data.pathAssets && data.pathAssets.length > 0}
+
- {/if}
-
+
+ {/if}
diff --git a/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.ts b/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.ts
index f04d7840e5..41800c1a7d 100644
--- a/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.ts
+++ b/web/src/routes/(user)/folders/[[photos=photos]]/[[assetId=id]]/+page.ts
@@ -1,7 +1,9 @@
+import { QueryParameter } from '$lib/constants';
import { foldersStore } from '$lib/stores/folders.store';
import { authenticate } from '$lib/utils/auth';
import { getFormatter } from '$lib/utils/i18n';
import { getAssetInfoFromParam } from '$lib/utils/navigation';
+import { buildTree, normalizeTreePath } from '$lib/utils/tree-utils';
import { get } from 'svelte/store';
import type { PageLoad } from './$types';
@@ -14,25 +16,24 @@ export const load = (async ({ params, url }) => {
const { uniquePaths } = get(foldersStore);
let pathAssets = null;
- const path = url.searchParams.get('folder');
+ const path = url.searchParams.get(QueryParameter.PATH);
if (path) {
await foldersStore.fetchAssetsByPath(path);
const { assets } = get(foldersStore);
pathAssets = assets[path] || null;
}
- const currentPath = path ? `${path}/`.replaceAll('//', '/') : '';
-
- const currentFolders = (uniquePaths || [])
- .filter((path) => path.startsWith(currentPath) && path !== currentPath)
- .map((path) => path.replaceAll(currentPath, '').split('/')[0])
- .filter((value, index, self) => self.indexOf(value) === index);
+ let tree = buildTree(uniquePaths || []);
+ const parts = normalizeTreePath(path || '').split('/');
+ for (const part of parts) {
+ tree = tree?.[part];
+ }
return {
asset,
path,
- currentFolders,
+ currentFolders: Object.keys(tree || {}),
pathAssets,
meta: {
title: $t('folders'),