/**
* @file Content and i18n data for the A. Morvan photographer portfolio (demo).
* Holds the FR/EN translation trees, the gallery photo metadata and the theme
* accent color. No React here — pure data, unit-tested in `data.test.js`.
* @module data
*/
/**
* A pair of strings for the two supported locales.
* @typedef {Object} LocalizedText
* @property {string} fr French text.
* @property {string} en English text.
*/
/**
* A project category shown on the Projects page.
* @typedef {Object} Category
* @property {string} number Two-digit index, e.g. `"01"`.
* @property {string} title Category name.
* @property {string} subtitle Short description.
* @property {string} quote Editorial pull-quote card text.
*/
/**
* A practice area listed on the "Œil et l'Intention" page.
* @typedef {Object} Terrain
* @property {string} title Area name.
* @property {string} desc One-line description.
*/
/**
* All translated UI strings for a single locale.
* @typedef {Object} Locale
* @property {string} brandRole Role shown under the logo.
* @property {{projets: string, oeil: string, contact: string}} nav Nav labels.
* @property {Object} hero Hero section strings.
* @property {Category[]} categories The three project categories.
* @property {Object} oeil Approach page strings (incl. `terrains: Terrain[]`).
* @property {Object} contact Contact page strings.
* @property {string} footer Footer text (may contain newlines).
* @property {string} lightboxClose Accessible label for the lightbox close button.
*/
/**
* Translation trees keyed by locale code.
* @type {{fr: Locale, en: Locale}}
*/
export const TRANSLATIONS = {
fr: {
brandRole: 'Photographe',
nav: {
projets: 'Projets',
oeil: "L'Œil et l'Intention",
contact: 'Contact',
},
hero: {
eyebrow: 'Portfolio',
title1: "Capturer l'instant,",
title2: "révéler l'intention.",
subtitle:
'Photographe basé entre scènes vivantes, architectures urbaines et instants volés — une exploration sensible de la lumière et du silence.',
cue: 'Découvrir',
},
categories: [
{
number: '01',
title: 'Live & Scène',
subtitle: "L'énergie brute des concerts, capturée dans la lumière et l'obscurité.",
quote: "Le bruit a une lumière qu'on ne voit qu'une fois.",
},
{
number: '02',
title: 'Géométrie Urbaine',
subtitle: 'Lignes, ombres et structures : la ville comme partition graphique.',
quote: "La ville dessine ce que l'œil n'ose pas cadrer.",
},
{
number: '03',
title: 'Instants Volés',
subtitle: 'Des scènes de vie saisies sur le vif, entre pudeur et vérité.',
quote: "Un regard volé dit parfois plus qu'un sourire posé.",
},
],
oeil: {
eyebrow: 'Démarche',
title: "L'Œil et l'Intention.",
portraitAlt: 'Portrait sombre du photographe',
aiNote: "Portrait d'illustration (photo libre de droits) utilisé à titre de maquette.",
p1: 'Je ne cherche pas à photographier ce qui se voit, mais ce qui se joue entre les gens, dans la seconde qui précède le geste.',
p2: 'Mon regard navigue entre trois territoires : la scène et son électricité collective, la ville et sa géométrie silencieuse, la rue et ses visages fugaces. Dans chacun, je traque la même chose — une vérité qui échappe à la pose.',
p3: "Le noir et blanc, le grain, le contraste : des outils pour révéler l'intention derrière l'image, jamais pour la maquiller.",
terrains: [
{
title: 'Scènes & Concerts',
desc: "L'instant électrique d'un show live, entre ombre et flash.",
},
{
title: 'Architectures Urbaines',
desc: 'Les villes comme grammaire de lignes et de perspectives.',
},
{
title: 'Instants Volés',
desc: "Les visages croisés, saisis avant qu'ils ne se dérobent.",
},
],
},
contact: {
eyebrow: 'Contact',
title: 'Donnons vie à vos projets visuels.',
emailNote: "(adresse fictive — cette boîte mail n'existe pas)",
demoTitle: 'Site de démonstration',
demoText:
"Ceci est une maquette : merci de ne pas envoyer de message à l'adresse ci-dessus, elle n'est pas surveillée.",
github: 'Voir le code',
docs: 'Voir la doc',
},
footer:
'Site de démonstration — photographies libres de droits (Unsplash),\npersonnes et lieux non affiliés à ce projet.\n© 2026 A. Morvan.',
lightboxClose: 'Fermer',
},
en: {
brandRole: 'Photographer',
nav: {
projets: 'Projects',
oeil: 'The Eye and the Intent',
contact: 'Contact',
},
hero: {
eyebrow: 'Portfolio',
title1: 'Capture the moment,',
title2: 'reveal the intent.',
subtitle:
'A photographer moving between live stages, urban architecture and stolen moments — a sensitive exploration of light and silence.',
cue: 'Discover',
},
categories: [
{
number: '01',
title: 'Live & Stage',
subtitle: 'The raw energy of concerts, captured in light and darkness.',
quote: 'Noise has a light you only see once.',
},
{
number: '02',
title: 'Urban Geometry',
subtitle: 'Lines, shadows and structure: the city as a graphic score.',
quote: 'The city draws what the eye dares not frame.',
},
{
number: '03',
title: 'Candid Moments',
subtitle: 'Scenes of life caught on the fly, between restraint and truth.',
quote: 'A stolen glance sometimes says more than a posed smile.',
},
],
oeil: {
eyebrow: 'Approach',
title: 'The Eye and the Intent.',
portraitAlt: 'Dark artistic portrait of the photographer',
aiNote: 'Illustrative portrait (royalty-free photo) used as a mockup.',
p1: "I don't try to photograph what is seen, but what unfolds between people, in the second before the gesture.",
p2: 'My eye moves across three territories: the stage and its collective electricity, the city and its silent geometry, the street and its fleeting faces. In each, I chase the same thing — a truth that escapes the pose.',
p3: 'Black and white, grain, contrast: tools to reveal the intent behind the image, never to disguise it.',
terrains: [
{
title: 'Stages & Concerts',
desc: 'The electric instant of a live show, between shadow and flash.',
},
{
title: 'Urban Architecture',
desc: 'Cities as a grammar of lines and perspective.',
},
{
title: 'Candid Moments',
desc: 'Faces crossed in passing, caught before they slip away.',
},
],
},
contact: {
eyebrow: 'Contact',
title: "Let's bring your visual projects to life.",
emailNote: "(fictional address — this mailbox doesn't exist)",
demoTitle: 'Demo website',
demoText: "This is a demo mockup — please don't send messages to the address above, it isn't monitored.",
github: 'View the code',
docs: 'View the docs',
},
footer:
'Demo website — royalty-free photographs (Unsplash),\npeople and places not affiliated with this project.\n© 2026 A. Morvan.',
lightboxClose: 'Close',
},
}
/**
* Builds a public asset URL prefixed with Vite's `BASE_URL`, so images resolve
* both locally (served at `/`) and under a GitHub Pages project subpath
* (e.g. `/demo-website/`).
* @param {string} name File name inside `public/images/`, e.g. `"Urban-01.jpg"`.
* @returns {string} The resolved URL, e.g. `"/images/Urban-01.jpg"`.
*/
const asset = (name) => `${import.meta.env.BASE_URL}images/${name}`
/**
* A gallery photo entry.
* @typedef {Object} Photo
* @property {string} url Resolved image URL (see {@link asset}).
* @property {string} aspect CSS aspect ratio, e.g. `"4/5"`.
* @property {LocalizedText} alt Bilingual alternative text.
*/
/**
* Gallery photos grouped by category. Order matters: it drives display order
* and the flat index used by the lightbox prev/next navigation.
* @type {{live: Photo[], urban: Photo[], portraits: Photo[]}}
*/
export const PHOTO_DATA = {
live: [
{
url: asset('LiveStage-01.jpg'),
aspect: '4/5',
alt: {
fr: 'Foule au concert sous les lumières de scène',
en: 'Crowd at a concert under stage lights',
},
},
{
url: asset('LiveStage-02.jpg'),
aspect: '4/3',
alt: {
fr: 'Scène de concert éclairée dans la nuit',
en: 'Concert stage lit up at night',
},
},
{
url: asset('LiveStage-03.jpg'),
aspect: '2/3',
alt: {
fr: 'Silhouettes du public en concert',
en: 'Silhouettes of the crowd at a concert',
},
},
{
url: asset('LiveStage-04.jpg'),
aspect: '1/1',
alt: {
fr: 'DJ sous projecteurs colorés',
en: 'DJ under colorful spotlights',
},
},
{
url: asset('LiveStage-05.jpg'),
aspect: '3/4',
alt: {
fr: 'Mains levées face aux lumières de scène',
en: 'Raised hands facing the stage lights',
},
},
{
url: asset('LiveStage-06.jpg'),
aspect: '4/3',
alt: {
fr: 'Public devant la scène, lumières vives',
en: 'Crowd in front of the stage, bright lights',
},
},
{
url: asset('LiveStage-07.jpg'),
aspect: '1/1',
alt: {
fr: 'Faisceaux laser au-dessus de la foule',
en: 'Laser beams sweeping over the crowd',
},
},
{
url: asset('LiveStage-08.jpg'),
aspect: '2/3',
alt: {
fr: 'Silhouettes dans un stade, contre-jour',
en: 'Silhouettes inside a stadium, backlit',
},
},
],
urban: [
{
url: asset('Urban-01.jpg'),
aspect: '2/3',
alt: {
fr: 'Architecture moderne en contre-plongée',
en: 'Modern architecture from a low angle',
},
},
{
url: asset('Urban-02.jpg'),
aspect: '1/1',
alt: {
fr: 'Lignes géométriques de la ville',
en: 'Geometric lines of the city',
},
},
{
url: asset('Urban-03.jpg'),
aspect: '4/5',
alt: {
fr: 'Façade architecturale contemporaine',
en: 'Contemporary architectural façade',
},
},
{
url: asset('Urban-04.jpg'),
aspect: '4/3',
alt: {
fr: 'Immeuble de verre et ombres portées',
en: 'Glass building and cast shadows',
},
},
{
url: asset('Urban-05.jpg'),
aspect: '3/4',
alt: {
fr: 'Tour moderne aux lignes épurées',
en: 'Modern tower with clean lines',
},
},
{
url: asset('Urban-06.jpg'),
aspect: '2/3',
alt: {
fr: 'Bâtiment gris en contre-plongée',
en: 'Gray building from a low angle',
},
},
{
url: asset('Urban-07.jpg'),
aspect: '4/3',
alt: {
fr: "Lignes d'un immeuble vues d'en bas",
en: 'Building lines seen from below',
},
},
{
url: asset('Urban-08.jpg'),
aspect: '1/1',
alt: {
fr: 'Façade de verre en niveaux de gris',
en: 'Grayscale glass façade',
},
},
],
portraits: [
{
url: asset('CandidMoment-01.jpg'),
aspect: '4/5',
alt: {
fr: 'Homme attendant un train, saisi sur le vif',
en: 'Man waiting for a train, caught candidly',
},
},
{
url: asset('CandidMoment-02.jpg'),
aspect: '1/1',
alt: {
fr: 'Silhouette dans un bus, ambiance argentique',
en: 'Silhouette on a bus, film-like mood',
},
},
{
url: asset('CandidMoment-03.jpg'),
aspect: '4/3',
alt: {
fr: 'Silhouette en marche dans la rue',
en: 'A figure walking down the street',
},
},
{
url: asset('CandidMoment-04.jpg'),
aspect: '2/3',
alt: {
fr: 'Silhouette descendant un escalier',
en: 'Silhouette walking down a stairway',
},
},
{
url: asset('CandidMoment-05.jpg'),
aspect: '3/4',
alt: {
fr: 'Silhouette féminine sur la route',
en: 'A figure walking along the road',
},
},
{
url: asset('CandidMoment-06.jpg'),
aspect: '4/3',
alt: {
fr: 'Passage piéton vu de haut, en niveaux de gris',
en: 'Pedestrian crossing seen from above, grayscale',
},
},
{
url: asset('CandidMoment-07.jpg'),
aspect: '2/3',
alt: {
fr: 'Silhouette sous la pluie, nuit urbaine',
en: 'Silhouette in the rain, urban night',
},
},
],
}
/**
* Warm-gold accent color used across the UI (nav underline, language pill,
* links, quote marks, logo).
* @type {string}
*/
export const ACCENT = '#c9a869'