Skip to content
This repository was archived by the owner on Jan 6, 2024. It is now read-only.

Commit 3155aa0

Browse files
authored
feat(assets): tree view for list mode (#157)
1 parent 5e9697d commit 3155aa0

File tree

2 files changed

+67
-11
lines changed

2 files changed

+67
-11
lines changed
+41-10
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
11
<script setup lang="ts">
2-
const props = defineProps<{
3-
asset: AssetInfo
4-
}>()
2+
const props = withDefaults(defineProps<{
3+
item: any
4+
index?: number
5+
modelValue: AssetInfo | undefined
6+
}>(), {
7+
index: 0,
8+
})
9+
10+
const emit = defineEmits<{ (...args: any): void }>()
11+
const model = useVModel(props, 'modelValue', emit, { passive: true })
12+
13+
const isCollection = computed(() => props.item?.children?.length)
14+
15+
const open = ref(true)
516
617
const icon = computed(() => {
18+
if (isCollection.value)
19+
return 'i-carbon-folder'
720
const assets = {
821
image: 'i-carbon-image',
922
video: 'i-carbon-video',
@@ -12,15 +25,33 @@ const icon = computed(() => {
1225
text: 'i-carbon-document',
1326
json: 'i-carbon-json',
1427
}
15-
return assets[props.asset.type] ?? 'i-carbon-document-blank'
28+
return assets[props.item.type] ?? 'i-carbon-document-blank'
1629
})
1730
</script>
1831

1932
<template>
20-
<button flex="~ gap-1" w-full items-center hover="bg-active" rounded px4 py2>
21-
<div :class="icon" />
22-
<div of-hidden truncate ws-nowrap text-center>
23-
{{ asset.path }}
24-
</div>
25-
</button>
33+
<div>
34+
<button
35+
flex="~ gap-2" w-full items-center hover="bg-active" px4 py1
36+
:style="{ paddingLeft: `calc(1rem + ${index * 1.5}em)` }"
37+
:class="{ 'bg-active': !isCollection && model?.filePath === item?.filePath }"
38+
@click="isCollection ? open = !open : model = item"
39+
>
40+
<div :class="icon" />
41+
<span :class="{ 'flex items-center': isCollection }" flex-auto text-start text-sm font-mono>
42+
{{ item.path }}
43+
</span>
44+
<VDIcon v-if="isCollection" icon="carbon:chevron-right" :transform-rotate="open ? 90 : 0" transition />
45+
</button>
46+
<div x-divider />
47+
<slot v-if="open">
48+
<AssetListItem
49+
v-for="subItem in item?.children"
50+
:key="subItem.filepath"
51+
v-model="model"
52+
:item="subItem"
53+
:index="index + 1"
54+
/>
55+
</slot>
56+
</div>
2657
</template>

packages/client/pages/assets.vue

+26-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,27 @@ const byFolders = computed(() => {
3737
return Object.entries(result).sort(([a], [b]) => a.localeCompare(b))
3838
})
3939
40+
const byTree = computed(() => {
41+
const root = { path: 'public', children: [] }
42+
const addToTree = (node: any, pathParts: any, file: AssetInfo) => {
43+
const [currentPart, ...remainingParts] = pathParts
44+
let child = node.children.find((child: any) => child.path === currentPart)
45+
if (!child) {
46+
child = { ...file, path: currentPart, children: [] }
47+
node.children.push(child)
48+
}
49+
if (remainingParts.length > 1)
50+
addToTree(child, remainingParts, file)
51+
else if (remainingParts.length === 1)
52+
child.children.push({ ...file, path: remainingParts[0] })
53+
}
54+
filtered.value.forEach((file) => {
55+
const pathParts = file.path.split('/').filter(part => part !== '')
56+
addToTree(root, pathParts, file)
57+
})
58+
return root.children
59+
})
60+
4061
const selected = ref<AssetInfo>()
4162
4263
const view = ref<'list' | 'grid'>('grid')
@@ -92,7 +113,11 @@ const navbar = ref<HTMLElement>()
92113
</div>
93114
</template>
94115
<div v-else>
95-
<AssetListItem v-for="a of filtered" :key="a.path" :asset="a" @click="selected = a" />
116+
<AssetListItem
117+
v-for="item, key of byTree" :key="key"
118+
v-model="selected"
119+
:item="item"
120+
/>
96121
</div>
97122
<DrawerRight
98123
:model-value="!!selected"

0 commit comments

Comments
 (0)