import { ChangeDetectionStrategy, Component, DestroyRef, inject, signal, } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { RouterLink } from '@angular/router'; import { PiIconComponent } from '@pi/ui'; import { ToastService } from '@task-stream/web/shared/ui'; import { IssuesGateway, IssueSummary, StatusCategory, } from '@task-stream/web/tracker/domain'; /** * The tickets I pinned, at hand on the home page: one strip, only when * there are some (they are pinned from the ticket's page). */ @Component({ selector: 'ts-pinned', changeDetection: ChangeDetectionStrategy.OnPush, imports: [RouterLink, PiIconComponent], template: ` @if (pins().length) {

Fijados

} `, host: { '[style.display]': "pins().length ? 'block' : 'none'" }, styles: ` .ts-pinned { display: flex; align-items: center; gap: 0.75rem 1rem; flex-wrap: wrap; } h2 { display: inline-flex; align-items: center; gap: 0.375rem; margin: 0; color: var(--ts-muted); font-size: 0.75rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; } ul { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0; padding: 0; list-style: none; } li { display: inline-flex; align-items: center; max-width: min(100%, 22rem); border: 1px solid var(--ts-line); border-radius: 999px; background: var(--ts-surface); &:hover, &:focus-within { border-color: color-mix(in srgb, var(--ts-brand) 45%, var(--ts-line)); } &.is-done .ts-pinned__title { color: var(--ts-muted); text-decoration: line-through; } } a { display: inline-flex; align-items: baseline; gap: 0.5rem; min-width: 0; padding: 0.375rem 0.25rem 0.375rem 0.875rem; color: inherit; font-size: 0.875rem; text-decoration: none; } .ts-pinned__key { flex: none; color: var(--ts-muted); font-family: var(--ts-font-mono); font-size: 0.75rem; } .ts-pinned__title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } /* A plain glyph, not @pi/ui's sized button. */ .ts-pinned__unpin { flex: none; width: 1.75rem !important; min-width: 0 !important; height: 1.75rem !important; margin-right: 0.25rem; padding: 0 !important; border: 0; border-radius: 50%; background: transparent; color: var(--ts-muted); font-size: 1.125rem; line-height: 1; cursor: pointer; &:hover, &:focus-visible { background: var(--ts-sunken); color: var(--ts-ink); } } `, }) export class PinnedComponent { private readonly gateway = inject(IssuesGateway); private readonly toast = inject(ToastService); private readonly destroyRef = inject(DestroyRef); protected readonly pins = signal([]); protected readonly done = StatusCategory.DONE; constructor() { this.gateway .pins() .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: (pins) => this.pins.set(pins), error: () => null }); } protected projectOf(key: string): string { return key.slice(0, key.lastIndexOf('-')); } protected unpin(pin: IssueSummary): void { this.pins.update((list) => list.filter((p) => p.id !== pin.id)); this.gateway .pin(pin.id, false) .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ error: () => { this.toast.error(`No se pudo quitar ${pin.key} de fijados`); this.pins.update((list) => [pin, ...list]); }, }); } }