Philosophy
This design system is built on three principles: clarity, restraint, and craft. We use a monolithic CSS file, the Lato sans-serif typeface, and a strict black-and-white palette. Shadows are soft and plush. Animations are subtle. Everything feels tactile and considered.
We don't chase trends. We build things that feel good to use and age gracefully.
Typography
Heading 1 - Lato
Heading 2 - Lato
Heading 3 - Lato
Body text uses Lato sans-serif at 1rem with 1.6 line height for comfortable reading.
Small text at 0.875rem for secondary information.
Colors
Base Colors
#ffffff
#f8f8f8
#000000
#666666
#999999
#e5e5e5
Semantic Colors
#10a37f
#f59e0b
#ef4444
Buttons
Cards
Example App
A beautiful card with soft shadows and rounded corners.
Links
Spacing
Shadows
Soft, layered shadows create depth without aggression. Multiple shadow layers at low opacity create a plush, tactile feeling.
Border Radius
Progress Bar
Table
App Name | MAU | Revenue | Status |
---|---|---|---|
Convo | 1,234 | $5,678 | Live |
Tale | 2,345 | $6,789 | Beta |
Grasp | 3,456 | $7,890 | Coming Soon |
Badges
Input Fields
Divider
Content above divider
Content below divider
Code Block
import Image from "next/image";
export default function Home() {
const apps = [
{
id: 1,
name: "Convo",
slug: "convo",
description: "Chat with multiple AI models.",
mau: "0",
revenue: "$0.00",
icon: "/convo-logo.png",
link: null,
},
];
return (
<div className="page-container">
<header className="header">
<h1>by John Leonardo</h1>
</header>
</div>
);
}
Theme Switcher
The theme system supports both light and dark modes with seamless transitions. The switcher is positioned in the top-right corner and respects user preferences through localStorage and system color scheme detection.
How It Works
- CSS Variables: All colors are defined as CSS custom properties that automatically update when the theme changes via a
data-theme
attribute on the root element. - Theme Context: A React context provider manages theme state and provides a toggle function to all components.
- Persistence: The selected theme is saved to localStorage and restored on subsequent visits.
- System Detection: If no theme is saved, the system automatically detects and applies the user's OS color scheme preference.
- Hydration Safe: The component uses a "mounted" state to prevent hydration mismatches between server and client rendering.
Component Example
"use client";
import { useTheme } from "./theme-provider";
import { useEffect, useState } from "react";
export function ThemeSwitcher() {
const { theme, toggleTheme } = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return null;
}
return (
<button
onClick={toggleTheme}
className="theme-switcher"
aria-label={`Switch to ${theme === "light" ? "dark" : "light"} mode`}
>
{theme === "light" ? (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M10 3V1M10 19V17M17 10H19M1 10H3M15.657 4.343L17.071 2.929M2.929 17.071L4.343 15.657M15.657 15.657L17.071 17.071M2.929 2.929L4.343 4.343M14 10C14 12.2091 12.2091 14 10 14C7.79086 14 6 12.2091 6 10C6 7.79086 7.79086 6 10 6C12.2091 6 14 7.79086 14 10Z"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
) : (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)}
</button>
);
}