feat: add shared design tokens, JetBrains Mono font, and fix cn() utility

- Add CSS custom properties for surfaces, text, borders, accent, radius, font stacks
- Add JetBrains Mono via next/font/google alongside Inter (both as CSS variables)
- Upgrade cn() from naive filter/join to twMerge(clsx()) for proper Tailwind class merging
- Standardize marketing section containers from max-w-7xl to max-w-6xl
- Install tailwind-merge and clsx dependencies
This commit is contained in:
Vectry
2026-02-10 17:22:45 +00:00
parent cccb3123ed
commit f9e7956e6f
6 changed files with 75 additions and 11 deletions

View File

@@ -16,6 +16,7 @@
"@dagrejs/dagre": "^2.0.4",
"@xyflow/react": "^12.10.0",
"bcryptjs": "^3.0.3",
"clsx": "^2.1.1",
"ioredis": "^5.9.2",
"lucide-react": "^0.469.0",
"next": "^15.1.0",
@@ -25,6 +26,7 @@
"react-dom": "^19.0.0",
"shiki": "^3.22.0",
"stripe": "^20.3.1",
"tailwind-merge": "^3.4.0",
"zod": "^4.3.6"
},
"devDependencies": {

View File

@@ -1 +1,38 @@
@import "tailwindcss";
@layer base {
:root {
/* Surfaces */
--surface-page: #0a0a0a;
--surface-card: rgb(23 23 23); /* neutral-900 */
--surface-card-hover: rgb(38 38 38 / 0.5); /* neutral-800/50 */
--surface-elevated: rgb(23 23 23); /* neutral-900 */
--surface-input: rgb(10 10 10); /* neutral-950 */
/* Text */
--text-primary: rgb(245 245 245); /* neutral-100 */
--text-secondary: rgb(163 163 163); /* neutral-400 */
--text-muted: rgb(115 115 115); /* neutral-500 */
/* Borders */
--border-default: rgb(38 38 38); /* neutral-800 */
--border-subtle: rgb(38 38 38 / 0.5); /* neutral-800/50 */
--border-strong: rgb(64 64 64); /* neutral-700 */
/* Accent (AgentLens emerald) */
--accent: #10b981;
--accent-hover: #34d399;
--accent-muted: rgba(16, 185, 129, 0.15);
--accent-foreground: #0a0a0a;
/* Radius */
--radius-card: 1rem;
--radius-button: 0.5rem;
--radius-icon: 0.75rem;
--radius-badge: 9999px;
/* Fonts */
--font-sans: var(--font-inter), system-ui, sans-serif;
--font-mono: var(--font-jetbrains), 'JetBrains Mono', 'Fira Code', monospace;
}
}

View File

@@ -1,9 +1,10 @@
import { Inter } from "next/font/google";
import { Inter, JetBrains_Mono } from "next/font/google";
import type { Metadata } from "next";
import { SessionProvider } from "next-auth/react";
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
const inter = Inter({ subsets: ["latin"], variable: "--font-inter", display: "swap" });
const jetbrainsMono = JetBrains_Mono({ subsets: ["latin"], variable: "--font-jetbrains", display: "swap" });
export const metadata: Metadata = {
metadataBase: new URL("https://agentlens.vectry.tech"),
@@ -72,7 +73,7 @@ export default function RootLayout({
}>) {
return (
<html lang="en" className="dark">
<body className={`${inter.className} bg-neutral-950 text-neutral-100 antialiased`}>
<body className={`${inter.variable} ${jetbrainsMono.variable} bg-neutral-950 text-neutral-100 antialiased`}>
<SessionProvider>{children}</SessionProvider>
</body>
</html>

View File

@@ -95,7 +95,7 @@ export default function HomePage() {
{/* Subtle grid pattern for depth */}
<div className="absolute inset-0 bg-[linear-gradient(rgba(255,255,255,0.012)_1px,transparent_1px),linear-gradient(90deg,rgba(255,255,255,0.012)_1px,transparent_1px)] bg-[size:64px_64px]" />
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 pt-20 pb-24">
<div className="relative max-w-6xl mx-auto px-4 sm:px-6 lg:px-8 pt-20 pb-24">
<div className="text-center">
{/* Top badges row */}
<div className="flex flex-wrap items-center justify-center gap-3 mb-8">
@@ -160,7 +160,7 @@ export default function HomePage() {
{/* Features Section */}
<section className="py-24 border-b border-neutral-800/50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-16">
<h2 className="text-3xl sm:text-4xl font-bold mb-4">
Everything you need to understand your agents
@@ -210,7 +210,7 @@ export default function HomePage() {
{/* How it Works Section */}
<section className="py-24 border-b border-neutral-800/50 relative">
<div className="absolute inset-0 bg-[radial-gradient(ellipse_60%_40%_at_50%_50%,rgba(16,185,129,0.04),transparent)]" />
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="relative max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-16">
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full border border-neutral-700 bg-neutral-800/30 text-neutral-400 text-sm mb-6">
<Zap className="w-4 h-4" />
@@ -300,7 +300,7 @@ export default function HomePage() {
{/* Code Example Section */}
<section className="py-24 border-b border-neutral-800/50">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="grid lg:grid-cols-2 gap-12 items-start">
<div className="lg:sticky lg:top-8">
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full border border-neutral-700 bg-neutral-800/30 text-neutral-400 text-sm mb-6">
@@ -487,7 +487,7 @@ export default function HomePage() {
{/* Integrations Section */}
<section className="py-24 border-b border-neutral-800/50 relative">
<div className="absolute inset-0 bg-[radial-gradient(ellipse_50%_50%_at_50%_50%,rgba(16,185,129,0.03),transparent)]" />
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="relative max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-16">
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full border border-neutral-700 bg-neutral-800/30 text-neutral-400 text-sm mb-6">
<Link2 className="w-4 h-4" />
@@ -544,7 +544,7 @@ export default function HomePage() {
{/* Pricing Section */}
<section className="py-24 border-b border-neutral-800/50 relative">
<div className="absolute inset-0 bg-[radial-gradient(ellipse_70%_50%_at_50%_50%,rgba(16,185,129,0.04),transparent)]" />
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="relative max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="text-center mb-16">
<div className="inline-flex items-center gap-2 px-4 py-2 rounded-full border border-neutral-700 bg-neutral-800/30 text-neutral-400 text-sm mb-6">
<Shield className="w-4 h-4" />

View File

@@ -19,6 +19,9 @@ export function formatRelativeTime(date: string | Date): string {
return `${diffDay}d ago`;
}
export function cn(...classes: (string | boolean | undefined | null)[]): string {
return classes.filter(Boolean).join(" ");
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

21
package-lock.json generated
View File

@@ -25,6 +25,7 @@
"@dagrejs/dagre": "^2.0.4",
"@xyflow/react": "^12.10.0",
"bcryptjs": "^3.0.3",
"clsx": "^2.1.1",
"ioredis": "^5.9.2",
"lucide-react": "^0.469.0",
"next": "^15.1.0",
@@ -34,6 +35,7 @@
"react-dom": "^19.0.0",
"shiki": "^3.22.0",
"stripe": "^20.3.1",
"tailwind-merge": "^3.4.0",
"zod": "^4.3.6"
},
"devDependencies": {
@@ -2395,6 +2397,15 @@
"integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
"license": "MIT"
},
"node_modules/clsx": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/cluster-key-slot": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
@@ -4156,6 +4167,16 @@
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/tailwind-merge": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",
"integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/dcastil"
}
},
"node_modules/tailwindcss": {
"version": "4.1.18",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz",