diff --git a/README.md b/README.md index cea3d3c..532bca5 100644 --- a/README.md +++ b/README.md @@ -28,23 +28,27 @@ npm test # browser tests, then Lighthouse budgets, on the last buil | `src/layouts/` | The HTML shell: metadata, fonts, theme selection | | `src/styles/` | Design tokens for the four themes, and base styles | | `src/assets/` | Portrait, badges and logos; optimised at build time (AVIF, WebP) | -| `public/` | Files served as they are: favicons | +| `public/` | Files served as they are: favicons, PDFs, robots.txt, sitemap | +| `scripts/` | `og-image.mjs` draws the card shown where the site is shared | | `.github/workflows/` | `ci.yml` checks pull requests; `deploy.yml` publishes `main` to Pages | To update the site, edit `src/data/profile.ts`. A new badge or logo goes in -`src/assets/` and is imported there. +`src/assets/` and is imported there. After a change to the name, the role or +the portrait, redraw the sharing card with `npm run og-image`. ## Design The palette is an autumn / winter colour analysis. The page picks one of four -themes from the visitor's clock, before the first paint: - -| Theme | When | Background | Accent | -| --------------- | ----------------------------- | ---------- | ---------- | -| Autumn, day | April to November, 7:00–19:00 | cream | terracotta | -| Autumn, evening | April to November, otherwise | espresso | terracotta | -| Winter, day | December to March, 7:00–19:00 | ivory | blackberry | -| Winter, evening | December to March, otherwise | navy | blackberry | +themes before the first paint: the season from the month, day or evening from +whether the sun is up where the visitor is (Brussels for Belgium and its +neighbours). + +| Theme | When | Background | Accent | +| --------------- | --------------------------- | ---------- | ---------- | +| Autumn, day | April to November, sun up | cream | terracotta | +| Autumn, evening | April to November, sun down | espresso | terracotta | +| Winter, day | December to March, sun up | ivory | blackberry | +| Winter, evening | December to March, sun down | navy | blackberry | Every text colour meets WCAG AA (4.5:1) in every theme. Fonts: Cinzel Decorative for the name only, Plus Jakarta Sans for headings, Inter for text; all three are diff --git a/package.json b/package.json index e73781d..84e440c 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "check": "astro check", "format": "prettier --write .", "format:check": "prettier --check .", - "test": "playwright test" + "test": "playwright test", + "og-image": "node scripts/og-image.mjs" }, "dependencies": { "@fontsource-variable/inter": "5.3.0", diff --git a/public/google7caeff32a4565021.html b/public/google7caeff32a4565021.html new file mode 100644 index 0000000..4991c85 --- /dev/null +++ b/public/google7caeff32a4565021.html @@ -0,0 +1 @@ +google-site-verification: google7caeff32a4565021.html diff --git a/public/robots.txt b/public/robots.txt index c2a49f4..8c90476 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,2 +1,4 @@ User-agent: * Allow: / + +Sitemap: https://rememberyou.github.io/sitemap.xml diff --git a/public/sitemap.xml b/public/sitemap.xml new file mode 100644 index 0000000..956615e --- /dev/null +++ b/public/sitemap.xml @@ -0,0 +1,6 @@ + + + + https://rememberyou.github.io/ + + diff --git a/scripts/og-image.mjs b/scripts/og-image.mjs new file mode 100644 index 0000000..b6ecbd9 --- /dev/null +++ b/scripts/og-image.mjs @@ -0,0 +1,46 @@ +// Draws the image shown when the site is shared (LinkedIn, Slack, WhatsApp…): +// 1200×630, as the hero looks by day, with the site's own fonts. Run it again +// after a change to the name, the role or the photo: +// npm run og-image +import { readFileSync } from 'node:fs'; +import { createRequire } from 'node:module'; + +import { chromium } from '@playwright/test'; + +const require = createRequire(import.meta.url); +const asDataUrl = (path, type) => `data:${type};base64,${readFileSync(path).toString('base64')}`; +const font = (pkg) => asDataUrl(require.resolve(pkg), 'font/woff2'); + +const html = ` + +
+

Terencio
Agozzino

+

Solutions Architect | AWS & Azure Certified

+

rememberyou.github.io

+
+`; + +const browser = await chromium.launch(); +const page = await browser.newPage({ viewport: { width: 1200, height: 630 } }); +await page.setContent(html); +await page.evaluate(() => document.fonts.ready); +await page.screenshot({ path: 'src/assets/og.png' }); +await browser.close(); +console.log('wrote src/assets/og.png'); diff --git a/src/assets/og.png b/src/assets/og.png new file mode 100644 index 0000000..34058e5 Binary files /dev/null and b/src/assets/og.png differ diff --git a/src/data/profile.ts b/src/data/profile.ts index 0aca91c..1ea0d80 100644 --- a/src/data/profile.ts +++ b/src/data/profile.ts @@ -28,12 +28,26 @@ export const person = { credentials: 'AWS & Azure Certified', country: 'Belgium', region: 'Wallonia', + /** What search engines show under the title: at most about 155 characters. */ + description: + 'Solutions Architect, AWS & Azure certified: secure cloud foundations, data platforms and the automation that runs them, with a research background.', pitch: '5+ years across cloud, data and software: secure AWS & Azure foundations, data platforms, and the automation that runs them — with a research background in knowledge graphs.', email: 'terencio.agozzino@gmail.com', linkedin: 'https://www.linkedin.com/in/terencioagozzino/', github: 'https://github.com/rememberYou', credly: 'https://www.credly.com/users/terencio-agozzino/badges', + employer: { name: 'CBTW', url: 'https://cbtw.tech' }, + school: 'Haute École en Hainaut', + /** What search engines associate with the name. */ + topics: [ + 'Cloud architecture', + 'Amazon Web Services', + 'Microsoft Azure', + 'Infrastructure as code', + 'Data engineering', + 'Knowledge graphs', + ], /** Served from public/; replace the file there to update it. */ cv: '/terencio-agozzino-cv.pdf', thesis: '/terencio-agozzino-master-thesis.pdf', diff --git a/src/layouts/Base.astro b/src/layouts/Base.astro index 34bd1af..3d335e5 100644 --- a/src/layouts/Base.astro +++ b/src/layouts/Base.astro @@ -1,8 +1,9 @@ --- import { Font, getImage } from 'astro:assets'; +import og from '../assets/og.png'; import portrait from '../assets/portrait.png'; -import { person } from '../data/profile'; +import { certifications, person } from '../data/profile'; import '../styles/global.css'; interface Props { @@ -12,19 +13,43 @@ interface Props { const { title, description } = Astro.props; const canonical = new URL(Astro.url.pathname, Astro.site); -const ogImage = await getImage({ src: portrait, width: 800, format: 'jpg' }); +// The card shown where the site is shared; the portrait, where search engines +// show the person. +const ogImage = await getImage({ src: og, format: 'jpg' }); const ogImageUrl = new URL(ogImage.src, Astro.site); +const photo = await getImage({ src: portrait, width: 800, format: 'jpg' }); +// Who the page is about, for search engines: a Person with their work, +// school, topics, credentials and the profiles that are also them. +const issuers: Record = { + AWS: 'Amazon Web Services', + Microsoft: 'Microsoft', + 'Scrum.org': 'Scrum.org', +}; const jsonLd = { '@context': 'https://schema.org', '@type': 'Person', name: `${person.firstName} ${person.lastName}`, + givenName: person.firstName, + familyName: person.lastName, jobTitle: person.role, + description, url: canonical.href, - image: ogImageUrl.href, + image: new URL(photo.src, Astro.site).href, email: `mailto:${person.email}`, address: { '@type': 'PostalAddress', addressCountry: 'BE', addressRegion: person.region }, - sameAs: [person.linkedin, person.github], + worksFor: { '@type': 'Organization', ...person.employer }, + alumniOf: { '@type': 'CollegeOrUniversity', name: person.school }, + knowsAbout: person.topics, + hasCredential: certifications + .flatMap(({ items }) => items) + .map(({ name, issuer }) => ({ + '@type': 'EducationalOccupationalCredential', + name, + credentialCategory: 'certification', + recognizedBy: { '@type': 'Organization', name: issuers[issuer] ?? issuer }, + })), + sameAs: [person.linkedin, person.github, person.credly], }; --- @@ -94,6 +119,7 @@ const jsonLd = { {title} + @@ -106,9 +132,15 @@ const jsonLd = { + + + - + diff --git a/src/pages/index.astro b/src/pages/index.astro index ec90866..70fd46f 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -12,10 +12,9 @@ import { person } from '../data/profile'; import Base from '../layouts/Base.astro'; const title = `${person.firstName} ${person.lastName} — ${person.role}`; -const description = `${person.role}, ${person.credentials}. ${person.pitch}`; --- - +