Saltar al contenido principal

logomark

Paquete: @tiendana/ngx-core/logomark

TdnLogomarkComponent es el logomark de Tiendana con inputs de tipo signal. El componente es el custom element tdn-logomark de @tiendana/utils/logomark (misma etiqueta, se registra en el primer uso), así que una página simple, React y Angular dibujan exactamente lo mismo. Las reglas de la marca están en Fundamentos: Logomark.

Cargando logomark…

Características​

✅ Componente standalone con ChangeDetectionStrategy.OnPush
✅ Inputs signal: clip, still, loop, colourway, size y label
✅ Output clipEnd al terminar un clip que no se repite
✅ Métodos play() y refresh() para control imperativo
✅ Decorativo por defecto; con label se anuncia como imagen
✅ Respeta prefers-reduced-motion y se pausa fuera de pantalla

Instalación​

El componente vive en un entry point propio de @tiendana/ngx-core, disponible desde la versión 0.9.0:

import { TdnLogomarkComponent } from '@tiendana/ngx-core/logomark';

Requiere @tiendana/utils >=0.4.0 como peer dependency, que aporta el elemento, los clips y los tipos (ClipName, StillName, LogomarkColourway).

Selector​

<tdn-logomark />

API​

Inputs​

InputTipoDefaultDescripción
clipInputSignal<ClipName | null>nullClip a reproducir, desde su inicio cada vez que cambia. Con null mantiene still
stillInputSignal<StillName | null>nullPose que se mantiene mientras no se reproduce ningún clip; SMILE si es null
loopInputSignal<boolean>falseReinicia el clip cuando termina
colourwayInputSignal<LogomarkColourway>'primary'Tonos: 'primary', 'reverse', 'neon' o 'mono'
sizeInputSignal<number | null>nullAlto de la marca en px. Con null lo decide el CSS (64 px si la página no dimensiona el elemento)
labelInputSignal<string | null>nullSe anuncia como imagen. Sin él, el logomark es decorativo y queda oculto a tecnologías de apoyo

Outputs​

OutputTipoDescripción
clipEndOutputEmitterRef<ClipName>Un clip que no se repite llegó a su fin (o habría llegado, con movimiento reducido)
nota

El output se llama clipEnd y no ended: ended es el evento DOM del propio elemento, y un binding (ended) en la plantilla lo recibiría una segunda vez. Si escuchas el evento DOM directamente, detail.clip lleva el nombre del clip.

Métodos​

MétodoFirmaDescripción
playplay(clip: ClipName, options?: { readonly loop?: boolean }): voidReproduce un clip desde el inicio, incluso el que ya se está reproduciendo (un segundo envío fallido vuelve a reproducir form-error)
refreshrefresh(): voidRelee las propiedades --logomark-* y repinta, tras un cambio de tema que solo intercambia esas propiedades
Nombres de clips y stills

Los nombres válidos de clip y still dependen de la versión instalada de @tiendana/utils. Con 0.5.0:

  • Clips (30): hello, blink, double-blink, play, congrat, mini-congrat, away, peek, squint, error, form-error, ah, doze, wake, thinking, draw, sale, conduct, heartbeat, celebrate, wow, doubt, confused, crash, y para estados de página loading, updating, offline, empty, no-results y warning.
  • Stills (17): smile, congrat, play, error, asleep, squint, peek, away, pop, wow, doubt, confused, downcast, draw-25, draw-50, draw-75, draw-100.

form-error es un clip sostenido: termina en ERROR y se queda ahí hasta que se reproduce otro. No se repite.

Los clips desde celebrate y los stills wow, doubt, confused y downcast llegan con 0.5.0: con 0.4.0 instalado no existen. Consulta Clips.

Ejemplos​

Marca viva​

import { Component } from '@angular/core';
import { TdnLogomarkComponent } from '@tiendana/ngx-core/logomark';

@Component({
selector: 'app-brand',
imports: [TdnLogomarkComponent],
template: `<tdn-logomark clip="hello" [loop]="true" [size]="48" label="Tiendana" />`
})
export class BrandComponent {}

Error de formulario con play('form-error')​

ERROR se sacude y se queda hasta que el formulario reproduce otra cosa. Al usar play(), un segundo fallo repite la animación.

import { Component, viewChild } from '@angular/core';
import { TdnLogomarkComponent } from '@tiendana/ngx-core/logomark';

@Component({
selector: 'app-login-form',
imports: [TdnLogomarkComponent],
template: `
<tdn-logomark [size]="40" />
<button type="button" (click)="submit()">Guardar</button>
`
})
export class LoginFormComponent {
private readonly mark = viewChild.required(TdnLogomarkComponent);

async submit(): Promise<void> {
try {
await this.save();
this.mark().play('congrat');
} catch {
this.mark().play('form-error');
}
}

private async save(): Promise<void> {
// llamada al API
}
}

Estado de carga y éxito​

clip se reproduce desde su inicio cada vez que cambia, y clipEnd avisa cuando un clip sin loop termina. Aquí thinking se repite mientras se carga y congrat se reproduce una vez al terminar.

import { Component, signal } from '@angular/core';
import { TdnLogomarkComponent } from '@tiendana/ngx-core/logomark';

@Component({
selector: 'app-sync-status',
imports: [TdnLogomarkComponent],
template: `
<tdn-logomark
[clip]="clip()"
[loop]="loading()"
[size]="56"
label="Estado de sincronización"
(clipEnd)="onClipEnd($event)" />
`
})
export class SyncStatusComponent {
readonly loading = signal(true);
readonly clip = signal<'thinking' | 'congrat'>('thinking');

finish(): void {
this.loading.set(false);
this.clip.set('congrat');
}

onClipEnd(clip: string): void {
console.log('terminó', clip);
}
}

Para una pose fija, usa still en lugar de clip:

<tdn-logomark still="error" colourway="reverse" label="Error" />

Colourways en el host de un componente​

colourway elige entre los tonos de la marca. Dentro de nuestras apps, el mixin colourway de @tiendana/utils/logomark/colourways fija las propiedades --logomark-* desde los tokens de web-foundation, para que la marca siga al tema de la página:

@use '@tiendana/utils/logomark/colourways' as logomark;

:host {
@include logomark.colourway(primary);
}

:host-context(.scheme-dark) {
@include logomark.colourway(reverse);
}

El segundo parámetro, $track, sustituye el tono de la parte aún no dibujada cuando el fondo no es blanco ni forrest. Los nombres válidos son primary, reverse, neon y mono; cualquier otro lanza un error de Sass.

tip

Si el tema cambia solo intercambiando propiedades CSS, llama a refresh() en el componente para que repinte con los nuevos tonos. Consulta Colourways.

Accesibilidad​

  • Sin label, el componente es decorativo (aria-hidden).
  • Con label, se anuncia como imagen (role="img") con ese texto.
  • Con prefers-reduced-motion: reduce no se reproduce ningún clip; se mantiene la pose que representa y clipEnd se emite de inmediato.
  • Se pausa fuera de pantalla y en pestañas ocultas.

Ver También​