Files
planilla/ui/src/views/SettingsView.vue
google-labs-jules[bot] 32aa41f59f feat: Add default index view setting for modules
This commit introduces a new customization option in the appearance settings, allowing you to choose your default index view (card or table) for each module (Empleados, Tareas, Planillas, Asistencias).

Key changes:

- **Store Updates (`useUi.js`):**
    - Added new state properties (e.g., `defaultViewEmpleados`) to store the preferred view for each module.
    - Added corresponding actions (e.g., `setDefaultViewEmpleados`) to update these settings.
    - Settings are persisted to local storage.

- **Settings UI (`SettingsView.vue`):**
    - Added dropdown selectors in the module-specific sections of the appearance settings page for you to choose 'Table' or 'Card' as your default view.
    - These selectors are bound to the new store properties.

- **Module Index Views (e.g., `EmpleadosIndex.vue`):**
    - Modified to read the default view setting from the `useUi` store.
    - Conditionally render either the table component or the card component based on this setting.
    - Removed manual view toggle buttons, as the default is now managed via settings.

- **Testing:**
    - I added unit tests for the new store actions and state.
    - I added component tests for `SettingsView.vue` to verify the new UI elements and their interaction with the store.
    - I added component tests for each module's index view to ensure they render the correct view (table or card) based on the global setting and display data or "no data" messages appropriately.

This feature provides you with more control over your preferred data display format within each module, enhancing the user experience.
2025-05-31 07:59:01 +00:00

278 lines
19 KiB
Vue

