Skip to content

slafleche/portfolio

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,143 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Stéphane LaFlèche’s Portfolio

Stack

Features

  • Accessibility in mind
  • Responsive
  • Localized copy (en/fr) backed by markdown + abbreviation shortcodes
  • Asset pipelines for fonts, images, videos, and favicons

Contact dialog debugging

  • For deeper wiring bugs, you can enable dev-only contact form logging by setting NEXT_PUBLIC_CONTACT_FORM_DEBUG=1 in your environment. With the flag on (and never in production), each submission logs [contact][form-debug] events in the browser console: a submit_attempt with the normalised payload snapshot and a submit_result with the flow submitStatus, server code, and a summary of invalid fields.

Helper Conventions

  • Require measurement helper values (from css-calipers) for anything that represents a scalar (lengths, angles, timings). Use measurement APIs (m, add, subtract, multiply, divide, round, floor, ceil, clamp, etc.) instead of CSS math functions (calc, min, max, clamp). Emit once you reach the style layer and rely on the shared helpers— paddings, margins, borders, boxShadow, etc.—to turn structured data into CSS.
  • When you need those symbolic values, define a dedicated type in src/styles/helpers/types.helper.ts instead of falling back to loose unions. SpacingKeyword is the reference example: it extracts the string-only portion of CSS_TYPES.Property.Margin and allows spacing.helper.ts to accept auto alongside real measurements without reopening the old MeasurementLike escape hatch.
  • Spacing helpers accept either structured intent objects or shorthand measurement/spacing keyword values. Use { all: ... }, { horizontal: ..., vertical: ... }, etc., whenever you need axis overrides, but never pass raw numbers or strings—the helper will throw unless the value is a css-calipers measurement instance or one of the approved spacing keywords.

Token Structure

  • Group reusable measurements/colors into pluralized helper bundles (e.g., paddings, borders, boxShadows) so styles can spread them straight into the helpers without rebuilding shorthands by hand.
  • When a component needs state-specific overrides (hover, focus, active, etc.), nest each state under its own key and reuse the same bundle names inside — hover.boxShadows, focus.borders, active.backgrounds, etc. Every override mirrors the base shape so swapping states never requires learning a new token layout.
  • Avoid leaking scalar shorthands (paddingInline, shadowColor, …) out of the token layer. Keep measurements grouped until the helper emits CSS in the style layer.

Localization — Abbreviation Shortcodes

  • Authors can mark abbreviations inline via [abbr:TERM] in any locale string. The locale loader resolves those tags before components render, so the UI sees trusted HTML (<abbr title="…">…</abbr>) rather than raw shortcodes.
  • Slugs are deterministic: we lowercase the term, preserve punctuation such as &, and prefix abbr-. Always reuse the canonical slug (e.g., [abbr:AI] everywhere) even when the rendered label changes per locale; translators can override label/definition inside the abbr-* entries.
  • Dev/CI builds throw when a slug is missing or its definition is empty; prod degrades gracefully by stripping the shortcode and logging once. Add the locale data (abbr-… entry) before using a new shortcode to avoid surprises.
  • The shortcode parser also runs across Markdown content and plain locale strings, so components stay “dumb”—they accept either plain strings or the branded LocaleRichText emitted by the loader without reimplementing parsing logic. Headings/titles automatically render the trusted HTML when present.

Linting & Guardrails

  • rules.yaml is the machine-readable source of truth for all hard rules (layering, helper usage, TODO cadence, forbidden properties). ESLint consumes it via eslint/rules.mjs, and the custom/forbidden-property rule surfaces friendly file:line:col errors (e.g., “Use backdropFilters.style()…”) instead of cryptic stack traces whenever a guarded property appears outside its helper.
  • The guardrail checks live in yarn lint:rules (via scripts/checkLintRules.mjs) and the pre-commit hook in scripts/pre-commit.sh. See that script for the branch-specific lint/publish checks.
  • Keep ai/ for narrative context, but treat rules.yaml + the automated checks as canonical—if you change the rules, update the YAML and the lint scripts in the same slice.

Setup

  • Run yarn install after cloning.
  • Run yarn generate (or yarn generate:staging) to build fonts/images/videos and locale artifacts.
  • Start the dev server with yarn dev.
  • For visual regression (Storybook + Chromatic + Playwright page renders), see visual-regression.md for the full pipeline and local/CI workflows.
  • When updating fonts.config.json, regenerate the Google Fonts URL bundle and optionally verify that each generated URL resolves:
    tsx scripts/generateFontUrls.mts
    VERIFY_FONT_URLS=true tsx scripts/generateFontUrls.mts
  • Enable the guardrail pre-commit hook so commits fail when locale markdown is missing or when the secret lookout finds potential emails/API keys in staged changes:
    cp scripts/pre-commit.sh .git/hooks/pre-commit
    chmod +x .git/hooks/pre-commit
    The hook always runs locale + secret checks and adds branch-specific checks; see scripts/pre-commit.sh for the exact command list.

Favicons pipeline

  • Maintain the master artwork in src/assets/SVG/faviconMaster.svg. Tag any shapes you want exported as the Safari mask with data-mask="true" and the Windows tile foreground with data-tile-fg="true". The generator will throw if those annotations are missing so we catch regressions early.
  • Run yarn generate:favicons whenever the master SVG or the favicon tokens change. The script resets public/favicons/, regenerates every hashed asset, and emits a TypeScript manifest under src/data/generated/favicons/manifest.favicons.gen.ts.
  • During development the generator also writes formatted .gen.svg artifacts for the tagged layers so the favicons debug page can preview them—they live in public/favicons/ and are replaced on every run. The directory is fully ignored by git, so only the source SVG lands in version control.

About

My portfolio

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors