Actividad 1 - Navegación en Ionic
En esta actividad se van a desarrollar las diferentes formas de navegar entre páginas en una aplicación Ionic. La navegación es un aspecto fundamental en el desarrollo de aplicaciones móviles, ya que permite a los usuarios moverse entre diferentes vistas y funcionalidades de la aplicación.
1. Tipos de Navegación
Section titled “1. Tipos de Navegación”Es la forma más común para aplicaciones móviles, ya que se encarga automáticamente de gestionar la pila de navegación, lo que facilita la implementación de transiciones y animaciones entre páginas. Además, es compatible con las características específicas de Ionic, como el manejo de gestos y la integración con componentes nativos.
import { NavController } from '@ionic/angular/standalone';
constructor(private navCtrl: NavController) {}
goToDetails() { this.navCtrl.navigateForward('/details');}Se utiliza directamente en las etiquetas HTML para crear enlaces de navegación. Es una forma más declarativa de manejar la navegación, ya que se basa en la estructura del DOM. Es útil para casos simples donde no se requiere una gestión compleja de la pila de navegación.
<ion-button routerLink=`}/new-page`}>Go to New Page</ion-button>
<ion-button [routerLink]=`}['/new-page', productId]`}>See Product</ion-button>Es la forma nativa de Angular para manejar la navegación. Permite una mayor flexibilidad y control sobre la navegación. Es útil para casos donde se requiere lógica adicional antes de navegar a una nueva página, como puede ser hacer una llamada a una API o cuando trabajamos en servicios donde no tenemos acceso a NavController.
import { Router } from '@angular/router';
constructor(private router: Router) {}
async processAndNavigate() { await this.myService.saveData(); this.router.navigate(['/new-page', this.id], { queryParams: { mode: 'edit' }, });}1.1. Resumen de métodos de navegación
Section titled “1.1. Resumen de métodos de navegación”| Método | Uso Principal | Ventaja Móvil |
|---|---|---|
| NavController | Lógica en el .ts | Control total de animaciones y Stack |
| RouterLink | Directamente en el .html | Más rápido de implementar y leer |
| Router | Lógica compleja o Servicios | Estándar de Angular, compatible con Guards |
2. Ejercicio
Section titled “2. Ejercicio”Se debe crear una aplicación Ionic con las siguientes características:
2.1. Configuración del Login y Rutas Principales
Section titled “2.1. Configuración del Login y Rutas Principales”Configurar las rutas principales de la aplicación y la pantalla inicial de inicio de sesión que se muestra fuera del sistema de pestañas.
-
Página de Login fuera de las pestañas
La página de Login se encuentra fuera de las pestañas gracias a la configuración de rutas en
src/app/app.routes.ts:src/app/app.routes.ts import { Routes } from '@angular/router';export const routes: Routes = [{path: '',loadComponent: () => import('./features/login/login.page').then((m) => m.LoginPage),},{path: 'login',loadComponent: () => import('./features/login/login.page').then((m) => m.LoginPage),},{path: 'tabs',loadChildren: () => import('./features/tabs/tabs.routes').then((m) => m.routes),},];Explicación:
- La ruta por defecto
path: ''y la rutapath: 'login'cargan el componente Login directamente como ruta raíz. - La ruta
path: 'tabs'carga el sistema de pestañas junto con todas sus rutas hijas.
- La ruta por defecto
-
Componente Login
La página de Login se encuentra en
src/app/features/login/login.page.ts:src/app/features/login/login.page.ts import { Component, inject } from '@angular/core';import { Router } from '@angular/router';import { IonHeader, IonToolbar, IonTitle, IonContent, IonButton, IonInput } from '@ionic/angular/standalone';@Component({selector: 'app-login',templateUrl: 'login.page.html',styleUrls: ['login.page.scss'],imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonButton, IonInput],})export class LoginPage {private router = inject(Router);login() {this.router.navigate(['/tabs']);}}Y su template en
src/app/features/login/login.page.html:src/app/features/login/login.page.html <ion-header [translucent]="true"><ion-toolbar><ion-title>Login</ion-title></ion-toolbar></ion-header><ion-content [fullscreen]="true"><ion-header collapse="condense"><ion-toolbar><ion-title size="large">Login</ion-title></ion-toolbar></ion-header><div class="login-container"><h2>Welcome</h2><p>Please sign in to continue</p><ion-input label="Username" labelPlacement="stacked" type="text" placeholder="Enter username" fill="outline" class="login-input"></ion-input><ion-input label="Password" labelPlacement="stacked" type="password" placeholder="Enter password" fill="outline" class="login-input"></ion-input><ion-button expand="block" class="login-btn" (click)="login()">Sign In</ion-button></div></ion-content>
2.2. Configuración de Pestañas
Section titled “2.2. Configuración de Pestañas”Configurar la estructura base de la aplicación con tres pestañas (Clients, Reservations y Products), estableciendo la segunda como la vista por defecto al iniciar.
-
Crear el template HTML
Crear o modificar el archivo
tabs.page.htmlcon el componenteion-tabs:src/app/features/tabs/tabs.page.html <ion-tabs><ion-tab-bar slot="bottom"><ion-tab-button tab="tab1" href="/tabs/tab1"><ion-icon aria-hidden="true" name="people"></ion-icon><ion-label>Clients</ion-label></ion-tab-button><ion-tab-button tab="tab2" href="/tabs/tab2"><ion-icon aria-hidden="true" name="calendar"></ion-icon><ion-label>Reservations</ion-label></ion-tab-button><ion-tab-button tab="tab3" href="/tabs/tab3"><ion-icon aria-hidden="true" name="cube"></ion-icon><ion-label>Products</ion-label></ion-tab-button></ion-tab-bar></ion-tabs> -
Definir las rutas
Crear el archivo
tabs.routes.tscon la configuración de rutas:src/app/features/tabs/tabs.routes.ts import { Routes } from '@angular/router';export const routes: Routes = [{path: '',loadComponent: () =>import('./tabs.page').then((m) => m.TabsPage),children: [{path: 'tab1',loadComponent: () =>import('../clients/clients.page').then((m) => m.ClientsPage),},{path: 'tab2',loadComponent: () =>import('../reservations/reservations.page').then((m) => m.ReservationsPage),},{path: 'tab3',loadComponent: () =>import('../products/products.page').then((m) => m.ProductsPage),},{path: 'client/:id',loadComponent: () =>import('../clients/client-detail.page').then((m) => m.ClientDetailPage),},{path: 'reservations/create',loadComponent: () =>import('../reservations/reservation-form.page').then((m) => m.ReservationFormPage),},{path: '',redirectTo: '/tabs/tab2',pathMatch: 'full',},],},{path: '',redirectTo: '/tabs/tab2',pathMatch: 'full',},]; -
Configurar las pestañas por defecto
La pestaña por defecto se configura mediante redirección del router:
src/app/features/tabs/tabs.routes.ts {path: '',redirectTo: '/tabs/tab2',pathMatch: 'full',} -
Crear el componente TypeScript
Crear el archivo
tabs.page.ts:src/app/features/tabs/tabs.page.ts import { Component } from '@angular/core';import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel } from '@ionic/angular/standalone';import { addIcons } from 'ionicons';import { people, calendar, cube } from 'ionicons/icons';@Component({selector: 'app-tabs',templateUrl: 'tabs.page.html',styleUrls: ['tabs.page.scss'],imports: [IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel],})export class TabsPage {constructor() {addIcons({ people, calendar, cube });}}
2.3. Iconos Representativos
Section titled “2.3. Iconos Representativos”Añadir y configurar iconos adecuados en el HTML para representar visualmente el contenido de cada pestaña.
-
Agregar iconos en el HTML
Modificar
src/app/features/tabs/tabs.page.htmlpara usarion-icon:src/app/features/tabs/tabs.page.html <ion-tabs><ion-tab-bar slot="bottom"><ion-tab-button tab="tab1" href="/tabs/tab1"><ion-icon aria-hidden="true" name="people"></ion-icon><ion-label>Clients</ion-label></ion-tab-button><ion-tab-button tab="tab2" href="/tabs/tab2"><ion-icon aria-hidden="true" name="calendar"></ion-icon><ion-label>Reservations</ion-label></ion-tab-button><ion-tab-button tab="tab3" href="/tabs/tab3"><ion-icon aria-hidden="true" name="cube"></ion-icon><ion-label>Products</ion-label></ion-tab-button></ion-tab-bar></ion-tabs> -
Importar iconos en el componente
En
tabs.page.tsimportar y registrar los iconos:src/app/features/tabs/tabs.page.ts import { Component } from '@angular/core';import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel } from '@ionic/angular/standalone';import { addIcons } from 'ionicons';import { people, calendar, cube } from 'ionicons/icons';@Component({selector: 'app-tabs',templateUrl: 'tabs.page.html',styleUrls: ['tabs.page.scss'],imports: [IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel],})export class TabsPage {constructor() {addIcons({ people, calendar, cube });}}
2.4. Navegación a Detalles (Clients)
Section titled “2.4. Navegación a Detalles (Clients)”Implementar la navegación desde la lista de clientes hacia una página de detalle utilizando routerLink, enviando el ID del cliente para recibirlo mediante el decorador @Input().
-
Definir datos del componente
Crear
src/app/features/clients/clients.page.tscon la interfazClienty el array de ejemplo:src/app/features/clients/clients.page.ts import { Component } from '@angular/core';import { RouterLink } from '@angular/router';import { IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonBackButton, IonList, IonItem, IonLabel } from '@ionic/angular/standalone';interface Client {id: number;name: string;email: string;phone: string;}@Component({selector: 'app-clients',templateUrl: 'clients.page.html',styleUrls: ['clients.page.scss'],imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonBackButton, IonList, IonItem, IonLabel, RouterLink],})export class ClientsPage {clients: Client[] = [{ id: 1, name: 'John Doe', email: 'john@example.com', phone: '+1 234 567 890' },{ id: 2, name: 'Jane Smith', email: 'jane@example.com', phone: '+1 234 567 891' },{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', phone: '+1 234 567 892' },{ id: 4, name: 'Alice Brown', email: 'alice@example.com', phone: '+1 234 567 893' },{ id: 5, name: 'Charlie Wilson', email: 'charlie@example.com', phone: '+1 234 567 894' },];constructor() {}} -
Crear template del listado con routerLink
En
src/app/features/clients/clients.page.htmlusar[routerLink]para navegar al detalle:src/app/features/clients/clients.page.html <ion-header [translucent]="true"><ion-toolbar><ion-buttons slot="start"><ion-back-button></ion-back-button></ion-buttons><ion-title>Clients</ion-title></ion-toolbar></ion-header><ion-content [fullscreen]="true"><ion-header collapse="condense"><ion-toolbar><ion-title size="large">Clients</ion-title></ion-toolbar></ion-header><ion-list>@for (client of clients; track client.id) {<ion-item [routerLink]="['/tabs/client', client.id]"><ion-label><h2>{{ client.name }}</h2><p>{{ client.email }}</p><p>{{ client.phone }}</p></ion-label></ion-item>}</ion-list></ion-content> -
Crear página de detalle con
@InputEn
src/app/features/clients/client-detail.page.tsusar el decorador@Input()para recibir el ID:src/app/features/clients/client-detail.page.ts import { Component, Input } from '@angular/core';import { IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonButton, IonIcon } from '@ionic/angular/standalone';import { addIcons } from 'ionicons';import { arrowBack } from 'ionicons/icons';@Component({selector: 'app-client-detail',templateUrl: 'client-detail.page.html',styleUrls: ['client-detail.page.scss'],imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonButton, IonIcon],})export class ClientDetailPage {@Input() id?: string;constructor() {addIcons({ arrowBack });}goBack() {window.history.back();}} -
Crear template del detalle
En
src/app/features/clients/client-detail.page.htmlmostrar el ID recibido:src/app/features/clients/client-detail.page.html <ion-header [translucent]="true"><ion-toolbar><ion-buttons slot="start"><ion-button (click)="goBack()" fill="clear"><ion-icon slot="icon-only" name="arrow-back"></ion-icon></ion-button></ion-buttons><ion-title>Client Details</ion-title></ion-toolbar></ion-header><ion-content [fullscreen]="true"><ion-header collapse="condense"><ion-toolbar><ion-title size="large">Client Details</ion-title></ion-toolbar></ion-header><div class="detail-container"><h2>Cliente ID: {{ id }}</h2></div></ion-content>
2.5. Pestaña Reservations (Listado y Creación)
Section titled “2.5. Pestaña Reservations (Listado y Creación)”Desarrollar la vista de reservas incluyendo un listado de datos de prueba y la funcionalidad para navegar a un formulario de creación utilizando NavController.
-
Definir datos del componente
Crear
src/app/features/reservations/reservations.page.tscon la interfazReservationy el array de ejemplo:src/app/features/reservations/reservations.page.ts import { Component } from '@angular/core';import { NavController } from '@ionic/angular/standalone';import { IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonBackButton, IonList, IonItem, IonLabel, IonButton } from '@ionic/angular/standalone';interface Reservation {id: number;clientName: string;service: string;date: string;time: string;}@Component({selector: 'app-reservations',templateUrl: 'reservations.page.html',styleUrls: ['reservations.page.scss'],imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonBackButton, IonList, IonItem, IonLabel, IonButton],})export class ReservationsPage {constructor(private navCtrl: NavController) {this.navCtrl = navCtrl;}reservations: Reservation[] = [{ id: 1, clientName: 'John Doe', service: 'Haircut', date: '2024-03-15', time: '10:00 AM' },{ id: 2, clientName: 'Jane Smith', service: 'Manicure', date: '2024-03-15', time: '2:00 PM' },{ id: 3, clientName: 'Bob Johnson', service: 'Massage', date: '2024-03-16', time: '11:30 AM' },{ id: 4, clientName: 'Alice Brown', service: 'Facial', date: '2024-03-16', time: '3:00 PM' },{ id: 5, clientName: 'Charlie Wilson', service: 'Hair Color', date: '2024-03-17', time: '9:00 AM' },];createReservation() {this.navCtrl.navigateForward('/tabs/reservations/create');}} -
Navegación con navCtrl.navigateForward
En el componente TypeScript, inyectar
NavControllery crear la funcióncreateReservation():src/app/features/reservations/reservations.page.ts import { Component } from '@angular/core';import { NavController } from '@ionic/angular/standalone';import { IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonBackButton, IonList, IonItem, IonLabel, IonButton } from '@ionic/angular/standalone';interface Reservation {id: number;clientName: string;service: string;date: string;time: string;}@Component({selector: 'app-reservations',templateUrl: 'reservations.page.html',styleUrls: ['reservations.page.scss'],imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonBackButton, IonList, IonItem, IonLabel, IonButton],})export class ReservationsPage {constructor(private navCtrl: NavController) {this.navCtrl = navCtrl;}reservations: Reservation[] = [{ id: 1, clientName: 'John Doe', service: 'Haircut', date: '2024-03-15', time: '10:00 AM' },{ id: 2, clientName: 'Jane Smith', service: 'Manicure', date: '2024-03-15', time: '2:00 PM' },{ id: 3, clientName: 'Bob Johnson', service: 'Massage', date: '2024-03-16', time: '11:30 AM' },{ id: 4, clientName: 'Alice Brown', service: 'Facial', date: '2024-03-16', time: '3:00 PM' },{ id: 5, clientName: 'Charlie Wilson', service: 'Hair Color', date: '2024-03-17', time: '9:00 AM' },];createReservation() {this.navCtrl.navigateForward('/tabs/reservations/create');}} -
Template del listado con botón
En
src/app/features/reservations/reservations.page.htmlusarion-listy el botón:src/app/features/reservations/reservations.page.html <ion-header [translucent]="true"><ion-toolbar><ion-buttons slot="start"><ion-back-button></ion-back-button></ion-buttons><ion-title>Reservations</ion-title></ion-toolbar></ion-header><ion-content [fullscreen]="true"><ion-header collapse="condense"><ion-toolbar><ion-title size="large">Reservations</ion-title></ion-toolbar></ion-header><ion-list>@for (reservation of reservations; track reservation.id) {<ion-item><ion-label><h2>{{ reservation.clientName }}</h2><p>{{ reservation.service }} - {{ reservation.date }} at {{ reservation.time }}</p></ion-label></ion-item>}</ion-list><ion-button expand="block" (click)="createReservation()" class="create-btn">New Reservation</ion-button></ion-content>
2.6. Pestaña Products (Listado y Logout)
Section titled “2.6. Pestaña Products (Listado y Logout)”Mostrar un listado de productos e implementar la lógica de cerrar sesión.
-
Definir datos del componente
Crear
src/app/features/products/products.page.tscon la interfazProducty el array de ejemplo:src/app/features/products/products.page.ts import { Component } from '@angular/core';import { Router } from '@angular/router';import { IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonBackButton, IonList, IonItem, IonLabel, IonButton } from '@ionic/angular/standalone';interface Product {id: number;name: string;price: number;description: string;}@Component({selector: 'app-products',templateUrl: 'products.page.html',styleUrls: ['products.page.scss'],imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonBackButton, IonList, IonItem, IonLabel, IonButton],})export class ProductsPage {constructor(private router: Router) {this.router = router;}products: Product[] = [{ id: 1, name: 'Shampoo', price: 15.99, description: 'Professional hair shampoo' },{ id: 2, name: 'Conditioner', price: 16.99, description: 'Deep conditioning treatment' },{ id: 3, name: 'Hair Oil', price: 24.99, description: 'Argan oil for hair care' },{ id: 4, name: 'Face Mask', price: 12.99, description: 'Hydrating facial treatment' },{ id: 5, name: 'Body Lotion', price: 18.99, description: 'Moisturizing body lotion' },];logout() {localStorage.clear();this.router.navigate(['/login']);}} -
Cerrar Sesión con router.navigate
En el componente TypeScript, inyectar
Routery crear la funciónlogout()que limpielocalStoragey navegue a/login:src/app/features/products/products.page.ts import { Component } from '@angular/core';import { Router } from '@angular/router';import { IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonBackButton, IonList, IonItem, IonLabel, IonButton } from '@ionic/angular/standalone';interface Product {id: number;name: string;price: number;description: string;}@Component({selector: 'app-products',templateUrl: 'products.page.html',styleUrls: ['products.page.scss'],imports: [IonHeader, IonToolbar, IonTitle, IonContent, IonButtons, IonBackButton, IonList, IonItem, IonLabel, IonButton],})export class ProductsPage {constructor(private router: Router) {this.router = router;}products: Product[] = [{ id: 1, name: 'Shampoo', price: 15.99, description: 'Professional hair shampoo' },{ id: 2, name: 'Conditioner', price: 16.99, description: 'Deep conditioning treatment' },{ id: 3, name: 'Hair Oil', price: 24.99, description: 'Argan oil for hair care' },{ id: 4, name: 'Face Mask', price: 12.99, description: 'Hydrating facial treatment' },{ id: 5, name: 'Body Lotion', price: 18.99, description: 'Moisturizing body lotion' },];logout() {localStorage.clear();this.router.navigate(['/login']);}} -
Template del listado con botón de logout
En
src/app/features/products/products.page.html:src/app/features/products/products.page.html <ion-header [translucent]="true"><ion-toolbar><ion-buttons slot="start"><ion-back-button></ion-back-button></ion-buttons><ion-title>Products</ion-title></ion-toolbar></ion-header><ion-content [fullscreen]="true"><ion-header collapse="condense"><ion-toolbar><ion-title size="large">Products</ion-title></ion-toolbar></ion-header><ion-list>@for (product of products; track product.id) {<ion-item><ion-label><h2>{{ product.name }}</h2><p>${{ product.price }}</p><p>{{ product.description }}</p></ion-label></ion-item>}</ion-list><ion-button expand="block" color="danger" (click)="logout()" class="logout-btn">Cerrar Sesión</ion-button></ion-content>
2.7. Diseño Personalizado
Section titled “2.7. Diseño Personalizado”Integrar un diseño personalizado y adaptarlas a los componentes de Ionic.
-
Generar tema en bearnie.dev
Se ha utilizado la herramienta online bearnie.dev para generar un tema de colores personalizado estilo shadcn/ui. Esta herramienta genera variables CSS utilizando el espacio de color OKLCH para mejor gestión de colores.
-
Definir variables del tema
Crear
src/theme/variables.scsscon las variables generadas:src/theme/variables.scss // For information on how to create your own theme, please refer to:// https://ionicframework.com/docs/theming//* Bearnie Theme - Generated at bearnie.dev/create-bearnie-theme */:root {--radius: 0.625rem;--spacing: 0.25rem;--font-sans: "Inter", sans-serif;--background: oklch(1 0 0);--foreground: oklch(0.147 0.004 49.25);--card: oklch(1 0 0);--card-foreground: oklch(0.147 0.004 49.25);--popover: oklch(1 0 0);--popover-foreground: oklch(0.147 0.004 49.25);--primary: oklch(0.546 0.245 262.881);--primary-foreground: oklch(0.985 0 0);--secondary: oklch(0.97 0.001 106.424);--secondary-foreground: oklch(0.147 0.004 49.25);--muted: oklch(0.97 0.001 106.424);--muted-foreground: oklch(0.553 0.013 58.071);--accent: oklch(0.97 0.001 106.424);--accent-foreground: oklch(0.147 0.004 49.25);--destructive: oklch(0.577 0.245 27.325);--destructive-foreground: oklch(0.985 0 0);--border: oklch(0.923 0.003 48.717);--input: oklch(0.923 0.003 48.717);--ring: oklch(0.546 0.245 262.881);}.dark {--background: oklch(0.147 0.004 49.25);--foreground: oklch(0.97 0.001 106.424);--card: oklch(0.147 0.004 49.25);--card-foreground: oklch(0.97 0.001 106.424);--popover: oklch(0.147 0.004 49.25);--popover-foreground: oklch(0.97 0.001 106.424);--primary: oklch(0.546 0.245 262.881);--primary-foreground: oklch(0.985 0 0);--secondary: oklch(0.268 0.007 34.298);--secondary-foreground: oklch(0.97 0.001 106.424);--muted: oklch(0.268 0.007 34.298);--muted-foreground: oklch(0.709 0.01 56.259);--accent: oklch(0.268 0.007 34.298);--accent-foreground: oklch(0.97 0.001 106.424);--destructive: oklch(0.577 0.245 27.325);--destructive-foreground: oklch(0.985 0 0);--border: oklch(0.268 0.007 34.298);--input: oklch(0.268 0.007 34.298);--ring: oklch(0.546 0.245 262.881);}Explicación de las variables:
--radius: Radio de borde para componentes (0.625rem)--spacing: Espaciado base--font-sans: Familia tipográfica (Inter)- Colores en notación OKLCH:
--primary,--secondary,--muted,--destructive, etc.
-
Mapear variables a Ionic
En
src/global.scssse mapean las variables shadcn a las variables de Ionic:src/global.scss /** App Global CSS* ----------------------------------------------------------------------------* Put style rules here that you want to apply globally. These styles are for* the entire app and not just one component. Additionally, this file can be* used as an entry point to import other CSS/Sass files to be included in the* output CSS.* For more information on global stylesheets, visit the documentation:* https://ionicframework.com/docs/layout/global-stylesheets*//* Core CSS required for Ionic components to work properly */@import "@ionic/angular/css/core.css";/* Basic CSS for apps built with Ionic */@import "@ionic/angular/css/normalize.css";@import "@ionic/angular/css/structure.css";@import "@ionic/angular/css/typography.css";@import "@ionic/angular/css/display.css";/* Optional CSS utils that can be commented out */@import "@ionic/angular/css/padding.css";@import "@ionic/angular/css/float-elements.css";@import "@ionic/angular/css/text-alignment.css";@import "@ionic/angular/css/text-transformation.css";@import "@ionic/angular/css/flex-utils.css";/*** Ionic Dark Mode* -----------------------------------------------------* For more info, please see:* https://ionicframework.com/docs/theming/dark-mode*//* @import "@ionic/angular/css/palettes/dark.always.css"; *//* @import "@ionic/angular/css/palettes/dark.class.css"; */@import '@ionic/angular/css/palettes/dark.system.css';/* ============================================Bearnie Theme - Map shadcn variables to Ionic============================================ */:root {/* Map shadcn colors to Ionic */--ion-color-primary: var(--primary);--ion-color-primary-contrast: var(--primary-foreground);--ion-color-secondary: var(--secondary);--ion-color-secondary-contrast: var(--secondary-foreground);--ion-color-danger: var(--destructive);--ion-color-danger-contrast: var(--destructive-foreground);/* Background & text */--ion-background-color: var(--background);--ion-text-color: var(--foreground);/* Cards & surfaces */--ion-item-background: var(--card);--ion-card-background: var(--card);/* Borders & inputs */--ion-border-color: var(--border);--ion-input-background: var(--input);/* Tab bar */--ion-tab-bar-background: var(--background);--ion-tab-bar-color: var(--muted-foreground);--ion-tab-bar-color-selected: var(--primary);/* Toolbar */--ion-toolbar-background: var(--background);--ion-toolbar-color: var(--foreground);}/* Dark mode */.dark, body.dark, :root[color-scheme="dark"] {--ion-color-primary: var(--primary);--ion-color-primary-contrast: var(--primary-foreground);--ion-color-secondary: var(--secondary);--ion-color-secondary-contrast: var(--secondary-foreground);--ion-color-danger: var(--destructive);--ion-color-danger-contrast: var(--destructive-foreground);--ion-background-color: var(--background);--ion-text-color: var(--foreground);--ion-item-background: var(--card);--ion-card-background: var(--card);--ion-border-color: var(--border);--ion-input-background: var(--input);--ion-tab-bar-background: var(--background);--ion-tab-bar-color: var(--muted-foreground);--ion-tab-bar-color-selected: var(--primary);--ion-toolbar-background: var(--background);--ion-toolbar-color: var(--foreground);}/* Apply border radius to Ionic components */ion-button, ion-card, ion-input, ion-item, ion-chip {--border-radius: var(--radius);}/* Global font */body, html, ion-content, ion-label, ion-text {--font-family: var(--font-sans);}Explicación del mapeo:
--ion-color-primary→--primary(color principal de la app)--ion-color-danger→--destructive(color de peligro/eliminar)--ion-background-color→--background(fondo de la app)--ion-text-color→--foreground(color del texto)--ion-item-background→--card(fondo de items y cards)--ion-tab-bar-*→ Configuración de la barra de pestañas
-
Aplicar estilos a componentes
El border-radius se aplica globalmente a los componentes Ionic:
ion-button,ion-card,ion-input,ion-item,ion-chip {--border-radius: var(--radius);}
3. Ejecución y Funcionamiento
Section titled “3. Ejecución y Funcionamiento”3.1. Pasos de ejecución
Section titled “3.1. Pasos de ejecución”-
Clonar el repositorio
Terminal window git clone https://github.com/aek676/dah-2026.gitcd dah-2026 -
Instalar dependencias y ejecutar
Terminal window npm installionic serve -
Esto abrirá la aplicación en el navegador por defecto en
http://localhost:8100.
3.2. Estructura y descripción de pantallas
Section titled “3.2. Estructura y descripción de pantallas”La aplicación está compuesta por las siguientes pantallas:
-
Login: Pantalla inicial de la aplicación. Se muestra fuera de las pestañas y contiene dos campos de texto (usuario y contraseña) y un botón
Sign In. Al pulsar el botón, se navega a las pestañas principales de la aplicación medianterouter.navigate(['/tabs']).
-
Clients (Pestaña 1): Muestra un listado de clientes con su nombre, email y teléfono. Cada ítem de la lista es un enlace (
routerLink) que envía el ID del cliente a una página de detalle.
-
Detalle de Cliente: Página accesible desde la lista de clientes. Recibe el ID del cliente mediante
@Input()y muestra la información del cliente seleccionado. Incluye un botón de retroceso (ion-back-button) para volver al listado.
-
Reservations (Pestaña 2): Es la pestaña por defecto al iniciar la aplicación. Muestra un listado de reservas con el nombre del cliente, la fecha y el servicio. Incluye un botón
}Crear Reserva} que utilizanavCtrl.navigateForwardpara navegar al formulario de creación.
-
Formulario de Reserva: Página accesible desde la pestaña de reservas. Contiene un formulario para crear una nueva reserva.
-
Products (Pestaña 3): Muestra un listado de productos con su nombre, precio y descripción. Al final de la lista se encuentra el botón
}Cerrar Sesión} de color rojo que permite salir de la aplicación.
3.3. Flujo de navegación
Section titled “3.3. Flujo de navegación”El flujo principal de la aplicación es el siguiente:
- El usuario accede a la aplicación y se muestra la pantalla de Login
- Al pulsar
Sign In, se navega a las pestañas (por defecto se muestra Reservations) - Desde las pestañas, el usuario puede:
- En Clients: pulsar un cliente para ver su detalle y volver con el botón atrás
- En Reservations: pulsar
Crear Reservapara acceder al formulario y volver con el botón atrás - En Products: consultar los productos o pulsar
Cerrar Sesión
- Al pulsar
Cerrar Sesión, se ejecutalocalStorage.clear()para simular la limpieza de datos de sesión y se utilizarouter.navigate(['/login'])para redirigir al usuario a la pantalla de Login, que se encuentra fuera de las pestañas