Files
BarangaySystem/resources/js/Components/Core/TableDensityToggle.vue
2026-06-06 18:43:00 +08:00

81 lines
3.0 KiB
Vue

<template>
<div class="dropdown table-density-toggle" ref="dropdownRef">
<button
class="btn btn-theme border dropdown-toggle rounded-12 px-3 shadow-sm d-flex align-items-center"
type="button"
@click="toggleDropdown"
@blur="closeDropdown"
style="padding-top: 12px; padding-bottom: 12px;"
>
<i class="fas fa-expand-alt me-2 opacity-50" style="font-size: 0.9rem;"></i>
<span class="fw_6" style="font-size: 0.95rem;">{{ currentLabel }}</span>
</button>
<ul class="dropdown-menu dropdown-menu-end shadow border-0 rounded-12 mt-2 py-2" :class="{ show: isOpen }">
<li v-for="option in options" :key="option.value">
<a class="dropdown-item py-2 px-3 d-flex align-items-center"
:class="{ active: modelValue === option.value }"
href="javascript:void(0);"
@mousedown.prevent="selectOption(option.value)">
<div class="icon-box me-3 rounded-circle d-flex align-items-center justify-content-center" :class="modelValue === option.value ? 'bg-primary text-white' : 'bg-light text-muted'">
<i :class="[option.icon, 'smallest']"></i>
</div>
<div class="flex-grow-1">
<div class="small fw_7 d-block">{{ option.label }}</div>
<div class="smallest text-muted d-block opacity-75">{{ option.description }}</div>
</div>
</a>
</li>
</ul>
</div>
</template>
<script setup>
import { computed, ref } from 'vue';
const props = defineProps({
modelValue: { type: String, default: 'comfortable' }
});
const emit = defineEmits(['update:modelValue']);
const isOpen = ref(false);
const dropdownRef = ref(null);
const options = [
{ value: 'comfortable', label: 'Comfortable', description: 'Standard row spacing', icon: 'fas fa-grip-lines' },
{ value: 'compact', label: 'Compact', description: 'Reduced row padding', icon: 'fas fa-grip-lines-vertical' },
{ value: 'ultra-compact', label: 'Ultra', description: 'Maximum density', icon: 'fas fa-list' }
];
const currentLabel = computed(() => {
return options.find(o => o.value === props.modelValue)?.label || 'Comfortable';
});
const toggleDropdown = () => {
isOpen.value = !isOpen.value;
};
const closeDropdown = () => {
// Small delay to allow click events to fire first
setTimeout(() => {
isOpen.value = false;
}, 150);
};
const selectOption = (value) => {
emit('update:modelValue', value);
isOpen.value = false;
};
</script>
<style scoped>
.rounded-12 { border-radius: 12px; }
.dropdown-item { transition: all 0.2s; cursor: pointer; }
.dropdown-item.active { background-color: rgba(66, 185, 131, 0.1) !important; color: #42b983 !important; }
:global(.dark-mode) .dropdown-item.active { background-color: rgba(66, 185, 131, 0.2) !important; }
.smallest { font-size: 0.75rem; }
.icon-box { width: 28px; height: 28px; flex-shrink: 0; }
.btn-theme { background: var(--bg-card); color: var(--text-primary); border-color: var(--border-color) !important; }
.dropdown-menu { background: var(--bg-card); min-width: 200px; }
</style>