feat: add AboutPage component with personal information and JSON-LD schema support
All checks were successful
Deploy / deploy (push) Successful in 47s
All checks were successful
Deploy / deploy (push) Successful in 47s
- Created AboutPage.astro to showcase personal details, including bio, contact information, and social media links. - Implemented localization support for German and English languages. - Added JsonLd.astro component for structured data representation using JSON-LD.
This commit is contained in:
parent
ae5c2564d5
commit
200d0b7181
9 changed files with 577 additions and 22 deletions
BIN
public/apple-touch-icon.png
Normal file
BIN
public/apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 71 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 655 B After Width: | Height: | Size: 31 KiB |
BIN
src/assets/me-bangkok.jpg
Normal file
BIN
src/assets/me-bangkok.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
BIN
src/assets/me.avif
Normal file
BIN
src/assets/me.avif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
558
src/components/AboutPage.astro
Normal file
558
src/components/AboutPage.astro
Normal file
|
|
@ -0,0 +1,558 @@
|
||||||
|
---
|
||||||
|
import { Image } from 'astro:assets';
|
||||||
|
import meBangkok from '~/assets/me-bangkok.jpg';
|
||||||
|
import JsonLd from '~/components/JsonLd.astro';
|
||||||
|
import BaseLayout from '~/layouts/BaseLayout.astro';
|
||||||
|
import type { Locale } from '~/consts';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
locale: Locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { locale } = Astro.props;
|
||||||
|
|
||||||
|
const identityLinks = [
|
||||||
|
{
|
||||||
|
platform: 'Mastodon',
|
||||||
|
handle: '@altner@mastodon.social',
|
||||||
|
href: 'https://mastodon.social/@altner',
|
||||||
|
rel: 'me noopener noreferrer',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
platform: 'Instagram',
|
||||||
|
handle: '@adrian.altner',
|
||||||
|
href: 'https://www.instagram.com/adrian.altner/',
|
||||||
|
rel: 'me noopener noreferrer',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const copy = {
|
||||||
|
de: {
|
||||||
|
title: 'Über mich',
|
||||||
|
description: 'Über Adrian Altner – Leidenschaft für das Web, Fotografie und Reisen.',
|
||||||
|
url: 'https://adrian-altner.de/ueber-mich',
|
||||||
|
country: 'Deutschland',
|
||||||
|
bio: [
|
||||||
|
'Begeistert vom Web seit 1997. Autodidakt aus Überzeugung – ich baue Dinge zum Vergnügen und bringe mir selbst bei, was mich gerade interessiert.',
|
||||||
|
'Fotografie ist eines meiner Hauptthemen. Meistens auf Reisen oder bei Photowalks – Straßenszenen, Architektur und das Licht, das nie wartet.',
|
||||||
|
],
|
||||||
|
contactHref: '/kontakt',
|
||||||
|
contactLabel: 'Kontakt →',
|
||||||
|
headings: { web: 'Im Netz', now: 'Gerade', site: 'Diese Seite' },
|
||||||
|
webNote: {
|
||||||
|
before: 'Diese Links tragen ',
|
||||||
|
code: 'rel="me"',
|
||||||
|
between: ' zur ',
|
||||||
|
linkLabel: 'IndieWeb-Identitätsverifikation',
|
||||||
|
after: '. Meine kanonische Identität ist ',
|
||||||
|
canonical: 'adrian-altner.de',
|
||||||
|
end: '.',
|
||||||
|
},
|
||||||
|
now: [
|
||||||
|
'Ich arbeite einen Stapel Fotos aus meiner letzten Reise nach Südostasien auf. In der Freizeit lerne ich mehr über Container-Orchestrierung und Selfhosting. Ich lese gerade zum zweiten Mal ',
|
||||||
|
'The Pragmatic Programmer',
|
||||||
|
'.',
|
||||||
|
],
|
||||||
|
nowNote: {
|
||||||
|
before: 'Inspiriert von ',
|
||||||
|
link: 'nownownow.com',
|
||||||
|
after: '. Zuletzt aktualisiert April 2026.',
|
||||||
|
},
|
||||||
|
site: [
|
||||||
|
{
|
||||||
|
before: 'Gebaut mit ',
|
||||||
|
link: { href: 'https://astro.build', label: 'Astro' },
|
||||||
|
after:
|
||||||
|
', betrieben auf einem selbst gehosteten VPS in Deutschland. Inhalte liegen als Markdown-Dateien vor, versioniert in Git. Kein Tracking, keine Cookies, keine JavaScript-Frameworks.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
before: 'Diese Seite unterstützt ',
|
||||||
|
link: { href: 'https://indieweb.org/Webmention', label: 'Webmentions' },
|
||||||
|
middle: ' – wer von der eigenen Website hierüber schreibt, bekomme ich möglicherweise mit. Neue Beiträge werden via ',
|
||||||
|
link2: { href: 'https://indieweb.org/POSSE', label: 'POSSE' },
|
||||||
|
after: ' auf Mastodon syndiziert.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
photoAlt: 'Adrian Altner in Bangkok',
|
||||||
|
},
|
||||||
|
en: {
|
||||||
|
title: 'About',
|
||||||
|
description: 'About Adrian Altner – passionate about the web, photography, and travel.',
|
||||||
|
url: 'https://adrian-altner.de/en/about',
|
||||||
|
country: 'Germany',
|
||||||
|
bio: [
|
||||||
|
'Fascinated by the web since 1997. Self-taught by conviction — I build things for fun and teach myself whatever happens to catch my interest.',
|
||||||
|
'Photography is one of my main pursuits. Usually while travelling or on photowalks — street scenes, architecture, and the light that never waits.',
|
||||||
|
],
|
||||||
|
contactHref: '/en/contact',
|
||||||
|
contactLabel: 'Contact →',
|
||||||
|
headings: { web: 'Elsewhere', now: 'Now', site: 'This site' },
|
||||||
|
webNote: {
|
||||||
|
before: 'These links carry ',
|
||||||
|
code: 'rel="me"',
|
||||||
|
between: ' for ',
|
||||||
|
linkLabel: 'IndieWeb identity verification',
|
||||||
|
after: '. My canonical identity is ',
|
||||||
|
canonical: 'adrian-altner.de',
|
||||||
|
end: '.',
|
||||||
|
},
|
||||||
|
now: [
|
||||||
|
"Working through a stack of photos from my latest trip to Southeast Asia. In my spare time I'm learning more about container orchestration and self-hosting. Currently reading ",
|
||||||
|
'The Pragmatic Programmer',
|
||||||
|
' for the second time.',
|
||||||
|
],
|
||||||
|
nowNote: {
|
||||||
|
before: 'Inspired by ',
|
||||||
|
link: 'nownownow.com',
|
||||||
|
after: '. Last updated April 2026.',
|
||||||
|
},
|
||||||
|
site: [
|
||||||
|
{
|
||||||
|
before: 'Built with ',
|
||||||
|
link: { href: 'https://astro.build', label: 'Astro' },
|
||||||
|
after:
|
||||||
|
', running on a self-hosted VPS in Germany. Content lives as Markdown files, versioned in Git. No tracking, no cookies, no JavaScript frameworks.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
before: 'This site supports ',
|
||||||
|
link: { href: 'https://indieweb.org/Webmention', label: 'Webmentions' },
|
||||||
|
middle: " – if you write about something here from your own site, there's a good chance I'll see it. New posts are syndicated to Mastodon via ",
|
||||||
|
link2: { href: 'https://indieweb.org/POSSE', label: 'POSSE' },
|
||||||
|
after: '.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
photoAlt: 'Adrian Altner in Bangkok',
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
const t = copy[locale];
|
||||||
|
|
||||||
|
const profilePageSchema = {
|
||||||
|
'@context': 'https://schema.org',
|
||||||
|
'@type': 'ProfilePage',
|
||||||
|
url: t.url,
|
||||||
|
...(locale === 'en' ? { inLanguage: 'en' } : {}),
|
||||||
|
mainEntity: {
|
||||||
|
'@type': 'Person',
|
||||||
|
name: 'Adrian Altner',
|
||||||
|
url: 'https://adrian-altner.de',
|
||||||
|
sameAs: [
|
||||||
|
'https://mastodon.social/@altner',
|
||||||
|
'https://www.instagram.com/adrian.altner/',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const techList = [
|
||||||
|
'Astro 6 · SSR · Node.js',
|
||||||
|
'Microformats2 · Webmentions · POSSE',
|
||||||
|
'Self-hosted · Germany · No CDN',
|
||||||
|
'RSS feeds for all content types',
|
||||||
|
];
|
||||||
|
---
|
||||||
|
|
||||||
|
<BaseLayout
|
||||||
|
title={t.title}
|
||||||
|
description={t.description}
|
||||||
|
locale={locale}
|
||||||
|
bodyClass="about-page"
|
||||||
|
>
|
||||||
|
<JsonLd schema={profilePageSchema} />
|
||||||
|
|
||||||
|
<div class="hero h-card">
|
||||||
|
<div class="hero__grain" aria-hidden="true"></div>
|
||||||
|
<div class="hero__inner">
|
||||||
|
<a href="https://adrian-altner.de" class="u-url hidden-url" rel="me" aria-hidden="true">adrian-altner.de</a>
|
||||||
|
|
||||||
|
<div class="hero__row">
|
||||||
|
<div class="hero__photo-wrap">
|
||||||
|
<Image
|
||||||
|
src={meBangkok}
|
||||||
|
alt={t.photoAlt}
|
||||||
|
class="hero__photo u-photo"
|
||||||
|
width={480}
|
||||||
|
height={640}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hero__bio">
|
||||||
|
<h1 class="hero__name p-name">Adrian Altner</h1>
|
||||||
|
<p class="hero__location">
|
||||||
|
<span class="p-locality">Dresden</span>,
|
||||||
|
<span class="p-region">SN</span>,
|
||||||
|
<span class="p-country-name">{t.country}</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="hero__bio-text p-note">
|
||||||
|
{t.bio.map((paragraph) => <p>{paragraph}</p>)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hero__contact">
|
||||||
|
<a class="hero__contact-link" href={t.contactHref}>{t.contactLabel}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<div class="content__inner">
|
||||||
|
<section class="section" aria-labelledby="web-heading">
|
||||||
|
<h2 class="section__heading" id="web-heading">{t.headings.web}</h2>
|
||||||
|
<ul class="identity-list">
|
||||||
|
{identityLinks.map((link) => (
|
||||||
|
<li class="identity-item">
|
||||||
|
<a
|
||||||
|
href={link.href}
|
||||||
|
class="identity-link"
|
||||||
|
rel={link.rel}
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<span class="identity-platform">{link.platform}</span>
|
||||||
|
<span class="identity-handle">{link.handle}</span>
|
||||||
|
<svg class="identity-arrow" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
||||||
|
<line x1="7" y1="17" x2="17" y2="7"></line>
|
||||||
|
<polyline points="7 7 17 7 17 17"></polyline>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<p class="section__note">
|
||||||
|
{t.webNote.before}<code>{t.webNote.code}</code>{t.webNote.between}
|
||||||
|
<a href="https://indieweb.org/rel-me" target="_blank" rel="noopener noreferrer">{t.webNote.linkLabel}</a>{t.webNote.after}
|
||||||
|
<a href="https://adrian-altner.de" rel="me">{t.webNote.canonical}</a>{t.webNote.end}
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section" aria-labelledby="now-heading">
|
||||||
|
<h2 class="section__heading" id="now-heading">{t.headings.now}</h2>
|
||||||
|
<div class="prose">
|
||||||
|
<p>{t.now[0]}<em>{t.now[1]}</em>{t.now[2]}</p>
|
||||||
|
<p class="section__note">
|
||||||
|
{t.nowNote.before}<a href="https://nownownow.com" target="_blank" rel="noopener noreferrer">{t.nowNote.link}</a>{t.nowNote.after}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="section" aria-labelledby="site-heading">
|
||||||
|
<h2 class="section__heading" id="site-heading">{t.headings.site}</h2>
|
||||||
|
<div class="prose">
|
||||||
|
<p>
|
||||||
|
{t.site[0].before}
|
||||||
|
<a href={t.site[0].link.href} target="_blank" rel="noopener noreferrer">{t.site[0].link.label}</a>
|
||||||
|
{t.site[0].after}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{t.site[1].before}
|
||||||
|
<a href={t.site[1].link.href} target="_blank" rel="noopener noreferrer">{t.site[1].link.label}</a>
|
||||||
|
{t.site[1].middle}
|
||||||
|
<a href={t.site[1].link2.href} target="_blank" rel="noopener noreferrer">{t.site[1].link2.label}</a>
|
||||||
|
{t.site[1].after}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<ul class="tech-list">
|
||||||
|
{techList.map((item) => <li>{item}</li>)}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BaseLayout>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.hero {
|
||||||
|
--content-wide: 1440px;
|
||||||
|
position: relative;
|
||||||
|
background: rgb(var(--black));
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.hidden-url {
|
||||||
|
position: absolute;
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
clip: rect(0 0 0 0);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.hero__grain {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
opacity: 0.035;
|
||||||
|
pointer-events: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
|
||||||
|
background-repeat: repeat;
|
||||||
|
background-size: 180px;
|
||||||
|
}
|
||||||
|
.hero__inner {
|
||||||
|
position: relative;
|
||||||
|
max-width: var(--content-wide);
|
||||||
|
margin: 0 auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
.hero__row {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
.hero__photo-wrap {
|
||||||
|
width: 440px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
box-shadow: 2px 0 24px rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
|
.hero__photo {
|
||||||
|
width: 440px;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
.hero__bio {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0.5rem;
|
||||||
|
padding: 4rem 2.5rem 3.5rem;
|
||||||
|
color: rgba(255, 255, 255, 0.78);
|
||||||
|
}
|
||||||
|
.hero__name {
|
||||||
|
font-size: clamp(2.5rem, 5vw, 3.5rem);
|
||||||
|
font-weight: 200;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
line-height: 1.1;
|
||||||
|
color: #fff;
|
||||||
|
margin-bottom: 0.1rem;
|
||||||
|
}
|
||||||
|
.hero__location {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-family: var(--font-maple-mono);
|
||||||
|
color: rgba(255, 255, 255, 0.55);
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
.hero__bio-text p {
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.75;
|
||||||
|
color: rgba(255, 255, 255, 0.78);
|
||||||
|
margin-bottom: 0.85rem;
|
||||||
|
max-width: 48ch;
|
||||||
|
text-wrap: balance;
|
||||||
|
}
|
||||||
|
.hero__bio-text p:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.hero__contact {
|
||||||
|
margin-top: 1.25rem;
|
||||||
|
padding-top: 1.25rem;
|
||||||
|
border-top: 1px solid rgba(255, 255, 255, 0.07);
|
||||||
|
}
|
||||||
|
.hero__contact-link {
|
||||||
|
font-size: 0.88rem;
|
||||||
|
font-family: var(--font-maple-mono);
|
||||||
|
color: rgba(255, 255, 255, 0.78);
|
||||||
|
text-decoration: none;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
.hero__contact-link:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
--content-wide: 1200px;
|
||||||
|
background: #fff;
|
||||||
|
padding: 3.5rem 0 5rem;
|
||||||
|
}
|
||||||
|
.content__inner {
|
||||||
|
max-width: var(--content-wide);
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 2.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section {
|
||||||
|
padding: 2.5rem 0;
|
||||||
|
border-top: 1px solid rgb(var(--gray-light));
|
||||||
|
}
|
||||||
|
.section:first-child {
|
||||||
|
border-top: none;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
.section__heading {
|
||||||
|
font-size: 0.72rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.14em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--accent);
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
.section__heading a {
|
||||||
|
color: inherit;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.section__heading a:hover {
|
||||||
|
color: rgb(var(--gray-dark));
|
||||||
|
}
|
||||||
|
.section__note {
|
||||||
|
font-size: 0.82rem;
|
||||||
|
color: rgb(var(--gray));
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-top: 1.25rem;
|
||||||
|
}
|
||||||
|
.section__note a {
|
||||||
|
color: rgb(var(--gray));
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
}
|
||||||
|
.section__note a:hover {
|
||||||
|
color: rgb(var(--gray-dark));
|
||||||
|
}
|
||||||
|
|
||||||
|
.identity-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.identity-item {
|
||||||
|
border-top: 1px solid rgb(var(--gray-light));
|
||||||
|
}
|
||||||
|
.identity-item:last-child {
|
||||||
|
border-bottom: 1px solid rgb(var(--gray-light));
|
||||||
|
}
|
||||||
|
.identity-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
padding: 0.85rem 0;
|
||||||
|
text-decoration: none;
|
||||||
|
color: rgb(var(--gray-dark));
|
||||||
|
transition: color 0.2s;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.identity-link:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
.identity-platform {
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: rgb(var(--gray));
|
||||||
|
min-width: 90px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
.identity-link:hover .identity-platform {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
.identity-handle {
|
||||||
|
font-size: 0.92rem;
|
||||||
|
font-family: var(--font-maple-mono);
|
||||||
|
color: inherit;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.identity-arrow {
|
||||||
|
color: rgb(var(--gray));
|
||||||
|
flex-shrink: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(-4px);
|
||||||
|
transition: opacity 0.2s, transform 0.2s;
|
||||||
|
}
|
||||||
|
.identity-link:hover .identity-arrow {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateX(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prose p {
|
||||||
|
font-size: 1rem;
|
||||||
|
line-height: 1.75;
|
||||||
|
color: rgb(var(--gray-dark));
|
||||||
|
margin-bottom: 0.85rem;
|
||||||
|
}
|
||||||
|
.prose p:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.prose a {
|
||||||
|
color: rgb(var(--gray-dark));
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
text-decoration-color: rgb(var(--gray-light));
|
||||||
|
transition: text-decoration-color 0.2s;
|
||||||
|
}
|
||||||
|
.prose a:hover {
|
||||||
|
text-decoration-color: var(--accent);
|
||||||
|
}
|
||||||
|
.prose em {
|
||||||
|
font-style: italic;
|
||||||
|
color: rgb(var(--gray-dark));
|
||||||
|
}
|
||||||
|
|
||||||
|
.tech-list {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
.tech-list li {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-family: var(--font-maple-mono);
|
||||||
|
color: rgb(var(--gray));
|
||||||
|
border: 1px solid rgb(var(--gray-light));
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0.3rem 0.65rem;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tablet: stack vertically, cap photo at 400px centered */
|
||||||
|
@media (max-width: 1023px) {
|
||||||
|
.hero__inner {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.hero__photo-wrap {
|
||||||
|
width: auto;
|
||||||
|
max-width: min(100%, 400px);
|
||||||
|
margin: 2.5rem auto 0;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.hero__photo {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
.hero__bio {
|
||||||
|
align-self: center;
|
||||||
|
max-width: min(100%, 36rem);
|
||||||
|
padding: 2.5rem 2rem 3rem;
|
||||||
|
}
|
||||||
|
.hero__bio-text p {
|
||||||
|
max-width: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Smartphone: tighter paddings, smaller photo */
|
||||||
|
@media (max-width: 639px) {
|
||||||
|
.hero__photo-wrap {
|
||||||
|
max-width: min(100%, 280px);
|
||||||
|
margin: 2rem auto 0;
|
||||||
|
}
|
||||||
|
.hero__bio {
|
||||||
|
padding: 2rem 1.5rem 2rem;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 2.5rem 0 3rem;
|
||||||
|
}
|
||||||
|
.content__inner {
|
||||||
|
padding: 0 1.5rem;
|
||||||
|
}
|
||||||
|
.identity-platform {
|
||||||
|
min-width: 75px;
|
||||||
|
}
|
||||||
|
.tech-list {
|
||||||
|
gap: 0.4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
9
src/components/JsonLd.astro
Normal file
9
src/components/JsonLd.astro
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
interface Props {
|
||||||
|
schema: Record<string, unknown>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { schema } = Astro.props;
|
||||||
|
---
|
||||||
|
|
||||||
|
<script is:inline type="application/ld+json" set:html={JSON.stringify(schema)} />
|
||||||
|
|
@ -1,14 +1,5 @@
|
||||||
---
|
---
|
||||||
import AboutHeroImage from '~/assets/placeholder.jpg';
|
import AboutPage from '~/components/AboutPage.astro';
|
||||||
import Layout from '~/layouts/Post.astro';
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout
|
<AboutPage locale="en" />
|
||||||
title="About Me"
|
|
||||||
description="Short introduction."
|
|
||||||
pubDate={new Date('August 08 2021')}
|
|
||||||
heroImage={AboutHeroImage}
|
|
||||||
locale="en"
|
|
||||||
>
|
|
||||||
<p>This is the English version of the about page.</p>
|
|
||||||
</Layout>
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,5 @@
|
||||||
---
|
---
|
||||||
import AboutHeroImage from '~/assets/placeholder.jpg';
|
import AboutPage from '~/components/AboutPage.astro';
|
||||||
import Layout from '~/layouts/Post.astro';
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout
|
<AboutPage locale="de" />
|
||||||
title="Über mich"
|
|
||||||
description="Kurze Vorstellung."
|
|
||||||
pubDate={new Date('August 08 2021')}
|
|
||||||
heroImage={AboutHeroImage}
|
|
||||||
locale="de"
|
|
||||||
>
|
|
||||||
<p>Hier steht die deutsche Version der Über-mich-Seite.</p>
|
|
||||||
</Layout>
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,12 @@ main {
|
||||||
body.home main {
|
body.home main {
|
||||||
width: 1040px;
|
width: 1040px;
|
||||||
}
|
}
|
||||||
|
body.about-page main {
|
||||||
|
width: 960px;
|
||||||
|
max-width: calc(100% - 2em);
|
||||||
|
margin: 2em auto;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
h1,
|
h1,
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue