import {
ChangeDetectionStrategy,
Component,
computed,
input,
} from '@angular/core';
import { copyFor, type Copy } from '../core/copy';
import { listingAlternates, listingPath } from '../core/routes';
import type { Locale } from '../core/api';
import { RadarPage } from './radar-page';
import { ServiceDetail } from './service-detail';
import { CallDetail } from './call-detail';
import type { RoutedPageData, RoutedRecord } from '../core/routed-page';
import { ContentPage } from './content-page';
import { ContributePage } from './contribute-page';
import { MemberDetail } from './member-detail';
import { PageShell, type PageSeo } from './page-shell';
import { ProjectDetail } from './project-detail';
/**
* A page reached by its address, whatever it holds: the shell around it, and
* the body for its type inside.
*/
@Component({
selector: 'app-routed-page',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
CallDetail,
ContentPage,
ContributePage,
MemberDetail,
PageShell,
ProjectDetail,
RadarPage,
ServiceDetail,
],
template: `
@if (data().found; as found) {
@switch (found.type) {
@case ('page') {
}
@case ('project') {
}
@case ('call') {
}
@case ('service') {
}
@case ('contribute') {
}
@case ('radar') {
}
@case ('member') {
}
}
}
`,
})
export class RoutedPage {
readonly data = input.required();
protected readonly copy = computed(() => copyFor(this.data().locale));
protected readonly seo = computed(() =>
seoFor(this.data().found, this.copy(), this.data().locale),
);
}
/** What each type puts in the document head. Null when nothing was found. */
export function seoFor(
found: RoutedRecord | null,
copy: Copy,
locale: Locale,
): PageSeo | null {
if (!found) {
return null;
}
switch (found.type) {
case 'page': {
const page = found.record;
return {
title: page.meta_title || `Pireon — ${page.title}`,
description: page.meta_description || page.excerpt || '',
path: page.path,
alternates: page.alternates ?? {},
type: 'article',
};
}
case 'project': {
const project = found.record;
return {
title: project.meta_title || `Pireon — ${project.title}`,
description: project.meta_description || project.tagline || '',
path: project.path,
alternates: project.alternates ?? {},
type: 'article',
};
}
case 'member': {
const member = found.record;
return {
title: `Pireon — ${member.name}`,
description: member.headline || member.bio?.slice(0, 160) || '',
path: member.path,
alternates: member.alternates ?? {},
type: 'profile',
};
}
case 'service': {
const service = found.record;
return {
title: service.meta_title || `Pireon — ${service.title}`,
description: service.meta_description || service.tagline || '',
path: service.path,
alternates: service.alternates ?? {},
type: 'article',
};
}
case 'contribute':
return {
title: `Pireon — ${copy.contribute.title}`,
description: copy.contribute.lead,
path: listingPath('contribute', locale),
alternates: listingAlternates('contribute'),
type: 'website',
};
case 'radar':
return {
title: `Pireon — ${copy.sections.radar.title}`,
description: copy.radar.lead,
path: listingPath('radar', locale),
alternates: listingAlternates('radar'),
type: 'website',
};
case 'call': {
const call = found.record;
const project = call.project?.title;
return {
title: `Pireon — ${call.title}${project ? ` · ${project}` : ''}`,
description: call.description?.slice(0, 160) || '',
path: call.path,
alternates: call.alternates ?? {},
type: 'article',
};
}
}
}