Merge branch 'main' into feat/chat-color-customization
This commit is contained in:
@@ -68,7 +68,7 @@ const transitionDurationStyle = computed(() => {
|
|||||||
// The global style.css will handle base background and text color via body styling
|
// The global style.css will handle base background and text color via body styling
|
||||||
// but we can keep specific overrides here if needed or theme classes.
|
// but we can keep specific overrides here if needed or theme classes.
|
||||||
// ui.theme === 'dark' ? 'bg-gray-800 text-gray-100' : 'bg-gray-100 text-gray-900'
|
// ui.theme === 'dark' ? 'bg-gray-800 text-gray-100' : 'bg-gray-100 text-gray-900'
|
||||||
]" :style="transitionDurationStyle">
|
]" :style="transitionDurationStyle">
|
||||||
<!-- NavBar fija -->
|
<!-- NavBar fija -->
|
||||||
<NavBar />
|
<NavBar />
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ watch(() => chat.items.length, scrollBottom)
|
|||||||
fontFamily: 'var(--chat-font-family)',
|
fontFamily: 'var(--chat-font-family)',
|
||||||
fontSize: 'var(--chat-font-size)'
|
fontSize: 'var(--chat-font-size)'
|
||||||
}">
|
}">
|
||||||
|
|
||||||
{{ m.text }}
|
{{ m.text }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -84,6 +85,7 @@ watch(() => chat.items.length, scrollBottom)
|
|||||||
@keydown="handleKey"
|
@keydown="handleKey"
|
||||||
rows="1"
|
rows="1"
|
||||||
placeholder="Escribí un mensaje… (Enter para enviar, Shift+Enter salto)"
|
placeholder="Escribí un mensaje… (Enter para enviar, Shift+Enter salto)"
|
||||||
|
|
||||||
class="flex-1 resize-none rounded-lg border p-3 focus:outline-none focus:ring-2 custom-scroll"
|
class="flex-1 resize-none rounded-lg border p-3 focus:outline-none focus:ring-2 custom-scroll"
|
||||||
:style="{
|
:style="{
|
||||||
backgroundColor: 'var(--chat-input-box-color)',
|
backgroundColor: 'var(--chat-input-box-color)',
|
||||||
@@ -102,6 +104,18 @@ watch(() => chat.items.length, scrollBottom)
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
.canvas-chat-root {
|
||||||
|
background-color: var(--background-color-chat, #F0F0F0); /* Fallback to store default */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default accent color for chat if not provided by CSS variable */
|
||||||
|
:root {
|
||||||
|
--accent-color-chat-fallback: #0D9488; /* Teal-700 as a fallback */
|
||||||
|
--accent-color-chat-alpha-35-fallback: rgba(13, 148, 136, 0.35);
|
||||||
|
--accent-color-chat-alpha-70-fallback: rgba(13, 148, 136, 0.7);
|
||||||
|
--accent-color-chat-alpha-60-fallback: rgba(13, 148, 136, 0.6);
|
||||||
|
}
|
||||||
|
|
||||||
.custom-scroll::-webkit-scrollbar { width: 8px; }
|
.custom-scroll::-webkit-scrollbar { width: 8px; }
|
||||||
.custom-scroll::-webkit-scrollbar-track { background: transparent; } /* Consider if track needs to adapt to --chat-background-color */
|
.custom-scroll::-webkit-scrollbar-track { background: transparent; } /* Consider if track needs to adapt to --chat-background-color */
|
||||||
.custom-scroll::-webkit-scrollbar-thumb { background-color: var(--chat-accent-color); opacity: 0.35; border-radius: 4px; }
|
.custom-scroll::-webkit-scrollbar-thumb { background-color: var(--chat-accent-color); opacity: 0.35; border-radius: 4px; }
|
||||||
|
|||||||
@@ -39,48 +39,54 @@
|
|||||||
@mouseleave="buttonHover($event, false)"
|
@mouseleave="buttonHover($event, false)"
|
||||||
:class="`focus:ring-[var(--accent-color-empleados)]`"
|
:class="`focus:ring-[var(--accent-color-empleados)]`"
|
||||||
>Editar</button>
|
>Editar</button>
|
||||||
<!-- "View Details" button removed for consistency as other modules use the edit view for details -->
|
<button
|
||||||
|
@click="confirmDeleteEmpleado"
|
||||||
|
class="px-3 py-1 md:px-4 md:py-2 text-xs md:text-sm font-medium rounded-md transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 bg-red-600 hover:bg-red-700 text-white focus:ring-red-500"
|
||||||
|
>Eliminar</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { PropType } from 'vue'
|
import { PropType } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useUi } from '../../stores/useUi.js';
|
import { useUi } from '../../stores/useUi.js';
|
||||||
|
|
||||||
const ui = useUi();
|
const ui = useUi();
|
||||||
|
const emit = defineEmits(['edit']);
|
||||||
interface Employee {
|
const empleadosStore = useEmpleadosStore();
|
||||||
id: string | number
|
|
||||||
name: string
|
|
||||||
cedula: number
|
|
||||||
avatar_url?: string
|
|
||||||
telefono?: string
|
|
||||||
ubicacion: string
|
|
||||||
idciat?: string
|
|
||||||
grupo_estudio?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
employee: {
|
employee: {
|
||||||
type: Object as PropType<Employee>,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const handleEdit = () => {
|
const handleEdit = () => {
|
||||||
// The router pushes to `/empleados/:id` as per current router config,
|
emit('edit', props.employee.id);
|
||||||
// which maps to `EmpleadoForm.vue`. This form serves for both editing and viewing details.
|
};
|
||||||
router.push(`/empleados/${props.employee.id}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleViewDetails method removed for consistency
|
const confirmDeleteEmpleado = () => {
|
||||||
|
if (confirm(`¿Está seguro de que desea eliminar al empleado "${props.employee.name}" (ID: ${props.employee.id})?`)) {
|
||||||
|
deleteEmpleado();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const buttonHover = (event: MouseEvent, isHovering: boolean) => {
|
const deleteEmpleado = async () => {
|
||||||
const target = event.target as HTMLElement;
|
try {
|
||||||
|
await empleadosStore.deleteEmpleado(props.employee.id);
|
||||||
|
// Optionally, show a success notification or emit an event if needed,
|
||||||
|
// though typically the list will update reactively from the store.
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting employee:', error);
|
||||||
|
alert('Ocurrió un error al eliminar el empleado.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const buttonHover = (event, isHovering) => {
|
||||||
|
const target = event.target;
|
||||||
if (isHovering) {
|
if (isHovering) {
|
||||||
target.style.filter = 'brightness(90%)';
|
target.style.filter = 'brightness(90%)';
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -63,8 +63,8 @@
|
|||||||
<button @click="handleEdit(employee.id)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-600/20 focus:ring-blue-500 dark:focus:ring-blue-400" title="Editar Empleado">
|
<button @click="handleEdit(employee.id)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-blue-600 dark:text-blue-400 hover:text-blue-800 dark:hover:text-blue-300 hover:bg-blue-100 dark:hover:bg-blue-600/20 focus:ring-blue-500 dark:focus:ring-blue-400" title="Editar Empleado">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10" /></svg>
|
||||||
</button>
|
</button>
|
||||||
<button @click="handleViewDetails(employee.id)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-green-600 dark:text-green-400 hover:text-green-800 dark:hover:text-green-300 hover:bg-green-100 dark:hover:bg-green-600/20 focus:ring-green-500 dark:focus:ring-green-400" title="Ver Detalles">
|
<button @click="confirmDeleteEmpleado(employee)" class="p-1.5 sm:p-2 rounded-md transition-all duration-150 ease-in-out focus:outline-none focus:ring-2 focus:ring-offset-2 text-red-600 dark:text-red-400 hover:text-red-800 dark:hover:text-red-300 hover:bg-red-100 dark:hover:bg-red-600/20 focus:ring-red-500 dark:focus:ring-red-400" title="Eliminar">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z" /></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5"><path stroke-linecap="round" stroke-linejoin="round" d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12.56 0c1.153 0 2.24.03 3.22.077m3.22-.077L10.879 3.28a2.25 2.25 0 012.244-2.077h.093c.956 0 1.853.543 2.244 2.077L14.74 5.79m-4.858 0l-2.828-2.828A1.875 1.875 0 016.188 2.188l2.828 2.828m6.912 0l2.828-2.828a1.875 1.875 0 00-2.652-2.652L12 5.79M9.26 9h5.48L9.26 9z" /></svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
@@ -74,43 +74,39 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup>
|
||||||
import { PropType } from 'vue'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { useUi } from '../../stores/useUi.js';
|
import { useUi } from '../../stores/useUi.js';
|
||||||
|
import { useEmpleadosStore } from '../../stores/useEmpleados';
|
||||||
|
|
||||||
const ui = useUi();
|
const ui = useUi();
|
||||||
|
const emit = defineEmits(['edit']);
|
||||||
// Interface for Employee object structure, aligning with prisma model (excluding sensitive or large fields for table view)
|
const empleadosStore = useEmpleadosStore();
|
||||||
interface Employee {
|
|
||||||
id: string | number; // Primary key for navigation and :key
|
|
||||||
name: string;
|
|
||||||
cedula: number; // Assuming cedula is a number; adjust if it's a string
|
|
||||||
avatar_url?: string;
|
|
||||||
telefono?: string;
|
|
||||||
ubicacion: string; // As per schema, this has a default and likely always present
|
|
||||||
idciat?: string;
|
|
||||||
grupo_estudio?: string;
|
|
||||||
// Omitting created_at, updated_at, empleado boolean for brevity in table
|
|
||||||
}
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
employees: {
|
employees: {
|
||||||
type: Array as PropType<Employee[]>,
|
type: Array,
|
||||||
required: true,
|
required: true,
|
||||||
default: () => [], // Provides a default empty array if no prop is passed
|
default: () => [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const router = useRouter();
|
const handleEdit = (employeeId) => {
|
||||||
|
emit('edit', employeeId);
|
||||||
const handleEdit = (employeeId: string | number) => {
|
|
||||||
router.push(`/empleados/edit/${employeeId}`);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleViewDetails = (employeeId: string | number) => {
|
const confirmDeleteEmpleado = (employee) => {
|
||||||
// This could navigate to a dedicated detail view or the edit view itself
|
if (confirm(`¿Está seguro de que desea eliminar al empleado "${employee.name}" (ID: ${employee.id})?`)) {
|
||||||
router.push(`/empleados/view/${employeeId}`); // Adjust route as per application structure
|
deleteEmpleadoInternal(employee.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteEmpleadoInternal = async (id) => {
|
||||||
|
try {
|
||||||
|
await empleadosStore.deleteEmpleado(id);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error deleting employee with id ${id}:`, error);
|
||||||
|
// Optional: Show error notification
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const appearanceSettingKeys = [
|
|||||||
'accentColorPlanillas',
|
'accentColorPlanillas',
|
||||||
'accentColorAsistencias',
|
'accentColorAsistencias',
|
||||||
'accentColorConfiguracion',
|
'accentColorConfiguracion',
|
||||||
|
'accentColorChat',
|
||||||
// Per-module table background colors
|
// Per-module table background colors
|
||||||
'tableBgColorEmpleados',
|
'tableBgColorEmpleados',
|
||||||
'tableBgColorTareas',
|
'tableBgColorTareas',
|
||||||
@@ -39,6 +40,7 @@ const appearanceSettingKeys = [
|
|||||||
'chatFontColor',
|
'chatFontColor',
|
||||||
'chatFontFamily',
|
'chatFontFamily',
|
||||||
'chatFontSize',
|
'chatFontSize',
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const loadSettingsFromLocalStorage = () => {
|
const loadSettingsFromLocalStorage = () => {
|
||||||
@@ -100,12 +102,14 @@ export const useUi = defineStore('ui', {
|
|||||||
accentColorPlanillas: '#FF9800', // Orange
|
accentColorPlanillas: '#FF9800', // Orange
|
||||||
accentColorAsistencias: '#E91E63', // Pink
|
accentColorAsistencias: '#E91E63', // Pink
|
||||||
accentColorConfiguracion: '#607D8B', // Blue Grey
|
accentColorConfiguracion: '#607D8B', // Blue Grey
|
||||||
|
accentColorChat: '#0D9488', // Teal - chosen as a default for chat
|
||||||
// Per-module table background colors - default to white
|
// Per-module table background colors - default to white
|
||||||
tableBgColorEmpleados: '#FFFFFF',
|
tableBgColorEmpleados: '#FFFFFF',
|
||||||
tableBgColorTareas: '#FFFFFF',
|
tableBgColorTareas: '#FFFFFF',
|
||||||
tableBgColorPlanillas: '#FFFFFF',
|
tableBgColorPlanillas: '#FFFFFF',
|
||||||
tableBgColorAsistencias: '#FFFFFF',
|
tableBgColorAsistencias: '#FFFFFF',
|
||||||
tableBgColorConfiguracion: '#FFFFFF',
|
tableBgColorConfiguracion: '#FFFFFF',
|
||||||
|
backgroundColorChat: '#F0F0F0', // A light gray for chat background by default
|
||||||
desktopNavbarPersistent: false,
|
desktopNavbarPersistent: false,
|
||||||
// Default module views
|
// Default module views
|
||||||
'defaultViewEmpleados': 'table',
|
'defaultViewEmpleados': 'table',
|
||||||
@@ -210,6 +214,10 @@ export const useUi = defineStore('ui', {
|
|||||||
this.accentColorConfiguracion = color
|
this.accentColorConfiguracion = color
|
||||||
_saveAppearanceState(this)
|
_saveAppearanceState(this)
|
||||||
},
|
},
|
||||||
|
setAccentColorChat(color) {
|
||||||
|
this.accentColorChat = color;
|
||||||
|
_saveAppearanceState(this);
|
||||||
|
},
|
||||||
|
|
||||||
// Actions for per-module table background colors
|
// Actions for per-module table background colors
|
||||||
setTableBgColorEmpleados(color) {
|
setTableBgColorEmpleados(color) {
|
||||||
@@ -232,6 +240,10 @@ export const useUi = defineStore('ui', {
|
|||||||
this.tableBgColorConfiguracion = color
|
this.tableBgColorConfiguracion = color
|
||||||
_saveAppearanceState(this)
|
_saveAppearanceState(this)
|
||||||
},
|
},
|
||||||
|
setBackgroundColorChat(color) {
|
||||||
|
this.backgroundColorChat = color;
|
||||||
|
_saveAppearanceState(this);
|
||||||
|
},
|
||||||
setDesktopNavbarPersistent(enabled) {
|
setDesktopNavbarPersistent(enabled) {
|
||||||
this.desktopNavbarPersistent = !!enabled // Ensure boolean
|
this.desktopNavbarPersistent = !!enabled // Ensure boolean
|
||||||
_saveAppearanceState(this)
|
_saveAppearanceState(this)
|
||||||
|
|||||||
@@ -4,11 +4,36 @@ import CanvasChat from '@/components/chat/CanvasChat.vue'
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-full flex flex-col">
|
<div class="chat-view-container flex flex-col h-full">
|
||||||
<CanvasChat class="flex-1" />
|
<header class="page-header">
|
||||||
|
<h1>Chat</h1>
|
||||||
|
</header>
|
||||||
|
<CanvasChat class="flex-1 min-h-0" /> <!-- Added min-h-0 -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
/* nada por ahora */
|
.chat-view-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
background-color: var(--background-color-chat, #F0F0F0); /* Fallback to store default */
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between; /* Consistent with other headers, even if no button on right */
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 25px; /* Consistent with PlanillasIndex */
|
||||||
|
padding: 10px 20px; /* Provides padding for the header itself */
|
||||||
|
border-bottom: 1px solid #eee; /* Consistent with PlanillasIndex */
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header h1 {
|
||||||
|
color: var(--accent-color-chat, #0D9488); /* Fallback to store default */
|
||||||
|
font-size: 2.2em; /* Consistent with PlanillasIndex */
|
||||||
|
font-weight: 600; /* Consistent with PlanillasIndex */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CanvasChat is expected to manage its own internal padding and scrolling */
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-6 bg-gray-100 min-h-screen">
|
<div class="p-6 min-h-screen empleado-form-page-container">
|
||||||
<h1 class="text-3xl font-bold mb-8 text-center text-gray-700">
|
<h1 class="text-3xl font-bold mb-8 text-center text-gray-700">
|
||||||
{{ isEditMode ? 'Editar Empleado' : 'Crear Empleado' }}
|
{{ isEditMode ? 'Editar Empleado' : 'Crear Empleado' }}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<form
|
<form
|
||||||
@submit.prevent="handleSubmit"
|
@submit.prevent="handleSubmit"
|
||||||
class="max-w-lg mx-auto p-8 rounded-lg shadow-lg"
|
class="max-w-lg mx-auto p-8 rounded-lg shadow-lg empleado-actual-form"
|
||||||
:style="{ backgroundColor: uiStore.tableBgColorEmpleados }"
|
|
||||||
>
|
>
|
||||||
<!-- ───────── Nombre ───────── -->
|
<!-- ───────── Nombre ───────── -->
|
||||||
<div class="mb-6">
|
<div class="mb-6">
|
||||||
@@ -242,6 +242,19 @@ input:required:invalid {
|
|||||||
/* Removing generic input:focus, button:focus as they are too broad */
|
/* Removing generic input:focus, button:focus as they are too broad */
|
||||||
|
|
||||||
/* --- Look & feel extra (opcional, podés ajustar) --- */
|
/* --- Look & feel extra (opcional, podés ajustar) --- */
|
||||||
|
.empleado-form-page-container {
|
||||||
|
background-color: var(--background-color, #f3f4f6); /* Fallback to a light gray */
|
||||||
|
}
|
||||||
|
|
||||||
|
.empleado-actual-form {
|
||||||
|
background-color: #ffffff; /* Default white for light theme */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Example for dark theme (assuming a parent class .dark or data attribute) */
|
||||||
|
.dark .empleado-actual-form {
|
||||||
|
background-color: #2d3748; /* A dark gray for dark theme */
|
||||||
|
}
|
||||||
|
|
||||||
.form-container { background-color: var(--background-color); } /* Use theme background */
|
.form-container { background-color: var(--background-color); } /* Use theme background */
|
||||||
.form-card { box-shadow: 0 10px 15px -3px rgba(0,0,0,.1),
|
.form-card { box-shadow: 0 10px 15px -3px rgba(0,0,0,.1),
|
||||||
0 4px 6px -2px rgba(0,0,0,.05); }
|
0 4px 6px -2px rgba(0,0,0,.05); }
|
||||||
|
|||||||
@@ -1,21 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-6 bg-gray-50 min-h-screen">
|
<div class="empleados-index-container">
|
||||||
<!-- … encabezado … -->
|
<!-- … encabezado … -->
|
||||||
<header class="mb-8">
|
<header class="page-header">
|
||||||
<div class="flex justify-between items-center">
|
<h1>Gestión de Empleados</h1>
|
||||||
<h1 class="text-4xl font-bold text-gray-800">Gestión de Empleados</h1>
|
<button @click="goToCreateEmployee" class="btn-create">
|
||||||
<button
|
Crear Empleado
|
||||||
@click="goToCreateEmployee"
|
</button>
|
||||||
class="create-button px-6 py-3 text-white font-semibold rounded-lg shadow-md focus:outline-none transition duration-150 ease-in-out"
|
|
||||||
>
|
|
||||||
<!-- ícono ➕ -->
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 inline-block mr-2" viewBox="0 0 20 20" fill="currentColor">
|
|
||||||
<path fill-rule="evenodd" d="M10 3a1 1 0 011 1v5h5a1 1 0 110 2h-5v5a1 1 0 11-2 0v-5H4a1 1 0 110-2h5V4a1 1 0 011-1z" clip-rule="evenodd" />
|
|
||||||
</svg>
|
|
||||||
Crear Empleado
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<p class="mt-2 text-gray-600">Visualiza, crea y gestiona los empleados de la organización.</p>
|
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- selector de vista -->
|
<!-- selector de vista -->
|
||||||
@@ -40,12 +30,11 @@
|
|||||||
|
|
||||||
<!-- contenido -->
|
<!-- contenido -->
|
||||||
<div>
|
<div>
|
||||||
<div v-if="loading" class="text-center py-10">
|
<div v-if="loading" class="loading-message">Cargando empleados...</div>
|
||||||
<p class="text-gray-500 text-xl">Cargando empleados...</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else-if="error" class="text-center py-10">
|
<div v-else-if="error" class="error-message-full">
|
||||||
<p class="text-red-500 text-xl">Error al cargar los empleados: {{ error }}</p>
|
<p>Error al cargar los empleados. Por favor, intente de nuevo más tarde.</p>
|
||||||
|
<p v-if="error">Detalle: {{ error }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else>
|
<div v-else>
|
||||||
@@ -59,19 +48,16 @@
|
|||||||
:key="employee.id"
|
:key="employee.id"
|
||||||
:employee="employee"
|
:employee="employee"
|
||||||
/>
|
/>
|
||||||
<div v-if="employees.length === 0" class="col-span-full text-center py-10">
|
</div>
|
||||||
<p class="text-gray-500 text-xl">No hay empleados para mostrar en la vista de tarjetas.</p>
|
<div v-if="currentView === 'card' && employees.length === 0 && !loading" class="no-data-message">
|
||||||
</div>
|
No hay empleados para mostrar en la vista de tarjetas.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- vista de tabla -->
|
<!-- vista de tabla -->
|
||||||
<div v-if="currentView === 'table'">
|
<div v-if="currentView === 'table'">
|
||||||
<TablaEmpleados :employees="employees" />
|
<TablaEmpleados :employees="employees" />
|
||||||
<div
|
<div v-if="employees.length === 0 && !loading" class="no-data-message">
|
||||||
v-if="employees.length === 0"
|
No hay empleados para mostrar en la vista de tabla.
|
||||||
class="text-center py-10 bg-white shadow-md rounded-lg mt-4"
|
|
||||||
>
|
|
||||||
<p class="text-gray-500 text-xl">No hay empleados para mostrar en la vista de tabla.</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -134,22 +120,84 @@ const goToCreateEmployee = () => router.push({ name: 'empleados-new' });
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.min-h-screen { min-height: calc(100vh - var(--navbar-height, 0px)); } /* Assuming --navbar-height is defined elsewhere or adjust */
|
.empleados-index-container {
|
||||||
|
padding: 20px;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
min-height: calc(100vh - var(--navbar-height, 0px)); /* Assuming --navbar-height is defined elsewhere or adjust */
|
||||||
|
}
|
||||||
|
|
||||||
.create-button {
|
.page-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-header h1 {
|
||||||
|
color: var(--accent-color-empleados); /* Accent for title */
|
||||||
|
font-size: 2.2em;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-create {
|
||||||
background-color: var(--accent-color-empleados);
|
background-color: var(--accent-color-empleados);
|
||||||
|
color: white; /* Assuming accent is dark enough */
|
||||||
|
padding: 12px 18px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s ease-in-out, box-shadow 0.2s ease, filter 0.2s ease;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
}
|
}
|
||||||
.create-button:hover {
|
|
||||||
filter: brightness(1.1);
|
.btn-create:hover {
|
||||||
|
filter: brightness(0.9);
|
||||||
|
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||||
}
|
}
|
||||||
.create-button:focus {
|
|
||||||
box-shadow: 0 0 0 2px var(--background-color), 0 0 0 4px var(--accent-color-empleados);
|
.btn-create:focus {
|
||||||
|
box-shadow: 0 0 0 2px var(--background-color, #fff), 0 0 0 4px var(--accent-color-empleados);
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-message,
|
||||||
|
.error-message-full,
|
||||||
|
.no-data-message {
|
||||||
|
text-align: center;
|
||||||
|
padding: 25px;
|
||||||
|
margin-top: 25px;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-message {
|
||||||
|
color: #7f8c8d; /* Gray */
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-message-full {
|
||||||
|
background-color: #fdedec; /* Lighter red */
|
||||||
|
color: #e74c3c; /* Strong red */
|
||||||
|
border: 1px solid #f5b7b1; /* Light red border */
|
||||||
|
}
|
||||||
|
.error-message-full p {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-data-message {
|
||||||
|
background-color: #eafaf1; /* Lighter green/blue */
|
||||||
|
color: #2ecc71; /* Green */
|
||||||
|
border: 1px solid #a3e4d7; /* Light green/blue border */
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-toggle-active {
|
.view-toggle-active {
|
||||||
background-color: var(--accent-color-empleados);
|
background-color: var(--accent-color-empleados);
|
||||||
/* For focus, assuming white text on accent. Adjust if needed. */
|
/* For focus, assuming white text on accent. Adjust if needed. */
|
||||||
box-shadow: 0 0 0 2px var(--background-color), 0 0 0 4px var(--accent-color-empleados);
|
box-shadow: 0 0 0 2px var(--background-color, #fff), 0 0 0 4px var(--accent-color-empleados);
|
||||||
}
|
}
|
||||||
/* Inactive toggle button styling is handled by Tailwind classes directly in btnClass function */
|
/* Inactive toggle button styling is handled by Tailwind classes directly in btnClass function */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user