feat: add canvas-confetti integration and AuroraButton component; enhance UI with animations and improve button interactions
This commit is contained in:
@@ -291,7 +291,7 @@ function RouteComponent() {
|
||||
// NEW: acciones carrito
|
||||
function addToCart(a: Asignatura) {
|
||||
setCart(prev => prev.find(x => x.id === a.id) ? prev : [...prev, a])
|
||||
toast.success('Asignatura añadida al carrito')
|
||||
toast.success('Asignatura añadida al carrito de asignaturas')
|
||||
}
|
||||
function removeFromCart(id: string) {
|
||||
setCart(prev => prev.filter(x => x.id !== id))
|
||||
@@ -355,7 +355,7 @@ function RouteComponent() {
|
||||
className="relative"
|
||||
>
|
||||
<Icons.ShoppingCart className="w-4 h-4 mr-2" />
|
||||
Carrito
|
||||
Carrito de asignaturas
|
||||
{cart.length > 0 && (
|
||||
<span className="ml-2 inline-flex h-5 min-w-[1.25rem] items-center justify-center rounded-full bg-white/90 text-[11px] text-neutral-900 px-1">
|
||||
{cart.length}
|
||||
@@ -369,36 +369,51 @@ function RouteComponent() {
|
||||
</div>
|
||||
|
||||
{/* Filtros */}
|
||||
<div className="grid gap-2 sm:grid-cols-[1fr,140px,180px,150px]">
|
||||
<Input
|
||||
value={q}
|
||||
onChange={(e) => setQ(e.target.value)}
|
||||
placeholder="Buscar por nombre, clave, plan, carrera, facultad…"
|
||||
className="w-full"
|
||||
/>
|
||||
<Select value={sem} onValueChange={setSem}>
|
||||
<SelectTrigger><SelectValue placeholder="Semestre" /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="todos">Todos</SelectItem>
|
||||
{semestres.map(s => <SelectItem key={s} value={s}>Semestre {s}</SelectItem>)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select value={tipo} onValueChange={setTipo}>
|
||||
<SelectTrigger><SelectValue placeholder="Tipo" /></SelectTrigger>
|
||||
<SelectContent className="max-h-64">
|
||||
<SelectItem value="todos">Todos</SelectItem>
|
||||
{tipos.map(t => <SelectItem key={t} value={t}>{t}</SelectItem>)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select value={groupBy} onValueChange={(v) => setGroupBy(v as any)}>
|
||||
<SelectTrigger><SelectValue placeholder="Agrupar por" /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="semestre">Agrupar por semestre</SelectItem>
|
||||
<SelectItem value="ninguno">Sin agrupación</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<div className="grid gap-4 sm:grid-cols-4">
|
||||
<div>
|
||||
<Label>Búsqueda</Label>
|
||||
<Input
|
||||
value={q}
|
||||
onChange={(e) => setQ(e.target.value)}
|
||||
placeholder="Nombre, clave, plan, carrera, facultad…"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label>Semestre</Label>
|
||||
<Select value={sem} onValueChange={setSem}>
|
||||
<SelectTrigger><SelectValue placeholder="Todos" /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="todos">Todos</SelectItem>
|
||||
{semestres.map(s => <SelectItem key={s} value={s}>Semestre {s}</SelectItem>)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label>Tipo</Label>
|
||||
<Select value={tipo} onValueChange={setTipo}>
|
||||
<SelectTrigger><SelectValue placeholder="Todos" /></SelectTrigger>
|
||||
<SelectContent className="max-h-64">
|
||||
<SelectItem value="todos">Todos</SelectItem>
|
||||
{tipos.map(t => <SelectItem key={t} value={t}>{t}</SelectItem>)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label>Agrupación</Label>
|
||||
<Select value={groupBy} onValueChange={(v) => setGroupBy(v as any)}>
|
||||
<SelectTrigger><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="semestre">Por semestre</SelectItem>
|
||||
<SelectItem value="ninguno">Sin agrupación</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* Chips de salud */}
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<HealthChip
|
||||
@@ -621,7 +636,7 @@ function RouteComponent() {
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<Button variant="ghost" onClick={clearCart}><Icons.Trash2 className="w-4 h-4 mr-1" /> Vaciar carrito</Button>
|
||||
<Button variant="ghost" onClick={clearCart}><Icons.Trash2 className="w-4 h-4 mr-1" /> Vaciar carrito de Asignaturas</Button>
|
||||
<div className="space-x-2">
|
||||
<Button variant="outline" onClick={() => setBulkOpen(false)}>Cerrar</Button>
|
||||
<Button onClick={cloneBulk}><Icons.CopyPlus className="w-4 h-4 mr-1" /> Clonar en lote</Button>
|
||||
@@ -686,7 +701,7 @@ function AsignaturaCard({ a, onClone, onAddToCart }: { a: Asignatura; onClone: (
|
||||
<Icons.Copy className="w-4 h-4" /> Clonar…
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="gap-2" onClick={onAddToCart}>
|
||||
<Icons.ShoppingCart className="w-4 h-4" /> Añadir al carrito
|
||||
<Icons.ShoppingCart className="w-4 h-4" /> Añadir al carrito de asignaturas
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
Reference in New Issue
Block a user