avances poderosos en ui
This commit is contained in:
@@ -1,30 +1,24 @@
|
||||
<script setup>
|
||||
import HelloWorld from './components/HelloWorld.vue'
|
||||
import TopBar from '@/components/ui/TopBar.vue'
|
||||
import NavBar from '@/components/ui/NavBar.vue'
|
||||
import { useUi } from '@/stores/useUi'
|
||||
const ui = useUi()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<a href="https://vite.dev" target="_blank">
|
||||
<img src="/vite.svg" class="logo" alt="Vite logo" />
|
||||
</a>
|
||||
<a href="https://vuejs.org/" target="_blank">
|
||||
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
|
||||
</a>
|
||||
<!-- TopBar fija -->
|
||||
<TopBar />
|
||||
|
||||
<!-- wrapper: deja espacio para TopBar (pt-14 = 56px) y, en desktop, para NavBar (pl-60) -->
|
||||
<div :class="['pt-14 min-h-screen bg-gray-100 text-gray-900 transition-[padding-left] duration-200', ui.sidebarOpen ? 'md:pl-60' : '']">
|
||||
<!-- NavBar fija -->
|
||||
<NavBar />
|
||||
|
||||
<!-- contenido principal -->
|
||||
<main class="min-h-[calc(100vh-56px)] flex flex-col overflow-hidden">
|
||||
<RouterView class="flex-1 overflow-auto" />
|
||||
</main>
|
||||
</div>
|
||||
<HelloWorld msg="Vite + Vue" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
transition: filter 300ms;
|
||||
}
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
.logo.vue:hover {
|
||||
filter: drop-shadow(0 0 2em #42b883aa);
|
||||
}
|
||||
</style>
|
||||
<style scoped></style>
|
||||
|
||||
1
ui/src/components/asistencias/cardAsistencia.vue
Normal file
1
ui/src/components/asistencias/cardAsistencia.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
ui/src/components/asistencias/tablaAsistencias.vue
Normal file
1
ui/src/components/asistencias/tablaAsistencias.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
83
ui/src/components/chat/CanvasChat.vue
Normal file
83
ui/src/components/chat/CanvasChat.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<script setup>
|
||||
import { ref, nextTick, onMounted, watch } from 'vue'
|
||||
import { useChat } from '@/stores/useChat'
|
||||
|
||||
const chat = useChat()
|
||||
const msg = ref('')
|
||||
const list = ref(null)
|
||||
|
||||
function scrollBottom () {
|
||||
nextTick(() => list.value?.scrollTo({ top: list.value.scrollHeight, behavior: 'smooth' }))
|
||||
}
|
||||
|
||||
function send () {
|
||||
const t = msg.value.trim()
|
||||
if (!t) return
|
||||
|
||||
if (t.startsWith('/')) chat.run(t.slice(1))
|
||||
else chat.add({ type: 'text', owner: 'yo', text: t })
|
||||
|
||||
msg.value = ''
|
||||
scrollBottom()
|
||||
}
|
||||
|
||||
function handleKey (e) {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault()
|
||||
send()
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!chat.items.length) {
|
||||
chat.add({ type: 'text', owner: 'bot', text: '¡Hola! Probá /empleados, /tareas, etc.' })
|
||||
}
|
||||
scrollBottom()
|
||||
})
|
||||
|
||||
watch(() => chat.items.length, scrollBottom)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- se adapta al contenedor flex, sin superponer la sidebar -->
|
||||
<div class="flex flex-col flex-1 min-h-0 bg-gray-50">
|
||||
<!-- historial -->
|
||||
<div ref="list" class="flex-1 min-h-0 overflow-auto p-6 space-y-4 custom-scroll">
|
||||
<template v-for="(m,i) in chat.items" :key="i">
|
||||
<!-- mensaje de texto -->
|
||||
<div :class="m.owner==='yo' ? 'flex justify-end' : 'flex justify-start'" v-if="m.type==='text'">
|
||||
<div
|
||||
class="max-w-lg rounded-lg px-4 py-2 shadow break-words"
|
||||
:class="m.owner==='yo' ? 'bg-teal-600 text-white' : 'bg-white text-gray-900'">
|
||||
{{ m.text }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- componente dinámico -->
|
||||
<component v-else :is="m.is" v-bind="m.props" />
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- input -->
|
||||
<form @submit.prevent="send" class="border-t bg-white p-4 flex gap-2">
|
||||
<textarea
|
||||
v-model="msg"
|
||||
@keydown="handleKey"
|
||||
rows="1"
|
||||
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 focus:ring-teal-500 custom-scroll"
|
||||
/>
|
||||
<button type="submit" class="px-4 py-2 rounded-lg bg-teal-600 text-white hover:bg-teal-700 transition">
|
||||
➤
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.custom-scroll::-webkit-scrollbar { width: 8px; }
|
||||
.custom-scroll::-webkit-scrollbar-track { background: transparent; }
|
||||
.custom-scroll::-webkit-scrollbar-thumb { background-color: rgba(13,148,136,.35); border-radius: 4px; }
|
||||
.custom-scroll:hover::-webkit-scrollbar-thumb { background-color: rgba(13,148,136,.7); }
|
||||
.custom-scroll { scrollbar-width: thin; scrollbar-color: rgba(13,148,136,.6) transparent; }
|
||||
</style>
|
||||
1
ui/src/components/empleados/cardEmpleado.vue
Normal file
1
ui/src/components/empleados/cardEmpleado.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
ui/src/components/empleados/tablaEmpleados.vue
Normal file
1
ui/src/components/empleados/tablaEmpleados.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
ui/src/components/planillas/cardPlanilla.vue
Normal file
1
ui/src/components/planillas/cardPlanilla.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
ui/src/components/planillas/tablaPlanillas.vue
Normal file
1
ui/src/components/planillas/tablaPlanillas.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
ui/src/components/tareas/cardTarea.vue
Normal file
1
ui/src/components/tareas/cardTarea.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
ui/src/components/tareas/tablaTareas.vue
Normal file
1
ui/src/components/tareas/tablaTareas.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
71
ui/src/components/ui/NavBar.vue
Normal file
71
ui/src/components/ui/NavBar.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<script setup>
|
||||
import { ref, watch, computed } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useUi } from '@/stores/useUi'
|
||||
|
||||
const ui = useUi()
|
||||
|
||||
// enlaces de la app
|
||||
const links = [
|
||||
{ to: '/', label: 'Chat', icon: '💬' },
|
||||
{ to: '/empleados', label: 'Empleados', icon: '👥' },
|
||||
{ to: '/tareas', label: 'Tareas', icon: '📋' },
|
||||
{ to: '/planillas', label: 'Planillas', icon: '📂' },
|
||||
{ to: '/asistencias', label: 'Asistencias', icon: '⏰' },
|
||||
{ to: '/config', label: 'Config', icon: '⚙️' },
|
||||
]
|
||||
|
||||
const route = useRoute()
|
||||
const activePath = ref(route.path)
|
||||
watch(route, v => (activePath.value = v.path))
|
||||
|
||||
// clases dinámicas p/ mostrar / ocultar barra
|
||||
const sidebarClasses = computed(() => ui.sidebarOpen ? 'translate-x-0' : '-translate-x-full')
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- backdrop en mobile -->
|
||||
<div v-if="ui.sidebarOpen" class="fixed inset-0 bg-black/40 md:hidden" @click="ui.closeSidebar" />
|
||||
|
||||
<!-- barra lateral -->
|
||||
<aside
|
||||
:class="['fixed left-0 top-0 md:top-14 h-screen w-60 bg-white dark:bg-zinc-900 border-r border-gray-200 dark:border-zinc-800 flex flex-col select-none z-50 transform transition-transform duration-200 ease-in-out', sidebarClasses]">
|
||||
|
||||
<!-- encabezado dentro de sidebar -->
|
||||
<div class="flex items-center justify-between px-4 py-4 md:px-5 md:py-4 border-b border-gray-200 dark:border-zinc-800 md:border-none">
|
||||
<span class="text-lg font-semibold text-teal-600 dark:text-teal-400 md:hidden">Núcleo</span>
|
||||
<button class="h-8 w-8 inline-flex items-center justify-center text-gray-500 hover:text-teal-600" @click="ui.toggleSidebar">
|
||||
✕
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- navegación -->
|
||||
<nav class="flex-1 overflow-y-auto custom-scroll pr-1 pt-4 md:pt-0">
|
||||
<ul class="space-y-1 px-2">
|
||||
<li v-for="l in links" :key="l.to">
|
||||
<RouterLink
|
||||
:to="l.to"
|
||||
class="flex items-center gap-3 w-full px-3 py-2 rounded-md font-medium transition group"
|
||||
:class="activePath.startsWith(l.to)
|
||||
? 'bg-teal-600 text-white shadow'
|
||||
: 'text-gray-700 dark:text-gray-100 hover:bg-teal-100 hover:text-teal-900 dark:hover:bg-zinc-800'"
|
||||
@click="ui.closeSidebar()"
|
||||
>
|
||||
<span class="text-lg" aria-hidden="true">{{ l.icon }}</span>
|
||||
<span class="truncate">{{ l.label }}</span>
|
||||
</RouterLink>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
ul { list-style: none; padding-left: 0; }
|
||||
|
||||
.custom-scroll::-webkit-scrollbar { width: 8px; }
|
||||
.custom-scroll::-webkit-scrollbar-track { background: transparent; }
|
||||
.custom-scroll::-webkit-scrollbar-thumb { background-color: rgba(13,148,136,.4); border-radius: 4px; }
|
||||
.custom-scroll:hover::-webkit-scrollbar-thumb { background-color: rgba(13,148,136,.7); }
|
||||
.custom-scroll { scrollbar-width: thin; scrollbar-color: rgba(13,148,136,.6) transparent; }
|
||||
</style>
|
||||
0
ui/src/components/ui/SideDrawer.vue
Normal file
0
ui/src/components/ui/SideDrawer.vue
Normal file
23
ui/src/components/ui/TopBar.vue
Normal file
23
ui/src/components/ui/TopBar.vue
Normal file
@@ -0,0 +1,23 @@
|
||||
<script setup>
|
||||
import { useUi } from '@/stores/useUi'
|
||||
const ui = useUi()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<!-- barra superior fija -->
|
||||
<header class="fixed top-0 left-0 right-0 h-14 bg-white dark:bg-zinc-900 border-b border-gray-200 dark:border-zinc-800 flex items-center justify-between px-4 md:px-6 z-50 shadow-sm">
|
||||
<!-- título -->
|
||||
<h1 class="text-lg font-semibold tracking-wide text-teal-600 dark:text-teal-400 select-none">Núcleo</h1>
|
||||
|
||||
<!-- botón hamburguesa (visible solo en mobile) -->
|
||||
<button
|
||||
@click="ui.toggleSidebar"
|
||||
class="inline-flex items-center justify-center h-9 w-9 rounded-md bg-teal-600 text-white hover:bg-teal-700 transition ">
|
||||
☰
|
||||
</button>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* sin estilos extra */
|
||||
</style>
|
||||
@@ -1,5 +1,14 @@
|
||||
import { createApp } from 'vue'
|
||||
import './style.css'
|
||||
import App from './App.vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import router from './router'
|
||||
|
||||
createApp(App).mount('#app')
|
||||
import App from './App.vue'
|
||||
import './style.css' // Tailwind o tus estilos globales
|
||||
|
||||
const app =
|
||||
createApp(App)
|
||||
|
||||
app.use(createPinia())
|
||||
app.use(router)
|
||||
|
||||
app.mount('#app')
|
||||
|
||||
35
ui/src/router/index.js
Normal file
35
ui/src/router/index.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { createRouter, createMemoryHistory } from 'vue-router'
|
||||
|
||||
const routes = [
|
||||
// Chat principal y config
|
||||
{ path: '/', name: 'chat', component: () => import('@/views/ChatView.vue') },
|
||||
{ path: '/config', name: 'settings', component: () => import('@/views/SettingsView.vue') },
|
||||
|
||||
// ────── Empleados ──────
|
||||
{ path: '/empleados', name: 'empleados-index', component: () => import('@/views/empleados/EmpleadosIndex.vue') },
|
||||
{ path: '/empleados/nuevo', name: 'empleados-new', component: () => import('@/views/empleados/EmpleadoForm.vue') },
|
||||
{ path: '/empleados/:id', name: 'empleados-edit', component: () => import('@/views/empleados/EmpleadoForm.vue'), props: true },
|
||||
|
||||
// ────── Tareas ──────
|
||||
{ path: '/tareas', name: 'tareas-index', component: () => import('@/views/tareas/TareasIndex.vue') },
|
||||
{ path: '/tareas/nuevo', name: 'tareas-new', component: () => import('@/views/tareas/TareaForm.vue') },
|
||||
{ path: '/tareas/:id', name: 'tareas-edit', component: () => import('@/views/tareas/TareaForm.vue'), props: true },
|
||||
|
||||
// ────── Planillas ──────
|
||||
{ path: '/planillas', name: 'planillas-index', component: () => import('@/views/planillas/PlanillasIndex.vue') },
|
||||
{ path: '/planillas/nuevo', name: 'planillas-new', component: () => import('@/views/planillas/PlanillaForm.vue') },
|
||||
{ path: '/planillas/:id', name: 'planillas-edit', component: () => import('@/views/planillas/PlanillaForm.vue'), props: true },
|
||||
|
||||
// ────── Asistencias ──────
|
||||
{ path: '/asistencias', name: 'asistencias-index', component: () => import('@/views/asistencias/AsistenciasIndex.vue') },
|
||||
{ path: '/asistencias/nuevo', name: 'asistencias-new', component: () => import('@/views/asistencias/AsistenciaForm.vue') },
|
||||
{ path: '/asistencias/:id', name: 'asistencias-edit', component: () => import('@/views/asistencias/AsistenciaForm.vue'), props: true },
|
||||
|
||||
// 404
|
||||
{ path: '/:pathMatch(.*)*', name: 'not-found', component: () => import('@/views/NotFound.vue') }
|
||||
]
|
||||
|
||||
export default createRouter({
|
||||
history: createMemoryHistory(),
|
||||
routes,
|
||||
})
|
||||
5
ui/src/stores/useAsistencias.js
Normal file
5
ui/src/stores/useAsistencias.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useAsistencias = defineStore('asistencias', {
|
||||
state: () => ({ asistencias: [] }),
|
||||
})
|
||||
42
ui/src/stores/useChat.js
Normal file
42
ui/src/stores/useChat.js
Normal file
@@ -0,0 +1,42 @@
|
||||
|
||||
|
||||
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
/**
|
||||
* Chat store
|
||||
* - items: hist de mensajes [{ type, owner, text, … }]
|
||||
* - add(): agrega un mensaje
|
||||
* - run(): ejecuta /comandos y mete componentes dinámicos
|
||||
*/
|
||||
export const useChat = defineStore('chat', {
|
||||
state: () => ({
|
||||
items: [],
|
||||
}),
|
||||
|
||||
actions: {
|
||||
add (item) {
|
||||
this.items.push(item)
|
||||
},
|
||||
|
||||
async run (cmd) {
|
||||
switch (cmd) {
|
||||
case 'empleados':
|
||||
// para demo solo mostramos un texto, después inyectaremos un componente
|
||||
this.add({ type: 'text', owner: 'bot', text: '🎉 Módulo Empleados aún en construcción.' })
|
||||
break
|
||||
case 'tareas':
|
||||
this.add({ type: 'text', owner: 'bot', text: '🛠️ Módulo Tareas aún en construcción.' })
|
||||
break
|
||||
case 'planillas':
|
||||
this.add({ type: 'text', owner: 'bot', text: '📂 Módulo Planillas en construcción.' })
|
||||
break
|
||||
case 'asistencias':
|
||||
this.add({ type: 'text', owner: 'bot', text: '⏰ Módulo Asistencias en construcción.' })
|
||||
break
|
||||
default:
|
||||
this.add({ type: 'text', owner: 'bot', text: `❓ No reconozco /${cmd}` })
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
12
ui/src/stores/useEmpleados.js
Normal file
12
ui/src/stores/useEmpleados.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useEmpleados = defineStore('empleados', {
|
||||
state: () => ({ empleados: [] }),
|
||||
actions: {
|
||||
// placeholder para cargar/crear empleados
|
||||
async fetchAll () {
|
||||
// simulamos fetch
|
||||
this.empleados = []
|
||||
},
|
||||
},
|
||||
})
|
||||
5
ui/src/stores/usePlanillas.js
Normal file
5
ui/src/stores/usePlanillas.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const usePlanillas = defineStore('planillas', {
|
||||
state: () => ({ planillas: [] }),
|
||||
})
|
||||
5
ui/src/stores/useTareas.js
Normal file
5
ui/src/stores/useTareas.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useTareas = defineStore('tareas', {
|
||||
state: () => ({ tareas: [] }),
|
||||
})
|
||||
20
ui/src/stores/useUI.js
Normal file
20
ui/src/stores/useUI.js
Normal file
@@ -0,0 +1,20 @@
|
||||
// src/stores/useUi.js
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useUi = defineStore('ui', {
|
||||
state: () => ({
|
||||
sidebarOpen: true, // visible por defecto en desktop
|
||||
}),
|
||||
|
||||
actions: {
|
||||
toggleSidebar () {
|
||||
this.sidebarOpen = !this.sidebarOpen
|
||||
},
|
||||
closeSidebar () {
|
||||
this.sidebarOpen = false
|
||||
},
|
||||
openSidebar () {
|
||||
this.sidebarOpen = true
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -1,79 +1,4 @@
|
||||
:root {
|
||||
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
line-height: 1.5;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
@import "tailwindcss";
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
14
ui/src/views/ChatView.vue
Normal file
14
ui/src/views/ChatView.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<script setup>
|
||||
/* Vista raíz “/” → muestra el chat estilo ChatGPT */
|
||||
import CanvasChat from '@/components/chat/CanvasChat.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-full flex flex-col">
|
||||
<CanvasChat class="flex-1" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* nada por ahora */
|
||||
</style>
|
||||
21
ui/src/views/NotFound.vue
Normal file
21
ui/src/views/NotFound.vue
Normal file
@@ -0,0 +1,21 @@
|
||||
<script setup>
|
||||
import { useRouter } from 'vue-router'
|
||||
const router = useRouter()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-full flex flex-col items-center justify-center gap-6 p-8 text-center">
|
||||
<h1 class="text-5xl font-bold text-teal-600">404</h1>
|
||||
<p class="text-lg text-gray-700">Uy, no encontramos esa página.</p>
|
||||
|
||||
<button
|
||||
@click="router.push('/')"
|
||||
class="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-teal-600 text-white hover:bg-teal-700 transition">
|
||||
← Volver al inicio
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* Estilos extra opcionales */
|
||||
</style>
|
||||
0
ui/src/views/SettingsView.vue
Normal file
0
ui/src/views/SettingsView.vue
Normal file
1
ui/src/views/asistencias/AsistenciaForm.vue
Normal file
1
ui/src/views/asistencias/AsistenciaForm.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
ui/src/views/asistencias/AsistenciasIndex.vue
Normal file
1
ui/src/views/asistencias/AsistenciasIndex.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
ui/src/views/empleados/EmpleadoForm.vue
Normal file
1
ui/src/views/empleados/EmpleadoForm.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
ui/src/views/empleados/EmpleadosIndex.vue
Normal file
1
ui/src/views/empleados/EmpleadosIndex.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
ui/src/views/planillas/PlanillaForm.vue
Normal file
1
ui/src/views/planillas/PlanillaForm.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
ui/src/views/planillas/PlanillasIndex.vue
Normal file
1
ui/src/views/planillas/PlanillasIndex.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
ui/src/views/tareas/TareaForm.vue
Normal file
1
ui/src/views/tareas/TareaForm.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
1
ui/src/views/tareas/TareasIndex.vue
Normal file
1
ui/src/views/tareas/TareasIndex.vue
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user