diff --git a/ui/src/App.vue b/ui/src/App.vue index 342e3d2..29901c9 100644 --- a/ui/src/App.vue +++ b/ui/src/App.vue @@ -16,6 +16,12 @@ watchEffect(() => { root.style.setProperty('--font-family', ui.fontFamily) root.style.setProperty('--font-size', `${ui.fontSize}px`) + // Module-specific accent colors + root.style.setProperty('--accent-color-empleados', ui.accentColorEmpleados) + root.style.setProperty('--accent-color-tareas', ui.accentColorTareas) + root.style.setProperty('--accent-color-planillas', ui.accentColorPlanillas) + root.style.setProperty('--accent-color-asistencias', ui.accentColorAsistencias) + if (ui.theme === 'dark') { root.classList.add('theme-dark') root.classList.remove('theme-light') diff --git a/ui/src/components/asistencias/cardAsistencia.vue b/ui/src/components/asistencias/cardAsistencia.vue index 6eaeed8..f8d8d29 100644 --- a/ui/src/components/asistencias/cardAsistencia.vue +++ b/ui/src/components/asistencias/cardAsistencia.vue @@ -98,7 +98,7 @@ const deleteAsistenciaInternal = async () => { .empleado-id { font-weight: bold; - color: #2c3e50; /* Dark blue/grey */ + color: var(--accent-color-asistencias); /* Accent color */ font-size: 1.05em; } @@ -126,7 +126,7 @@ const deleteAsistenciaInternal = async () => { color: #666; background-color: #f8f9fa; /* Very light grey background */ padding: 10px; /* More padding */ - border-left: 3px solid #007bff; /* Blue accent line */ + border-left: 3px solid var(--accent-color-asistencias); /* Accent color for border */ border-radius: 4px; margin-top:10px; font-size: 0.9em; /* Slightly smaller for observation */ @@ -155,19 +155,19 @@ const deleteAsistenciaInternal = async () => { } .edit-button { - background-color: #007bff; + background-color: var(--accent-color-asistencias); color: white; } .edit-button:hover { - background-color: #0056b3; + filter: brightness(0.9); } .delete-button { - background-color: #dc3545; + background-color: var(--warning-color); /* Use warning color for delete */ color: white; } .delete-button:hover { - background-color: #c82333; + filter: brightness(0.9); } /* Estado specific styling */ diff --git a/ui/src/components/asistencias/tablaAsistencias.vue b/ui/src/components/asistencias/tablaAsistencias.vue index 0f26c68..1cf0671 100644 --- a/ui/src/components/asistencias/tablaAsistencias.vue +++ b/ui/src/components/asistencias/tablaAsistencias.vue @@ -136,19 +136,19 @@ const deleteAsistenciaInternal = async (id) => { } .edit-button { - background-color: #007bff; /* Blue */ + background-color: var(--accent-color-asistencias); color: white; } .edit-button:hover { - background-color: #0056b3; + filter: brightness(0.9); } .delete-button { - background-color: #dc3545; /* Red */ + background-color: var(--warning-color); /* Use warning color for delete */ color: white; } .delete-button:hover { - background-color: #c82333; + filter: brightness(0.9); } /* Estado specific styling (using text color for tables is often cleaner) */ diff --git a/ui/src/components/empleados/cardEmpleado.vue b/ui/src/components/empleados/cardEmpleado.vue index 7cec4a0..41712bf 100644 --- a/ui/src/components/empleados/cardEmpleado.vue +++ b/ui/src/components/empleados/cardEmpleado.vue @@ -4,7 +4,7 @@ Avatar del empleado

{{ employee.name }}

@@ -13,24 +13,24 @@
- + {{ employee.telefono }}
- + {{ employee.ubicacion }}
- + Cedula: {{ employee.cedula }}
- + Grupo Estudio: {{ employee.grupo_estudio }}
-
@@ -45,10 +51,8 @@ const sidebarClasses = computed(() => ui.sidebarOpen ? 'translate-x-0' : '-trans
  • @@ -63,9 +67,35 @@ const sidebarClasses = computed(() => ui.sidebarOpen ? 'translate-x-0' : '-trans diff --git a/ui/src/components/ui/TopBar.vue b/ui/src/components/ui/TopBar.vue index 8f13576..a53f262 100644 --- a/ui/src/components/ui/TopBar.vue +++ b/ui/src/components/ui/TopBar.vue @@ -5,19 +5,28 @@ const ui = useUi() diff --git a/ui/src/stores/__tests__/useUi.spec.js b/ui/src/stores/__tests__/useUi.spec.js index 5eb9cf4..e869c82 100644 --- a/ui/src/stores/__tests__/useUi.spec.js +++ b/ui/src/stores/__tests__/useUi.spec.js @@ -43,6 +43,15 @@ describe('useUi Store', () => { expect(store.primaryColor).toBe('#1976D2') expect(store.theme).toBe('light') expect(store.fontSize).toBe(16) + // Check new accent color defaults + expect(store.accentColorEmpleados).toBe('#2196F3') + expect(store.accentColorTareas).toBe('#4CAF50') + expect(store.accentColorPlanillas).toBe('#FF9800') + expect(store.accentColorAsistencias).toBe('#E91E63') + expect(localStorageMock.getItem).toHaveBeenCalledWith(APPEARANCE_STORAGE_KEY) + }) + + it('loads settings from localStorage including new accent colors if present', () => { expect(localStorageMock.getItem).toHaveBeenCalledWith(APPEARANCE_STORAGE_KEY) }) @@ -52,6 +61,10 @@ describe('useUi Store', () => { theme: 'dark', fontSize: 20, animationsEnabled: false, + accentColorEmpleados: '#0000FF', + accentColorTareas: '#00FF00', + accentColorPlanillas: '#FFFF00', + accentColorAsistencias: '#FF00FF', // other settings... } localStorageMock.getItem.mockReturnValueOnce(JSON.stringify(storedSettings)) @@ -63,6 +76,30 @@ describe('useUi Store', () => { expect(store.theme).toBe('dark') expect(store.fontSize).toBe(20) expect(store.animationsEnabled).toBe(false) + expect(store.accentColorEmpleados).toBe('#0000FF') + expect(store.accentColorTareas).toBe('#00FF00') + expect(store.accentColorPlanillas).toBe('#FFFF00') + expect(store.accentColorAsistencias).toBe('#FF00FF') + }) + + it('loads older settings from localStorage and uses defaults for new accent colors if not present', () => { + const olderStoredSettings = { + primaryColor: '#ABCDEF', + theme: 'dark', + fontSize: 18, + } // Does not include new accent colors + localStorageMock.getItem.mockReturnValueOnce(JSON.stringify(olderStoredSettings)) + + const store = useUi() + + expect(store.primaryColor).toBe('#ABCDEF') + expect(store.theme).toBe('dark') + expect(store.fontSize).toBe(18) + // New accent colors should fall back to defaults + expect(store.accentColorEmpleados).toBe('#2196F3') + expect(store.accentColorTareas).toBe('#4CAF50') + expect(store.accentColorPlanillas).toBe('#FF9800') + expect(store.accentColorAsistencias).toBe('#E91E63') }) it('falls back to default settings if localStorage data is invalid JSON', () => { @@ -88,6 +125,11 @@ describe('useUi Store', () => { }) describe('Actions', () => { + // Update this list to match the store's appearanceSettingKeys + const appearanceSettingKeysInTest = [ + 'primaryColor', 'secondaryColor', 'warningColor', 'fontFamily', + 'fontSize', 'animationsEnabled', 'backgroundColor', 'theme', + 'accentColorEmpleados', 'accentColorTareas', 'accentColorPlanillas', 'accentColorAsistencias', const appearanceSettingKeys = [ 'primaryColor', 'secondaryColor', 'warningColor', 'fontFamily', 'fontSize', 'animationsEnabled', 'backgroundColor', 'theme', @@ -170,6 +212,53 @@ describe('useUi Store', () => { const savedDataString = localStorageMock.setItem.mock.calls[0][1]; const savedData = JSON.parse(savedDataString); + expect(Object.keys(savedData).length).toBe(appearanceSettingKeysInTest.length); + expect(savedData.sidebarOpen).toBeUndefined() // Ensure non-appearance data is not saved + appearanceSettingKeysInTest.forEach(key => { + expect(savedData.hasOwnProperty(key)).toBe(true) + }) + }) + + // Tests for new accent color actions + it('setAccentColorEmpleados updates state and saves to localStorage', () => { + const store = useUi() + store.setAccentColorEmpleados('#FF1122') + expect(store.accentColorEmpleados).toBe('#FF1122') + expect(localStorageMock.setItem).toHaveBeenCalledWith( + APPEARANCE_STORAGE_KEY, + expect.stringContaining('"accentColorEmpleados":"#FF1122"') + ) + }) + + it('setAccentColorTareas updates state and saves to localStorage', () => { + const store = useUi() + store.setAccentColorTareas('#33FF44') + expect(store.accentColorTareas).toBe('#33FF44') + expect(localStorageMock.setItem).toHaveBeenCalledWith( + APPEARANCE_STORAGE_KEY, + expect.stringContaining('"accentColorTareas":"#33FF44"') + ) + }) + + it('setAccentColorPlanillas updates state and saves to localStorage', () => { + const store = useUi() + store.setAccentColorPlanillas('#5566FF') + expect(store.accentColorPlanillas).toBe('#5566FF') + expect(localStorageMock.setItem).toHaveBeenCalledWith( + APPEARANCE_STORAGE_KEY, + expect.stringContaining('"accentColorPlanillas":"#5566FF"') + ) + }) + + it('setAccentColorAsistencias updates state and saves to localStorage', () => { + const store = useUi() + store.setAccentColorAsistencias('#FF7788') + expect(store.accentColorAsistencias).toBe('#FF7788') + expect(localStorageMock.setItem).toHaveBeenCalledWith( + APPEARANCE_STORAGE_KEY, + expect.stringContaining('"accentColorAsistencias":"#FF7788"') + ) + }) expect(Object.keys(savedData).length).toBe(appearanceSettingKeys.length); expect(savedData.sidebarOpen).toBeUndefined() // Ensure non-appearance data is not saved appearanceSettingKeys.forEach(key => { diff --git a/ui/src/stores/useUi.js b/ui/src/stores/useUi.js index 803932d..c448aa1 100644 --- a/ui/src/stores/useUi.js +++ b/ui/src/stores/useUi.js @@ -12,6 +12,10 @@ const appearanceSettingKeys = [ 'animationsEnabled', 'backgroundColor', 'theme', + 'accentColorEmpleados', + 'accentColorTareas', + 'accentColorPlanillas', + 'accentColorAsistencias', ] const loadSettingsFromLocalStorage = () => { @@ -67,6 +71,11 @@ export const useUi = defineStore('ui', { animationsEnabled: true, backgroundColor: '#FFFFFF', theme: 'light', // 'light' or 'dark' + // Module-specific accent colors + accentColorEmpleados: '#2196F3', // Blue + accentColorTareas: '#4CAF50', // Green + accentColorPlanillas: '#FF9800', // Orange + accentColorAsistencias: '#E91E63', // Pink } const loadedSettings = loadSettingsFromLocalStorage() @@ -130,6 +139,24 @@ export const useUi = defineStore('ui', { toggleTheme() { this.theme = this.theme === 'light' ? 'dark' : 'light' _saveAppearanceState(this) + }, + + // Actions for module-specific accent colors + setAccentColorEmpleados(color) { + this.accentColorEmpleados = color + _saveAppearanceState(this) + }, + setAccentColorTareas(color) { + this.accentColorTareas = color + _saveAppearanceState(this) + }, + setAccentColorPlanillas(color) { + this.accentColorPlanillas = color + _saveAppearanceState(this) + }, + setAccentColorAsistencias(color) { + this.accentColorAsistencias = color + _saveAppearanceState(this) } }, }) diff --git a/ui/src/style.css b/ui/src/style.css index 8ea4666..7e95078 100644 --- a/ui/src/style.css +++ b/ui/src/style.css @@ -12,6 +12,12 @@ --font-size: 16px; /* Add other variables as needed, e.g., text colors for themes */ --text-color: #212121; /* Default text color for light theme */ + + /* Module-specific accent colors - Default Fallbacks */ + --accent-color-empleados: #2196F3; + --accent-color-tareas: #4CAF50; + --accent-color-planillas: #FF9800; + --accent-color-asistencias: #E91E63; } html.theme-dark { diff --git a/ui/src/views/SettingsView.vue b/ui/src/views/SettingsView.vue index e2e92e1..b320242 100644 --- a/ui/src/views/SettingsView.vue +++ b/ui/src/views/SettingsView.vue @@ -70,6 +70,33 @@ + +
    +

    Module Accent Colors

    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    + diff --git a/ui/src/views/__tests__/SettingsView.spec.js b/ui/src/views/__tests__/SettingsView.spec.js index 920fea0..0af6493 100644 --- a/ui/src/views/__tests__/SettingsView.spec.js +++ b/ui/src/views/__tests__/SettingsView.spec.js @@ -11,6 +11,41 @@ const getFreshStore = () => { } describe('SettingsView.vue', () => { + // No global 'store' variable here, it will be test-specific or wrapper-specific + + beforeEach(() => { + // Ensure a fresh Pinia instance is active for each test. + setActivePinia(createPinia()) + + // Clear localStorage mock before each test + // Note: The mock itself is defined globally in this file or via setupFiles in Vitest config. + // Re-stubbing it or ensuring its state is clean. + const localStorageMock = window.localStorage; // Assuming it's already stubbed globally by Vitest setup or top of file + localStorageMock.clear(); + if (localStorageMock.setItem.mockClear) { // vi.fn() specific + localStorageMock.setItem.mockClear(); + localStorageMock.getItem.mockClear(); + } + }) + + // createWrapper now also handles store creation and returns the store for spying if needed + const createWrapperAndStore = (initialStoreState = {}) => { + if (Object.keys(initialStoreState).length > 0) { + localStorage.setItem('appearanceSettings', JSON.stringify(initialStoreState)); + } + + const currentStore = useUi(); // Store is created AFTER localStorage is set for this test + + const wrapper = mount(SettingsView, { + global: { + // Pinia is active via setActivePinia, component should pick it up + }, + }); + return { wrapper, store: currentStore }; // Return store for spying + } + + it('renders all input elements with initial values from store', () => { + const { wrapper } = createWrapperAndStore({ // Store is created inside here after LS mock let store beforeEach(() => { @@ -60,6 +95,14 @@ describe('SettingsView.vue', () => { fontSize: 18, animationsEnabled: false, theme: 'dark', + // Add new accent colors for comprehensive initial state testing + accentColorEmpleados: '#123456', + accentColorTareas: '#654321', + accentColorPlanillas: '#abcdef', + accentColorAsistencias: '#fedcba', + }) + + // Check general appearance settings }) expect(wrapper.find('input#primaryColor').element.value).toBe('#111111') @@ -70,6 +113,33 @@ describe('SettingsView.vue', () => { expect(wrapper.find('input#fontSize').element.value).toBe('18') expect(wrapper.find('input#animationsEnabled').element.checked).toBe(false) expect(wrapper.find('select#theme').element.value).toBe('dark') + + // Check new module accent color pickers + const h2Elements = wrapper.findAll('h2') + const sectionTitles = h2Elements.map(h => h.text()) + expect(sectionTitles).toContain('Module Accent Colors') + expect(wrapper.find('input#accentColorEmpleados').element.value).toBe('#123456') + expect(wrapper.find('input#accentColorTareas').element.value).toBe('#654321') + expect(wrapper.find('input#accentColorPlanillas').element.value).toBe('#abcdef') + expect(wrapper.find('input#accentColorAsistencias').element.value).toBe('#fedcba') + }) + + it('calls setPrimaryColor action when primary color input changes', async () => { + const { wrapper, store } = createWrapperAndStore() + const spy = vi.spyOn(store, 'setPrimaryColor') + const colorInput = wrapper.find('input#primaryColor') + + colorInput.element.value = '#FF00FF' + await colorInput.trigger('input') + + expect(spy).toHaveBeenCalledWith('#ff00ff') + }) + + it('calls setFontFamily action when font family input changes', async () => { + const { wrapper, store } = createWrapperAndStore() + const spy = vi.spyOn(store, 'setFontFamily') + const input = wrapper.find('input#fontFamily') + await input.setValue('Helvetica') }) it('calls setPrimaryColor action when primary color input changes', async () => { @@ -94,6 +164,7 @@ describe('SettingsView.vue', () => { }) it('calls setFontSize action when font size input changes', async () => { + const { wrapper, store } = createWrapperAndStore() const wrapper = createWrapper() const spy = vi.spyOn(store, 'setFontSize') const input = wrapper.find('input#fontSize') @@ -102,6 +173,11 @@ describe('SettingsView.vue', () => { }) it('calls setAnimationsEnabled action when animations checkbox changes', async () => { + const { wrapper, store } = createWrapperAndStore({ animationsEnabled: true }) + const spy = vi.spyOn(store, 'setAnimationsEnabled') + const checkbox = wrapper.find('input#animationsEnabled') + + await checkbox.setChecked(false) const wrapper = createWrapper({ animationsEnabled: true }) // Start with true const spy = vi.spyOn(store, 'setAnimationsEnabled') const checkbox = wrapper.find('input#animationsEnabled') @@ -113,6 +189,56 @@ describe('SettingsView.vue', () => { }) it('calls setTheme action when theme select changes', async () => { + const { wrapper, store } = createWrapperAndStore() + const spy = vi.spyOn(store, 'setTheme') + const select = wrapper.find('select#theme') + await select.setValue('dark') + expect(spy).toHaveBeenCalledWith('dark') + }) + + // New tests for module accent color pickers + it('calls setAccentColorEmpleados action when empleados accent color input changes', async () => { + const { wrapper, store } = createWrapperAndStore() + const spy = vi.spyOn(store, 'setAccentColorEmpleados') + const colorInput = wrapper.find('input#accentColorEmpleados') + colorInput.element.value = '#aabbcc' + await colorInput.trigger('input') + expect(spy).toHaveBeenCalledWith('#aabbcc') + }) + + it('calls setAccentColorTareas action when tareas accent color input changes', async () => { + const { wrapper, store } = createWrapperAndStore() + const spy = vi.spyOn(store, 'setAccentColorTareas') + const colorInput = wrapper.find('input#accentColorTareas') + colorInput.element.value = '#ccbbaa' + await colorInput.trigger('input') + expect(spy).toHaveBeenCalledWith('#ccbbaa') + }) + + it('calls setAccentColorPlanillas action when planillas accent color input changes', async () => { + const { wrapper, store } = createWrapperAndStore() + const spy = vi.spyOn(store, 'setAccentColorPlanillas') + const colorInput = wrapper.find('input#accentColorPlanillas') + colorInput.element.value = '#a1b2c3' + await colorInput.trigger('input') + expect(spy).toHaveBeenCalledWith('#a1b2c3') + }) + + it('calls setAccentColorAsistencias action when asistencias accent color input changes', async () => { + const { wrapper, store } = createWrapperAndStore() + const spy = vi.spyOn(store, 'setAccentColorAsistencias') + const colorInput = wrapper.find('input#accentColorAsistencias') + colorInput.element.value = '#c3b2a1' + await colorInput.trigger('input') + expect(spy).toHaveBeenCalledWith('#c3b2a1') + }) + + it('updates input values when store state changes programmatically', async () => { + const { wrapper, store } = createWrapperAndStore() // Store instance for this test + + // Test primaryColor + store.primaryColor = '#001122' // Directly manipulate the store used by the component +======= const wrapper = createWrapper() const spy = vi.spyOn(store, 'setTheme') const select = wrapper.find('select#theme') @@ -147,6 +273,11 @@ describe('SettingsView.vue', () => { store.theme = 'dark' await wrapper.vm.$nextTick() expect(wrapper.find('select#theme').element.value).toBe('dark') + + // Test one of the new accent colors + store.accentColorEmpleados = '#998877' + await wrapper.vm.$nextTick() + expect(wrapper.find('input#accentColorEmpleados').element.value).toBe('#998877') }) // Test for the initial fade-in animation - checking class @@ -154,6 +285,7 @@ describe('SettingsView.vue', () => { // Mock setTimeout to control its execution vi.useFakeTimers() + const { wrapper } = createWrapperAndStore() // Use the new function name const wrapper = createWrapper() expect(wrapper.find('.settings-view').classes()).not.toContain('opacity-100') diff --git a/ui/src/views/asistencias/AsistenciaForm.vue b/ui/src/views/asistencias/AsistenciaForm.vue index cad12e1..29c5f49 100644 --- a/ui/src/views/asistencias/AsistenciaForm.vue +++ b/ui/src/views/asistencias/AsistenciaForm.vue @@ -214,7 +214,7 @@ const handleCancel = () => { h2 { text-align: center; - color: #333; + color: var(--accent-color-asistencias); /* Accent color for title */ margin-bottom: 25px; } @@ -235,10 +235,19 @@ h2 { .form-group textarea { width: 100%; padding: 10px; - border: 1px solid #ccc; + border: 1px solid var(--secondary-color); /* Theme border */ border-radius: 4px; box-sizing: border-box; font-size: 1em; + background-color: var(--background-color); /* Theme background */ + color: var(--text-color); /* Theme text */ +} +.form-group input:focus, +.form-group select:focus, +.form-group textarea:focus { + border-color: var(--accent-color-asistencias); + box-shadow: 0 0 0 2px var(--accent-color-asistencias); + outline: none; } .form-group textarea { @@ -247,7 +256,7 @@ h2 { .error-message { display: block; - color: #e74c3c; + color: var(--warning-color); /* Theme warning color */ font-size: 0.9em; margin-top: 5px; } @@ -266,31 +275,33 @@ h2 { cursor: pointer; font-size: 1em; font-weight: 500; - transition: background-color 0.2s ease, box-shadow 0.2s ease; + transition: background-color 0.2s ease, box-shadow 0.2s ease, filter 0.2s ease; } .form-actions button[type="submit"] { - background-color: #3498db; /* Blue */ - color: white; + background-color: var(--accent-color-asistencias); + color: white; /* Assuming accent is dark enough */ } .form-actions button[type="submit"]:hover { - background-color: #2980b9; + filter: brightness(0.9); box-shadow: 0 2px 4px rgba(0,0,0,0.1); } .form-actions button[type="submit"]:disabled { - background-color: #bdc3c7; + background-color: var(--secondary-color); + opacity: 0.7; cursor: not-allowed; } .form-actions button[type="button"] { - background-color: #e74c3c; /* Red for cancel */ - color: white; + background-color: var(--secondary-color); /* Using secondary for cancel */ + color: var(--text-color); /* Ensure text contrasts */ } .form-actions button[type="button"]:hover { - background-color: #c0392b; + filter: brightness(0.9); } .form-actions button[type="button"]:disabled { - background-color: #bdc3c7; + background-color: var(--secondary-color); + opacity: 0.5; cursor: not-allowed; } diff --git a/ui/src/views/asistencias/AsistenciasIndex.vue b/ui/src/views/asistencias/AsistenciasIndex.vue index aa867b0..e59a47a 100644 --- a/ui/src/views/asistencias/AsistenciasIndex.vue +++ b/ui/src/views/asistencias/AsistenciasIndex.vue @@ -89,26 +89,26 @@ const handleEditAsistencia = (asistenciaId) => { } .page-header h1 { - color: #212529; + color: var(--accent-color-asistencias); /* Accent color for title */ font-size: 1.8em; font-weight: 600; } .btn-create { - background-color: #17a2b8; /* Info Blue */ - color: white; + background-color: var(--accent-color-asistencias); + color: white; /* Assuming accent is dark enough */ padding: 10px 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; + transition: background-color 0.2s ease-in-out, box-shadow 0.2s ease, filter 0.2s ease; box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .btn-create:hover { - background-color: #138496; + filter: brightness(0.9); box-shadow: 0 4px 8px rgba(0,0,0,0.15); } diff --git a/ui/src/views/empleados/EmpleadoForm.vue b/ui/src/views/empleados/EmpleadoForm.vue index a812bd0..f52006d 100644 --- a/ui/src/views/empleados/EmpleadoForm.vue +++ b/ui/src/views/empleados/EmpleadoForm.vue @@ -19,8 +19,8 @@ v-model="form.name" type="text" required - class="w-full px-4 py-2 border border-gray-300 rounded-md - focus:outline-none focus:ring-2 focus:ring-blue-500" + class="form-input w-full px-4 py-2 border border-gray-300 rounded-md + focus:outline-none" placeholder="Ej: Juan Pérez" /> @@ -36,8 +36,8 @@ v-model="form.cedula" type="number" required - class="w-full px-4 py-2 border border-gray-300 rounded-md - focus:outline-none focus:ring-2 focus:ring-blue-500" + class="form-input w-full px-4 py-2 border border-gray-300 rounded-md + focus:outline-none" placeholder="Ej: 123456789" /> @@ -52,8 +52,8 @@ id="ubicacion" v-model="form.ubicacion" type="text" - class="w-full px-4 py-2 border border-gray-300 rounded-md - focus:outline-none focus:ring-2 focus:ring-blue-500" + class="form-input w-full px-4 py-2 border border-gray-300 rounded-md + focus:outline-none" placeholder="Ej: Oficina Principal" /> @@ -68,8 +68,8 @@ id="grupo_estudio" v-model="form.grupo_estudio" type="text" - class="w-full px-4 py-2 border border-gray-300 rounded-md - focus:outline-none focus:ring-2 focus:ring-blue-500" + class="form-input w-full px-4 py-2 border border-gray-300 rounded-md + focus:outline-none" placeholder="Ej: Grupo A" /> @@ -84,8 +84,8 @@ id="avatar_url" v-model="form.avatar_url" type="url" - class="w-full px-4 py-2 border border-gray-300 rounded-md - focus:outline-none focus:ring-2 focus:ring-blue-500" + class="form-input w-full px-4 py-2 border border-gray-300 rounded-md + focus:outline-none" placeholder="Ej: https://example.com/avatar.png" /> @@ -100,8 +100,8 @@ id="telefono" v-model="form.telefono" type="tel" - class="w-full px-4 py-2 border border-gray-300 rounded-md - focus:outline-none focus:ring-2 focus:ring-blue-500" + class="form-input w-full px-4 py-2 border border-gray-300 rounded-md + focus:outline-none" placeholder="Ej: 0991234567" /> @@ -116,8 +116,8 @@ id="idciat" v-model="form.idciat" type="text" - class="w-full px-4 py-2 border border-gray-300 rounded-md - focus:outline-none focus:ring-2 focus:ring-blue-500" + class="form-input w-full px-4 py-2 border border-gray-300 rounded-md + focus:outline-none" placeholder="Ej: CIAT123" /> @@ -127,16 +127,15 @@ @@ -234,39 +233,53 @@ const handleCancel = () => { diff --git a/ui/src/views/empleados/EmpleadosIndex.vue b/ui/src/views/empleados/EmpleadosIndex.vue index b363741..72e29c0 100644 --- a/ui/src/views/empleados/EmpleadosIndex.vue +++ b/ui/src/views/empleados/EmpleadosIndex.vue @@ -6,7 +6,7 @@

    Gestión de Empleados