))}
-
-
diff --git a/src/i18n/en.ts b/src/i18n/en.ts
index 84d2fc3..8ce9324 100644
--- a/src/i18n/en.ts
+++ b/src/i18n/en.ts
@@ -13,7 +13,7 @@ export const en: Copy = {
aiMeta: {
title: 'AI · Andrea Lisi · Frontend Platform & Governance',
description:
- 'How I use AI in engineering work: generated code follows the same review, testing and verification as code written by hand.',
+ 'How I use AI assistants and agents in development: where they help, how I review the result and what checks I apply.',
},
skipLink: 'Skip to content',
@@ -45,14 +45,14 @@ export const en: Copy = {
{ label: 'FOUNDATION', value: 'Art school, Florence', tone: 'root' },
],
intro:
- 'I am a Senior Software Engineer with over 18 years of experience, focused on frontend platforms and the problems that appear when many teams work on the same codebase. I came to code through art and design, and I still care whether the structure makes sense at a glance.',
+ 'I’m a Senior Software Engineer with over 18 years of experience. Today I work on the frontend platform behind Tosca Cloud, a monorepo containing 16 projects and shared by more than 12 teams. My focus is architecture, dependencies, builds and shared standards.',
buttons: { github: 'GITHUB', linkedin: 'LINKEDIN', email: 'EMAIL', cv: 'CV.PDF ↓' },
},
sections: {
approach: { num: '01', title: 'How I work' },
focus: { num: '02', title: 'What I work on' },
- ai: { num: '03', title: 'AI', eyebrow: 'TOOLS, REVIEW AND VERIFICATION' },
+ ai: { num: '03', title: 'AI', eyebrow: 'USE, REVIEW AND TESTING' },
experience: { num: '04', title: 'Experience' },
projects: { num: '05', title: 'Personal projects' },
contact: { num: '06', title: 'Get in touch' },
@@ -62,18 +62,18 @@ export const en: Copy = {
{
label: 'Art_School',
tone: 'root',
- title: 'I still look at code the way I looked at design',
- body: 'I started in design, then moved through frontend, full-stack work and infrastructure. That background probably explains why I care so much about structure. I like software that makes sense when you look at it, not only when you run it.',
+ title: 'From design to frontend engineering',
+ body: 'I started in design, but my career is in frontend engineering. Over time I have also worked on backend systems and infrastructure. That experience helps me see what changes elsewhere in the system when I work on the frontend.',
},
{
label: 'The_Boundaries',
- title: 'The rules should survive my absence',
- body: 'A large part of my work sits between teams: module boundaries, shared code, dependencies, build tooling and CI. I write down the reason for a rule, then turn it into a check when possible. The codebase should not depend on somebody remembering how things are supposed to work.',
+ title: 'Rules and automated checks',
+ body: 'I often work on problems that affect several teams: module boundaries, dependencies, builds and CI. When a rule matters, I document the reason and add an automated check where I can. That lets the check do the reminding, so I do not have to repeat the same thing to dozens of people one at a time.',
},
{
label: 'Hands_On',
- title: 'I stay close to the code',
- body: 'I still spend a lot of time in implementation and debugging. I work on shared tooling, investigate platform-wide breakage and automate decisions that would otherwise be repeated in reviews. When a problem belongs to another team, I document it, hand it over clearly and stay available without taking the work away from them.',
+ title: 'I work on the code and alongside the teams',
+ body: 'I continue to implement, debug and work on shared engineering tools. Every day I work with developers across the teams, from junior to senior, and I regularly speak with their managers. When a decision affects several products, I also work with design, security and sales to understand what is needed and apply it consistently.',
},
],
@@ -84,39 +84,50 @@ export const en: Copy = {
'Monorepo architecture',
'Micro-frontends',
'Module boundaries',
- 'Dependency architecture',
- 'RFCs',
+ 'Dependency governance',
+ 'Technical RFCs',
],
},
{
- title: 'Frontend',
- items: ['React', 'TypeScript', 'Vue', 'GraphQL', 'Node.js'],
+ title: 'Frontend & integrations',
+ items: [
+ 'React',
+ 'TypeScript',
+ 'Vue',
+ 'GraphQL',
+ 'Node.js',
+ 'Frontend Okta integration',
+ 'JWT handling',
+ 'OpenTelemetry',
+ ],
},
{
- title: 'Tooling & delivery',
- items: ['Nx', 'Vite', 'Webpack', 'CI/CD', 'Testing', 'Build performance', 'Quality gates'],
+ title: 'Build & delivery',
+ items: [
+ 'CI architecture',
+ 'Pipeline automation',
+ 'Build caching & performance',
+ 'Quality gates',
+ 'Automated testing',
+ ],
},
{
title: 'Developer experience',
- items: [
- 'Shared tooling',
- 'Engineering standards',
- 'Developer experience',
- 'AI-assisted and agentic workflows',
- ],
+ items: ['Shared tooling', 'Engineering standards', 'Documentation', 'AI tooling evaluation'],
},
],
ai: {
- heading: 'How I use AI in engineering work',
+ heading: 'How I use AI in development',
paragraphs: [
- 'AI-assisted and agentic development is part of my workflow, but generated code follows the same standard as any other code. If it cannot be reviewed, tested and verified, it does not go in.',
+ 'I use AI assistants and agents to analyse a project’s code, prepare changes and reduce repetitive work. I use them only when I can understand what they did and check that it works.',
+ 'I test them on real work to see where they lose context in the codebase. I use that to update the repository’s documentation, rules and tooling.',
],
- rulesLead: 'Three rules keep that practical.',
+ rulesLead: 'In practice:',
rules: [
- 'I only delegate what I can verify. If I cannot review and understand the result, doing it faster is not useful.',
- 'I check whether the change belongs before I check whether it works. Agents will rebuild things that already exist and make the suggestion sound convincing. The first question is whether the new code should exist at all.',
- 'The same gates apply to every contributor. Human or generated, code has to respect the same module boundaries, tests and quality checks before it reaches main.',
+ 'First I check whether the change is needed. An agent can suggest rebuilding something that already exists in the project.',
+ 'I review the result like any other contribution. I read the diff, run the tests and check that it respects the project’s boundaries.',
+ 'I need to be able to explain and maintain every change. If I cannot, I do not use it.',
],
backLabel: 'ANDREA LISI',
},
@@ -131,12 +142,11 @@ export const en: Copy = {
tags: ['Micro-frontends', '16 projects', '12+ teams', 'Quality gates'],
current: true,
paragraphs: [
- 'I work on the frontend platform behind Tosca Cloud, a micro-frontend monorepo shared across 16 projects and more than 12 teams.',
- 'I own architectural and governance work across the monorepo, including module boundaries, dependency rules and shared frontend standards.',
- 'I work with the platform architect on build performance, CI topology and quality gates.',
- 'I handle platform-wide upgrades and shared integrations, fixing breakage centrally before individual teams inherit it.',
- 'I review RFCs and cross-team changes when they affect shared frontend boundaries.',
- 'I turn conventions into machine-checkable rules for both human and agent-generated code, and stay hands-on with implementation and debugging when issues affect the platform as a whole.',
+ 'I work on the frontend platform behind Tosca Cloud, a micro-frontend monorepo containing 16 projects and shared by more than 12 teams.',
+ 'I work on the monorepo’s architecture and governance, particularly module boundaries, dependency rules and shared frontend standards. I also review RFCs that affect the shared frontend.',
+ 'I administer the Tosca Cloud repository on GitHub and automate its pipelines, including on Azure. With the platform architect, I work on build caching and performance, CI structure and quality gates.',
+ 'I implement and maintain integrations shared across multiple frontend applications. These include observability with OpenTelemetry and the application-side authentication flow after the Okta login, including JWT handling and HTTP interceptors. When an issue appears across several projects, I debug it at platform level.',
+ 'I regularly evaluate AI tools, including Claude and Cursor, on real repository work. If they keep stumbling over the same parts of the codebase, I improve its documentation, rules or shared tooling.',
],
},
{
@@ -147,10 +157,10 @@ export const en: Copy = {
context: 'E-commerce platform for tree planting',
tags: ['React', 'Vue', 'GraphQL', 'Storefront migration'],
paragraphs: [
- 'Joined the frontend team and later led the frontend side of the storefront migration away from the monolith, working with React, Vue and GraphQL.',
- 'Rebuilt the storefront foundations as the company grew from around 20 to more than 150 people.',
- 'Built high-traffic campaign experiences for a platform that has planted millions of trees.',
- 'In my final year, built the frontend of the company’s internal back-office tools from scratch, working closely with the backend team and the people using those tools for forestry operations.',
+ 'As part of the frontend team, I worked on moving the storefront out of the monolith using React, Vue and GraphQL.',
+ 'I helped rebuild the storefront as the company grew from around 20 to more than 150 people.',
+ 'I built interfaces for high-traffic campaigns. I worked regularly with the design and design system teams to integrate requests, match the mockups and follow the shared standards.',
+ 'For my final two years, I built the frontend for the internal back-office tools from scratch. I was the project’s only frontend developer and worked alongside the backend team and the people who used those tools for forestry operations.',
],
},
{
@@ -161,25 +171,23 @@ export const en: Copy = {
context: 'Luxury e-commerce',
tags: ['ASP', 'jQuery', 'React', 'Webpack'],
paragraphs: [
- 'Modernized a live luxury e-commerce platform without a full rewrite, moving it from legacy ASP and jQuery to React with a Webpack-based frontend toolchain.',
- 'Kept shipping features while the migration was in progress and the production shop remained live.',
+ 'Modernized a luxury e-commerce platform while it was in production. Gradually replaced ASP and jQuery with React and a new Webpack setup.',
+ 'Continued to build new features during the migration without taking the shop offline.',
'Worked on both the storefront and the internal CMS used for orders and day-to-day shop operations.',
- 'Gradually replaced the legacy frontend while changing the architecture underneath it.',
],
},
{
years: '2007 · 2017',
place: 'FIGLINE VALDARNO, IT',
- title: 'Head of Web · Full-Stack Designer',
+ title: 'Head of Web · Designer & Developer',
company: 'Easysystem',
context: 'Web agency and IT services',
tags: ['Design', 'Web', 'Backend', 'Infrastructure'],
paragraphs: [
- 'I joined Easysystem as a designer and gradually ended up doing almost every technical part of client work: web development, backend systems and eventually on-premise infrastructure.',
+ 'I joined as a designer. Over the years I also worked on web development, backend systems and infrastructure installed at client sites.',
'Designed websites, interfaces, visual identities and print material from scratch for client projects.',
'Built and maintained both frontend and backend applications.',
'Installed servers, networks and firewalls on site for client companies, including manufacturers in Tuscany’s leather and fashion district.',
- 'Followed projects from the first design concepts through development and, in some cases, all the way down to the infrastructure they ran on.',
],
},
],
@@ -189,7 +197,7 @@ export const en: Copy = {
name: 'Lumina',
kind: 'FANTASY MUD',
description:
- 'A fantasy MUD I built end to end, from the Node.js/MongoDB backend to the React client and Cloudflare infrastructure.',
+ 'A fantasy MUD I built myself: a Node.js/MongoDB backend, a React client and Cloudflare infrastructure.',
tags: ['Node.js', 'MongoDB', 'React', 'Cloudflare'],
},
{
@@ -202,9 +210,6 @@ export const en: Copy = {
},
],
- workClosing:
- 'I started in design, moved through frontend, backend and infrastructure, and ended up working on the structure shared by many teams. The scale changed but the habit did not: understand how the whole thing fits together, then fix the part that keeps making the same problem return.',
-
footer: {
built: 'Written, designed and shipped by me.',
},
@@ -212,9 +217,9 @@ export const en: Copy = {
nowBadge: 'CURRENT',
contact: {
- invite: 'Write any time, even just to talk.',
- inviteMore:
- 'A new conversation has never once bothered me, and a proposal that makes me curious even less so.',
+ invite:
+ 'Hey! If you want to talk about frontend platforms, developer experience or simply compare notes, send me a message.',
+ inviteMore: 'It doesn’t need to be formal. A quick message is fine too.',
cv: 'CV (PDF)',
github: 'GitHub',
linkedin: 'LinkedIn',
diff --git a/src/i18n/it.ts b/src/i18n/it.ts
index 5111fc8..e7a45f1 100644
--- a/src/i18n/it.ts
+++ b/src/i18n/it.ts
@@ -14,7 +14,7 @@ export const it: Copy = {
aiMeta: {
title: 'AI · Andrea Lisi · Frontend Platform & Governance',
description:
- 'Come uso l’AI nel lavoro di engineering: il codice generato passa dalla stessa revisione, dagli stessi test e dalle stesse verifiche.',
+ 'Come uso assistenti AI e agenti nello sviluppo: quando servono, come rivedo il risultato e quali controlli applico.',
},
skipLink: 'Vai al contenuto',
@@ -46,14 +46,14 @@ export const it: Copy = {
{ label: 'FORMAZIONE', value: 'Istituto d’Arte, Firenze', tone: 'root' },
],
intro:
- 'Sono un Senior Software Engineer con più di 18 anni di esperienza, oggi concentrato sulle piattaforme frontend e sui problemi che emergono quando molti team lavorano sulla stessa codebase. Sono arrivato al codice passando dall’arte e dal design, e mi interessa ancora che la struttura si capisca al primo sguardo.',
+ 'Sono un Senior Software Engineer con più di 18 anni di esperienza. Oggi lavoro sulla piattaforma frontend di Tosca Cloud, una monorepo che raccoglie 16 progetti ed è condivisa da più di 12 team. Mi occupo soprattutto di architettura, dipendenze, build e standard condivisi.',
buttons: { github: 'GITHUB', linkedin: 'LINKEDIN', email: 'EMAIL', cv: 'CV.PDF ↓' },
},
sections: {
approach: { num: '01', title: 'Come lavoro' },
focus: { num: '02', title: 'Su cosa lavoro' },
- ai: { num: '03', title: 'AI', eyebrow: 'STRUMENTI, REVISIONE E VERIFICA' },
+ ai: { num: '03', title: 'AI', eyebrow: 'USO, REVISIONE E TEST' },
experience: { num: '04', title: 'Esperienza' },
projects: { num: '05', title: 'Progetti personali' },
contact: { num: '06', title: 'Restiamo in contatto' },
@@ -63,18 +63,18 @@ export const it: Copy = {
{
label: 'Art_School',
tone: 'root',
- title: 'Guardo ancora il codice con l’occhio del design',
- body: 'Ho cominciato dal design, poi sono passato dal frontend al full-stack e all’infrastruttura. Probabilmente è per questo che tengo così tanto alla struttura. Mi piace il software che ha senso quando lo guardi, non solo quando lo esegui.',
+ title: 'Dal design al frontend',
+ body: 'Ho cominciato dal design, ma la mia carriera è nel frontend. Nel tempo ho lavorato anche su backend e infrastruttura. Questa esperienza mi aiuta a vedere cosa cambia nel resto del sistema quando intervengo sul frontend.',
},
{
label: 'The_Boundaries',
- title: 'Le regole devono reggere anche quando non ci sono',
- body: 'Una parte importante del mio lavoro sta fra i team: confini dei moduli, codice condiviso, dipendenze, build tooling e CI. Scrivo il motivo di una regola e, quando posso, la trasformo in un controllo. La codebase non deve dipendere da qualcuno che si ricorda come dovrebbero funzionare le cose.',
+ title: 'Regole e controlli automatici',
+ body: 'Lavoro spesso su problemi che coinvolgono più team: confini tra moduli, dipendenze, build e CI. Quando una regola è importante, ne documento il motivo e, se possibile, aggiungo un controllo automatico. Così è il controllo a ricordare la regola, e io evito di ripeterla a decine di persone, una alla volta.',
},
{
label: 'Hands_On',
- title: 'Resto dentro il codice',
- body: 'Passo ancora molto tempo a implementare e fare debugging. Lavoro sul tooling condiviso, indago i problemi che toccano tutta la piattaforma e automatizzo decisioni che altrimenti si ripeterebbero in ogni review. Quando un problema appartiene a un altro team, lo documento, lo passo in modo chiaro e resto disponibile senza portargli via il lavoro.',
+ title: 'Lavoro sul codice e con i team',
+ body: 'Continuo a implementare, fare debugging e lavorare sugli strumenti condivisi. Collaboro ogni giorno con gli sviluppatori dei team, dagli junior ai senior, e mi confronto spesso con i loro manager. Quando una decisione coinvolge più prodotti, lavoro anche con design, security e sales per capire cosa serve e applicarlo in modo coerente.',
},
],
@@ -84,40 +84,56 @@ export const it: Copy = {
items: [
'Architettura di monorepo',
'Micro-frontend',
- 'Confini dei moduli',
- 'Architettura delle dipendenze',
- 'RFC',
+ 'Confini tra moduli',
+ 'Governance delle dipendenze',
+ 'RFC tecnici',
],
},
{
- title: 'Frontend',
- items: ['React', 'TypeScript', 'Vue', 'GraphQL', 'Node.js'],
+ title: 'Frontend e integrazioni',
+ items: [
+ 'React',
+ 'TypeScript',
+ 'Vue',
+ 'GraphQL',
+ 'Node.js',
+ 'Integrazione Okta lato frontend',
+ 'Gestione JWT',
+ 'OpenTelemetry',
+ ],
},
{
- title: 'Tooling e delivery',
- items: ['Nx', 'Vite', 'Webpack', 'CI/CD', 'Testing', 'Build performance', 'Quality gates'],
+ title: 'Build e rilascio',
+ items: [
+ 'Architettura CI',
+ 'Automazione delle pipeline',
+ 'Cache e performance delle build',
+ 'Controlli di qualità',
+ 'Test automatici',
+ ],
},
{
title: 'Developer experience',
items: [
- 'Tool condivisi',
- 'Standard di engineering',
- 'Developer experience',
- 'Workflow assistiti e agentici',
+ 'Strumenti condivisi',
+ 'Standard tecnici',
+ 'Documentazione',
+ 'Valutazione di strumenti AI',
],
},
],
ai: {
- heading: 'Come uso l’AI nel lavoro di engineering',
+ heading: 'Come uso l’AI nello sviluppo',
paragraphs: [
- 'Lo sviluppo assistito e agentico fa parte del mio workflow, ma il codice generato segue gli stessi standard di tutto il resto. Se non può essere revisionato, testato e verificato, non entra.',
+ 'Uso assistenti AI e agenti per analizzare il codice di un progetto, preparare modifiche e ridurre il lavoro ripetitivo. Li uso solo se posso capire cosa hanno fatto e verificare che funzioni.',
+ 'Li provo su attività reali per capire dove perdono il contesto della codebase. In base a quello aggiorno documentazione, regole e strumenti del repository.',
],
- rulesLead: 'Tre regole tengono questo lavoro sul pratico.',
+ rulesLead: 'In pratica:',
rules: [
- 'Delego solo quello che so verificare. Se non riesco a revisionare e capire il risultato, farlo più in fretta non serve.',
- 'Prima controllo se la modifica deve esistere, poi se funziona. Gli agenti propongono di ricostruire cose che esistono già e lo fanno in modo convincente. La prima domanda è se quel nuovo codice abbia davvero un posto nel progetto.',
- 'Gli stessi gate valgono per ogni contributore. Scritto da una persona o generato, il codice deve rispettare gli stessi confini dei moduli, gli stessi test e gli stessi controlli di qualità prima di arrivare in main.',
+ 'Prima verifico che la modifica serva. Un agente può suggerire di ricostruire qualcosa che nel progetto esiste già.',
+ 'Rivedo il risultato come qualsiasi altro contributo. Leggo il diff, eseguo i test e controllo che rispetti i confini del progetto.',
+ 'Devo poter spiegare e mantenere ogni modifica. Se non ci riesco, non la uso.',
],
backLabel: 'ANDREA LISI',
},
@@ -132,12 +148,11 @@ export const it: Copy = {
tags: ['Microfrontend', '16 progetti', '12+ team', 'Quality gates'],
current: true,
paragraphs: [
- 'Lavoro sulla piattaforma frontend dietro Tosca Cloud, una monorepo a micro-frontend condivisa da 16 progetti e più di 12 team.',
- 'Mi occupo dell’architettura e della governance della monorepo, dai confini dei moduli alle regole sulle dipendenze e agli standard frontend condivisi.',
- 'Lavoro con il platform architect sulle performance di build, sulla topologia della CI e sui quality gate.',
- 'Gestisco gli aggiornamenti che riguardano tutta la piattaforma e le integrazioni condivise, sistemando il guasto al centro prima che arrivi ai singoli team.',
- 'Rivedo RFC e modifiche trasversali quando toccano i confini del frontend condiviso.',
- 'Trasformo le convenzioni in regole verificabili dalla macchina, per il codice scritto dalle persone e dagli agenti, e continuo a implementare e fare debugging quando il problema riguarda la piattaforma nel suo insieme.',
+ 'Lavoro sulla piattaforma frontend di Tosca Cloud, una monorepo a micro-frontend che raccoglie 16 progetti ed è condivisa da più di 12 team.',
+ 'Lavoro sull’architettura e sulla governance della monorepo, in particolare su confini tra moduli, regole sulle dipendenze e standard frontend condivisi. Rivedo anche gli RFC che coinvolgono il frontend condiviso.',
+ 'Amministro la repository di Tosca Cloud su GitHub e automatizzo le pipeline, anche su Azure. Con il platform architect lavoro sulla cache e sulle performance delle build, sulla struttura della CI e sui quality gate.',
+ 'Implemento e mantengo integrazioni condivise tra più applicazioni frontend. Tra queste ci sono l’osservabilità con OpenTelemetry e la parte applicativa dell’autenticazione dopo il login Okta, compresa la gestione dei JWT e degli interceptor HTTP. Quando un problema compare in più progetti, lo indago a livello di piattaforma.',
+ 'Valuto regolarmente strumenti AI, tra cui Claude e Cursor, su attività reali nel repository. Se inciampano sempre negli stessi punti, intervengo sulla documentazione, sulle regole o sugli strumenti condivisi.',
],
},
{
@@ -148,10 +163,10 @@ export const it: Copy = {
context: 'Piattaforma e-commerce per piantare alberi',
tags: ['React', 'Vue', 'GraphQL', 'Migrazione storefront'],
paragraphs: [
- 'Sono entrato nel team frontend e poi ho guidato la parte frontend della migrazione dello storefront fuori dal monolite, lavorando con React, Vue e GraphQL.',
- 'Ho ricostruito le fondamenta dello storefront mentre l’azienda cresceva da circa 20 a più di 150 persone.',
- 'Ho costruito esperienze per campagne ad alto traffico, su una piattaforma che ha piantato milioni di alberi.',
- 'Nell’ultimo anno ho costruito da zero il frontend degli strumenti back-office interni, lavorando a stretto contatto con il team backend e con le persone che li usavano per le operazioni forestali.',
+ 'Nel team frontend ho lavorato alla migrazione dello storefront fuori dal monolite, usando React, Vue e GraphQL.',
+ 'Ho contribuito a ricostruire lo storefront mentre l’azienda cresceva da circa 20 a più di 150 persone.',
+ 'Ho sviluppato le interfacce per campagne ad alto traffico. Mi confrontavo regolarmente con il team di design e con quello del design system per integrare le richieste e rispettare i mockup e gli standard condivisi.',
+ 'Negli ultimi due anni ho sviluppato da zero il frontend degli strumenti back-office interni. Ero l’unico frontend developer del progetto e lavoravo insieme al team backend e alle persone che usavano quegli strumenti per le operazioni forestali.',
],
},
{
@@ -162,25 +177,23 @@ export const it: Copy = {
context: 'E-commerce di lusso',
tags: ['ASP', 'jQuery', 'React', 'Webpack'],
paragraphs: [
- 'Ho modernizzato una piattaforma e-commerce di lusso live senza un rewrite completo, portandola da ASP legacy e jQuery a React con una toolchain frontend basata su Webpack.',
- 'Ho continuato a rilasciare funzionalità mentre la migrazione era in corso e il negozio di produzione restava online.',
+ 'Ho modernizzato un e-commerce di lusso mentre era in produzione. Ho sostituito gradualmente ASP e jQuery con React e una nuova configurazione Webpack.',
+ 'Durante la migrazione ho continuato a sviluppare nuove funzionalità senza fermare il negozio.',
'Ho lavorato sia sullo storefront sia sul CMS interno usato per gli ordini e per la gestione quotidiana del negozio.',
- 'Ho sostituito gradualmente il frontend legacy mentre cambiavo l’architettura sottostante.',
],
},
{
years: '2007 · 2017',
place: 'FIGLINE VALDARNO, IT',
- title: 'Head of Web · Full-Stack Designer',
+ title: 'Head of Web · Designer & Developer',
company: 'Easysystem',
context: 'Agenzia web e servizi IT',
tags: ['Design', 'Web', 'Backend', 'Infrastruttura'],
paragraphs: [
- 'Sono entrato in Easysystem come designer e ho finito per occuparmi di quasi tutta la parte tecnica dei progetti: sviluppo web, sistemi backend e infine infrastruttura on-premise.',
+ 'Sono entrato come designer. Negli anni ho lavorato anche sullo sviluppo web, sui sistemi backend e sull’infrastruttura installata presso i clienti.',
'Ho disegnato da zero siti, interfacce, identità visive e materiali stampati per i progetti dei clienti.',
'Ho costruito e mantenuto applicazioni frontend e backend.',
'Ho installato server, reti e firewall direttamente nelle aziende dei clienti, comprese le manifatture del distretto toscano della pelle e della moda.',
- 'Ho seguito i progetti dai primi concetti di design allo sviluppo e, in alcuni casi, fino all’infrastruttura su cui giravano.',
],
},
],
@@ -190,7 +203,7 @@ export const it: Copy = {
name: 'Lumina',
kind: 'FANTASY MUD',
description:
- 'Un MUD fantasy costruito end to end, dal backend Node.js/MongoDB al client React e all’infrastruttura Cloudflare.',
+ 'Un MUD fantasy che ho sviluppato interamente: backend Node.js/MongoDB, client React e infrastruttura Cloudflare.',
tags: ['Node.js', 'MongoDB', 'React', 'Cloudflare'],
},
{
@@ -203,9 +216,6 @@ export const it: Copy = {
},
],
- workClosing:
- 'Ho cominciato dal design, sono passato dal frontend, dal backend e dall’infrastruttura, e sono arrivato a lavorare sulla struttura condivisa da molti team. La scala è cambiata, l’abitudine no: capire come sta insieme il sistema e poi correggere il punto che continua a far tornare lo stesso problema.',
-
footer: {
built: 'Scritto, disegnato e messo online da me.',
},
@@ -213,9 +223,9 @@ export const it: Copy = {
nowBadge: 'IN CORSO',
contact: {
- invite: 'Scrivimi quando vuoi, anche solo per parlare.',
- inviteMore:
- 'Una conversazione nuova non mi ha mai dato fastidio, e una proposta che mi incuriosisce ancora meno.',
+ invite:
+ 'Hey! Se ti va di parlare di piattaforme frontend, developer experience o semplicemente di scambiarci due idee, scrivimi.',
+ inviteMore: 'Non serve una proposta formale: anche un messaggio al volo va benissimo.',
cv: 'CV (PDF)',
github: 'GitHub',
linkedin: 'LinkedIn',
diff --git a/src/i18n/types.ts b/src/i18n/types.ts
index 92de1c0..2d19fd9 100644
--- a/src/i18n/types.ts
+++ b/src/i18n/types.ts
@@ -144,13 +144,6 @@ export type Copy = {
projects: ProjectEntry[];
- /**
- * HTML: the line that closes the career, after the four entries. It only
- * works there, because it is about what the steps add up to, and a reader
- * cannot be told that before being shown them.
- */
- workClosing: string;
-
/** Small print at the very bottom. */
footer: {
built: string;
diff --git a/src/layouts/layout.astro b/src/layouts/layout.astro
index 057dca1..3faeee5 100644
--- a/src/layouts/layout.astro
+++ b/src/layouts/layout.astro
@@ -33,7 +33,7 @@ const fontHref =
-
+
{meta.title}
diff --git a/tests/e2e/homepage.spec.ts b/tests/e2e/homepage.spec.ts
index 4216e2b..1d8a1d5 100644
--- a/tests/e2e/homepage.spec.ts
+++ b/tests/e2e/homepage.spec.ts
@@ -30,6 +30,7 @@ for (const locale of ['en', 'it'] as const) {
const copy = getCopy(locale);
const home = hrefFor(locale, 'home');
const ai = hrefFor(locale, 'ai');
+ const cvPath = locale === 'it' ? '/andrea-lisi-cv-it.pdf' : '/andrea-lisi-cv.pdf';
test.describe(`home page (${locale})`, () => {
test('declares its language and links both alternates', async ({ page }) => {
@@ -146,12 +147,6 @@ for (const locale of ['en', 'it'] as const) {
await expect(card.locator('.duty')).toHaveCount(job.paragraphs.length);
await expect(card.locator('.chip')).toHaveCount(job.tags.length);
}
-
- // The closing line only means anything after the entries, so it has to be
- // the last thing in the section, not a lead over it.
- const closing = page.locator('.work .closing');
- await expect(closing).toHaveText(plain(copy.workClosing));
- expect(await closing.evaluate((el) => el === el.parentElement?.lastElementChild)).toBe(true);
});
test('closes on an invitation, with the address behind the mail icon', async ({ page }) => {
@@ -171,12 +166,12 @@ for (const locale of ['en', 'it'] as const) {
for (const scope of ['.hero', '.contact']) {
const cv = page.locator(scope).getByRole('link', { name: copy.hero.buttons.cv });
- await expect(cv).toHaveAttribute('href', '/andrea-lisi-cv.pdf');
+ await expect(cv).toHaveAttribute('href', cvPath);
}
});
test('serves the CV PDF and the portrait', async ({ request }) => {
- for (const asset of ['/andrea-lisi-cv.pdf', '/andrea-lisi.webp', '/andrea-lisi.jpg']) {
+ for (const asset of [cvPath, '/andrea-lisi.webp', '/andrea-lisi.jpg']) {
expect((await request.get(asset)).status(), asset).toBe(200);
}
});
@@ -197,18 +192,16 @@ for (const locale of ['en', 'it'] as const) {
});
/*
- * The architecture is named once, as the thing he governs. In the work
- * history that is evidence of scale. In the hero or in how-I-work it would
- * read as the only thing he does, which is why it was cut the first time.
- * The rule was never the word, it was the position.
+ * The hero now opens with the scale of the current platform instead of a
+ * general claim. The focus and work sections then add the technical detail.
*/
- test('keeps the architecture out of the hero and names it where it adds evidence', async ({
- page,
- }) => {
+ test('opens with platform scale and adds architecture detail later', async ({ page }) => {
await page.goto(home);
const architecture = /micro-?frontend|monorepo/i;
- await expect(page.locator('.hero').getByText(architecture)).toHaveCount(0);
+ await expect(page.locator('.hero')).toContainText('16');
+ await expect(page.locator('.hero')).toContainText('12');
+ await expect(page.locator('.hero').getByText(architecture)).toHaveCount(1);
await expect(page.locator('.approach').getByText(architecture)).toHaveCount(0);
await expect(page.locator('.focus').getByText(architecture).first()).toBeVisible();
await expect(page.locator('.work').getByText(architecture).first()).toBeVisible();