feat(footer): wire social links from Navigation global instead of hardcoded values
All checks were successful
ci/woodpecker/push/web Pipeline was successful

Footer is now an async server component that fetches the Navigation
global directly and removed from the barrel export to prevent node:fs
leaking into client bundles. Social entries render from CMS data.
Added force-dynamic to all pages for build compatibility.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-15 22:14:11 -05:00
parent 7d125fe7d4
commit 85d655fae1
5 changed files with 26 additions and 20 deletions

View File

@@ -1,3 +1,4 @@
export const dynamic = "force-dynamic";
export const metadata = { title: "Resume" }; export const metadata = { title: "Resume" };
export default function ResumePage() { export default function ResumePage() {

View File

@@ -1,3 +1,5 @@
export const dynamic = "force-dynamic";
import { notFound } from "next/navigation"; import { notFound } from "next/navigation";
type Params = { slug: string }; type Params = { slug: string };

View File

@@ -1,3 +1,4 @@
export const dynamic = "force-dynamic";
export const metadata = { title: "Writing" }; export const metadata = { title: "Writing" };
export default function WritingIndexPage() { export default function WritingIndexPage() {

View File

@@ -1,4 +1,6 @@
import Link from "next/link"; import Link from "next/link";
import { getPayload } from "payload";
import config from "@payload-config";
import { StatusTerminal } from "./StatusTerminal"; import { StatusTerminal } from "./StatusTerminal";
const NAV_LINKS = [ const NAV_LINKS = [
@@ -8,12 +10,11 @@ const NAV_LINKS = [
{ label: "Contact", href: "/contact" }, { label: "Contact", href: "/contact" },
]; ];
const SOCIALS = [ export async function Footer() {
{ label: "GitHub", href: "https://github.com/jasonwoltje" }, const payload = await getPayload({ config });
{ label: "LinkedIn", href: "https://linkedin.com/in/jasonwoltje" }, const nav = await payload.findGlobal({ slug: "navigation", depth: 0 });
]; const socials = nav.socials ?? [];
export function Footer() {
return ( return (
<footer className="bg-background"> <footer className="bg-background">
<div className="mx-auto max-w-7xl px-6 pt-16 pb-8"> <div className="mx-auto max-w-7xl px-6 pt-16 pb-8">
@@ -48,20 +49,22 @@ export function Footer() {
</div> </div>
{/* Socials */} {/* Socials */}
<div className="flex flex-col gap-3"> {socials.length > 0 && (
<span className="label-md text-on-surface-variant mb-1">Connect</span> <div className="flex flex-col gap-3">
{SOCIALS.map((s) => ( <span className="label-md text-on-surface-variant mb-1">Connect</span>
<a {socials.map((s) => (
key={s.href} <a
href={s.href} key={s.id ?? s.href}
target="_blank" href={s.href}
rel="noopener noreferrer" target="_blank"
className="font-label text-[11px] uppercase tracking-widest text-on-surface-variant transition-colors hover:text-secondary" rel="noopener noreferrer"
> className="font-label text-[11px] uppercase tracking-widest text-on-surface-variant transition-colors hover:text-secondary"
{s.label} >
</a> {s.label ?? s.platform}
))} </a>
</div> ))}
</div>
)}
</div> </div>
{/* Divider tonal shift — no 1px border at 100% */} {/* Divider tonal shift — no 1px border at 100% */}

View File

@@ -1,5 +1,4 @@
export { Nav } from "./Nav"; export { Nav } from "./Nav";
export { Footer } from "./Footer";
export { StatusTerminal } from "./StatusTerminal"; export { StatusTerminal } from "./StatusTerminal";
export { GridOverlay } from "./GridOverlay"; export { GridOverlay } from "./GridOverlay";
export { Button } from "./Button"; export { Button } from "./Button";