feat: compose the portfolio journey layer
This commit is contained in:
@@ -15,14 +15,13 @@ const sectionIds = [
|
||||
] as const;
|
||||
|
||||
const sectionHeadings = [
|
||||
'START',
|
||||
'PROFILE',
|
||||
'EXPERIENCE',
|
||||
'INFRASTRUCTURE',
|
||||
'SELECTED BUILDS',
|
||||
'ADDITIONAL WORK',
|
||||
'TOOLKIT',
|
||||
'CONTACT',
|
||||
'Profile',
|
||||
'Experience',
|
||||
'Infrastructure',
|
||||
'Selected builds',
|
||||
'Additional work',
|
||||
'Toolkit',
|
||||
'Contact',
|
||||
] as const;
|
||||
|
||||
const navigationLabels: Readonly<Record<(typeof sectionIds)[number], string>> = {
|
||||
@@ -90,14 +89,15 @@ const expectedVisibleTextSegments = (
|
||||
content.navigation.map((item) => [item.id, item.label]),
|
||||
);
|
||||
const section = (
|
||||
id: (typeof sectionIds)[number],
|
||||
index: number,
|
||||
id: Exclude<(typeof sectionIds)[number], 'start'>,
|
||||
body: readonly string[],
|
||||
eyebrow?: string,
|
||||
): string[] => {
|
||||
const label = navigationById.get(id);
|
||||
if (label === undefined) throw new Error(`Missing navigation label: ${id}`);
|
||||
const heading = label.toUpperCase();
|
||||
return [`${String(index).padStart(2, '0')} / ${heading}`, heading, ...body];
|
||||
return [eyebrow, label, ...body].filter(
|
||||
(segment): segment is string => segment !== undefined,
|
||||
);
|
||||
};
|
||||
const projectLinkText = (
|
||||
project: PortfolioContent['projects']['selected'][number],
|
||||
@@ -105,18 +105,19 @@ const expectedVisibleTextSegments = (
|
||||
project.visibility === 'public' && project.url ? [project.title] : [];
|
||||
|
||||
return [
|
||||
...sectionIds.map((id) => navigationLabels[id]),
|
||||
content.identity.name,
|
||||
content.identity.role,
|
||||
...sectionIds.map((id) => navigationLabels[id]),
|
||||
...section('start', 1, [content.identity.valueProposition]),
|
||||
...section('profile', 2, [
|
||||
content.identity.valueProposition,
|
||||
'Explore work',
|
||||
...section('profile', [
|
||||
content.profile.introduction,
|
||||
...content.profile.screeningFacts.flatMap((fact) => [
|
||||
fact.label,
|
||||
fact.value,
|
||||
]),
|
||||
]),
|
||||
...section('experience', 3, [
|
||||
...section('experience', [
|
||||
...content.experience.flatMap((record) => [
|
||||
record.role,
|
||||
`${record.organization} · ${record.dates}${record.location === undefined ? '' : ` · ${record.location}`}`,
|
||||
@@ -126,7 +127,7 @@ const expectedVisibleTextSegments = (
|
||||
content.systemsOperations.summary,
|
||||
...content.systemsOperations.evidence,
|
||||
]),
|
||||
...section('infrastructure', 4, [
|
||||
...section('infrastructure', [
|
||||
content.infrastructure.title,
|
||||
content.infrastructure.summary,
|
||||
...content.infrastructure.bands.map((band) => band.title),
|
||||
@@ -137,7 +138,6 @@ const expectedVisibleTextSegments = (
|
||||
]),
|
||||
...section(
|
||||
'selected-builds',
|
||||
5,
|
||||
content.projects.selected.flatMap((project) => [
|
||||
project.title,
|
||||
project.summary,
|
||||
@@ -151,10 +151,10 @@ const expectedVisibleTextSegments = (
|
||||
project.outcome,
|
||||
...projectLinkText(project),
|
||||
]),
|
||||
'Selected work',
|
||||
),
|
||||
...section(
|
||||
'additional-work',
|
||||
6,
|
||||
content.projects.additional.flatMap((project) => [
|
||||
project.title,
|
||||
project.summary,
|
||||
@@ -165,19 +165,18 @@ const expectedVisibleTextSegments = (
|
||||
),
|
||||
...section(
|
||||
'toolkit',
|
||||
7,
|
||||
content.toolkit.flatMap((group) => [
|
||||
group.title,
|
||||
...group.technologies.map((technology) => technology.name),
|
||||
]),
|
||||
),
|
||||
...section('contact', 8, [
|
||||
content.identity.name,
|
||||
content.identity.role,
|
||||
...section('contact', [
|
||||
"Thanks for making the trip. The road's open if you'd like to build something together.",
|
||||
'Start a conversation',
|
||||
content.contact.email,
|
||||
content.contact.cvMessage,
|
||||
...content.contact.social.map((link) => link.service),
|
||||
]),
|
||||
], 'Destination'),
|
||||
];
|
||||
};
|
||||
|
||||
@@ -347,7 +346,7 @@ test('keeps every raw SSR reading-path segment visible without JavaScript', asyn
|
||||
|
||||
await expect(page.locator('h1:visible')).toHaveCount(1);
|
||||
await expect(page.locator('h1')).toHaveText('Luca Pîslaru');
|
||||
await expect(page.locator('.site-header > p').first()).toHaveText(
|
||||
await expect(page.locator('.hero-journey__role')).toHaveText(
|
||||
'System Administrator & Full-Stack Developer',
|
||||
);
|
||||
await expect(page.locator('main')).toBeVisible();
|
||||
@@ -381,7 +380,7 @@ test('keeps every raw SSR reading-path segment visible without JavaScript', asyn
|
||||
|
||||
const email = page.locator('a[href="mailto:luca.pislaru@gmail.com"]');
|
||||
await expect(email).toBeVisible();
|
||||
await expect(email).toHaveText('luca.pislaru@gmail.com');
|
||||
await expect(email).toHaveText('Start a conversation');
|
||||
await expect(
|
||||
page.getByText(
|
||||
'For a current CV or role-specific information, contact me directly.',
|
||||
|
||||
Reference in New Issue
Block a user