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) {
}
`,
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]);
},
});
}
}