feat(scaffold): Next 16 + Payload 3 scaffold with Kaniko CI and Swarm deploy
Initial app scaffold wired end-to-end: Payload 3.82 CMS integrated with Next 16.2 App Router (standalone output), PostgreSQL 17 adapter, Lexical rich text, Tailwind 3 with Material 3 token palette ported from the stitch technical- editorial design, self-hosted Space Grotesk + Inter via next/font, and lucide-react icons. Admin lives at /admin, REST/GraphQL at /api/*, and /api/health returns build SHA/REV for deploy verification. Seven collections (Users, Media, Categories, Projects, Posts, Gear, ContactSubmissions) and six globals (Home, About, Contact, Resume, Navigation, SEO) model the content outlined in docs/PRD.md. Multi-stage Dockerfile builds a non-root standalone runner; Woodpecker pipeline lints, typechecks, builds, audits, builds with Kaniko to git.mosaicstack.dev, scans with Trivy, and links the package. Swarm compose mirrors the mosaic-stack-website Traefik entrypoints=web pattern with www->apex redirect and immutable WEB_IMAGE_TAG. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
14
src/components/SiteFooter.tsx
Normal file
14
src/components/SiteFooter.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
export function SiteFooter() {
|
||||
return (
|
||||
<footer className="mt-24 border-t border-outline-variant/10 bg-surface-container-lowest">
|
||||
<div className="mx-auto flex max-w-7xl flex-col gap-6 px-6 py-12 md:flex-row md:items-center md:justify-between">
|
||||
<div className="font-headline text-sm uppercase tracking-[0.2em] text-on-surface-variant">
|
||||
© {new Date().getFullYear()} Jason Woltje · All rights reserved
|
||||
</div>
|
||||
<div className="font-label text-[10px] uppercase tracking-[0.2em] text-tertiary/80">
|
||||
LATENCY: 42ms · CORE STATUS: NOMINAL
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
35
src/components/SiteHeader.tsx
Normal file
35
src/components/SiteHeader.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import Link from "next/link";
|
||||
|
||||
const links = [
|
||||
{ label: "Home", href: "/" },
|
||||
{ label: "Projects", href: "/projects" },
|
||||
{ label: "Writing", href: "/writing" },
|
||||
{ label: "About", href: "/about" },
|
||||
{ label: "Contact", href: "/contact" },
|
||||
];
|
||||
|
||||
export function SiteHeader() {
|
||||
return (
|
||||
<header className="sticky top-0 z-50 w-full bg-background/80 backdrop-blur-xl">
|
||||
<nav className="mx-auto flex max-w-7xl items-center justify-between px-6 py-4">
|
||||
<Link
|
||||
href="/"
|
||||
className="font-headline text-xl font-bold uppercase tracking-tighter text-primary"
|
||||
>
|
||||
JASON WOLTJE
|
||||
</Link>
|
||||
<div className="hidden items-center gap-8 md:flex">
|
||||
{links.map((link) => (
|
||||
<Link
|
||||
key={link.href}
|
||||
href={link.href}
|
||||
className="font-label text-[14px] uppercase tracking-tighter text-on-surface-variant transition-colors hover:text-primary"
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
23
src/components/StatusTerminal.tsx
Normal file
23
src/components/StatusTerminal.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
const BUILD_SHA = process.env.NEXT_PUBLIC_BUILD_SHA ?? "dev";
|
||||
const BUILD_REV = process.env.NEXT_PUBLIC_BUILD_REV ?? "local";
|
||||
|
||||
type Props = {
|
||||
location?: string;
|
||||
status?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
export function StatusTerminal({
|
||||
location = "39.0997° N, 94.5786° W",
|
||||
status = "ONLINE",
|
||||
className = "",
|
||||
}: Props) {
|
||||
return (
|
||||
<div className={`flex items-center gap-3 ${className}`}>
|
||||
<span className="flex h-2 w-2 rounded-full bg-tertiary shadow-[0_0_8px_#8eff71]" />
|
||||
<span className="font-label text-[10px] uppercase tracking-[0.2em] text-tertiary">
|
||||
LOC: {location} · STATUS: {status} · REV: {BUILD_REV} · SHA: {BUILD_SHA}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user