prepara update
This commit is contained in:
@@ -6,7 +6,6 @@ import {
|
||||
} from '@angular/core';
|
||||
import { provideAnimationsAsync } from '@angular/platform-browser/animations/async';
|
||||
import { provideRouter, withInMemoryScrolling } from '@angular/router';
|
||||
import { provideStore } from '@ngrx/store';
|
||||
|
||||
import { routes } from './app.routes';
|
||||
import {
|
||||
@@ -16,7 +15,7 @@ import {
|
||||
} from '@ngx-translate/core';
|
||||
import { Observable, of } from 'rxjs';
|
||||
|
||||
import { IconRegistryService, deviceConfigsReducer, featureKey } from '@pi/ui';
|
||||
import { DeviceConfigsService, IconRegistryService } from '@pi/ui';
|
||||
|
||||
/**
|
||||
* Diccionario en línea: la librería resuelve los textos con `| translate`, y
|
||||
@@ -62,12 +61,15 @@ export const appConfig: ApplicationConfig = {
|
||||
// Los iconos son SVG registrados en el MatIconRegistry (assets/icons).
|
||||
provideAppInitializer(() => inject(IconRegistryService).init()),
|
||||
|
||||
// data-table, carousel y background-image leen el tipo de dispositivo;
|
||||
// instanciarlo arranca el listener de breakpoints.
|
||||
provideAppInitializer(() => {
|
||||
inject(DeviceConfigsService);
|
||||
}),
|
||||
|
||||
provideTranslateService({
|
||||
fallbackLang: 'es',
|
||||
loader: { provide: TranslateLoader, useClass: PlaygroundTranslateLoader },
|
||||
}),
|
||||
|
||||
// data-table y background-image leen el tipo de dispositivo del store.
|
||||
provideStore({ [featureKey]: deviceConfigsReducer }),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -9,10 +9,19 @@
|
||||
</div>
|
||||
|
||||
<div class="theme-toggles">
|
||||
<label class="theme-toggle">
|
||||
<span>Tema alternativo</span>
|
||||
<pi-slide-toggle [(checked)]="alternativeTheme" />
|
||||
</label>
|
||||
<div class="theme-switcher" role="radiogroup" aria-label="Tema">
|
||||
@for (option of themeOptions; track option.value) {
|
||||
<button
|
||||
type="button"
|
||||
role="radio"
|
||||
[attr.aria-checked]="theme() === option.value"
|
||||
[class.is-active]="theme() === option.value"
|
||||
(click)="theme.set(option.value)"
|
||||
>
|
||||
{{ option.label }}
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
<label class="theme-toggle">
|
||||
<span>Modo oscuro</span>
|
||||
<pi-slide-toggle [(checked)]="darkMode" />
|
||||
@@ -32,16 +41,14 @@
|
||||
</nav>
|
||||
|
||||
<p class="theme-hint">
|
||||
Tema:
|
||||
<strong>{{ alternativeTheme() ? 'alternative' : 'default' }}</strong> ·
|
||||
<code
|
||||
>{{ alternativeTheme() ? 'pi-shell__alternative' : 'pi-shell__default'
|
||||
}}</code
|
||||
>
|
||||
en el <code><body></code>. Los dos temas comparten exactamente los
|
||||
Tema: <strong>{{ theme() }}</strong> ·
|
||||
<code>{{ shellClassByTheme[theme()] }}</code>
|
||||
en el <code><body></code>. Los cuatro temas comparten exactamente los
|
||||
mismos selectores: solo cambian los tokens <code>--pi-color-*</code> y
|
||||
<code>--pi-theme-*</code> que definen <code>themes/_default.scss</code> y
|
||||
<code>themes/_alternative.scss</code>.
|
||||
<code>--pi-theme-*</code> que definen <code>themes/_default.scss</code>,
|
||||
<code>themes/_alternative.scss</code>, <code>themes/_minimal.scss</code> y
|
||||
<code>themes/_gradient.scss</code>. Prueba "Gradient" y enfoca un campo del
|
||||
formulario.
|
||||
</p>
|
||||
</header>
|
||||
|
||||
|
||||
@@ -47,6 +47,30 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.theme-switcher {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
padding: 0.2rem;
|
||||
border: 1px solid var(--pg-card-border);
|
||||
border-radius: 8px;
|
||||
|
||||
button {
|
||||
padding: 0.3rem 0.75rem;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
background: transparent;
|
||||
color: var(--pg-text-muted);
|
||||
font-size: 0.8rem;
|
||||
cursor: pointer;
|
||||
|
||||
&.is-active {
|
||||
background: var(--pg-badge-bg);
|
||||
color: var(--pg-badge-text);
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.theme-hint {
|
||||
margin: 0.75rem 0 0;
|
||||
font-size: 0.8rem;
|
||||
|
||||
@@ -33,13 +33,30 @@ export class App {
|
||||
|
||||
protected readonly darkMode = signal(false);
|
||||
|
||||
protected readonly themeOptions: ReadonlyArray<{
|
||||
value: ThemeVariant;
|
||||
label: string;
|
||||
}> = [
|
||||
{ value: 'default', label: 'Default' },
|
||||
{ value: 'alternative', label: 'Alternative' },
|
||||
{ value: 'minimal', label: 'Minimal' },
|
||||
{ value: 'gradient', label: 'Gradient' },
|
||||
];
|
||||
|
||||
/**
|
||||
* Tema visual de la librería. `ShellClass` devuelve las dos clases que hay
|
||||
* que poner juntas (`pi-shell pi-shell__<tema>`); van en el `<body>` porque
|
||||
* los overlays de Material (diálogos, snackbars) se montan fuera de
|
||||
* `<app-root>` y también deben heredarlas.
|
||||
*/
|
||||
protected readonly alternativeTheme = signal(false);
|
||||
protected readonly theme = signal<ThemeVariant>('default');
|
||||
|
||||
protected readonly shellClassByTheme: Record<ThemeVariant, string> = {
|
||||
default: ShellClass.Default,
|
||||
alternative: ShellClass.Alternative,
|
||||
minimal: ShellClass.Minimal,
|
||||
gradient: ShellClass.Gradient,
|
||||
};
|
||||
|
||||
constructor() {
|
||||
effect(() => {
|
||||
@@ -50,10 +67,9 @@ export class App {
|
||||
});
|
||||
|
||||
effect(() => {
|
||||
const shell = this.alternativeTheme()
|
||||
? ShellClass.Alternative
|
||||
: ShellClass.Default;
|
||||
this.document.body.className = shell;
|
||||
this.document.body.className = this.shellClassByTheme[this.theme()];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
type ThemeVariant = 'default' | 'alternative' | 'minimal' | 'gradient';
|
||||
|
||||
@@ -195,6 +195,26 @@
|
||||
<pi-divider color="primary" width="large" label="Separador" />
|
||||
</app-section>
|
||||
|
||||
<app-section
|
||||
title="Avatar y Badge"
|
||||
hint="pi-avatar cae en cascada a iniciales (con name) y luego a icono; pi-badge envuelve cualquier contenido proyectado con un indicador superpuesto."
|
||||
>
|
||||
<pi-avatar image="https://i.pravatar.cc/128?img=12" alt="Ada Lovelace" />
|
||||
<pi-avatar name="Ada Lovelace" color="primary" />
|
||||
<pi-avatar name="Grace Hopper" color="accent" size="large" />
|
||||
<pi-avatar color="highlighted" shape="square" />
|
||||
|
||||
<pi-badge [value]="3" color="warn">
|
||||
<pi-icon-button icon="notification-on" />
|
||||
</pi-badge>
|
||||
<pi-badge color="success">
|
||||
<pi-avatar name="Ada Lovelace" color="primary" />
|
||||
</pi-badge>
|
||||
<pi-badge [value]="128" [max]="99" color="primary" position="top-left">
|
||||
<pi-icon-button icon="email" />
|
||||
</pi-badge>
|
||||
</app-section>
|
||||
|
||||
<app-section
|
||||
title="Cabecera y listado"
|
||||
hint="pi-headline para portadas de sección, pi-list-item para filas de listado. pi-headline resuelve pathImg contra un CDN externo fijo, así que la ilustración solo carga con red."
|
||||
@@ -481,6 +501,49 @@
|
||||
</button>
|
||||
</app-section>
|
||||
|
||||
<app-section
|
||||
title="Drawer"
|
||||
hint="pi-drawer tampoco se usa como etiqueta: se abre vía MatDialog con getDrawerConfigs, igual que pi-modal pero anclado a un borde."
|
||||
>
|
||||
<button pi-primary (click)="openDemoDrawer('right')">
|
||||
Abrir drawer (derecha)
|
||||
</button>
|
||||
<button pi-outline (click)="openDemoDrawer('left')">
|
||||
Abrir drawer (izquierda)
|
||||
</button>
|
||||
<ng-template #drawerTemplate>
|
||||
<p>Contenido de ejemplo dentro del drawer.</p>
|
||||
<p>Puede llevar cualquier plantilla: formularios, listas, filtros…</p>
|
||||
</ng-template>
|
||||
</app-section>
|
||||
|
||||
<app-section
|
||||
title="Popover"
|
||||
hint="pi-popover es una directiva ([pi-popover]) sobre @angular/cdk/overlay: no hay componente Material de contenido enriquecido que envolver."
|
||||
>
|
||||
<button
|
||||
pi-outline
|
||||
pi-popover
|
||||
[popoverContent]="popoverTemplate"
|
||||
popoverPosition="below"
|
||||
>
|
||||
Click (popover)
|
||||
</button>
|
||||
<button
|
||||
pi-outline
|
||||
pi-popover
|
||||
[popoverContent]="popoverTemplate"
|
||||
popoverPosition="above"
|
||||
popoverTrigger="hover"
|
||||
>
|
||||
Hover (popover)
|
||||
</button>
|
||||
<ng-template #popoverTemplate let-close="close">
|
||||
<p>Contenido del popover, con cierre programático.</p>
|
||||
<button pi-ghost (click)="close()">Cerrar</button>
|
||||
</ng-template>
|
||||
</app-section>
|
||||
|
||||
<app-section title="Data grid">
|
||||
<div class="stack full">
|
||||
<pi-data-grid
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
TemplateRef,
|
||||
inject,
|
||||
signal,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
FormField,
|
||||
@@ -19,6 +21,8 @@ import {
|
||||
PiAccordionItemContentDirective,
|
||||
PiAccordionItemDirective,
|
||||
PiActionButtonComponent,
|
||||
PiAvatarComponent,
|
||||
PiBadgeComponent,
|
||||
PiBannerComponent,
|
||||
PiBaseDataTableComponent,
|
||||
PiCardBottomContentDirective,
|
||||
@@ -46,6 +50,9 @@ import {
|
||||
DatasetColor,
|
||||
Device,
|
||||
PiDividerComponent,
|
||||
DrawerConfigKeys,
|
||||
PiDrawerComponent,
|
||||
getDrawerConfigs,
|
||||
PiEmailFieldComponent,
|
||||
PiExpansionPanelComponent,
|
||||
PiGhostButtonDirective,
|
||||
@@ -83,6 +90,7 @@ import {
|
||||
PiPanelExpandableContentDirective,
|
||||
PiPasswordFieldComponent,
|
||||
PiPhoneFieldComponent,
|
||||
PiPopoverDirective,
|
||||
PiProgressBarComponent,
|
||||
PiRadioButtonComponent,
|
||||
PiRange,
|
||||
@@ -189,6 +197,8 @@ interface DemoModel {
|
||||
PiIconComponent,
|
||||
PiTextViewerComponent,
|
||||
PiDividerComponent,
|
||||
PiAvatarComponent,
|
||||
PiBadgeComponent,
|
||||
PiChipComponent,
|
||||
PiChipStatusComponent,
|
||||
PiChipValueComponent,
|
||||
@@ -205,6 +215,7 @@ interface DemoModel {
|
||||
PiListItemRightContentDirective,
|
||||
PiListItemRightIconDirective,
|
||||
PiTooltipDirective,
|
||||
PiPopoverDirective,
|
||||
PiNotFoundComponent,
|
||||
// Feedback
|
||||
PiProgressSpinnerComponent,
|
||||
@@ -497,6 +508,23 @@ export class CatalogPage {
|
||||
);
|
||||
}
|
||||
|
||||
/* --- Drawer -------------------------------------------------------------- */
|
||||
|
||||
/** Igual que `pi-modal`: se abre desde TypeScript vía `MatDialog`. */
|
||||
private readonly drawerTemplate =
|
||||
viewChild.required<TemplateRef<unknown>>('drawerTemplate');
|
||||
|
||||
protected openDemoDrawer(side: 'left' | 'right'): void {
|
||||
this.dialog.open(
|
||||
PiDrawerComponent,
|
||||
getDrawerConfigs(
|
||||
side === 'left' ? DrawerConfigKeys.Left : DrawerConfigKeys.Right,
|
||||
{ title: 'Detalle', template: this.drawerTemplate() },
|
||||
),
|
||||
);
|
||||
this.log(`drawer abierto (${side})`);
|
||||
}
|
||||
|
||||
/* --- Datos: grid, tabla, gráfico, carrusel ------------------------------ */
|
||||
|
||||
protected readonly employees = [
|
||||
|
||||
Reference in New Issue
Block a user