Files
antrean-operasi/components/content/MenuTreeItem.vue
2026-01-22 09:11:15 +07:00

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>