187 lines
4.9 KiB
Vue
187 lines
4.9 KiB
Vue
<template>
|
|
<div class="menu-tree-item">
|
|
<v-row
|
|
no-gutters
|
|
class="pa-2 border-b"
|
|
:class="{
|
|
'bg-grey-lighten-4': level > 0,
|
|
'bg-red-lighten-5': !item.isActive
|
|
}"
|
|
align="center"
|
|
>
|
|
<!-- Menu Title with Icon -->
|
|
<v-col cols="6" sm="4" class="d-flex align-center">
|
|
<div :style="{ marginLeft: `${level * 20}px` }" class="d-flex align-center">
|
|
<!-- Expand/Collapse Button -->
|
|
<v-btn
|
|
v-if="item.children && item.children.length > 0"
|
|
icon
|
|
size="x-small"
|
|
variant="text"
|
|
@click="toggleExpanded"
|
|
class="me-1"
|
|
>
|
|
<v-icon>{{ isExpanded ? 'mdi-chevron-down' : 'mdi-chevron-right' }}</v-icon>
|
|
</v-btn>
|
|
|
|
<!-- Menu Icon -->
|
|
<v-icon
|
|
:icon="item.icon || 'mdi-circle-outline'"
|
|
size="small"
|
|
class="me-2"
|
|
:color="item.isActive ? 'primary' : 'grey'"
|
|
/>
|
|
|
|
<!-- Menu Title -->
|
|
<span
|
|
class="text-body-2 font-weight-medium"
|
|
:class="{ 'text-grey': !item.isActive }"
|
|
>
|
|
{{ item.title }}
|
|
</span>
|
|
|
|
<!-- Active Status Badge -->
|
|
<v-chip
|
|
v-if="!item.isActive"
|
|
size="x-small"
|
|
color="error"
|
|
class="ml-2"
|
|
>
|
|
Inactive
|
|
</v-chip>
|
|
</div>
|
|
</v-col>
|
|
|
|
<!-- URL Link (Hidden on mobile) -->
|
|
<v-col cols="4" sm="5" class="d-none d-sm-block">
|
|
<span class="text-body-2 text-grey-darken-1">
|
|
{{ item.url || '-' }}
|
|
</span>
|
|
</v-col>
|
|
|
|
<!-- Action Buttons -->
|
|
<v-col cols="6" sm="3" class="text-right">
|
|
<v-btn-group variant="text" density="compact">
|
|
<!-- Toggle Active/Inactive -->
|
|
<v-btn
|
|
:icon="item.isActive ? 'mdi-eye' : 'mdi-eye-off'"
|
|
size="small"
|
|
:color="item.isActive ? 'success' : 'warning'"
|
|
@click="$emit('toggle', item.id)"
|
|
>
|
|
<v-icon />
|
|
<v-tooltip activator="parent" location="top">
|
|
{{ item.isActive ? 'Active' : 'Inactive' }}
|
|
</v-tooltip>
|
|
</v-btn>
|
|
|
|
<!-- Edit Button -->
|
|
<v-btn
|
|
icon="mdi-pencil"
|
|
size="small"
|
|
color="primary"
|
|
@click="$emit('edit', item)"
|
|
>
|
|
<v-icon />
|
|
<v-tooltip activator="parent" location="top">Edit</v-tooltip>
|
|
</v-btn>
|
|
|
|
<!-- Delete Button -->
|
|
<v-btn
|
|
icon="mdi-delete"
|
|
size="small"
|
|
color="error"
|
|
@click="confirmDelete"
|
|
>
|
|
<v-icon />
|
|
<v-tooltip activator="parent" location="top">Delete</v-tooltip>
|
|
</v-btn>
|
|
</v-btn-group>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<!-- Child Items -->
|
|
<template v-if="item.children && isExpanded">
|
|
<MenuTreeItem
|
|
v-for="child in item.children"
|
|
:key="child.id"
|
|
:item="child"
|
|
:level="level + 1"
|
|
@edit="$emit('edit', $event)"
|
|
@delete="$emit('delete', $event)"
|
|
@toggle="$emit('toggle', $event)"
|
|
/>
|
|
</template>
|
|
|
|
<!-- Delete Confirmation Dialog -->
|
|
<v-dialog v-model="showDeleteDialog" max-width="400">
|
|
<v-card>
|
|
<v-card-title class="text-h6">Confirm Delete</v-card-title>
|
|
<v-card-text>
|
|
Are you sure you want to delete "{{ item.title }}"?
|
|
<span v-if="item.children && item.children.length > 0" class="text-error">
|
|
This will also delete all child items.
|
|
</span>
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-spacer />
|
|
<v-btn color="grey" variant="text" @click="showDeleteDialog = false">
|
|
Cancel
|
|
</v-btn>
|
|
<v-btn color="error" variant="elevated" @click="handleDelete">
|
|
Delete
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type { MenuItem } from '../../types/menu'
|
|
|
|
interface Props {
|
|
item: MenuItem
|
|
level: number
|
|
}
|
|
|
|
const props = defineProps<Props>()
|
|
|
|
const emit = defineEmits<{
|
|
edit: [item: MenuItem]
|
|
delete: [itemId: string]
|
|
toggle: [itemId: string]
|
|
}>()
|
|
|
|
const isExpanded = ref(props.level === 0) // Top level items expanded by default
|
|
const showDeleteDialog = ref(false)
|
|
|
|
const toggleExpanded = () => {
|
|
isExpanded.value = !isExpanded.value
|
|
}
|
|
|
|
const confirmDelete = () => {
|
|
showDeleteDialog.value = true
|
|
}
|
|
|
|
const handleDelete = () => {
|
|
showDeleteDialog.value = false
|
|
// Emit delete event
|
|
emit('delete', props.item.id)
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.menu-tree-item {
|
|
border-bottom: 1px solid #e0e0e0;
|
|
}
|
|
|
|
.menu-tree-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.border-b {
|
|
border-bottom: 1px solid #e0e0e0;
|
|
}
|
|
</style>
|