81 lines
3.0 KiB
Vue
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>
|