Initial commit

This commit is contained in:
pigui
2026-08-30 21:11:59 +02:00
commit 3f930bb46a
168 changed files with 35708 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
import { ChangeDetectionStrategy, Component, computed, input, output } from '@angular/core';
import {
PiActionButtonComponent,
PiCardBottomContentDirective,
PiCardCenterContentDirective,
PiCardComponent,
PiCardTopContentDirective,
PiChipComponent,
PiTextColorDirective,
PiTextSmallDirective,
PiTextWeightBoldDirective,
PiTextXSmallDirective,
} from '@pi/ui';
import type { Copy } from '../core/copy';
import type { Locale } from '../core/api';
import type { PublicCall } from '../core/api.types';
@Component({
selector: 'app-call-card',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
PiCardComponent,
PiCardTopContentDirective,
PiCardCenterContentDirective,
PiCardBottomContentDirective,
PiChipComponent,
PiActionButtonComponent,
PiTextSmallDirective,
PiTextXSmallDirective,
PiTextColorDirective,
PiTextWeightBoldDirective,
],
template: `
<pi-card
class="landing-card"
[hasShadow]="true"
[isStroked]="true"
gap="m"
padding="l"
innerPadding="none"
alignment="stretch"
context="public"
>
<pi-card-top-content>
<div class="landing-card__chips">
@if (hours(); as label) {
<pi-chip size="small" color="accent" icon="time-detail" [label]="label" />
}
@if (weeks(); as label) {
<pi-chip size="small" appearance="outline" [label]="label" />
}
@if (call().seniority; as seniority) {
<pi-chip size="small" appearance="outline" [label]="seniority" />
}
</div>
</pi-card-top-content>
<pi-card-center-content>
<h3 bold class="landing-card__title">{{ call().title }}</h3>
@if (call().project?.title; as project) {
<p xs pi-color color="grey">{{ project }}</p>
}
@if (call().description; as description) {
<p s pi-color color="grey">{{ description }}</p>
}
@if (call().technologies?.length) {
<ul class="landing-card__chips">
@for (technology of call().technologies; track technology.id) {
<li>
<pi-chip size="small" appearance="outline" [label]="technology.name" />
</li>
}
</ul>
}
</pi-card-center-content>
<pi-card-bottom-content>
<div class="landing-card__footer">
@if (closesAt(); as closes) {
<span xs pi-color color="grey"
>{{ copy().labels.closes }} {{ closes }}</span
>
}
<pi-action-button
size="small"
color="primary"
appearance="outline"
[hasIcon]="true"
[text]="copy().labels.apply"
(execute)="apply.emit()"
/>
</div>
</pi-card-bottom-content>
</pi-card>
`,
})
export class CallCard {
readonly call = input.required<PublicCall>();
readonly copy = input.required<Copy>();
readonly locale = input.required<Locale>();
readonly apply = output<void>();
// `pi-chip-value` renders the number and its unit as adjacent spans with no
// separation, so "4h/semana" comes out as one word. Built here instead.
protected readonly hours = computed(() => {
const hours = this.call().hours_per_week;
return hours ? `${hours} ${this.copy().labels.hoursPerWeek}` : null;
});
protected readonly weeks = computed(() => {
const weeks = this.call().duration_weeks;
return weeks ? `${weeks} ${this.copy().labels.weeks}` : null;
});
protected readonly closesAt = computed(() => {
const value = this.call().closes_at;
if (!value) {
return null;
}
return new Intl.DateTimeFormat(this.locale(), {
day: 'numeric',
month: 'long',
}).format(new Date(value));
});
}