Merge pull request #52 from josedario87/codex/remove-chat-interface-and-navbar,-add-floating-chat-button
Add floating chat widget
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
import { watchEffect, computed } from 'vue' // Added computed
|
||||
import TopBar from '@/components/ui/TopBar.vue'
|
||||
import NavBar from '@/components/ui/NavBar.vue'
|
||||
import FloatingChat from '@/components/chat/FloatingChat.vue'
|
||||
import SnackbarContainer from '@/components/ui/SnackbarContainer.vue'
|
||||
|
||||
import { useUi } from '@/stores/useUi'
|
||||
|
||||
const ui = useUi()
|
||||
@@ -72,6 +74,7 @@ const transitionDurationStyle = computed(() => {
|
||||
]" :style="transitionDurationStyle">
|
||||
<!-- NavBar fija -->
|
||||
<NavBar />
|
||||
<FloatingChat />
|
||||
|
||||
<!-- contenido principal -->
|
||||
<main class="min-h-[calc(100vh-56px)] flex flex-col overflow-hidden">
|
||||
|
||||
101
ui/src/components/chat/FloatingChat.vue
Normal file
101
ui/src/components/chat/FloatingChat.vue
Normal file
@@ -0,0 +1,101 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import CanvasChat from './CanvasChat.vue'
|
||||
|
||||
const open = ref(false)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<button
|
||||
v-if="!open"
|
||||
@click="open = true"
|
||||
class="chat-fab"
|
||||
aria-label="Abrir chat"
|
||||
>
|
||||
💬
|
||||
</button>
|
||||
<transition name="fade">
|
||||
<div v-if="open" class="chat-window">
|
||||
<header class="chat-header">
|
||||
<h3 class="title">Chat</h3>
|
||||
<button
|
||||
@click="open = false"
|
||||
class="close-btn"
|
||||
aria-label="Cerrar chat"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
</header>
|
||||
<CanvasChat class="flex-1 min-h-0" />
|
||||
</div>
|
||||
</transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.chat-fab {
|
||||
position: fixed;
|
||||
bottom: 1rem;
|
||||
right: 1rem;
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
border-radius: 50%;
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.3);
|
||||
z-index: 60;
|
||||
}
|
||||
.chat-window {
|
||||
position: fixed;
|
||||
bottom: 1rem;
|
||||
right: 1rem;
|
||||
width: 24rem; /* 384px */
|
||||
height: 32rem; /* 512px */
|
||||
background: var(--background-color);
|
||||
background-image: linear-gradient(
|
||||
135deg,
|
||||
rgba(255, 255, 255, 0.6),
|
||||
rgba(255, 255, 255, 0.2)
|
||||
);
|
||||
border: 1px solid var(--border-color);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
border-radius: 0.5rem;
|
||||
backdrop-filter: blur(8px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 60;
|
||||
}
|
||||
.chat-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-weight: 600;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.close-btn {
|
||||
background: var(--secondary-color);
|
||||
border: none;
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
color: var(--background-color);
|
||||
font-size: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.close-btn:hover {
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
.fade-enter-active, .fade-leave-active {
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
.fade-enter-from, .fade-leave-to { opacity: 0; }
|
||||
</style>
|
||||
@@ -10,7 +10,7 @@ const realtime = useRealtimeStore()
|
||||
|
||||
// enlaces de la app
|
||||
const links = [
|
||||
{ to: '/', label: 'Chat', icon: '💬' },
|
||||
|
||||
{ to: '/empleados', label: 'Empleados', icon: moduleInfo.Cliente.icon },
|
||||
{ to: '/tareas', label: 'Tareas', icon: moduleInfo.TareaRealizada.icon },
|
||||
{ to: '/planillas', label: 'Planillas', icon: moduleInfo.Planilla.icon },
|
||||
@@ -39,7 +39,7 @@ const accentColorForPath = (path) => {
|
||||
if (path.startsWith('/asistencias')) return ui.accentColorAsistencias
|
||||
if (path.startsWith('/feed')) return ui.primaryColor
|
||||
if (path.startsWith('/config')) return ui.accentColorConfiguracion
|
||||
return ui.accentColorChat
|
||||
return ui.primaryColor
|
||||
}
|
||||
|
||||
const tableForPath = (path) => {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { createRouter, createMemoryHistory , createWebHashHistory} from 'vue-router'
|
||||
|
||||
const routes = [
|
||||
// Chat principal y config
|
||||
{ path: '/', name: 'chat', component: () => import('@/views/ChatView.vue') },
|
||||
// Configuración
|
||||
{ path: '/', name: 'home', component: () => import('@/views/HomeView.vue') },
|
||||
{ path: '/config', name: 'settings', component: () => import('@/views/SettingsView.vue') },
|
||||
|
||||
// ────── Empleados ──────
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
<script setup>
|
||||
/* Vista raíz “/” → muestra el chat estilo ChatGPT */
|
||||
import CanvasChat from '@/components/chat/CanvasChat.vue'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="chat-view-container flex flex-col h-full">
|
||||
<header class="page-header">
|
||||
<h1>Chat</h1>
|
||||
</header>
|
||||
<CanvasChat class="flex-1 min-h-0" /> <!-- Added min-h-0 -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.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>
|
||||
83
ui/src/views/HomeView.vue
Normal file
83
ui/src/views/HomeView.vue
Normal file
@@ -0,0 +1,83 @@
|
||||
<script setup>
|
||||
import { onMounted } from 'vue'
|
||||
|
||||
const features = [
|
||||
{ title: 'Empleados', text: 'Administra tu equipo y sus perfiles.' },
|
||||
{ title: 'Tareas', text: 'Asigna tareas y realiza seguimiento.' },
|
||||
{ title: 'Planillas', text: 'Gestiona las planillas de trabajo.' },
|
||||
{ title: 'Asistencias', text: 'Controla la asistencia del personal.' }
|
||||
]
|
||||
|
||||
onMounted(() => {
|
||||
document.querySelectorAll('.feature').forEach((el, i) => {
|
||||
el.style.animationDelay = `${i * 0.2}s`
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="landing">
|
||||
<section class="hero">
|
||||
<h1>Núcleo</h1>
|
||||
<p>Gestión integral de tu organización</p>
|
||||
<RouterLink to="/empleados" class="btn-start">Comenzar</RouterLink>
|
||||
</section>
|
||||
<section class="features">
|
||||
<div v-for="f in features" :key="f.title" class="feature">
|
||||
<h2>{{ f.title }}</h2>
|
||||
<p>{{ f.text }}</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.landing {
|
||||
text-align: center;
|
||||
padding: 2rem 1rem;
|
||||
}
|
||||
.hero h1 {
|
||||
font-size: 3rem;
|
||||
color: var(--primary-color);
|
||||
animation: fade-in-down 0.6s ease both;
|
||||
}
|
||||
.hero p {
|
||||
margin-top: 0.5rem;
|
||||
animation: fade-in-down 0.8s ease both;
|
||||
}
|
||||
.btn-start {
|
||||
margin-top: 1.5rem;
|
||||
display: inline-block;
|
||||
padding: 0.75rem 1.5rem;
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border-radius: 0.5rem;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
.btn-start:hover { background-color: var(--secondary-color); }
|
||||
.features {
|
||||
margin-top: 3rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 1rem;
|
||||
max-width: 800px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.feature {
|
||||
padding: 1rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 0.5rem;
|
||||
background-color: var(--background-color);
|
||||
opacity: 0;
|
||||
animation: fade-in-up 0.5s forwards;
|
||||
}
|
||||
@keyframes fade-in-down {
|
||||
from { opacity: 0; transform: translateY(-20px); }
|
||||
to { opacity: 1; transform: none; }
|
||||
}
|
||||
@keyframes fade-in-up {
|
||||
from { opacity: 0; transform: translateY(20px); }
|
||||
to { opacity: 1; transform: none; }
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user