This commit is contained in:
2026-05-14 14:14:07 +02:00
parent fac8a6e412
commit 06c7603451
8 changed files with 685 additions and 357 deletions

View File

@@ -1,286 +1,300 @@
// App.js
import { $, watch, h, when } from "sigpro";
import {
Navbar,
Drawer,
DrawerToggle,
DrawerContent,
DrawerSide,
DrawerOverlay,
Menu,
Tabs,
Swap,
SwapToggle,
SwapOn,
SwapOff,
Icon,
Avatar,
Dropdown,
DropdownButton,
DropdownContent,
Modal,
Fieldset,
Input,
Button
Navbar,
Drawer,
DrawerToggle,
DrawerContent,
DrawerSide,
DrawerOverlay,
Menu,
MenuTitle,
MenuItem,
Tabs,
Tab,
Swap,
SwapToggle,
SwapOn,
SwapOff,
Icon,
Avatar,
Dropdown,
DropdownButton,
DropdownContent,
Modal,
ModalBox,
ModalClose,
ModalAction,
ModalBackdrop,
Fieldset,
Input,
LabelFloating,
Button,
Loading
} from "sigpro-ui";
import 'sigpro-ui/css';
import { Desktop } from "./tabs/Desktop.js";
import { ModalSearch } from "./components/ModalSearch.js";
export const isDark = $(false, "theme-mode");
export const App = () => {
// Tema oscuro/claro
const showSearchModal = $(false);
// Tema oscuro/claro
watch(isDark, (dark) => {
document.documentElement.setAttribute("data-theme", dark ? "dark" : "light");
});
document.documentElement.setAttribute("data-theme", isDark() ? "dark" : "light");
watch(isDark, (dark) => {
document.documentElement.setAttribute("data-theme", dark ? "dark" : "light");
});
// Activar tema inicial
document.documentElement.setAttribute("data-theme", isDark() ? "dark" : "light");
// Estado de login persistente
const logged = $(false, "logged");
// Estado para buscador
const searchQuery = $("");
// Estado para modal de login
const showLoginModal = $(false);
const loginForm = {
username: $(""),
password: $("")
};
// Pestañas: la primera (Escritorio) no es cerrable
const tabs = $([
{
label: "Escritorio",
content: () => Desktop,
closable: false
}
]);
const activeTab = $(0);
const openDrawer = $(false);
// Elementos del menú en el drawer
const menuItems = [
{
label: "Clientes",
children: [
{ label: "Buscar Cliente", onclick: () => openTab("Clientes") },
]
},
{
label: "Recibos",
children: [
{ label: "Buscar Recibo" },
{ label: "Pendientes" },
{ label: "Extornos" },
],
},
{
label: "Polizas",
children: [
{ label: "Buscar Póliza", onclick: () => openTab("Polizas") },
{ label: "Nueva producción", onclick: () => openTab("Polizas") },
{ label: "Anulaciones", onclick: () => openTab("Polizas") },
{ label: "Renovación Cartera", onclick: () => openTab("Polizas") }
]
},
{
label: "Comercial",
children: [
{ label: "Oportunidades" },
],
},
{
label: "Siniestros",
children: [
{ label: "Nuevo Siniestro" },
{ label: "Buscar Siniestro" },
]
},
{
label: "Soporte",
children: [
{ label: "Tickets" },
{ label: "Reportes" },
]
}
];
// Referencia al contenedor de pestañas para manejar el foco
let tabsContainerRef = null;
let drawerToggleRef = null;
// Abre o crea una pestaña, cierra el drawer
const openTab = (label) => {
const currentTabs = tabs();
if (currentTabs.length >= 15) return;
const newTab = {
label,
content: () => `¡Bienvenido al escritorio!`,
closable: true
// Estado de login persistente
const logged = $(false, "logged");
const showLoginModal = $(false);
const loginForm = {
username: $(""),
password: $("")
};
tabs([...currentTabs, newTab]);
activeTab(tabs().length - 1);
closeDrawer();
};
// Pestañas: la primera (Escritorio) no es cerrable
const tabs = $([
{
label: "Escritorio",
content: () => Desktop,
closable: false
}
]);
const activeTab = $(0);
const openDrawer = $(false);
const closeDrawer = () => {
openDrawer(false);
if (drawerToggleRef) drawerToggleRef.checked = false;
};
// Elementos del menú en el drawer
const menuItems = [
{
label: "Clientes",
children: [
{ label: "Buscar Cliente", onclick: () => openTab("Clientes") },
]
},
{
label: "Recibos",
children: [
{ label: "Buscar Recibo" },
{ label: "Pendientes" },
{ label: "Extornos" },
],
},
{
label: "Polizas",
children: [
{ label: "Buscar Póliza", onclick: () => openTab("Polizas") },
{ label: "Nueva producción", onclick: () => openTab("Polizas") },
{ label: "Anulaciones", onclick: () => openTab("Polizas") },
{ label: "Renovación Cartera", onclick: () => openTab("Polizas") }
]
},
{
label: "Comercial",
children: [
{ label: "Oportunidades" },
],
},
{
label: "Siniestros",
children: [
{ label: "Nuevo Siniestro" },
{ label: "Buscar Siniestro" },
]
},
{
label: "Soporte",
children: [
{ label: "Tickets" },
{ label: "Reportes" },
]
}
];
// Manejo del login
const handleLogin = () => {
logged(true);
showLoginModal(false);
loginForm.username("");
loginForm.password("");
};
let tabsContainerRef = null;
let drawerToggleRef = null;
const handleLogout = () => {
logged(false);
};
const openTab = (label) => {
const currentTabs = tabs();
if (currentTabs.length >= 15) return;
const newTab = {
label,
content: () => `¡Bienvenido a ${label}!`,
closable: true
};
tabs([...currentTabs, newTab]);
activeTab(tabs().length - 1);
closeDrawer();
};
return [
Drawer({}, [
// Control oculto del drawer
DrawerToggle({
id: "app-drawer",
ref: (el) => drawerToggleRef = el,
checked: openDrawer,
onchange: (e) => openDrawer(e.target.checked)
}),
const closeDrawer = () => {
openDrawer(false);
if (drawerToggleRef) drawerToggleRef.checked = false;
};
// Contenido principal
DrawerContent({}, [
Navbar({ class: "bg-base-100 shadow-lg align-center" }, [
// Botón hamburguesa
div({ class: "flex-none" }, [
label({ for: "app-drawer", class: "btn btn-ghost btn-square" }, [
Icon({}, "icon-[lucide--menu]")
])
]),
const handleLogin = () => {
if (!loginForm.username() || !loginForm.password()) {
alert('Por favor, complete todos los campos');
return;
}
logged(true);
showLoginModal(false);
loginForm.username("");
loginForm.password("");
};
// Buscador
div({ class: "flex-1 max-w-md mx-4" }, [
Input({
type: "search",
placeholder: "Buscar...",
value: searchQuery,
left: span({ class: "icon-[lucide--search]" }),
oninput: (e) => console.log(e.target.value)
})
]),
const handleLogout = () => {
logged(false);
};
// Espaciador central
div({ class: "flex-1" }, []),
return [
Drawer({}, [
DrawerToggle({
id: "app-drawer",
ref: (el) => drawerToggleRef = el,
checked: openDrawer,
onchange: (e) => openDrawer(e.target.checked)
}),
// Swap para tema claro/oscuro
Swap({ class: "text-xl" }, [
SwapToggle({ value: isDark, class: "swap-rotate" }),
SwapOn({}, span({ class: "icon-[lucide--moon]" })),
SwapOff({}, span({ class: "icon-[lucide--sun]" })),
]),
DrawerContent({}, [
Navbar({ class: "bg-base-100 shadow-lg align-center" }, [
div({ class: "flex-none" }, [
label({ for: "app-drawer", class: "btn btn-ghost btn-square" }, [
Icon({}, "icon-[lucide--menu]")
])
]),
Button({ class: "icon-[lucide--search] btn-ghost", onclick: () => showSearchModal(true) }),
div({ class: "flex-1" }),
Swap({ class: "text-xl" }, [
SwapToggle({ value: isDark, class: "swap-rotate" }),
SwapOn({}, h('span', { class: "icon-[lucide--moon]" })),
SwapOff({}, h('span', { class: "icon-[lucide--sun]" })),
]),
when(logged,
() => Dropdown({ class: "flex-none ml-2 dropdown-bottom dropdown-end" }, [
DropdownButton({ class: "btn-circle btn btn-ghost", tabindex: "0", role: "button" }, [
Avatar({ class: "placeholder" }, [
div({ class: "bg-neutral text-neutral-content w-10 rounded-full" }, [
h('span', { class: "text-xl" }, "U")
])
])
]),
DropdownContent(
{ class: "menu bg-base-100 rounded-box w-52 p-2 shadow" },
[
Menu({ class: "bg-base-100 max-w-xs w-full" },
[
MenuItem({ label: "Mi Perfil", onclick: () => openTab("Mi Perfil") }),
MenuItem({ label: "Configuración", onclick: () => openTab("Configuración") }),
MenuItem({ label: "Cerrar Sesión", onclick: handleLogout }),
]
),
],
),
]),
() => Button({
class: "flex-none ml-2 btn btn-ghost btn-circle relative",
onclick: () => showLoginModal(true)
}, [
Icon({}, "icon-[lucide--user] text-xl"),
])
)
]),
// Avatar con dropdown o botón de login
when(logged,
() => Dropdown({ class: "flex-none ml-2 dropdown-bottom dropdown-end" }, [
DropdownButton({ class: "btn-circle btn btn-ghost", tabindex: "0", role: "button" }, [
div({ class: "w-10 rounded-full flex items-center justify-center" }, [
Icon({}, "icon-[lucide--user] text-xl")
// Área principal con pestañas
div({
class: "p-4",
ref: (el) => tabsContainerRef = el
}, [
h('div', { class: 'tabs tabs-box' },
() => tabs().map((item, idx) =>
Tab({
name: "app-tabs",
"aria-label": item.label,
checked: activeTab() === idx,
onchange: () => activeTab(idx),
content: item.content,
closable: item.closable,
tabs,
index: idx
})
)
)
])
]),
DropdownContent(
{ class: "menu bg-base-100 rounded-box w-52 p-2 shadow" },
[
Menu({
class: "bg-base-100 max-w-xs w-full",
items: [
{ label: "Mis mensajes", onclick: () => hide() },
{ label: "Delete", onclick: () => hide() },
{ label: "Cerrar Sesión", onclick: handleLogout },
],
}),
],
),
]),
() => Button({
class: "flex-none ml-2 btn btn-ghost btn-circle relative",
onclick: () => showLoginModal(true)
}, [
Icon({}, "icon-[lucide--user] text-xl"),
DrawerSide({ class: "z-50" }, [
DrawerOverlay({ for: "app-drawer" }),
div({
class: "menu bg-base-200 text-base-content min-h-full w-80 p-4"
}, [
h('h2', { class: "text-lg font-bold mb-4" }, "Menú"),
Menu({ class: "bg-base-200 max-w-xs w-full" },
menuItems.flatMap(item => [
MenuTitle({}, item.label),
...item.children.map(child =>
MenuItem({ label: child.label, onclick: child.onclick })
)
])
)
])
])
)
]),
// Área principal con las pestañas
div({
class: "p-4",
ref: (el) => tabsContainerRef = el
}, [
Tabs({
class: 'tabs-box',
items: tabs,
activeIndex: activeTab
})
])
]),
// Lateral del drawer
DrawerSide({ class: "z-50" }, [
DrawerOverlay({ for: "app-drawer" }),
div({
class: "menu bg-base-200 text-base-content min-h-full w-80 p-4"
}, [
h2({ class: "text-lg font-bold mb-4" }, ["Menú"]),
Menu({ items: menuItems, class: "bg-base-200 max-w-xs w-full" })
])
])
]),
ModalSearch({
open: showSearchModal,
onSelect: (item) => {
console.log("Item seleccionado:", item);
showSearchModal(false);
}
}),
// Modal de login
Modal({
open: showLoginModal,
actions: [
Button({
class: "btn btn-ghost",
onclick: () => showLoginModal(false)
}, "Cancelar"),
Button({
class: "btn btn-primary",
onclick: handleLogin
}, "Entrar")
]
}, [
Fieldset({ label: "Iniciar sesión", class: "bg-base-200 border-base-300 rounded-box border gap-3 p-4", }, [
Input({
class: "w-full",
type: "text",
label: "Usuario",
float: true,
placeholder: "Nombre de usuario",
value: loginForm.username
})
,
Input({
class: "w-full",
type: "password",
label: "Contraseña",
float: true,
placeholder: "Contraseña",
value: loginForm.password
})
])
])
];
// Modal de Login adaptado
when(showLoginModal, () =>
Modal({ open: true, class: '' }, [
ModalBox({}, [
ModalClose({ onclick: () => showLoginModal(false) }),
h('h3', { class: "text-lg font-bold" }, "Iniciar Sesión"),
Fieldset({
class: "bg-base-200 border-base-300 rounded-box border gap-3 p-4"
}, [
LabelFloating({ class: "w-full" }, [
Input({
class: "w-full",
type: "text",
placeholder: "Nombre de usuario",
value: loginForm.username,
oninput: (e) => loginForm.username(e.target.value)
}),
h('span', {}, "Usuario")
]),
LabelFloating({ class: "w-full" }, [
Input({
class: "w-full",
type: "password",
placeholder: "Contraseña",
value: loginForm.password,
oninput: (e) => loginForm.password(e.target.value)
}),
h('span', {}, "Contraseña")
])
]),
ModalAction({}, [
Button({
class: "btn btn-ghost",
onclick: () => showLoginModal(false)
}, "Cancelar"),
Button({
class: "btn btn-primary",
onclick: handleLogin
}, "Entrar")
])
]),
ModalBackdrop({ onclick: () => showLoginModal(false) })
])
)
];
};