update frontend ui, i18n, filters, and deps
This commit is contained in:
94
frontend/components/TreeList.vue
Normal file
94
frontend/components/TreeList.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<ul class="tree-list">
|
||||
<li v-for="node in flatNodes" :key="node.id" :style="{ paddingLeft: `${node.depth * 12}px` }">
|
||||
<button
|
||||
v-if="node.hasChildren"
|
||||
class="card"
|
||||
type="button"
|
||||
style="margin-right: 6px;"
|
||||
@click="toggle(node.id)"
|
||||
>
|
||||
{{ isCollapsed(node.id) ? '+' : '-' }}
|
||||
</button>
|
||||
<span>{{ node.nom }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
type TreeItem = {
|
||||
id: string
|
||||
nom: string
|
||||
parent_id?: string | null
|
||||
}
|
||||
|
||||
type FlatNode = TreeItem & {
|
||||
depth: number
|
||||
hasChildren: boolean
|
||||
}
|
||||
|
||||
const props = defineProps<{ items: TreeItem[] }>()
|
||||
|
||||
const collapsed = ref<Set<string>>(new Set())
|
||||
|
||||
const childrenMap = computed(() => {
|
||||
const map = new Map<string | null, TreeItem[]>()
|
||||
props.items.forEach((item) => {
|
||||
const key = item.parent_id || null
|
||||
const list = map.get(key) || []
|
||||
list.push(item)
|
||||
map.set(key, list)
|
||||
})
|
||||
return map
|
||||
})
|
||||
|
||||
const hasChildren = (id: string) => {
|
||||
const list = childrenMap.value.get(id)
|
||||
return !!(list && list.length)
|
||||
}
|
||||
|
||||
const buildFlat = (parentId: string | null, depth: number, acc: FlatNode[]) => {
|
||||
const children = childrenMap.value.get(parentId) || []
|
||||
children
|
||||
.slice()
|
||||
.sort((a, b) => a.nom.localeCompare(b.nom))
|
||||
.forEach((child) => {
|
||||
acc.push({
|
||||
...child,
|
||||
depth,
|
||||
hasChildren: hasChildren(child.id)
|
||||
})
|
||||
if (!collapsed.value.has(child.id)) {
|
||||
buildFlat(child.id, depth + 1, acc)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const flatNodes = computed(() => {
|
||||
const acc: FlatNode[] = []
|
||||
buildFlat(null, 0, acc)
|
||||
return acc
|
||||
})
|
||||
|
||||
const toggle = (id: string) => {
|
||||
const next = new Set(collapsed.value)
|
||||
if (next.has(id)) {
|
||||
next.delete(id)
|
||||
} else {
|
||||
next.add(id)
|
||||
}
|
||||
collapsed.value = next
|
||||
}
|
||||
|
||||
const isCollapsed = (id: string) => collapsed.value.has(id)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.tree-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user