feat: refine portfolio content, contact, and supporting media

This commit is contained in:
2026-09-05 20:08:57 +03:00
parent 15bcdf7cec
commit 103427f95b
53 changed files with 824 additions and 204 deletions

View File

@@ -98,6 +98,7 @@ const readManifest = async (repositoryRoot) => {
const assetReferences = (content) => {
const references = [];
if (content.contact?.avatarAssetId !== undefined) references.push(content.contact.avatarAssetId);
const projects = content.projects;
if (typeof projects !== 'object' || projects === null || Array.isArray(projects)) {
throw new Error('Portfolio content must contain project collections.');

View File

@@ -9,12 +9,11 @@ const publicMetadata = Object.freeze({
name: 'Luca Pîslaru',
role: 'System Administrator & Full-Stack Developer',
title: 'Luca Pîslaru — System Administrator & Full-Stack Developer',
description: 'Portfolio of Luca Pîslaru, a Bucharest-based System Administrator and Full-Stack Developer working across Linux infrastructure and end-to-end software delivery.',
email: 'mailto:luca.pislaru@gmail.com',
description: 'I’m Luca Pîslaru, a System Administrator & Full-Stack Developer based in Bucharest. Explore my work in Linux infrastructure and end-to-end application development.',
sameAs: Object.freeze([
'https://linkedin.com/in/luca-pisl',
'https://github.com/LucaPisl',
'https://gitlab.com/luca_pisl',
'https://linkedin.com/in/luca-pisl',
]),
location: Object.freeze({ city: 'Bucharest', countryCode: 'RO' }),
socialImagePath: '/assets/project-social-preview.webp',
@@ -121,13 +120,13 @@ function verifyMetadata(html, canonicalUrl) {
try { jsonLd = JSON.parse(jsonLdText); } catch { throw new Error('JSON-LD is not valid JSON.'); }
exactObjectKeys(jsonLd, ['@context', '@type', 'name', 'description', 'url', 'mainEntity'], 'ProfilePage JSON-LD');
const person = jsonLd.mainEntity;
exactObjectKeys(person, ['@type', 'name', 'jobTitle', 'description', 'url', 'email', 'homeLocation', 'sameAs'], 'Person JSON-LD');
exactObjectKeys(person, ['@type', 'name', 'jobTitle', 'description', 'url', 'homeLocation', 'sameAs'], 'Person JSON-LD');
exactObjectKeys(person.homeLocation, ['@type', 'address'], 'homeLocation JSON-LD');
exactObjectKeys(person.homeLocation.address, ['@type', 'addressLocality', 'addressCountry'], 'PostalAddress JSON-LD');
if (jsonLd['@context'] !== 'https://schema.org' || jsonLd['@type'] !== 'ProfilePage' ||
jsonLd.name !== publicMetadata.name || jsonLd.description !== description || jsonLd.url !== canonicalUrl ||
person['@type'] !== 'Person' || person.name !== publicMetadata.name || person.jobTitle !== publicMetadata.role ||
person.description !== description || person.url !== canonicalUrl || person.email !== publicMetadata.email ||
person.description !== description || person.url !== canonicalUrl ||
person.homeLocation['@type'] !== 'Place' || person.homeLocation.address['@type'] !== 'PostalAddress' ||
person.homeLocation.address.addressLocality !== publicMetadata.location.city ||
person.homeLocation.address.addressCountry !== publicMetadata.location.countryCode ||

View File

@@ -4,6 +4,7 @@ import { dirname, relative, resolve, sep } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import { loadProductionInputs } from '../src/content/load-production-inputs.ts';
import { createPageMetadata, createStaticHostArtifacts } from '../src/content/metadata.ts';
import { contactAddress, readableContactAddress } from '../src/content/contact-email.ts';
import { Window } from 'happy-dom';
import { parseArtifactContract, parseBuildAuthority } from './build-contract.mjs';
import { parseExactConfigArgument } from './config-argument.mjs';
@@ -232,19 +233,31 @@ const assertSemanticHtml = (html, inputs, contract) => {
...inputs.content.infrastructure.bands.flatMap((band) => [band.title, band.summary]),
...inputs.content.projects.selected.flatMap((project) => [project.title, project.summary]),
...inputs.content.toolkit.flatMap((group) => [group.title, ...group.technologies.map((technology) => technology.name)]),
inputs.content.contact.email,
];
for (const copy of requiredVisibleCopy) {
if (!semanticText.includes(copy)) throw new Error(`Missing visible semantic evidence: ${copy}`);
}
const mailLinks = [...document.querySelectorAll('a[href^="mailto:"]')];
const startMailLinks = [...document.querySelectorAll('#start a[href^="mailto:"]')];
const contactMailLinks = [...document.querySelectorAll('#contact a[href^="mailto:"]')];
if (mailLinks.length !== 2 || startMailLinks.length !== 1 || contactMailLinks.length !== 1 || mailLinks.some((link) =>
link.getAttribute('href') !== `mailto:${inputs.content.contact.email}` || link.textContent !== 'Email Luca'
)) {
throw new Error('Mailto links must be exactly one Email Luca action beneath each hero and contact section.');
const contactActions = [...document.querySelectorAll('#start a[href="#contact"]')];
if (contactActions.length !== 1 || contactActions[0].textContent !== 'Contact Me' ||
!isVisibleSemanticNode(contactActions[0], appRoot)) {
throw new Error('The hero must contain one visible Contact Me link to the contact section.');
}
if (document.querySelector('a[href^="mailto:"]') || html.includes(contactAddress(inputs.content.contact.email))) {
throw new Error('The initial document must not expose a complete email address or mailto link.');
}
const disclosures = [...document.querySelectorAll('#contact details#contact-email-details')];
if (disclosures.length !== 1 || disclosures[0].hasAttribute('open') ||
disclosures[0].querySelector(':scope > summary')?.textContent !== 'Email Me' ||
!isVisibleSemanticNode(disclosures[0], appRoot)) {
throw new Error('Contact must contain a closed native Email Me disclosure.');
}
disclosures[0].setAttribute('open', '');
const readableEmail = disclosures[0].querySelector('.contact-email__address');
if (readableEmail?.textContent !== readableContactAddress(inputs.content.contact.email) ||
!isVisibleSemanticNode(readableEmail, appRoot)) {
throw new Error('Email disclosure must provide a readable address without JavaScript.');
}
disclosures[0].removeAttribute('open');
const moduleScript = document.querySelector(`script[type="module"][src="/${contract.entryModule}"]`);
const snapshot = document.querySelector('script#portfolio-inputs[type="application/json"]');
@@ -353,7 +366,7 @@ const assertMetadata = (html, expected) => {
} catch {
throw new Error('JSON-LD is malformed.');
}
if (/"(?:streetAddress|postalCode|telephone|image|interactionStatistic)"\s*:/iu.test(jsonLdMatch[1])) {
if (/"(?:streetAddress|postalCode|telephone|image|interactionStatistic|email)"\s*:/iu.test(jsonLdMatch[1])) {
throw new Error('JSON-LD contains unsafe private, portrait, or interaction metadata.');
}
if (jsonLd['@type'] !== 'ProfilePage' || jsonLd.mainEntity?.['@type'] !== 'Person') {