This commit is contained in:
@@ -4,9 +4,16 @@ import Image from "next/image";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { BlurFade } from "@/components/magicui/blur-fade";
|
import { BlurFade } from "@/components/magicui/blur-fade";
|
||||||
import { TrackedLink } from "@/components/util-tracked-link";
|
import { TrackedLink } from "@/components/util-tracked-link";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
|
||||||
const BLUR_FADE_DELAY = 0.01;
|
const BLUR_FADE_DELAY = 0.01;
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
alternates: {
|
||||||
|
canonical: `${DATA.url}/connect`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export default function ConnectPage() {
|
export default function ConnectPage() {
|
||||||
const featuredSocials = ["Email", "LinkedIn", "GoogleScholar", "arXiv", "ResearchGate", "Gitea"];
|
const featuredSocials = ["Email", "LinkedIn", "GoogleScholar", "arXiv", "ResearchGate", "Gitea"];
|
||||||
const socialLinks = Object.entries(DATA.contact.social)
|
const socialLinks = Object.entries(DATA.contact.social)
|
||||||
|
|||||||
@@ -9,8 +9,10 @@ type Props = {
|
|||||||
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const page = "experience"
|
||||||
|
|
||||||
export async function generateStaticParams() {
|
export async function generateStaticParams() {
|
||||||
const slugs = getPostSlugs('experience');
|
const slugs = getPostSlugs(page);
|
||||||
return slugs.map((slug) => ({ slug }));
|
return slugs.map((slug) => ({ slug }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,13 +23,16 @@ export async function generateMetadata({ params }: Props) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const post = await getPostBySlug('experience', slug);
|
const post = await getPostBySlug(page, slug);
|
||||||
if (!post) {
|
if (!post) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
title: post.frontmatter.title,
|
title: post.frontmatter.title,
|
||||||
description: post.frontmatter.teaser || DATA.description,
|
description: post.frontmatter.teaser || DATA.description,
|
||||||
|
alternates: {
|
||||||
|
canonical: `${DATA.url}/${page}/${slug}`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +43,7 @@ export default async function ExperiencePage({ params }: Props) {
|
|||||||
notFound();
|
notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
const post = await getPostBySlug('experience', slug);
|
const post = await getPostBySlug(page, slug);
|
||||||
const publications = getPublicationsData();
|
const publications = getPublicationsData();
|
||||||
|
|
||||||
if (!post) {
|
if (!post) {
|
||||||
@@ -46,18 +51,18 @@ export default async function ExperiencePage({ params }: Props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Navigation Logic ---
|
// --- Navigation Logic ---
|
||||||
const allSlugs = getPostSlugs('experience');
|
const allSlugs = getPostSlugs(page);
|
||||||
const currentIndex = allSlugs.findIndex((s) => s === slug);
|
const currentIndex = allSlugs.findIndex((s) => s === slug);
|
||||||
const prevSlug = currentIndex > 0 ? allSlugs[currentIndex - 1] : null;
|
const prevSlug = currentIndex > 0 ? allSlugs[currentIndex - 1] : null;
|
||||||
const nextSlug = currentIndex < allSlugs.length - 1 ? allSlugs[currentIndex + 1] : null;
|
const nextSlug = currentIndex < allSlugs.length - 1 ? allSlugs[currentIndex + 1] : null;
|
||||||
|
|
||||||
const prevPost: Post | null = prevSlug ? await getPostBySlug('experience', prevSlug) : null;
|
const prevPost: Post | null = prevSlug ? await getPostBySlug(page, prevSlug) : null;
|
||||||
const nextPost: Post | null = nextSlug ? await getPostBySlug('experience', nextSlug) : null;
|
const nextPost: Post | null = nextSlug ? await getPostBySlug(page, nextSlug) : null;
|
||||||
|
|
||||||
const navigation = {
|
const navigation = {
|
||||||
prev: prevPost ? { slug: prevSlug!, title: prevPost.frontmatter.title } : null,
|
prev: prevPost ? { slug: prevSlug!, title: prevPost.frontmatter.title } : null,
|
||||||
next: nextPost ? { slug: nextSlug!, title: nextPost.frontmatter.title } : null,
|
next: nextPost ? { slug: nextSlug!, title: nextPost.frontmatter.title } : null,
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Article post={post} publications={publications} navigation={navigation} basePath="experience" />;
|
return <Article post={post} publications={publications} navigation={navigation} basePath={page} />;
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,14 @@
|
|||||||
|
|
||||||
import { getAllTags, getSortedPostsData } from "@/lib/posts";
|
import { getAllTags, getSortedPostsData } from "@/lib/posts";
|
||||||
import { FilterableExperienceGrid } from "@/components/filterable-experience-list";
|
import { FilterableExperienceGrid } from "@/components/filterable-experience-list";
|
||||||
|
import { DATA } from "../resume";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
alternates: {
|
||||||
|
canonical: `${DATA.url}/experience`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export default function ExperiencePage() {
|
export default function ExperiencePage() {
|
||||||
const posts = getSortedPostsData("experience");
|
const posts = getSortedPostsData("experience");
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ export const metadata: Metadata = {
|
|||||||
},
|
},
|
||||||
description: DATA.description,
|
description: DATA.description,
|
||||||
openGraph: {
|
openGraph: {
|
||||||
title: `${DATA.name}`,
|
title: DATA.name,
|
||||||
description: DATA.description,
|
description: DATA.description,
|
||||||
url: DATA.url,
|
url: DATA.url,
|
||||||
siteName: `${DATA.name}`,
|
siteName: DATA.name,
|
||||||
locale: "en_US",
|
locale: "en_US",
|
||||||
type: "website",
|
type: "website",
|
||||||
},
|
},
|
||||||
@@ -39,8 +39,11 @@ export const metadata: Metadata = {
|
|||||||
"max-snippet": -1,
|
"max-snippet": -1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
alternates: {
|
||||||
|
canonical: DATA.url,
|
||||||
|
},
|
||||||
twitter: {
|
twitter: {
|
||||||
title: `${DATA.name}`,
|
title: DATA.name,
|
||||||
card: "summary_large_image",
|
card: "summary_large_image",
|
||||||
},
|
},
|
||||||
verification: {
|
verification: {
|
||||||
|
|||||||
@@ -5,6 +5,13 @@ import { Badge } from "@/components/ui/badge";
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { TrackedLink } from "@/components/util-tracked-link";
|
import { TrackedLink } from "@/components/util-tracked-link";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
alternates: {
|
||||||
|
canonical: `${DATA.url}/publications`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export default function PublicationsPage() {
|
export default function PublicationsPage() {
|
||||||
const publicationsRaw = getPublicationsData();
|
const publicationsRaw = getPublicationsData();
|
||||||
|
|||||||
@@ -7,26 +7,31 @@ import { Article } from '@/components/page-article';
|
|||||||
import { DATA } from '@/app/resume';
|
import { DATA } from '@/app/resume';
|
||||||
import { Props } from '@/components/types';
|
import { Props } from '@/components/types';
|
||||||
|
|
||||||
|
const page = "research"
|
||||||
|
|
||||||
export async function generateStaticParams() {
|
export async function generateStaticParams() {
|
||||||
const slugs = getPostSlugs('research');
|
const slugs = getPostSlugs(page);
|
||||||
return slugs.map((slug) => ({ slug }));
|
return slugs.map((slug) => ({ slug }));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateMetadata({ params }: Props ) {
|
export async function generateMetadata({ params }: Props ) {
|
||||||
const { slug } = await params;
|
const { slug } = await params;
|
||||||
|
|
||||||
const post = await getPostBySlug('research', slug);
|
const post = await getPostBySlug(page, slug);
|
||||||
if (!post) { return {}; }
|
if (!post) { return {}; }
|
||||||
return {
|
return {
|
||||||
title: post.frontmatter.title,
|
title: post.frontmatter.title,
|
||||||
description: post.frontmatter.teaser || DATA.description,
|
description: post.frontmatter.teaser || DATA.description,
|
||||||
|
alternates: {
|
||||||
|
canonical: `${DATA.url}/${page}/${slug}`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function ResearchPage({ params }: Props ) {
|
export default async function ResearchPage({ params }: Props ) {
|
||||||
const { slug } = await params;
|
const { slug } = await params;
|
||||||
|
|
||||||
const post = await getPostBySlug('research', slug);
|
const post = await getPostBySlug(page, slug);
|
||||||
const publications = getPublicationsData();
|
const publications = getPublicationsData();
|
||||||
|
|
||||||
if (!post) {
|
if (!post) {
|
||||||
@@ -34,18 +39,18 @@ export default async function ResearchPage({ params }: Props ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --- Navigation Logic ---
|
// --- Navigation Logic ---
|
||||||
const allSlugs = getPostSlugs('research');
|
const allSlugs = getPostSlugs(page);
|
||||||
const currentIndex = allSlugs.findIndex((s) => s === slug);
|
const currentIndex = allSlugs.findIndex((s) => s === slug);
|
||||||
const prevSlug = currentIndex > 0 ? allSlugs[currentIndex - 1] : null;
|
const prevSlug = currentIndex > 0 ? allSlugs[currentIndex - 1] : null;
|
||||||
const nextSlug = currentIndex < allSlugs.length - 1 ? allSlugs[currentIndex + 1] : null;
|
const nextSlug = currentIndex < allSlugs.length - 1 ? allSlugs[currentIndex + 1] : null;
|
||||||
|
|
||||||
const prevPost = prevSlug ? await getPostBySlug('research', prevSlug) : null;
|
const prevPost = prevSlug ? await getPostBySlug(page, prevSlug) : null;
|
||||||
const nextPost = nextSlug ? await getPostBySlug('research', nextSlug) : null;
|
const nextPost = nextSlug ? await getPostBySlug(page, nextSlug) : null;
|
||||||
|
|
||||||
const navigation = {
|
const navigation = {
|
||||||
prev: prevPost ? { slug: prevSlug!, title: prevPost.frontmatter.title } : null,
|
prev: prevPost ? { slug: prevSlug!, title: prevPost.frontmatter.title } : null,
|
||||||
next: nextPost ? { slug: nextSlug!, title: nextPost.frontmatter.title } : null,
|
next: nextPost ? { slug: nextSlug!, title: nextPost.frontmatter.title } : null,
|
||||||
};
|
};
|
||||||
|
|
||||||
return <Article post={post} publications={publications} navigation={navigation} basePath="research" />;
|
return <Article post={post} publications={publications} navigation={navigation} basePath={page} />;
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,14 @@
|
|||||||
|
|
||||||
import { getSortedPostsData, getAllTags } from "@/lib/posts";
|
import { getSortedPostsData, getAllTags } from "@/lib/posts";
|
||||||
import { FilterableResearchGrid } from "@/components/filterable-research-list"; // Import the new client component
|
import { FilterableResearchGrid } from "@/components/filterable-research-list"; // Import the new client component
|
||||||
|
import { DATA } from "../resume";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
alternates: {
|
||||||
|
canonical: `${DATA.url}/research`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export default function ResearchPage() {
|
export default function ResearchPage() {
|
||||||
// These functions run safely on the server because this is a Server Component.
|
// These functions run safely on the server because this is a Server Component.
|
||||||
|
|||||||
@@ -6,10 +6,13 @@ import {
|
|||||||
ClipboardListIcon,
|
ClipboardListIcon,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
|
const domain: string = "steffenillium.de"
|
||||||
|
|
||||||
export const DATA = {
|
export const DATA = {
|
||||||
name: "Steffen Illium",
|
name: "Steffen Illium",
|
||||||
initials: "SI",
|
initials: "SI",
|
||||||
url: "https://steffenillium.de",
|
url: `https://${domain}.de`,
|
||||||
|
domain: `${domain}`,
|
||||||
location: "Augsburg, Germany",
|
location: "Augsburg, Germany",
|
||||||
locationLink: "https://www.google.com/maps/place/Augsburg",
|
locationLink: "https://www.google.com/maps/place/Augsburg",
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
// app/sitemap.ts
|
// app/sitemap.ts
|
||||||
import { getAllTags, getSortedPostsData } from '@/lib/posts';
|
import { getAllTags, getSortedPostsData } from '@/lib/posts';
|
||||||
import { MetadataRoute } from 'next';
|
import { MetadataRoute } from 'next';
|
||||||
|
import { DATA } from './resume';
|
||||||
|
|
||||||
export default function sitemap(): MetadataRoute.Sitemap {
|
export default function sitemap(): MetadataRoute.Sitemap {
|
||||||
const baseUrl = 'https://steffenillium.de';
|
const baseUrl = DATA.url;
|
||||||
|
|
||||||
// Improvement 1: Fetch all posts with a single, more efficient call
|
// Improvement 1: Fetch all posts with a single, more efficient call
|
||||||
const allPosts = getSortedPostsData();
|
const allPosts = getSortedPostsData();
|
||||||
const postUrls: MetadataRoute.Sitemap = allPosts.map((post) => ({
|
const postUrls: MetadataRoute.Sitemap = allPosts.map((post) => ({
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
import { BlurFade } from "@/components/magicui/blur-fade";
|
import { BlurFade } from "@/components/magicui/blur-fade";
|
||||||
|
import { DATA } from "../resume";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
|
||||||
const BLUR_FADE_DELAY = 0.01;
|
const BLUR_FADE_DELAY = 0.01;
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
alternates: {
|
||||||
|
canonical: `${DATA.url}/status`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export default function StatusPage() {
|
export default function StatusPage() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ import { BlurFade } from "@/components/magicui/blur-fade";
|
|||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { Breadcrumbs } from "@/components/element-breadcrumbs";
|
import { Breadcrumbs } from "@/components/element-breadcrumbs";
|
||||||
import { TagProps } from "@/components/types";
|
import { TagProps } from "@/components/types";
|
||||||
|
import { DATA } from "@/app/resume";
|
||||||
|
|
||||||
|
const page = "tags"
|
||||||
const BLUR_FADE_DELAY = 0.01;
|
const BLUR_FADE_DELAY = 0.01;
|
||||||
|
|
||||||
export async function generateStaticParams() {
|
export async function generateStaticParams() {
|
||||||
@@ -20,6 +21,9 @@ export async function generateMetadata({ params }: TagProps ) {
|
|||||||
return {
|
return {
|
||||||
title: tag,
|
title: tag,
|
||||||
description: tagData?.definition || `Posts tagged with ${tag}`,
|
description: tagData?.definition || `Posts tagged with ${tag}`,
|
||||||
|
alternates: {
|
||||||
|
canonical: `${DATA.url}/${page}/${tag}`,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +31,7 @@ export default async function TagPage({ params }: TagProps) {
|
|||||||
const { tag } = await params;
|
const { tag } = await params;
|
||||||
const posts = getPostsByTag(tag);
|
const posts = getPostsByTag(tag);
|
||||||
const tagData = getTagData(tag);
|
const tagData = getTagData(tag);
|
||||||
const basePath = "tags";
|
const basePath = page;
|
||||||
|
|
||||||
if (posts.length === 0) {
|
if (posts.length === 0) {
|
||||||
return notFound();
|
return notFound();
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
import { getAllTags } from "@/lib/posts";
|
import { getAllTags } from "@/lib/posts";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { BlurFade } from "@/components/magicui/blur-fade";
|
import { BlurFade } from "@/components/magicui/blur-fade";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
import { DATA } from "../resume";
|
||||||
|
|
||||||
const BLUR_FADE_DELAY = 0.01;
|
const BLUR_FADE_DELAY = 0.01;
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
alternates: {
|
||||||
|
canonical: `${DATA.url}/tags`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export default function TagsPage() {
|
export default function TagsPage() {
|
||||||
const tags = getAllTags(2);
|
const tags = getAllTags(2);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
|
import { DATA } from "./app/resume";
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
/* your other config options here */
|
/* your other config options here */
|
||||||
@@ -7,7 +8,7 @@ const nextConfig: NextConfig = {
|
|||||||
remotePatterns: [
|
remotePatterns: [
|
||||||
{
|
{
|
||||||
protocol: "https",
|
protocol: "https",
|
||||||
hostname: "*.steffenillium.de",
|
hostname: `*.${DATA.domain}`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user