App web familiar de rutinas visuales para niños con TDAH: muestra cada día el material del cole y las rutinas de tarde, con gamificación por monedas y tienda de recompensas. Multi-niño y bilingüe ES/CA. Uso doméstico/homelab. Backend (Spring Boot 3.5 / Java 21 / Gradle): - Dominio por capas, PostgreSQL + Liquibase, datos semilla. - API REST con DTOs: /today, toggle con monedas y bonos de bloque/día, monedero, tienda/canje, ajustes y CRUD del panel de padres. - Seguridad ligera por PIN (BCrypt + sesion en memoria), sin Keycloak. - Tests JUnit: generacion del dia, monedas/bonos con reversion, canje, seguridad. Frontend (Angular 19, standalone + signals): - Perfiles, Home (Tablero y Foco), Tienda y panel de padres (5 pestañas). - Tipografia OpenDyslexic conmutable (accesibilidad), i18n ES/CA, TTS y sonido. - Tokens de diseño fieles al handoff (paleta, animaciones, monedas voladoras). Empaquetado: - Docker multi-stage + docker-compose (PostgreSQL + backend + Nginx). - Decisiones de arquitectura documentadas en docs/adr.
50 lines
1.4 KiB
TypeScript
50 lines
1.4 KiB
TypeScript
import { Component, ElementRef, Input, inject, signal } from '@angular/core';
|
|
|
|
/** Monedero: pill con 🪙 y el saldo. Hace walletBump cuando se le pide (al ganar). */
|
|
@Component({
|
|
selector: 'app-wallet',
|
|
imports: [],
|
|
template: `
|
|
<span class="wallet" [class.wallet--bump]="bumping()">
|
|
<span class="wallet__coin">🪙</span>
|
|
<span class="wallet__amount">{{ coins }}</span>
|
|
</span>
|
|
`,
|
|
styles: [
|
|
`
|
|
.wallet {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 9px 18px;
|
|
border-radius: var(--radius-pill);
|
|
background: var(--coin-bg);
|
|
color: var(--coin-text);
|
|
font-family: var(--font-display);
|
|
font-weight: 700;
|
|
font-size: 1.4rem;
|
|
}
|
|
.wallet--bump { animation: walletBump 0.45s ease; }
|
|
`,
|
|
],
|
|
})
|
|
export class WalletComponent {
|
|
@Input({ required: true }) coins = 0;
|
|
|
|
protected readonly bumping = signal(false);
|
|
private readonly el = inject(ElementRef<HTMLElement>);
|
|
|
|
/** Rectángulo del monedero: destino de las monedas voladoras. */
|
|
getRect(): DOMRect {
|
|
return (this.el.nativeElement as HTMLElement).getBoundingClientRect();
|
|
}
|
|
|
|
/** Dispara la animación de "rebote" del monedero. */
|
|
bump(): void {
|
|
this.bumping.set(false);
|
|
// Reinicia la animación en el siguiente frame.
|
|
requestAnimationFrame(() => this.bumping.set(true));
|
|
setTimeout(() => this.bumping.set(false), 500);
|
|
}
|
|
}
|