248 lines
7.7 KiB
JavaScript
248 lines
7.7 KiB
JavaScript
// App.js
|
|
|
|
/**
|
|
* Vistas de la aplicación (pueden ir en archivos separados luego)
|
|
*/
|
|
|
|
import { Navbar, Swap, Menu, Checkbox, Input, Button, Autocomplete, Datepicker, Colorpicker, Fileinput, Toast } from "sigpro-ui";
|
|
|
|
const toggle = $(false);
|
|
// const consoleToggle = $(()=>console.log(toggle()))
|
|
const Home = () => {
|
|
const valor = $("jjj");
|
|
const miCheck = $(false); // Creamos la señal
|
|
return Div({ class: "gap-3 flex flex-col" }, [
|
|
H1("Dashboard Principal"),
|
|
Button({ tooltip: "tooltip", badge: "22" }, "Hola"),
|
|
Input({
|
|
label: "Correo Electrónico",
|
|
type: "email",
|
|
placeholder: "ejemplo@correo.com",
|
|
value: valor, // Binding automático
|
|
}),
|
|
Span({ class: "gap-4 text-4xl" }, () => valor()),
|
|
P("Bienvenido a la interfaz reactiva de SigPro. Aquí puedes ver el estado global."),
|
|
Checkbox({ tooltip: "Tooltip", toggle: toggle, value: miCheck, label: "Checkbox" }),
|
|
miCheck,
|
|
toggle,
|
|
Button(
|
|
{
|
|
class: "btn-primary",
|
|
onclick: () => {
|
|
Toast("Cambio de toggle");
|
|
toggle(!toggle());
|
|
},
|
|
},
|
|
"Lanzar Toast",
|
|
),
|
|
]);
|
|
};
|
|
|
|
const Profile = (params) => {
|
|
const miFecha = $();
|
|
const miRango = $();
|
|
const selectedFruit = $("Apple");
|
|
const fruits = ["Apple", "Banana", "Cherry", "Dragonfruit", "Elderberry"];
|
|
const colorFondo = $("#ef4444");
|
|
const misArchivos = $([]);
|
|
|
|
const textoInput = $(() => {
|
|
const f = miFecha;
|
|
if (!f.start) return "";
|
|
return f.end ? `${f.start} - ${f.end}` : `${f.start}...`;
|
|
});
|
|
|
|
return Div({ class: "p-4 space-y-4" }, [
|
|
H2({ class: "text-xl font-bold" }, `Perfil: ${params.id}`),
|
|
Autocomplete({
|
|
label: "Selecciona una fruta",
|
|
value: selectedFruit,
|
|
options: fruits,
|
|
onSelect: (val) => console.log("Seleccionado:", val),
|
|
}),
|
|
Datepicker({ value: miFecha, label: "Fecha", placeholder: textoInput, hour: true }),
|
|
Datepicker({ value: miRango, label: "Fecha", placeholder: textoInput, range: true, hour: true }),
|
|
Colorpicker({ show: true, label: "Color del tema", value: colorFondo }),
|
|
Input({ type: "number", label: "Number" }),
|
|
Input({ type: "email", label: "Email" }),
|
|
Input({ label: "Text" }),
|
|
Input({ type: "date", label: "Date" }),
|
|
Input({ type: "password", label: "Password" }),
|
|
$html("p", {}, () => `Has elegido: ${selectedFruit()}`),
|
|
Fileinput({
|
|
tooltip: "Formatos: PDF, JPG",
|
|
max: 5,
|
|
// Cada vez que la lista cambia, se dispara esto
|
|
onSelect: async (files) => {
|
|
if (files.length === 0) return;
|
|
|
|
console.log("Subiendo archivos automáticamente...", files);
|
|
|
|
const formData = new FormData();
|
|
files.forEach((file) => formData.append("files[]", file));
|
|
|
|
// await fetch('/api/upload', { method: 'POST', body: formData });
|
|
},
|
|
}),
|
|
Div({ class: "pt-4" }, [
|
|
Button(
|
|
{
|
|
class: "btn-sm btn-outline",
|
|
onclick: () => $router.to("/"),
|
|
},
|
|
"Volver",
|
|
),
|
|
]),
|
|
]);
|
|
};
|
|
/**
|
|
* Componente Principal
|
|
*/
|
|
export const App = () => {
|
|
// Estado local de la App (ejemplo: tema o usuario)
|
|
const isDark = $(false, "sigpro-theme");
|
|
|
|
// Efecto para cambiar el tema en el HTML
|
|
$watch(() => {
|
|
document.documentElement.setAttribute("data-theme", isDark() ? "dark" : "light");
|
|
});
|
|
|
|
const menuItems = [
|
|
{ label: "Inicio", onclick: () => $router.to("/") },
|
|
{ label: "Mi Perfil", onclick: () => $router.to("/profile/42") },
|
|
{ label: "Tareas TODO", onclick: () => $router.to("/todo") }, // <-- Nueva opción
|
|
{ label: "Ajustes", onclick: () => Toast("Ajustes no disponibles", "alert-error") },
|
|
];
|
|
|
|
return Div({ class: "min-h-screen flex flex-col" }, [
|
|
Navbar({ class: "sticky top-0 z-50 bg-base-100/80 backdrop-blur border-b border-base-300" }, [
|
|
Div({ class: "flex-1" }, [
|
|
A(
|
|
{
|
|
class: "btn btn-ghost text-xl font-black tracking-tighter",
|
|
onclick: () => $router.to("/"),
|
|
},
|
|
"SIGPRO",
|
|
),
|
|
]),
|
|
Button({ disabled: true }, "Disabled"),
|
|
|
|
Div({ class: "flex items-center gap-2" }, [
|
|
Swap({
|
|
class: "swap-rotate",
|
|
value: isDark,
|
|
on: "🌙",
|
|
off: "☀️",
|
|
}),
|
|
Button({ class: "btn-circle btn-ghost", icon: "👤" }),
|
|
]),
|
|
]),
|
|
|
|
// --- LAYOUT PRINCIPAL ---
|
|
Div({ class: "flex flex-1" }, [
|
|
// Sidebar Lateral
|
|
Aside({ class: "w-64 bg-base-200 p-4 hidden md:block" }, [Menu({ items: menuItems, class: "bg-transparent" })]),
|
|
|
|
// Contenido Dinámico (Router)
|
|
Main({ class: "flex-1 p-6 bg-base-100" }, [
|
|
$router([
|
|
{ path: "/", component: Home },
|
|
{ path: "/profile/:id", component: Profile },
|
|
{ path: "/todo", component: TodoPage },
|
|
{
|
|
path: "*",
|
|
component: () =>
|
|
Div({ class: "text-center py-20" }, [H1({ class: "text-9xl font-bold opacity-20" }, "404"), P("La página que buscas no existe.")]),
|
|
},
|
|
]),
|
|
]),
|
|
]),
|
|
|
|
// --- FOOTER ---
|
|
Footer({ class: "footer footer-center p-4 bg-base-300 text-base-content text-xs" }, [P("© 2026 - Built with SigPro Engine")]),
|
|
]);
|
|
};
|
|
|
|
const TodoPage = () => {
|
|
const newTask = $("");
|
|
// Persistencia automática en localStorage gracias a tu Core
|
|
const tasks = $([], "sigpro-todo-list");
|
|
|
|
const addTask = () => {
|
|
const val = newTask().trim();
|
|
if (!val) return Toast("Escribe algo...", "alert-warning");
|
|
|
|
tasks([...tasks(), { id: crypto.randomUUID(), text: val, done: false }]);
|
|
newTask(""); // Limpia el input
|
|
};
|
|
|
|
const removeTask = (id) => {
|
|
tasks(tasks().filter((t) => t.id !== id));
|
|
};
|
|
|
|
const toggleTask = (id) => {
|
|
tasks(tasks().map((t) => (t.id === id ? { ...t, done: !t.done } : t)));
|
|
};
|
|
|
|
// Señal computada para el contador
|
|
const pendingCount = $(() => tasks().filter((t) => !t.done).length);
|
|
const misDatos = $([{ id: 1 }]);
|
|
return Div({ class: "max-w-md mx-auto space-y-6" }, [
|
|
H1({ class: "text-3xl font-black italic" }, "TODO LIST"),
|
|
|
|
// Input Group
|
|
Div({ class: "join w-full" }, [
|
|
Input({
|
|
class: "join-item w-full",
|
|
placeholder: "Nueva tarea...",
|
|
value: newTask,
|
|
onkeydown: (e) => e.key === "Enter" && addTask(),
|
|
}),
|
|
Button({ class: "btn-primary join-item", onclick: addTask }, "Añadir"),
|
|
]),
|
|
|
|
// Stats
|
|
Div({ class: "flex justify-between items-center opacity-70 text-sm" }, [
|
|
Span(() => `Total: ${tasks().length}`),
|
|
Span({ class: "badge badge-secondary" }, () => `${pendingCount()} pendientes`),
|
|
]),
|
|
|
|
// Lista Reactiva (Aquí evaluamos tu append con sweep)
|
|
Ul({ class: "menu bg-base-200 rounded-box w-full p-2" }, () =>
|
|
tasks().length === 0
|
|
? Li({ class: "p-4 text-center opacity-50" }, "No hay tareas pendientes")
|
|
: tasks().map((task) =>
|
|
Li({ class: "flex flex-row items-center gap-2 p-2 border-b border-base-300 last:border-0" }, [
|
|
Checkbox({
|
|
class: "checkbox-sm",
|
|
value: () => task.done,
|
|
onclick: () => toggleTask(task.id),
|
|
}),
|
|
Span(
|
|
{
|
|
class: `flex-1 ${task.done ? "line-through opacity-40" : ""}`,
|
|
onclick: () => toggleTask(task.id),
|
|
},
|
|
task.text,
|
|
),
|
|
Button(
|
|
{
|
|
class: "btn-ghost btn-xs text-error",
|
|
onclick: () => removeTask(task.id),
|
|
},
|
|
"✕",
|
|
),
|
|
]),
|
|
),
|
|
),
|
|
|
|
Button(
|
|
{
|
|
class: "btn-link btn-xs text-error p-0",
|
|
onclick: () => tasks([]),
|
|
},
|
|
"Limpiar todo",
|
|
),
|
|
]);
|
|
};
|