<template>
<div class="settings-view p-4 md:p-8 max-w-4xl mx-auto text-[var(--text-color)] bg-[var(--background-color)] transition-opacity duration-500 ease-in-out opacity-0"
:class="{ 'opacity-100': isMounted }">
<h1 class="text-3xl md:text-4xl font-bold mb-8 border-b pb-4 border-[var(--secondary-color)]">Appearance Settings</h1>
<!-- General Settings Section -->
<section class="mb-10">
<h2 class="text-2xl font-semibold mb-6 text-[var(--primary-color)]">General</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 items-center">
<div class="setting-item">
<label for="theme" class="block text-sm font-medium mb-1">Theme</label>
<select id="theme" v-model="ui.theme" @change="ui.setTheme($event.target.value)"
class="w-full p-3 border rounded-lg shadow-sm focus:ring-[var(--primary-color)] focus:border-[var(--primary-color)] transition-all duration-150 ease-in-out bg-white/10 dark:bg-black/10 border-[var(--secondary-color)] hover:border-[var(--primary-color)]">
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
</div>
<div class="setting-item flex items-center justify-between mt-4 md:mt-0 md:pt-6">
<label for="animationsEnabled" class="text-sm font-medium">Enable Animations</label>
<input type="checkbox" id="animationsEnabled" v-model="ui.animationsEnabled" @change="ui.setAnimationsEnabled($event.target.checked)"
class="custom-checkbox relative w-10 h-5 appearance-none bg-gray-300 dark:bg-gray-600 rounded-full cursor-pointer transition-colors duration-300 ease-in-out checked:bg-[var(--primary-color)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--primary-color)] focus:ring-offset-[var(--background-color)]">
</div>
<div class="setting-item flex items-center justify-between mt-4 md:mt-0 md:pt-6">
<label for="desktopNavbarPersistent" class="text-sm font-medium">Persistent Desktop Navbar</label>
<input type="checkbox" id="desktopNavbarPersistent" v-model="ui.desktopNavbarPersistent" @change="ui.setDesktopNavbarPersistent($event.target.checked)"
class="custom-checkbox relative w-10 h-5 appearance-none bg-gray-300 dark:bg-gray-600 rounded-full cursor-pointer transition-colors duration-300 ease-in-out checked:bg-[var(--primary-color)] focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--primary-color)] focus:ring-offset-[var(--background-color)]">
</div>
</div>
</section>
<!-- Colors Section -->
<section class="mb-10">
<h2 class="text-2xl font-semibold mb-6 text-[var(--primary-color)]">Color Palette</h2>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
<div class="setting-item">
<label for="primaryColor" class="block text-sm font-medium mb-1">Primary Color</label>
<input type="color" id="primaryColor" v-model="ui.primaryColor" @input="ui.setPrimaryColor($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="secondaryColor" class="block text-sm font-medium mb-1">Secondary Color</label>
<input type="color" id="secondaryColor" v-model="ui.secondaryColor" @input="ui.setSecondaryColor($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="warningColor" class="block text-sm font-medium mb-1">Warning Color</label>
<input type="color" id="warningColor" v-model="ui.warningColor" @input="ui.setWarningColor($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="backgroundColor" class="block text-sm font-medium mb-1">Background Color</label>
<input type="color" id="backgroundColor" v-model="ui.backgroundColor" @input="ui.setBackgroundColor($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
</div>
</section>
<!-- Typography Section -->
<section class="mb-10">
<h2 class="text-2xl font-semibold mb-6 text-[var(--primary-color)]">Typography</h2>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="setting-item">
<label for="fontFamily" class="block text-sm font-medium mb-1">Font Family</label>
<input type="text" id="fontFamily" v-model="ui.fontFamily" @input="ui.setFontFamily($event.target.value)"
class="w-full p-3 border rounded-lg shadow-sm focus:ring-[var(--primary-color)] focus:border-[var(--primary-color)] transition-all duration-150 ease-in-out bg-white/10 dark:bg-black/10 border-[var(--secondary-color)] hover:border-[var(--primary-color)]"
placeholder="e.g., Roboto, sans-serif">
</div>
<div class="setting-item">
<label for="fontSize" class="block text-sm font-medium mb-1">Base Font Size (px)</label>
<input type="number" id="fontSize" v-model.number="ui.fontSize" @input="ui.setFontSize(Number($event.target.value))"
class="w-full p-3 border rounded-lg shadow-sm focus:ring-[var(--primary-color)] focus:border-[var(--primary-color)] transition-all duration-150 ease-in-out bg-white/10 dark:bg-black/10 border-[var(--secondary-color)] hover:border-[var(--primary-color)]"
min="8" max="32" step="1">
</div>
</div>
</section>
<!-- Per-Module Color Settings -->
<section class="mb-10 module-settings-group">
<h3 class="text-xl font-semibold mb-4 text-[var(--primary-color)] border-b border-[var(--secondary-color)] pb-2">Empleados Module</h3>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
<div class="setting-item">
<label for="accentColorEmpleados" class="block text-sm font-medium mb-1">Accent Color</label>
<input type="color" id="accentColorEmpleados" v-model="ui.accentColorEmpleados" @input="ui.setAccentColorEmpleados($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="tableBgColorEmpleados" class="block text-sm font-medium mb-1">Table Background</label>
<input type="color" id="tableBgColorEmpleados" v-model="ui.tableBgColorEmpleados" @input="ui.setTableBgColorEmpleados($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="defaultViewEmpleados" class="block text-sm font-medium mb-1">Default View</label>
<select id="defaultViewEmpleados" v-model="ui.defaultViewEmpleados" @change="ui.setDefaultViewEmpleados($event.target.value)"
class="w-full p-3 border rounded-lg shadow-sm focus:ring-[var(--primary-color)] focus:border-[var(--primary-color)] transition-all duration-150 ease-in-out bg-white/10 dark:bg-black/10 border-[var(--secondary-color)] hover:border-[var(--primary-color)]">
<option value="table">Table</option>
<option value="card">Card</option>
</select>
</div>
</div>
</section>
<section class="mb-10 module-settings-group">
<h3 class="text-xl font-semibold mb-4 text-[var(--primary-color)] border-b border-[var(--secondary-color)] pb-2">Tareas Module</h3>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
<div class="setting-item">
<label for="accentColorTareas" class="block text-sm font-medium mb-1">Accent Color</label>
<input type="color" id="accentColorTareas" v-model="ui.accentColorTareas" @input="ui.setAccentColorTareas($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="tableBgColorTareas" class="block text-sm font-medium mb-1">Table Background</label>
<input type="color" id="tableBgColorTareas" v-model="ui.tableBgColorTareas" @input="ui.setTableBgColorTareas($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="defaultViewTareas" class="block text-sm font-medium mb-1">Default View</label>
<select id="defaultViewTareas" v-model="ui.defaultViewTareas" @change="ui.setDefaultViewTareas($event.target.value)"
class="w-full p-3 border rounded-lg shadow-sm focus:ring-[var(--primary-color)] focus:border-[var(--primary-color)] transition-all duration-150 ease-in-out bg-white/10 dark:bg-black/10 border-[var(--secondary-color)] hover:border-[var(--primary-color)]">
<option value="table">Table</option>
<option value="card">Card</option>
</select>
</div>
</div>
</section>
<section class="mb-10 module-settings-group">
<h3 class="text-xl font-semibold mb-4 text-[var(--primary-color)] border-b border-[var(--secondary-color)] pb-2">Planillas Module</h3>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
<div class="setting-item">
<label for="accentColorPlanillas" class="block text-sm font-medium mb-1">Accent Color</label>
<input type="color" id="accentColorPlanillas" v-model="ui.accentColorPlanillas" @input="ui.setAccentColorPlanillas($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="tableBgColorPlanillas" class="block text-sm font-medium mb-1">Table Background</label>
<input type="color" id="tableBgColorPlanillas" v-model="ui.tableBgColorPlanillas" @input="ui.setTableBgColorPlanillas($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="defaultViewPlanillas" class="block text-sm font-medium mb-1">Default View</label>
<select id="defaultViewPlanillas" v-model="ui.defaultViewPlanillas" @change="ui.setDefaultViewPlanillas($event.target.value)"
class="w-full p-3 border rounded-lg shadow-sm focus:ring-[var(--primary-color)] focus:border-[var(--primary-color)] transition-all duration-150 ease-in-out bg-white/10 dark:bg-black/10 border-[var(--secondary-color)] hover:border-[var(--primary-color)]">
<option value="table">Table</option>
<option value="card">Card</option>
</select>
</div>
</div>
</section>
<section class="mb-10 module-settings-group">
<h3 class="text-xl font-semibold mb-4 text-[var(--primary-color)] border-b border-[var(--secondary-color)] pb-2">Asistencias Module</h3>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
<div class="setting-item">
<label for="accentColorAsistencias" class="block text-sm font-medium mb-1">Accent Color</label>
<input type="color" id="accentColorAsistencias" v-model="ui.accentColorAsistencias" @input="ui.setAccentColorAsistencias($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="tableBgColorAsistencias" class="block text-sm font-medium mb-1">Table Background</label>
<input type="color" id="tableBgColorAsistencias" v-model="ui.tableBgColorAsistencias" @input="ui.setTableBgColorAsistencias($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="defaultViewAsistencias" class="block text-sm font-medium mb-1">Default View</label>
<select id="defaultViewAsistencias" v-model="ui.defaultViewAsistencias" @change="ui.setDefaultViewAsistencias($event.target.value)"
class="w-full p-3 border rounded-lg shadow-sm focus:ring-[var(--primary-color)] focus:border-[var(--primary-color)] transition-all duration-150 ease-in-out bg-white/10 dark:bg-black/10 border-[var(--secondary-color)] hover:border-[var(--primary-color)]">
<option value="table">Table</option>
<option value="card">Card</option>
</select>
</div>
</div>
</section>
<section class="mb-10 module-settings-group">
<h3 class="text-xl font-semibold mb-4 text-[var(--primary-color)] border-b border-[var(--secondary-color)] pb-2">Configuración Module</h3>
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-6">
<div class="setting-item">
<label for="accentColorConfiguracion" class="block text-sm font-medium mb-1">Accent Color</label>
<input type="color" id="accentColorConfiguracion" v-model="ui.accentColorConfiguracion" @input="ui.setAccentColorConfiguracion($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="tableBgColorConfiguracion" class="block text-sm font-medium mb-1">Table Background</label>
<input type="color" id="tableBgColorConfiguracion" v-model="ui.tableBgColorConfiguracion" @input="ui.setTableBgColorConfiguracion($event.target.value)"
class="w-full h-12 p-1 border rounded-lg cursor-pointer shadow-sm hover:opacity-80 transition-opacity border-[var(--secondary-color)] focus:border-[var(--primary-color)] focus:ring-1 focus:ring-[var(--primary-color)]">
</div>
<div class="setting-item">
<label for="defaultViewConfiguracion" class="block text-sm font-medium mb-1">Default View</label>
<select id="defaultViewConfiguracion" v-model="ui.defaultViewConfiguracion" @change="ui.setDefaultViewConfiguracion($event.target.value)"
class="w-full p-3 border rounded-lg shadow-sm focus:ring-[var(--primary-color)] focus:border-[var(--primary-color)] transition-all duration-150 ease-in-out bg-white/10 dark:bg-black/10 border-[var(--secondary-color)] hover:border-[var(--primary-color)]">
<option value="table">Table</option>
<option value="card">Card</option>
</select>
</div>
</div>
</section>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useUi } from '@/stores/useUi'
const ui = useUi()
const isMounted = ref(false)
onMounted(() => {
// Slight delay to allow transition to be visible
setTimeout(() => {
isMounted.value = true
}, 50)
})
</script>
<style scoped>
.settings-view {
/* display: flex; */ /* Replaced by Tailwind max-w-4xl mx-auto and sectioning */
/* flex-direction: column; */
/* gap: 1rem; */ /* Handled by margins on sections/items */
/* padding: 1rem; */ /* Replaced by p-4 md:p-8 on the root div */
}
.setting-item { /* New class for spacing, can replace .setting if desired */
/* @apply mb-4 md:mb-0; */ /* Add some bottom margin on mobile - Temporarily commented out for testing */
}
/* Old .setting class and general label styling are no longer needed as Tailwind utilities are used per element. */
/*
.setting {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 1rem;
}
label {
font-weight: bold;
}
*/
/* Custom styling for color inputs to ensure the color preview is visible */
input[type="color"]::-webkit-color-swatch-wrapper {
padding: 0; /* Remove default padding to make color fill the input */
}
input[type="color"]::-webkit-color-swatch {
border: none; /* Remove default border */
border-radius: 0.375rem; /* Tailwind's rounded-md */
}
/* For Firefox */
input[type="color"]::-moz-color-swatch {
border: none;
border-radius: 0.375rem;
}
/* Custom checkbox style */
.custom-checkbox::before {
content: "";
/* @apply absolute top-1/2 left-0.5 w-4 h-4 bg-white rounded-full shadow transform -translate-y-1/2 transition-transform duration-300 ease-in-out; */
/* Basic styles to allow tests to pass, actual style handled by Tailwind if processed */
position: absolute;
top: 50%;
left: 0.125rem; /* Corresponds to left-0.5 in Tailwind */
width: 1rem; /* w-4 */
height: 1rem; /* h-4 */
background-color: white;
border-radius: 9999px; /* rounded-full */
box-shadow: 0 1px 3px 0 rgba(0,0,0,0.1), 0 1px 2px 0 rgba(0,0,0,0.06); /* shadow */
transform: translateY(-50%);
transition-property: transform;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 300ms;
}
.custom-checkbox:checked::before {
/* @apply translate-x-5; */ /* Moves the toggle to the right */
transform: translateY(-50%) translateX(1.25rem); /* translate-x-5 (1.25rem for 20px) */
}
</style>