Initial commit
This commit is contained in:
131
landing/src/app/ui/call-card.ts
Normal file
131
landing/src/app/ui/call-card.ts
Normal 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));
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user