2026-02-14 10:30:27 +01:00
|
|
|
/**
|
|
|
|
|
* About page — Bauhaus / Leica minimalist layout.
|
|
|
|
|
* Reads content from content/about.md (frontmatter + markdown body).
|
|
|
|
|
*/
|
|
|
|
|
|
2026-04-28 11:16:18 +00:00
|
|
|
import { promises as fsPromises } from 'fs';
|
2026-02-14 10:30:27 +01:00
|
|
|
import { join } from 'path';
|
2026-03-08 21:12:52 +01:00
|
|
|
import yaml from 'js-yaml';
|
2026-02-14 10:30:27 +01:00
|
|
|
import Image from 'next/image';
|
security: add Trivy container scan to Docker publish workflow (#399)
* feat(admin): add backup manager UI with 1-click restore
* feat(admin): collapse older backup entries by default
* fix(theme): isolate admin layout, instant DOM theme updates, and add Light/Dark mode toggle
* feat(admin): replace text controls for Photo Frame and Hero Style with visual preview cards
* fix(admin): define missing CSS rules for button system (.btn, .preset-btn)
* feat(admin): redesign theme settings with segmented mode toggle, accent color swatches, and custom iOS-style toggle cards
* feat(admin): upgrade all settings tabs with visual grid previews, Google SEO snippet preview, and toggle cards
* feat(admin): overhaul Pages Builder UX with slide-over drawer, card hover badges, real-time search, and floating save bar
* fix(admin): remove leftover dangling syntax snippet in PageBuilder.tsx
* fix(admin): add position: relative to subpage-tile so hover overlay is contained inside the tile
* style(admin): replace all emojis with clean Leica-style vector SVG icons
* fix(types): extend IconProps with SVGProps to allow style prop on Leica SVG icons
* feat(admin): add subpage live-preview, privacy analytics, and asset protection settings
* fix(typecheck): fix AlbumEntry property access in subpage drawer preview mode
* fix(types): fix ImmichAlbumInfo property names thumbnailAssetId and albumName in PageBuilder.tsx
* fix(types): add protection and watermark optional properties to AppConfig interface
* feat(settings): add toggle for disabling analytics tracking (defaults to enabled)
* feat(ux): show status banner when analytics tracking is disabled + add live sync indicator
* feat(watermark): render customizable watermark overlay on Lightbox images + rename section to Portfolio Features & Modules
* fix(types): import type LightboxWatermark in PhotoGrid.tsx
* fix(types): destructure watermark prop in PhotoGrid function signature
* feat(seo): add configurable subpage title template and metadata descriptions
* feat(seo): add generateMetadata to about page for title template support
* feat(proofing): add client proofing, favorites selection, compact URL bitmasking, and export modal
* feat(essay): add Photo Essay storytelling mode with RSC markdown parser and fullbleed/pair layouts
* feat(subpages): add page enabled toggle to deactivate subpages without deleting them
* feat(admin): add visual essay block builder for photo essay storytelling pages
* security: add Trivy container scan to Docker publish workflow
Scans the built image for CRITICAL/HIGH CVEs on every release and
uploads results to the GitHub Security tab. Non-blocking for now
(exit-code 0) so releases aren't gated on findings. Also documents
the scan and existing Dependabot coverage in the README.
---------
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
2026-08-07 11:08:04 +02:00
|
|
|
import type { Metadata } from 'next';
|
2026-02-14 10:30:27 +01:00
|
|
|
import { imageUrl, assetPlaceholder } from '@/lib/urls';
|
2026-10-02 18:14:23 +02:00
|
|
|
import { ogImageUrl } from '@/lib/ogImage';
|
2026-02-14 10:30:27 +01:00
|
|
|
import { immich } from '@/lib/immich';
|
2026-08-14 21:19:54 +02:00
|
|
|
import { getConfig } from '@/lib/config';
|
2026-08-23 23:18:14 +02:00
|
|
|
import { getServerDictionary } from '@/lib/i18n/server';
|
2026-08-14 21:19:54 +02:00
|
|
|
import { notFound } from 'next/navigation';
|
2026-09-22 14:12:13 +02:00
|
|
|
import { BackLink } from '@/components/BackLink';
|
2026-02-14 10:30:27 +01:00
|
|
|
import './about.css';
|
|
|
|
|
|
2026-02-15 22:23:16 +01:00
|
|
|
export const dynamic = 'force-dynamic';
|
|
|
|
|
|
2026-02-14 10:30:27 +01:00
|
|
|
interface AboutFrontmatter {
|
2026-02-14 11:47:26 +01:00
|
|
|
portrait?: string;
|
|
|
|
|
name?: string;
|
|
|
|
|
location?: string;
|
|
|
|
|
gear?: string[];
|
2026-02-14 10:30:27 +01:00
|
|
|
}
|
|
|
|
|
|
2026-04-28 11:16:18 +00:00
|
|
|
async function getAboutContent() {
|
2026-03-08 20:53:45 +01:00
|
|
|
const filePath = join(process.cwd(), 'content', 'about.md');
|
2026-04-28 11:16:18 +00:00
|
|
|
let raw: string;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
raw = await fsPromises.readFile(filePath, 'utf-8');
|
|
|
|
|
} catch {
|
2026-03-08 20:53:45 +01:00
|
|
|
return { meta: {} as AboutFrontmatter, body: '' };
|
|
|
|
|
}
|
2026-03-08 21:12:52 +01:00
|
|
|
|
|
|
|
|
let meta = {} as AboutFrontmatter;
|
|
|
|
|
let body = raw;
|
|
|
|
|
|
|
|
|
|
const match = raw.match(/^(?:---\r?\n)([\s\S]*?)(?:\r?\n---\r?\n)([\s\S]*)$/);
|
|
|
|
|
if (match) {
|
|
|
|
|
try {
|
|
|
|
|
meta = (yaml.load(match[1]) || {}) as AboutFrontmatter;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('Failed to parse about.md frontmatter', e);
|
|
|
|
|
}
|
|
|
|
|
body = match[2];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return { meta, body: body.trim() };
|
2026-02-14 10:30:27 +01:00
|
|
|
}
|
|
|
|
|
|
security: add Trivy container scan to Docker publish workflow (#399)
* feat(admin): add backup manager UI with 1-click restore
* feat(admin): collapse older backup entries by default
* fix(theme): isolate admin layout, instant DOM theme updates, and add Light/Dark mode toggle
* feat(admin): replace text controls for Photo Frame and Hero Style with visual preview cards
* fix(admin): define missing CSS rules for button system (.btn, .preset-btn)
* feat(admin): redesign theme settings with segmented mode toggle, accent color swatches, and custom iOS-style toggle cards
* feat(admin): upgrade all settings tabs with visual grid previews, Google SEO snippet preview, and toggle cards
* feat(admin): overhaul Pages Builder UX with slide-over drawer, card hover badges, real-time search, and floating save bar
* fix(admin): remove leftover dangling syntax snippet in PageBuilder.tsx
* fix(admin): add position: relative to subpage-tile so hover overlay is contained inside the tile
* style(admin): replace all emojis with clean Leica-style vector SVG icons
* fix(types): extend IconProps with SVGProps to allow style prop on Leica SVG icons
* feat(admin): add subpage live-preview, privacy analytics, and asset protection settings
* fix(typecheck): fix AlbumEntry property access in subpage drawer preview mode
* fix(types): fix ImmichAlbumInfo property names thumbnailAssetId and albumName in PageBuilder.tsx
* fix(types): add protection and watermark optional properties to AppConfig interface
* feat(settings): add toggle for disabling analytics tracking (defaults to enabled)
* feat(ux): show status banner when analytics tracking is disabled + add live sync indicator
* feat(watermark): render customizable watermark overlay on Lightbox images + rename section to Portfolio Features & Modules
* fix(types): import type LightboxWatermark in PhotoGrid.tsx
* fix(types): destructure watermark prop in PhotoGrid function signature
* feat(seo): add configurable subpage title template and metadata descriptions
* feat(seo): add generateMetadata to about page for title template support
* feat(proofing): add client proofing, favorites selection, compact URL bitmasking, and export modal
* feat(essay): add Photo Essay storytelling mode with RSC markdown parser and fullbleed/pair layouts
* feat(subpages): add page enabled toggle to deactivate subpages without deleting them
* feat(admin): add visual essay block builder for photo essay storytelling pages
* security: add Trivy container scan to Docker publish workflow
Scans the built image for CRITICAL/HIGH CVEs on every release and
uploads results to the GitHub Security tab. Non-blocking for now
(exit-code 0) so releases aren't gated on findings. Also documents
the scan and existing Dependabot coverage in the README.
---------
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
2026-08-07 11:08:04 +02:00
|
|
|
export async function generateMetadata(): Promise<Metadata> {
|
|
|
|
|
const { meta, body } = await getAboutContent();
|
2026-08-23 23:18:14 +02:00
|
|
|
const t = getServerDictionary();
|
|
|
|
|
const title = meta.name ? t.about.metaTitle(meta.name) : t.about.title;
|
security: add Trivy container scan to Docker publish workflow (#399)
* feat(admin): add backup manager UI with 1-click restore
* feat(admin): collapse older backup entries by default
* fix(theme): isolate admin layout, instant DOM theme updates, and add Light/Dark mode toggle
* feat(admin): replace text controls for Photo Frame and Hero Style with visual preview cards
* fix(admin): define missing CSS rules for button system (.btn, .preset-btn)
* feat(admin): redesign theme settings with segmented mode toggle, accent color swatches, and custom iOS-style toggle cards
* feat(admin): upgrade all settings tabs with visual grid previews, Google SEO snippet preview, and toggle cards
* feat(admin): overhaul Pages Builder UX with slide-over drawer, card hover badges, real-time search, and floating save bar
* fix(admin): remove leftover dangling syntax snippet in PageBuilder.tsx
* fix(admin): add position: relative to subpage-tile so hover overlay is contained inside the tile
* style(admin): replace all emojis with clean Leica-style vector SVG icons
* fix(types): extend IconProps with SVGProps to allow style prop on Leica SVG icons
* feat(admin): add subpage live-preview, privacy analytics, and asset protection settings
* fix(typecheck): fix AlbumEntry property access in subpage drawer preview mode
* fix(types): fix ImmichAlbumInfo property names thumbnailAssetId and albumName in PageBuilder.tsx
* fix(types): add protection and watermark optional properties to AppConfig interface
* feat(settings): add toggle for disabling analytics tracking (defaults to enabled)
* feat(ux): show status banner when analytics tracking is disabled + add live sync indicator
* feat(watermark): render customizable watermark overlay on Lightbox images + rename section to Portfolio Features & Modules
* fix(types): import type LightboxWatermark in PhotoGrid.tsx
* fix(types): destructure watermark prop in PhotoGrid function signature
* feat(seo): add configurable subpage title template and metadata descriptions
* feat(seo): add generateMetadata to about page for title template support
* feat(proofing): add client proofing, favorites selection, compact URL bitmasking, and export modal
* feat(essay): add Photo Essay storytelling mode with RSC markdown parser and fullbleed/pair layouts
* feat(subpages): add page enabled toggle to deactivate subpages without deleting them
* feat(admin): add visual essay block builder for photo essay storytelling pages
* security: add Trivy container scan to Docker publish workflow
Scans the built image for CRITICAL/HIGH CVEs on every release and
uploads results to the GitHub Security tab. Non-blocking for now
(exit-code 0) so releases aren't gated on findings. Also documents
the scan and existing Dependabot coverage in the README.
---------
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
2026-08-07 11:08:04 +02:00
|
|
|
const description = body ? body.slice(0, 160).replace(/\s+/g, ' ').trim() : undefined;
|
2026-10-02 18:14:23 +02:00
|
|
|
// A page's openGraph replaces the layout's whole, images included, so
|
|
|
|
|
// leaving them out shared /about with no picture at all. The portrait is the
|
|
|
|
|
// obvious one (it is a published asset); without it, the generated card.
|
|
|
|
|
// The portrait's asset for its edit marker (#831), from the cache the page
|
|
|
|
|
// body reads as well.
|
|
|
|
|
const portraitAsset = meta.portrait
|
|
|
|
|
? await immich.getAssetInfo(meta.portrait).catch(() => null)
|
|
|
|
|
: null;
|
|
|
|
|
const ogImage = meta.portrait
|
|
|
|
|
? imageUrl(portraitAsset ?? meta.portrait, 'preview')
|
|
|
|
|
: ogImageUrl(title);
|
security: add Trivy container scan to Docker publish workflow (#399)
* feat(admin): add backup manager UI with 1-click restore
* feat(admin): collapse older backup entries by default
* fix(theme): isolate admin layout, instant DOM theme updates, and add Light/Dark mode toggle
* feat(admin): replace text controls for Photo Frame and Hero Style with visual preview cards
* fix(admin): define missing CSS rules for button system (.btn, .preset-btn)
* feat(admin): redesign theme settings with segmented mode toggle, accent color swatches, and custom iOS-style toggle cards
* feat(admin): upgrade all settings tabs with visual grid previews, Google SEO snippet preview, and toggle cards
* feat(admin): overhaul Pages Builder UX with slide-over drawer, card hover badges, real-time search, and floating save bar
* fix(admin): remove leftover dangling syntax snippet in PageBuilder.tsx
* fix(admin): add position: relative to subpage-tile so hover overlay is contained inside the tile
* style(admin): replace all emojis with clean Leica-style vector SVG icons
* fix(types): extend IconProps with SVGProps to allow style prop on Leica SVG icons
* feat(admin): add subpage live-preview, privacy analytics, and asset protection settings
* fix(typecheck): fix AlbumEntry property access in subpage drawer preview mode
* fix(types): fix ImmichAlbumInfo property names thumbnailAssetId and albumName in PageBuilder.tsx
* fix(types): add protection and watermark optional properties to AppConfig interface
* feat(settings): add toggle for disabling analytics tracking (defaults to enabled)
* feat(ux): show status banner when analytics tracking is disabled + add live sync indicator
* feat(watermark): render customizable watermark overlay on Lightbox images + rename section to Portfolio Features & Modules
* fix(types): import type LightboxWatermark in PhotoGrid.tsx
* fix(types): destructure watermark prop in PhotoGrid function signature
* feat(seo): add configurable subpage title template and metadata descriptions
* feat(seo): add generateMetadata to about page for title template support
* feat(proofing): add client proofing, favorites selection, compact URL bitmasking, and export modal
* feat(essay): add Photo Essay storytelling mode with RSC markdown parser and fullbleed/pair layouts
* feat(subpages): add page enabled toggle to deactivate subpages without deleting them
* feat(admin): add visual essay block builder for photo essay storytelling pages
* security: add Trivy container scan to Docker publish workflow
Scans the built image for CRITICAL/HIGH CVEs on every release and
uploads results to the GitHub Security tab. Non-blocking for now
(exit-code 0) so releases aren't gated on findings. Also documents
the scan and existing Dependabot coverage in the README.
---------
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
2026-08-07 11:08:04 +02:00
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
title,
|
|
|
|
|
description,
|
|
|
|
|
openGraph: {
|
|
|
|
|
title,
|
|
|
|
|
description,
|
2026-10-02 18:14:23 +02:00
|
|
|
images: [ogImage],
|
security: add Trivy container scan to Docker publish workflow (#399)
* feat(admin): add backup manager UI with 1-click restore
* feat(admin): collapse older backup entries by default
* fix(theme): isolate admin layout, instant DOM theme updates, and add Light/Dark mode toggle
* feat(admin): replace text controls for Photo Frame and Hero Style with visual preview cards
* fix(admin): define missing CSS rules for button system (.btn, .preset-btn)
* feat(admin): redesign theme settings with segmented mode toggle, accent color swatches, and custom iOS-style toggle cards
* feat(admin): upgrade all settings tabs with visual grid previews, Google SEO snippet preview, and toggle cards
* feat(admin): overhaul Pages Builder UX with slide-over drawer, card hover badges, real-time search, and floating save bar
* fix(admin): remove leftover dangling syntax snippet in PageBuilder.tsx
* fix(admin): add position: relative to subpage-tile so hover overlay is contained inside the tile
* style(admin): replace all emojis with clean Leica-style vector SVG icons
* fix(types): extend IconProps with SVGProps to allow style prop on Leica SVG icons
* feat(admin): add subpage live-preview, privacy analytics, and asset protection settings
* fix(typecheck): fix AlbumEntry property access in subpage drawer preview mode
* fix(types): fix ImmichAlbumInfo property names thumbnailAssetId and albumName in PageBuilder.tsx
* fix(types): add protection and watermark optional properties to AppConfig interface
* feat(settings): add toggle for disabling analytics tracking (defaults to enabled)
* feat(ux): show status banner when analytics tracking is disabled + add live sync indicator
* feat(watermark): render customizable watermark overlay on Lightbox images + rename section to Portfolio Features & Modules
* fix(types): import type LightboxWatermark in PhotoGrid.tsx
* fix(types): destructure watermark prop in PhotoGrid function signature
* feat(seo): add configurable subpage title template and metadata descriptions
* feat(seo): add generateMetadata to about page for title template support
* feat(proofing): add client proofing, favorites selection, compact URL bitmasking, and export modal
* feat(essay): add Photo Essay storytelling mode with RSC markdown parser and fullbleed/pair layouts
* feat(subpages): add page enabled toggle to deactivate subpages without deleting them
* feat(admin): add visual essay block builder for photo essay storytelling pages
* security: add Trivy container scan to Docker publish workflow
Scans the built image for CRITICAL/HIGH CVEs on every release and
uploads results to the GitHub Security tab. Non-blocking for now
(exit-code 0) so releases aren't gated on findings. Also documents
the scan and existing Dependabot coverage in the README.
---------
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
2026-08-07 11:08:04 +02:00
|
|
|
},
|
|
|
|
|
twitter: {
|
|
|
|
|
card: 'summary_large_image',
|
|
|
|
|
title,
|
|
|
|
|
description,
|
2026-10-02 18:14:23 +02:00
|
|
|
images: [ogImage],
|
security: add Trivy container scan to Docker publish workflow (#399)
* feat(admin): add backup manager UI with 1-click restore
* feat(admin): collapse older backup entries by default
* fix(theme): isolate admin layout, instant DOM theme updates, and add Light/Dark mode toggle
* feat(admin): replace text controls for Photo Frame and Hero Style with visual preview cards
* fix(admin): define missing CSS rules for button system (.btn, .preset-btn)
* feat(admin): redesign theme settings with segmented mode toggle, accent color swatches, and custom iOS-style toggle cards
* feat(admin): upgrade all settings tabs with visual grid previews, Google SEO snippet preview, and toggle cards
* feat(admin): overhaul Pages Builder UX with slide-over drawer, card hover badges, real-time search, and floating save bar
* fix(admin): remove leftover dangling syntax snippet in PageBuilder.tsx
* fix(admin): add position: relative to subpage-tile so hover overlay is contained inside the tile
* style(admin): replace all emojis with clean Leica-style vector SVG icons
* fix(types): extend IconProps with SVGProps to allow style prop on Leica SVG icons
* feat(admin): add subpage live-preview, privacy analytics, and asset protection settings
* fix(typecheck): fix AlbumEntry property access in subpage drawer preview mode
* fix(types): fix ImmichAlbumInfo property names thumbnailAssetId and albumName in PageBuilder.tsx
* fix(types): add protection and watermark optional properties to AppConfig interface
* feat(settings): add toggle for disabling analytics tracking (defaults to enabled)
* feat(ux): show status banner when analytics tracking is disabled + add live sync indicator
* feat(watermark): render customizable watermark overlay on Lightbox images + rename section to Portfolio Features & Modules
* fix(types): import type LightboxWatermark in PhotoGrid.tsx
* fix(types): destructure watermark prop in PhotoGrid function signature
* feat(seo): add configurable subpage title template and metadata descriptions
* feat(seo): add generateMetadata to about page for title template support
* feat(proofing): add client proofing, favorites selection, compact URL bitmasking, and export modal
* feat(essay): add Photo Essay storytelling mode with RSC markdown parser and fullbleed/pair layouts
* feat(subpages): add page enabled toggle to deactivate subpages without deleting them
* feat(admin): add visual essay block builder for photo essay storytelling pages
* security: add Trivy container scan to Docker publish workflow
Scans the built image for CRITICAL/HIGH CVEs on every release and
uploads results to the GitHub Security tab. Non-blocking for now
(exit-code 0) so releases aren't gated on findings. Also documents
the scan and existing Dependabot coverage in the README.
---------
Co-authored-by: ralksta <ralksta@users.noreply.github.com>
2026-08-07 11:08:04 +02:00
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-14 10:30:27 +01:00
|
|
|
export default async function AboutPage() {
|
2026-08-14 21:19:54 +02:00
|
|
|
const config = getConfig();
|
|
|
|
|
if (!config.aboutEnabled) notFound();
|
2026-08-23 23:18:14 +02:00
|
|
|
const t = getServerDictionary();
|
2026-08-14 21:19:54 +02:00
|
|
|
|
2026-04-28 11:16:18 +00:00
|
|
|
const { meta, body } = await getAboutContent();
|
2026-02-14 10:30:27 +01:00
|
|
|
|
2026-02-14 11:47:26 +01:00
|
|
|
// Fetch ThumbHash for portrait placeholder
|
|
|
|
|
const portraitAsset = meta.portrait ? await immich.getAssetInfo(meta.portrait) : null;
|
|
|
|
|
const portraitPlaceholder = portraitAsset ? assetPlaceholder(portraitAsset) : null;
|
2026-02-14 10:30:27 +01:00
|
|
|
|
2026-02-14 11:47:26 +01:00
|
|
|
return (
|
|
|
|
|
<div className="about">
|
|
|
|
|
{/* ── Portrait ─────────────────────────────────── */}
|
|
|
|
|
<div className="about__portrait-col">
|
|
|
|
|
{meta.portrait ? (
|
|
|
|
|
<Image
|
2026-10-02 18:14:23 +02:00
|
|
|
src={imageUrl(portraitAsset ?? meta.portrait, 'preview')}
|
2026-08-23 23:18:14 +02:00
|
|
|
alt={meta.name || t.about.portraitAlt}
|
2026-02-14 11:47:26 +01:00
|
|
|
className="about__portrait"
|
|
|
|
|
fill
|
|
|
|
|
sizes="(max-width: 768px) 100vw, 40vw"
|
|
|
|
|
{...(portraitPlaceholder
|
|
|
|
|
? { placeholder: 'blur' as const, blurDataURL: portraitPlaceholder.blurDataURL }
|
|
|
|
|
: {})}
|
|
|
|
|
/>
|
|
|
|
|
) : (
|
|
|
|
|
<div className="about__portrait about__portrait--placeholder" />
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2026-02-14 10:30:27 +01:00
|
|
|
|
2026-02-14 11:47:26 +01:00
|
|
|
{/* ── Text ─────────────────────────────────────── */}
|
|
|
|
|
<div className="about__text-col">
|
2026-09-22 14:12:13 +02:00
|
|
|
<BackLink href="/" label={t.common.backToGallery} />
|
chore(release): v0.10.0 (#400)
Photo Essay mode, client proofing, studio-modern preset, admin panel overhaul, watermark, cookieless analytics, subpage toggle, SEO title templates. Analytics API now admin-only, Trivy scan on publish. Album order mirrors the Immich timeline; map theme, admin status panel, lightbox counter and Docker health check fixed.
See CHANGELOG.md for the full list and the health-check upgrade note.
2026-08-10 09:56:20 +02:00
|
|
|
<p className="about__kicker" aria-hidden="true">
|
2026-08-23 23:18:14 +02:00
|
|
|
{t.about.kicker}
|
chore(release): v0.10.0 (#400)
Photo Essay mode, client proofing, studio-modern preset, admin panel overhaul, watermark, cookieless analytics, subpage toggle, SEO title templates. Analytics API now admin-only, Trivy scan on publish. Album order mirrors the Immich timeline; map theme, admin status panel, lightbox counter and Docker health check fixed.
See CHANGELOG.md for the full list and the health-check upgrade note.
2026-08-10 09:56:20 +02:00
|
|
|
</p>
|
2026-02-14 11:47:26 +01:00
|
|
|
{meta.name && <h1 className="about__name">{meta.name}</h1>}
|
|
|
|
|
{meta.location && <p className="about__location">{meta.location}</p>}
|
2026-02-14 10:30:27 +01:00
|
|
|
|
2026-02-14 11:47:26 +01:00
|
|
|
<hr className="about__rule" />
|
2026-02-14 10:30:27 +01:00
|
|
|
|
2026-02-14 11:47:26 +01:00
|
|
|
{body && (
|
|
|
|
|
<div className="about__bio">
|
|
|
|
|
{body
|
|
|
|
|
.split('\n')
|
|
|
|
|
.filter(Boolean)
|
|
|
|
|
.map((line, i) => (
|
|
|
|
|
<p key={i}>{line}</p>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2026-02-14 10:30:27 +01:00
|
|
|
|
2026-02-14 11:47:26 +01:00
|
|
|
{meta.gear && meta.gear.length > 0 && (
|
|
|
|
|
<>
|
|
|
|
|
<hr className="about__rule" />
|
2026-08-23 23:18:14 +02:00
|
|
|
<h2 className="about__section-label">{t.about.gear}</h2>
|
2026-02-14 11:47:26 +01:00
|
|
|
<ul className="about__gear">
|
|
|
|
|
{meta.gear.map((item) => (
|
|
|
|
|
<li key={item}>{item}</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
|
|
|
|
</>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
2026-02-14 10:30:27 +01:00
|
|
|
}
|