Datos y multimedia
Stats Card
Destaca una métrica, su etiqueta y el contexto que la acompaña.
Importación
import { NeuStatsCardComponent } from '@neural-ui/native/stats-card';Ejemplos
Importa ExampleComponent en su padre y coloca <app-example /> dentro del neu-theme raíz de tu aplicación. El preview aporta el marco y las zonas seguras; utiliza la estructura raíz de Instalación en tu app.
Ritmo creativo
Usa StatsCard para resumir la semana del estudio. La métrica principal incluye un gráfico accesible de cinco días; al cambiar el periodo se actualizan el total, las barras, las tareas y los miembros. Los colores de superficie son tokens personalizados solo en este ejemplo.
Ver y copiar el ejemplo completo
import { Component, signal, computed } from '@angular/core';
import { NeuStatsCardComponent } from '@neural-ui/native/stats-card';
import { NeuToggleButtonGroupComponent } from '@neural-ui/native/toggle-button-group';
import { View, Text, ScrollView } from '@ng-native/components';
@Component({
selector: 'app-example',
imports: [NeuStatsCardComponent, NeuToggleButtonGroupComponent, View, Text, ScrollView],
template: `
<scroll-view class="product-scroll" keyboardShouldPersistTaps="handled" [showsVerticalScrollIndicator]="false"><view class="product-stack"><view class="product-section"><text class="product-title" accessibilityRole="header">Ritmo creativo</text><text class="product-caption">Neural Studio · Tu semana en perspectiva</text></view>
<neu-toggle-button-group label="Periodo del resumen" [options]="periods" [value]="period()" (valueChange)="choosePeriod($event)" />
<view class="focus-metric"><neu-stats-card label="Horas de concentración" [value]="hours()" [change]="period()[0] === 'current' ? '+5,5 h respecto a la semana pasada' : 'Tu semana anterior'" description="Espacio para el trabajo que importa" [svg]="trendIcon" tone="brand">
<view class="week-chart">
@for (day of week().days; track day.label) {
<view class="week-column" [accessible]="true" [accessibilityLabel]="day.label + ': ' + number.format(day.hours) + ' h'">
<text class="week-value">{{ number.format(day.hours) }}</text><view class="week-track"><view class="week-bar" [class.last-day]="$last" [style.height]="(day.hours * 8) + 'px'"></view></view><text class="week-day">{{ day.label.slice(0, 3) }}</text>
</view>
}
</view>
</neu-stats-card></view>
<view class="metric-pair"><view class="metric-small metric-mint"><neu-stats-card label="Tareas completadas" [value]="week().tasks" description="Ideas realizadas" [svg]="checkIcon" tone="success" /></view><view class="metric-small metric-lilac"><neu-stats-card label="Miembros activos" [value]="week().members" description="Personas creando" [svg]="membersIcon" tone="brand" /></view></view>
<text class="product-caption">Datos ilustrativos del estudio. Elige una semana para comparar todo el resumen.</text></view></scroll-view>
`,
styles: `
.actions { gap: 12px; align-items: flex-start; } text { color: var(--neu-text, #172033); font-size: 16px; }
:host { flex: 1; flex-shrink: 1; min-height: 0; }
.product-scroll { flex: 1; flex-shrink: 1; height: 0px; min-height: 0; }
.product-stack { gap: 24px; padding-bottom: 20px; }
.product-section { gap: 12px; }
.product-row { flex-direction: row; align-items: center; gap: 12px; }
.product-copy { flex: 1; min-width: 0; gap: 4px; }
.product-title { color: var(--neu-text, #172033); font-size: 24px; line-height: 30px; font-weight: 600; }
.product-heading { color: var(--neu-text, #172033); font-size: 17px; line-height: 23px; font-weight: 600; }
.product-caption { color: var(--neu-muted, #596477); font-size: 14px; line-height: 20px; }
.product-actions { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 8px; }
.product-surface { gap: 16px; padding: 16px; border-radius: 16px; background-color: var(--neu-surface, #ffffff); border-width: 1px; border-color: var(--neu-border, #a5afbf); }
.product-stack { gap: 20px; }
.focus-metric { --neu-surface: #132e57; --neu-surface-border: #132e57; --neu-text: #f7faff; --neu-muted: #c6d8f0; --neu-metric-size: 40px; --neu-metric-line: 46px; }
.week-chart { flex-direction: row; gap: 12px; padding-top: 8px; }
.week-column { flex: 1; min-width: 0; gap: 8px; align-items: stretch; }
.week-value { color: #f7faff; text-align: center; font-size: 12px; }
.week-track { height: 64px; justify-content: flex-end; background-color: #244572; border-radius: 6px; overflow: hidden; }
.week-bar { background-color: #94ccff; border-radius: 6px; }
.week-bar.last-day { background-color: #ffbdad; }
.week-day { color: #c6d8f0; text-align: center; font-size: 12px; }
.metric-pair { flex-direction: row; align-items: stretch; gap: 12px; }
.metric-small { flex: 1; min-width: 0; --neu-metric-size: 28px; --neu-metric-line: 34px; }
.metric-mint { --neu-surface: #e3f0e9; --neu-surface-border: #e3f0e9; --neu-text: #183e32; --neu-muted: #426556; }
.metric-lilac { --neu-surface: #eee8f7; --neu-surface-border: #eee8f7; --neu-text: #3d2b5d; --neu-muted: #65537c; }
@media (max-width: 360px) { .metric-pair { flex-direction: column; } }
`,
})
export class ExampleComponent {
readonly metricLocale = 'es-ES';
readonly number = new Intl.NumberFormat(this.metricLocale, { maximumFractionDigits: 1 });
readonly periods = [{ id: 'current', label: 'Esta semana' }, { id: 'previous', label: 'Semana pasada' }];
readonly period = signal<readonly string[]>(['current']);
choosePeriod(values: readonly string[]) { this.period.set(values.length ? values : [...this.period()]); }
readonly weeks = {
current: { tasks: 18, members: 6, days: [{ label: 'Lunes', hours: 5 }, { label: 'Martes', hours: 6 }, { label: 'Miércoles', hours: 4 }, { label: 'Jueves', hours: 7 }, { label: 'Viernes', hours: 4.5 }] },
previous: { tasks: 14, members: 5, days: [{ label: 'Lunes', hours: 4 }, { label: 'Martes', hours: 5 }, { label: 'Miércoles', hours: 3 }, { label: 'Jueves', hours: 5 }, { label: 'Viernes', hours: 4 }] },
};
readonly week = computed(() => this.period()[0] === 'previous' ? this.weeks.previous : this.weeks.current);
readonly hours = computed(() => this.number.format(this.week().days.reduce((sum, day) => sum + day.hours, 0)) + ' h');
readonly trendIcon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="m3 17 6-6 4 4 8-8M15 7h6v6"/></svg>';
readonly checkIcon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"><path d="m5 12 4 4L19 6"/></svg>';
readonly membersIcon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="9" cy="8" r="3"/><path d="M3 21v-2a6 6 0 0 1 12 0v2M16 5a3 3 0 0 1 0 6M21 21v-2a6 6 0 0 0-4-5"/></svg>';
}Resumen del espacio
Muestra el trabajo resuelto y el almacenamiento disponible con variaciones contextualizadas.
Ver y copiar el ejemplo completo
import { Component } from '@angular/core';
import { NeuStatsCardComponent } from '@neural-ui/native/stats-card';
import { View, ScrollView } from '@ng-native/components';
@Component({
selector: 'app-example',
imports: [NeuStatsCardComponent, View, ScrollView],
template: `
<scroll-view class="usage-scroll" keyboardShouldPersistTaps="handled"><view class="usage-stack">
<neu-stats-card label="Solicitudes resueltas" value="128" change="+12 esta semana" description="Espacio de soporte" [svg]="resolvedIcon" tone="success" />
<neu-stats-card label="Almacenamiento utilizado" value="85%" change="15% disponibles" description="Revisa los archivos antes del próximo lanzamiento" [svg]="storageIcon" tone="warning" />
</view></scroll-view>
`,
styles: `
.actions { gap: 12px; align-items: flex-start; } text { color: var(--neu-text, #172033); font-size: 16px; }
.usage-scroll { flex: 1; }
.usage-stack { gap: 20px; padding-bottom: 20px; }
.usage-section { gap: 12px; }
.usage-heading { color: var(--neu-text, #172033); font-size: 16px; font-weight: 600; }
.usage-caption { color: var(--neu-muted, #64748b); font-size: 14px; }
.usage-row { flex-direction: row; flex-wrap: wrap; gap: 12px; align-items: center; }
.usage-actions { flex-direction: row; flex-wrap: wrap; gap: 8px; align-items: center; }
`,
})
export class ExampleComponent {
readonly resolvedIcon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m8 12 3 3 5-6"/><circle cx="12" cy="12" r="9"/></svg>';
readonly storageIcon = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="16" height="16" rx="3"/><path d="M4 14h16M8 17h.01M12 17h.01"/></svg>';
}Ajusta la configuración y prueba el resultado.
Capturas del dispositivo en inglés.


Personalización
Contenido proyectado
Después de la estadística y sus textos de apoyo. Añade una gráfica, tendencia o acción complementaria sin sustituir el valor predeterminado.
Utiliza elementos nativos de @ng-native/components y controles públicos de Neural Native. Los estilos Angular pertenecen al componente que declara este contenido.
Referencia API
Inputs
| Nombre | Tipo | Predeterminado | Enlace | Descripción |
|---|---|---|---|---|
| label | string | Obligatorio | Input | Nombre legible del control, acción o grupo. |
| value | string | number | Obligatorio | Input | Valor mostrado por este componente de presentación, según el tipo declarado. |
| change | string | '' | Input | Texto de cambio que acompaña a la estadística. La aplicación calcula el cambio; el componente lo muestra. |
| description | string | '' | Input | Texto de apoyo. Cada componente determina dónde muestra esta descripción opcional. |
| svg | string | '' | Input | SVG decorativo opcional junto a la cabecera de la métrica. Si está vacío, no se crea el contenedor ni se reserva espacio. Utiliza currentColor para aplicar el color del tema. |
| tone | NeuTone | 'brand' | Input | Color semántico del icono opcional y su fondo suave. No cambia el valor de la métrica ni sus textos. |
Models
Este componente no declara models bidireccionales.
Outputs
Este componente no declara outputs públicos.
Tipos e interfaces de datos
Utiliza los imports en tu aplicación. Las definiciones siguientes se muestran como referencia.
NeuTone
import type { NeuTone } from '@neural-ui/native/foundation';
// Public definition for reference only. Import this type; do not redeclare it.
export type NeuTone = 'neutral' | 'brand' | 'accent' | 'success' | 'info' | 'warning' | 'danger';