feat(design-system): complete blueprint aesthetic redesign with editorial typography

- Replace Geist fonts with Space Grotesk + Space Mono via next/font/google
- Make dotted borders default for all card variants (default, elevated, outline)
- Add blueprint grid backgrounds to homepage sections and playground
- Create Section layout component with flexible semantic elements and spacing variants
- Create GridContainer component with auto-fit/auto-fill responsive grid support
- Add blueprint variants to Tabs and Button components (dotted borders)
- Add editorial typography tokens (line-heights, letter-spacing) to Tailwind config
- Add spacing tokens for airy editorial layouts
- Add shadow utilities for blueprint aesthetic (shadow-blueprint, shadow-blueprint-hover)
- Update 59 component tests for new variants and styling
- All 429 tests passing, zero hardcoded colors, fully themeable

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ajax Davis 2025-11-26 08:33:03 +10:00
parent 8e122aa468
commit 27f867ff24
30 changed files with 1265 additions and 73 deletions

View file

@ -66,9 +66,32 @@
--radius-xl: 12px;
--radius: var(--radius-md);
/* Spacing - Editorial scale for airy layouts */
--spacing-section: 6rem; /* 96px - Between major sections */
--spacing-component: 3rem; /* 48px - Between components */
--spacing-element: 1.5rem; /* 24px - Between related elements */
--spacing-tight: 0.75rem; /* 12px - Tight groupings */
--spacing-comfortable: 2rem; /* 32px - Comfortable breathing room */
/* Typography */
--font-sans: 'Geist', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
--font-mono: 'Geist Mono', 'SF Mono', Consolas, monospace;
--font-sans: var(--font-sans), -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
--font-mono: var(--font-mono), 'SF Mono', Consolas, monospace;
/* Editorial Line Heights - Airy, readable */
--leading-tight: 1.25;
--leading-snug: 1.375;
--leading-normal: 1.5;
--leading-relaxed: 1.625;
--leading-loose: 1.75;
--leading-editorial: 1.8; /* Extra generous for body copy */
/* Letter Spacing - Technical precision */
--tracking-tighter: -0.05em;
--tracking-tight: -0.025em;
--tracking-normal: 0;
--tracking-wide: 0.025em;
--tracking-wider: 0.05em;
--tracking-widest: 0.1em;
}
/* Dark mode (opt-in) - Vercel/Cursor/Perplexity aesthetic */
@ -199,6 +222,11 @@
border-style: dashed;
}
.border-dotted-2 {
border-width: 2px;
border-style: dotted;
}
/* Directional dotted borders */
.border-t-dotted {
border-top-width: 1px;
@ -220,6 +248,19 @@
border-right-style: dotted;
}
/* Shadow utilities - Blueprint aesthetic */
.shadow-blueprint {
box-shadow:
0 1px 2px 0 rgb(0 0 0 / 0.03),
0 0 0 1px rgb(0 0 0 / 0.02);
}
.shadow-blueprint-hover {
box-shadow:
0 2px 4px 0 rgb(0 0 0 / 0.05),
0 0 0 1px rgb(0 0 0 / 0.03);
}
/* Transition presets */
.transition-base {
transition-property: background-color, border-color, color, fill, stroke;

View file

@ -1,7 +1,21 @@
import type { Metadata } from "next";
import { Space_Grotesk, Space_Mono } from "next/font/google";
import { ThemeProvider } from "../components/providers/ThemeProvider";
import "./globals.css";
const spaceGrotesk = Space_Grotesk({
subsets: ["latin"],
variable: "--font-sans",
display: "swap",
});
const spaceMono = Space_Mono({
subsets: ["latin"],
weight: ["400", "700"],
variable: "--font-mono",
display: "swap",
});
export const metadata: Metadata = {
title: "TPMJS - Tool Package Manager for AI Agents",
description:
@ -14,8 +28,12 @@ export default function RootLayout({
children: React.ReactNode;
}): React.ReactElement {
return (
<html lang="en" suppressHydrationWarning>
<body>
<html
lang="en"
suppressHydrationWarning
className={`${spaceGrotesk.variable} ${spaceMono.variable}`}
>
<body className={spaceGrotesk.className}>
<ThemeProvider
attribute="class"
defaultTheme="light"

View file

@ -71,8 +71,8 @@ export default function HomePage(): React.ReactElement {
<main className="flex-1">
{/* Hero Section */}
<section className="relative py-24 overflow-hidden">
<div className="absolute inset-0 bg-gradient-to-r from-orange-500 via-amber-500 to-red-500 opacity-10" />
<section className="relative py-24 overflow-hidden dotted-grid-background">
<div className="absolute inset-0 bg-background/95" />
<Container size="xl" padding="lg">
<div className="max-w-3xl mx-auto text-center space-y-8 relative z-10">
<h1 className="text-5xl md:text-6xl font-bold tracking-tight">
@ -97,7 +97,7 @@ export default function HomePage(): React.ReactElement {
</section>
{/* Featured Tools Section */}
<section className="py-16 bg-surface">
<section className="py-16 bg-surface blueprint-background">
<Container size="xl" padding="lg">
<div className="flex items-center justify-between mb-8">
<h2 className="text-3xl font-semibold">Featured Tools</h2>
@ -164,14 +164,14 @@ export default function HomePage(): React.ReactElement {
</section>
{/* Statistics Section */}
<section className="py-16 bg-surface">
<section className="py-16 bg-surface grid-background">
<Container size="xl" padding="lg">
<h2 className="text-3xl font-semibold mb-8 text-center">
Platform Statistics
</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{statistics.map((stat, index) => (
<Card key={index}>
{statistics.map((stat) => (
<Card key={stat.label}>
<CardContent className="p-6 text-center space-y-3">
<Icon
icon={stat.icon}

View file

@ -27,7 +27,7 @@ export default function PlaygroundPage() {
const [progress, setProgress] = useState(65);
return (
<div className="min-h-screen flex flex-col">
<div className="min-h-screen flex flex-col dotted-grid-background">
{/* Header */}
<Header
title={
@ -53,7 +53,8 @@ export default function PlaygroundPage() {
}
/>
<main className="flex-1 py-12">
<main className="flex-1 py-12 relative">
<div className="absolute inset-0 bg-background/95 -z-10" />
<Container size="xl" padding="lg">
<div className="space-y-16">
{/* Page Title */}
@ -166,7 +167,7 @@ export default function PlaygroundPage() {
<div className="space-y-4">
<h3 className="text-xl font-medium">Available Icons</h3>
<div className="grid grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-6">
{[
{([
"check",
"x",
"chevronDown",
@ -175,12 +176,12 @@ export default function PlaygroundPage() {
"github",
"sun",
"moon",
].map((icon) => (
] as const).map((icon) => (
<div
key={icon}
className="flex flex-col items-center gap-2 p-3 rounded-lg hover:bg-surface transition-colors"
>
<Icon icon={icon as any} size="lg" />
<Icon icon={icon} size="lg" />
<span className="text-xs text-center">{icon}</span>
</div>
))}