fix: replace em dashes with hyphens in README.md, package.json, scene.ts, projects.ts, site.ts, BaseLayout.astro, about.astro, contact.astro, index.astro, [slug].astro, and work/index.astro
This commit is contained in:
@@ -1,13 +1,11 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Ambient space background: starfield, subtle nebula, and a slow-drifting,
|
||||
// slow-rotating asteroid. No scroll binding, no engine flames.
|
||||
// Slight pointer parallax. Respects prefers-reduced-motion.
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface SceneHandle {
|
||||
/** Kept for compatibility — no-op (no more impact/flame effect). */
|
||||
/** Kept for compatibility - no-op (no more impact/flame effect). */
|
||||
setImpact(value: number): void;
|
||||
destroy(): void;
|
||||
}
|
||||
@@ -64,7 +62,7 @@ export function initScene(canvas: HTMLCanvasElement): SceneHandle {
|
||||
);
|
||||
camera.position.set(0, 0, 18);
|
||||
|
||||
// ── Lighting (cold, consistent with Nova tokens) ───────────────────────────
|
||||
// Lighting (cold, consistent with Nova tokens)
|
||||
const ambient = new THREE.AmbientLight(0x16323a, 1.0);
|
||||
scene.add(ambient);
|
||||
const key = new THREE.DirectionalLight(COLORS.starCool, 0.9);
|
||||
@@ -74,7 +72,7 @@ export function initScene(canvas: HTMLCanvasElement): SceneHandle {
|
||||
rimLight.position.set(8, -3, 4);
|
||||
scene.add(rimLight);
|
||||
|
||||
// ── Starfield ──────────────────────────────────────────────────────────────
|
||||
// Starfield
|
||||
const STAR_COUNT = prefersReduced ? 700 : 1700;
|
||||
const starGeo = new THREE.BufferGeometry();
|
||||
const starPos = new Float32Array(STAR_COUNT * 3);
|
||||
@@ -106,7 +104,7 @@ export function initScene(canvas: HTMLCanvasElement): SceneHandle {
|
||||
const stars = new THREE.Points(starGeo, starMat);
|
||||
scene.add(stars);
|
||||
|
||||
// ── Nebula (soft sprites, pushed far into the background) ──────────────────
|
||||
// Nebula (soft sprites, pushed far into the background)
|
||||
const nebula = new THREE.Group();
|
||||
const nebTex = radialTexture('rgba(40,129,129,0.55)');
|
||||
[
|
||||
@@ -129,7 +127,7 @@ export function initScene(canvas: HTMLCanvasElement): SceneHandle {
|
||||
});
|
||||
scene.add(nebula);
|
||||
|
||||
// ── Asteroid (cold rock, subtle halo) ──────────────────────────────────────
|
||||
// Asteroid (cold rock, subtle halo)
|
||||
const asteroid = new THREE.Group();
|
||||
const rockGeo = new THREE.IcosahedronGeometry(1.9, 2);
|
||||
const pos = rockGeo.attributes.position as THREE.BufferAttribute;
|
||||
@@ -171,7 +169,7 @@ export function initScene(canvas: HTMLCanvasElement): SceneHandle {
|
||||
asteroid.position.set(6.5, 4.5, -2);
|
||||
scene.add(asteroid);
|
||||
|
||||
// ── State & loop ───────────────────────────────────────────────────────────
|
||||
// State & loop
|
||||
const pointer = { x: 0, y: 0, tx: 0, ty: 0 };
|
||||
let running = true;
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// Projects — real content. Edit freely.
|
||||
// Projects - real content. Edit freely.
|
||||
// `icon` matches a simple-icons-astro component (using PascalCase elsewhere).
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
export type ProjectStatus = 'live' | 'maintenu' | 'archive' | 'r&d';
|
||||
|
||||
@@ -32,8 +30,8 @@ export const projects: Project[] = [
|
||||
slug: 'nova-design-system',
|
||||
designation: '01',
|
||||
title: 'Nova Design System',
|
||||
tagline: 'Astro component library — tokens, accessibility, npm distribution.',
|
||||
period: '2026 — ongoing',
|
||||
tagline: 'Astro component library - tokens, accessibility, npm distribution.',
|
||||
period: '2026 - ongoing',
|
||||
role: 'Author · maintainer',
|
||||
status: 'maintenu',
|
||||
featured: true,
|
||||
@@ -65,7 +63,7 @@ export const projects: Project[] = [
|
||||
designation: '02',
|
||||
title: 'Self-hosted Infrastructure & Deployment',
|
||||
tagline: 'Containerized services, CI/CD, and secured ingress on a fully controlled infrastructure.',
|
||||
period: '2025 — ongoing',
|
||||
period: '2025 - ongoing',
|
||||
role: 'Design & operations',
|
||||
status: 'live',
|
||||
featured: true,
|
||||
@@ -120,9 +118,9 @@ export const projects: Project[] = [
|
||||
{
|
||||
slug: 'rust-file-organizer',
|
||||
designation: '04',
|
||||
title: 'File Organizer — Java to Rust',
|
||||
title: 'File Organizer - Java to Rust',
|
||||
tagline: 'File sorting tool, currently being ported from Java to Rust.',
|
||||
period: '2025 — ongoing',
|
||||
period: '2025 - ongoing',
|
||||
role: 'Development',
|
||||
status: 'r&d',
|
||||
featured: false,
|
||||
@@ -147,7 +145,7 @@ export const projects: Project[] = [
|
||||
designation: '05',
|
||||
title: 'LLM Training & Inference',
|
||||
tagline: 'Small language model trained on a Reddit conversation dataset.',
|
||||
period: '2025 — ongoing',
|
||||
period: '2025 - ongoing',
|
||||
role: 'Development',
|
||||
status: 'r&d',
|
||||
featured: false,
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ export const site = {
|
||||
domain: "louis-potevin.dev",
|
||||
location: "Limoges · Nouvelle-Aquitaine",
|
||||
// Job Search
|
||||
availability: "Permanent contract (CDI) — September 2026",
|
||||
availability: "Permanent contract (CDI) - September 2026",
|
||||
mobility: "Anywhere in France, on-site or remote",
|
||||
// Contact
|
||||
email: "contact@louis-potevin.dev",
|
||||
|
||||
@@ -15,7 +15,7 @@ export interface Props {
|
||||
}
|
||||
|
||||
const {
|
||||
title = 'Louis Potevin — Full-stack Developer (front, back, web)',
|
||||
title = 'Louis Potevin - Full-stack Developer (front, back, web)',
|
||||
description = "Louis Potevin, full-stack web developer: front-end, back-end, TypeScript, Astro, Node. Available for a permanent contract (CDI) starting September 2026, anywhere in France or remote.",
|
||||
keywords = [],
|
||||
} = Astro.props;
|
||||
@@ -91,7 +91,7 @@ const personLd = {
|
||||
const siteLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'WebSite',
|
||||
name: `${site.name} — Portfolio`,
|
||||
name: `${site.name} - Portfolio`,
|
||||
url: Astro.site?.href ?? 'https://louis-potevin.dev',
|
||||
inLanguage: ['en-US', 'fr-FR'],
|
||||
};
|
||||
@@ -113,7 +113,7 @@ const siteLd = {
|
||||
<link rel="canonical" href={canonical} />
|
||||
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:site_name" content={`${site.name} — Portfolio`} />
|
||||
<meta property="og:site_name" content={`${site.name} - Portfolio`} />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
<meta property="og:locale:alternate" content="fr_FR" />
|
||||
<meta property="og:title" content={title} />
|
||||
|
||||
@@ -16,23 +16,23 @@ import {
|
||||
import { Send, Mail } from '@lucide/astro';
|
||||
import { site } from '../data/site';
|
||||
|
||||
const title = 'About — Louis Potevin, full-stack web developer / développeur full-stack';
|
||||
const title = 'About - Louis Potevin, full-stack web developer / développeur full-stack';
|
||||
const description =
|
||||
"Louis Potevin, full-stack web developer with a BUT MMI degree (DWDI track). 18 months of professional experience at Legrand France. Available for a permanent contract (CDI), anywhere in France or remote.";
|
||||
|
||||
const parcours = [
|
||||
{
|
||||
year: '2024 — 2026',
|
||||
year: '2024 - 2026',
|
||||
title: 'Professional Experience · Legrand France',
|
||||
body: "18 months total: 12 weeks of internship, 1 month on a fixed-term contract (CDD), followed by 1 year of work-study apprenticeship. Web development on a production-ready internal corporate application.",
|
||||
},
|
||||
{
|
||||
year: '2024 — 2026',
|
||||
title: 'BUT MMI — DWDI Track · IUT du Limousin',
|
||||
year: '2024 - 2026',
|
||||
title: 'BUT MMI - DWDI Track · IUT du Limousin',
|
||||
body: "Multimedia and Internet Job Degrees (Métiers du Multimédia et de l'Internet), specializing in Web Development and Interactive Devices (DWDI). Degree completed in 2026.",
|
||||
},
|
||||
{
|
||||
year: '2026 — ongoing',
|
||||
year: '2026 - ongoing',
|
||||
title: 'Personal Projects',
|
||||
body: "Designing an open-source design system published on npm, managing a self-hosted server infrastructure, and building system tools with Rust and Python.",
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@ import { Send, Mail } from '@lucide/astro';
|
||||
import BrandLinkedin from '../components/BrandLinkedin.astro';
|
||||
import { site } from '../data/site';
|
||||
|
||||
const title = 'Contact — Louis Potevin';
|
||||
const title = 'Contact - Louis Potevin';
|
||||
const description =
|
||||
'Contact Louis Potevin, full-stack web developer. Available for permanent positions (CDI) starting September 2026, anywhere in France or remote.';
|
||||
|
||||
@@ -46,7 +46,7 @@ const directLinks = [
|
||||
</section>
|
||||
|
||||
<div class="layout">
|
||||
{/* ── Form (Nova components) ── */}
|
||||
{/* Form (Nova components) */}
|
||||
<section class="formWrap" aria-labelledby="form-title">
|
||||
<h2 id="form-title" class="formWrap__title">Message</h2>
|
||||
|
||||
@@ -95,7 +95,7 @@ const directLinks = [
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ── Direct Links ── */}
|
||||
{/* Direct Links */}
|
||||
<aside class="direct" aria-label="Direct channels">
|
||||
<p class="direct__title">Direct Channels</p>
|
||||
<ul class="direct__list">
|
||||
@@ -140,7 +140,7 @@ const directLinks = [
|
||||
const subject = subjectEl?.textContent?.trim() || 'Inquiry';
|
||||
const message = val('cf-message');
|
||||
|
||||
const body = `${message}\n\n— ${name}${from ? ` (${from})` : ''}`;
|
||||
const body = `${message}\n\n- ${name}${from ? ` (${from})` : ''}`;
|
||||
const href = `mailto:${email}?subject=${encodeURIComponent(
|
||||
'[Portfolio] ' + subject,
|
||||
)}&body=${encodeURIComponent(body)}`;
|
||||
@@ -289,7 +289,7 @@ const directLinks = [
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ── RESPONSIVE ── */
|
||||
/* RESPONSIVE */
|
||||
@media (max-width: 820px) {
|
||||
.layout { grid-template-columns: 1fr; gap: var(--nds-spacing-xl); }
|
||||
.direct { position: static; }
|
||||
|
||||
+15
-15
@@ -13,7 +13,7 @@ import { featuredProjects } from '../data/projects';
|
||||
const capabilities = [
|
||||
{
|
||||
label: 'Front-end',
|
||||
body: 'Sleek and accessible interfaces built with Astro, TypeScript, and Sass — all the way to an in-house design system.',
|
||||
body: 'Sleek and accessible interfaces built with Astro, TypeScript, and Sass - all the way to an in-house design system.',
|
||||
},
|
||||
{
|
||||
label: 'Back-end',
|
||||
@@ -42,7 +42,7 @@ const instruments = [
|
||||
---
|
||||
|
||||
<BaseLayout>
|
||||
{/* ─────────────────────────── HERO ─────────────────────────── */}
|
||||
{/* HERO */}
|
||||
<section class="hero" aria-labelledby="hero-title">
|
||||
<div class="hero__status">
|
||||
<span class="hero__dot" aria-hidden="true"></span>
|
||||
@@ -55,7 +55,7 @@ const instruments = [
|
||||
</h1>
|
||||
|
||||
<p class="hero__lede">
|
||||
I design and develop web applications from end to end — from front-end
|
||||
I design and develop web applications from end to end - from front-end
|
||||
to back-end and production deployment. I am equally comfortable working
|
||||
on the user interface as I am with the services and infrastructure running them.
|
||||
</p>
|
||||
@@ -79,7 +79,7 @@ const instruments = [
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ─────────────────────── PROFILE / CAPABILITIES ─────────────────────── */}
|
||||
{/* PROFILE / CAPABILITIES */}
|
||||
<section class="band" aria-labelledby="profile-title">
|
||||
<Eyebrow index="01" label="Profile" />
|
||||
<div class="band__split">
|
||||
@@ -93,7 +93,7 @@ const instruments = [
|
||||
on npm, a self-hosted infrastructure, and tools built with Rust and Python.
|
||||
</p>
|
||||
<p>
|
||||
What drives me: mastering the entire cycle — the component you look at,
|
||||
What drives me: mastering the entire cycle - the component you look at,
|
||||
the service that delivers it, and the CI that deploys it. This website is
|
||||
a prime example, built entirely on top of my own design system.
|
||||
</p>
|
||||
@@ -112,7 +112,7 @@ const instruments = [
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
{/* ─────────────────────────── FEATURED PROJECTS ─────────────────────────── */}
|
||||
{/* FEATURED PROJECTS */}
|
||||
<section class="band" aria-labelledby="proj-title">
|
||||
<Eyebrow index="02" label="Featured projects" />
|
||||
<div class="band__head">
|
||||
@@ -126,7 +126,7 @@ const instruments = [
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ─────────────────────────── STACK ─────────────────────────── */}
|
||||
{/* STACK */}
|
||||
<section class="band" aria-labelledby="stack-title">
|
||||
<Eyebrow index="03" label="Tech stack" />
|
||||
<h2 id="stack-title" class="band__lead band__lead--center">
|
||||
@@ -146,9 +146,9 @@ const instruments = [
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
{/* ─────────────────────────── CONTACT CTA ─────────────────────────── */}
|
||||
{/* CONTACT CTA */}
|
||||
<section class="closing" aria-labelledby="cta-title">
|
||||
<p class="closing__eyebrow">Available — {site.availability}</p>
|
||||
<p class="closing__eyebrow">Available - {site.availability}</p>
|
||||
<h2 id="cta-title" class="closing__title">Let's talk!</h2>
|
||||
<p class="closing__text">
|
||||
I am looking for a full-stack permanent position (CDI) starting September 2026.
|
||||
@@ -170,7 +170,7 @@ const instruments = [
|
||||
<style lang="scss">
|
||||
@use 'styles/type' as *;
|
||||
|
||||
/* ── HERO ── */
|
||||
/* HERO */
|
||||
.hero {
|
||||
min-height: clamp(520px, 80vh, 820px);
|
||||
display: flex;
|
||||
@@ -247,7 +247,7 @@ const instruments = [
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
/* ── SECTION BANDS ── */
|
||||
/* SECTION BANDS */
|
||||
.band { padding: var(--nds-spacing-2xl) 0; }
|
||||
.band__lead {
|
||||
@include text-3xl;
|
||||
@@ -295,7 +295,7 @@ const instruments = [
|
||||
&:hover { color: var(--nds-accent); }
|
||||
}
|
||||
|
||||
/* ── Capabilities ── */
|
||||
/* Capabilities */
|
||||
.caps {
|
||||
list-style: none;
|
||||
margin: var(--nds-spacing-2xl) 0 0;
|
||||
@@ -330,7 +330,7 @@ const instruments = [
|
||||
gap: var(--nds-spacing-lg);
|
||||
}
|
||||
|
||||
/* ── INSTRUMENTS ── */
|
||||
/* INSTRUMENTS */
|
||||
.instruments {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
@@ -364,7 +364,7 @@ const instruments = [
|
||||
color: var(--nds-neutral);
|
||||
}
|
||||
|
||||
/* ── CLOSING ── */
|
||||
/* CLOSING */
|
||||
.closing {
|
||||
text-align: center;
|
||||
padding: var(--nds-spacing-3xl) 0;
|
||||
@@ -403,7 +403,7 @@ const instruments = [
|
||||
.hero__dot { animation: none; }
|
||||
}
|
||||
|
||||
/* ── RESPONSIVE ── */
|
||||
/* RESPONSIVE */
|
||||
@media (max-width: 900px) {
|
||||
.band__split { grid-template-columns: 1fr; gap: var(--nds-spacing-lg); }
|
||||
.caps { grid-template-columns: 1fr; }
|
||||
|
||||
@@ -24,7 +24,7 @@ interface Props {
|
||||
}
|
||||
const { project } = Astro.props;
|
||||
const status = statusMeta[project.status];
|
||||
const title = `${project.title} — Louis Potevin`;
|
||||
const title = `${project.title} - Louis Potevin`;
|
||||
---
|
||||
|
||||
<BaseLayout title={title} description={project.tagline}>
|
||||
@@ -115,7 +115,7 @@ const title = `${project.title} — Louis Potevin`;
|
||||
project.links.length === 0 && (
|
||||
<div class="panel panel--muted">
|
||||
<p class="panel__note">
|
||||
Internal or private project — no public link available.
|
||||
Internal or private project - no public link available.
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
@@ -297,7 +297,7 @@ const title = `${project.title} — Louis Potevin`;
|
||||
border-top: var(--nds-border-width-thin) solid var(--nds-border);
|
||||
}
|
||||
|
||||
/* ── RESPONSIVE ── */
|
||||
/* RESPONSIVE */
|
||||
@media (max-width: 820px) {
|
||||
.detail__grid { grid-template-columns: 1fr; gap: var(--nds-spacing-xl); }
|
||||
.detail__side { position: static; }
|
||||
|
||||
@@ -5,7 +5,7 @@ import ProjectCard from '../../components/ProjectCard.astro';
|
||||
import { Breadcrumb, BreadcrumbItem } from '@unkn0wndo3s/nova-design-system';
|
||||
import { projects } from '../../data/projects';
|
||||
|
||||
const title = 'Projects — Louis Potevin, full-stack web developer / développeur full-stack';
|
||||
const title = 'Projects - Louis Potevin, full-stack web developer / développeur full-stack';
|
||||
const description =
|
||||
'Projects by Louis Potevin: Astro design system, self-hosted infrastructure, systems tools in Rust, and LLM explorations. Full-stack web developer.';
|
||||
---
|
||||
@@ -20,7 +20,7 @@ const description =
|
||||
<Eyebrow index="//" label="All projects" />
|
||||
<h1 class="head__title">Projects</h1>
|
||||
<p class="head__lede">
|
||||
A showcase of everything I build — from business software running in production to
|
||||
A showcase of everything I build - from business software running in production to
|
||||
the infrastructure supporting it, alongside my personal tools.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user