237 lines
5.5 KiB
Vue
237 lines
5.5 KiB
Vue
<template>
|
|
<div class="tree-demo">
|
|
<v-container fluid>
|
|
<v-row>
|
|
<v-col cols="12">
|
|
<h1>Tree View Demo</h1>
|
|
<p>This is a demonstration of the TreeView component with all required features.</p>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-row>
|
|
<v-col cols="12">
|
|
<v-card>
|
|
<v-card-title>Tree View Component</v-card-title>
|
|
<v-card-text>
|
|
<div class="tree-container">
|
|
<TreeView
|
|
:root-node="sampleData"
|
|
:load-function="loadChildren"
|
|
@select="handleSelect"
|
|
@delete="handleDelete"
|
|
@copy="handleCopy"
|
|
@move="handleMove"
|
|
@add="handleAdd"
|
|
/>
|
|
</div>
|
|
</v-card-text>
|
|
</v-card>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-row>
|
|
<v-col cols="12">
|
|
<v-card>
|
|
<v-card-title>Event Log</v-card-title>
|
|
<v-card-text>
|
|
<div class="event-log">
|
|
<div v-for="(event, index) in eventLog" :key="index" class="event-item">
|
|
<strong>{{ event.type }}:</strong> {{ event.message }}
|
|
</div>
|
|
<div v-if="eventLog.length === 0" class="no-events">
|
|
No events yet. Interact with the tree to see events here.
|
|
</div>
|
|
</div>
|
|
</v-card-text>
|
|
</v-card>
|
|
</v-col>
|
|
</v-row>
|
|
</v-container>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
import TreeView from '@/components/TreeView.vue'
|
|
import type { TreeNodeData } from '@/components/TreeView.vue'
|
|
|
|
// Sample data for demonstration
|
|
const sampleData = ref<TreeNodeData[]>([
|
|
{
|
|
id: 'root',
|
|
label: 'Root',
|
|
icon: 'mdi-folder',
|
|
hasChildren: true,
|
|
expanded: false,
|
|
children: [
|
|
{
|
|
id: 'leaf1',
|
|
label: 'Leaf 1',
|
|
icon: 'mdi-file',
|
|
hasChildren: true,
|
|
expanded: false,
|
|
children: []
|
|
},
|
|
{
|
|
id: 'leaf2',
|
|
label: 'Leaf 2',
|
|
icon: 'mdi-file',
|
|
hasChildren: true,
|
|
expanded: false,
|
|
children: []
|
|
},
|
|
{
|
|
id: 'leaf3',
|
|
label: 'Leaf 3',
|
|
icon: 'mdi-file',
|
|
hasChildren: false
|
|
}
|
|
]
|
|
}
|
|
])
|
|
|
|
const eventLog = ref<Array<{ type: string; message: string }>>([])
|
|
|
|
// Simulate async loading of children
|
|
const loadChildren = async (nodeId: string): Promise<TreeNodeData[]> => {
|
|
// Simulate API delay
|
|
await new Promise((resolve) => setTimeout(resolve, 1000))
|
|
|
|
// Return mock data based on nodeId
|
|
if (nodeId === 'root') {
|
|
return [
|
|
{
|
|
id: 'leaf1',
|
|
label: 'Leaf 1',
|
|
icon: 'mdi-file',
|
|
hasChildren: true,
|
|
expanded: false,
|
|
children: []
|
|
},
|
|
{
|
|
id: 'leaf2',
|
|
label: 'Leaf 2',
|
|
icon: 'mdi-file',
|
|
hasChildren: true,
|
|
expanded: false,
|
|
children: []
|
|
},
|
|
{
|
|
id: 'leaf3',
|
|
label: 'Leaf 3',
|
|
icon: 'mdi-file',
|
|
hasChildren: false
|
|
}
|
|
]
|
|
} else if (nodeId === 'leaf1') {
|
|
return [
|
|
{
|
|
id: 'leaf1.1',
|
|
label: 'Leaf 1.1',
|
|
icon: 'mdi-file-document',
|
|
hasChildren: false
|
|
},
|
|
{
|
|
id: 'leaf1.2',
|
|
label: 'Leaf 1.2',
|
|
icon: 'mdi-file-document',
|
|
hasChildren: false
|
|
}
|
|
]
|
|
} else if (nodeId === 'leaf2') {
|
|
return [
|
|
{
|
|
id: 'leaf2.1',
|
|
label: 'Leaf 2.1',
|
|
icon: 'mdi-file-document',
|
|
hasChildren: false
|
|
}
|
|
]
|
|
}
|
|
|
|
return []
|
|
}
|
|
|
|
const addEvent = (type: string, message: string) => {
|
|
eventLog.value.unshift({ type, message })
|
|
// Keep only last 10 events
|
|
if (eventLog.value.length > 10) {
|
|
eventLog.value = eventLog.value.slice(0, 10)
|
|
}
|
|
}
|
|
|
|
const handleSelect = (items: TreeNodeData | TreeNodeData[]) => {
|
|
if (Array.isArray(items)) {
|
|
addEvent('SELECT', `Selected ${items.length} items: ${items.map((i) => i.label).join(', ')}`)
|
|
} else {
|
|
addEvent('SELECT', `Selected: ${items.label}`)
|
|
}
|
|
}
|
|
|
|
const handleDelete = (items: TreeNodeData | TreeNodeData[]) => {
|
|
if (Array.isArray(items)) {
|
|
addEvent('DELETE', `Delete ${items.length} items: ${items.map((i) => i.label).join(', ')}`)
|
|
} else {
|
|
addEvent('DELETE', `Delete: ${items.label}`)
|
|
}
|
|
}
|
|
|
|
const handleCopy = (items: TreeNodeData | TreeNodeData[]) => {
|
|
if (Array.isArray(items)) {
|
|
addEvent('COPY', `Copy ${items.length} items: ${items.map((i) => i.label).join(', ')}`)
|
|
} else {
|
|
addEvent('COPY', `Copy: ${items.label}`)
|
|
}
|
|
}
|
|
|
|
const handleMove = (items: TreeNodeData | TreeNodeData[]) => {
|
|
if (Array.isArray(items)) {
|
|
addEvent('MOVE', `Move ${items.length} items: ${items.map((i) => i.label).join(', ')}`)
|
|
} else {
|
|
addEvent('MOVE', `Move: ${items.label}`)
|
|
}
|
|
}
|
|
|
|
const handleAdd = (parentId: string) => {
|
|
addEvent('ADD', `Add new item under parent: ${parentId}`)
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.tree-demo {
|
|
padding: 20px;
|
|
}
|
|
|
|
.tree-container {
|
|
height: 500px;
|
|
border: 1px solid rgb(var(--v-theme-outline));
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.event-log {
|
|
max-height: 300px;
|
|
overflow-y: auto;
|
|
border: 1px solid rgb(var(--v-theme-outline));
|
|
border-radius: 4px;
|
|
padding: 12px;
|
|
}
|
|
|
|
.event-item {
|
|
padding: 4px 0;
|
|
border-bottom: 1px solid rgb(var(--v-theme-surface-variant));
|
|
font-family: monospace;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.event-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.no-events {
|
|
color: rgb(var(--v-theme-on-surface-variant));
|
|
font-style: italic;
|
|
text-align: center;
|
|
padding: 20px;
|
|
}
|
|
</style>
|