Design System

Simple, refined, and purposeful. Every element serves a function. No decoration for decoration's sake.

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

Background#ffffff
Secondary#f8f8f8
Foreground#000000
Secondary Text#666666
Tertiary Text#999999
Border#e5e5e5

Semantic Colors

Success#10a37f
Warning#f59e0b
Error#ef4444

Buttons

Cards

📱

Example App

A beautiful card with soft shadows and rounded corners.

MAU1,234
Revenue$5,678

Links

Spacing

xs - 8px
sm - 16px
md - 24px
lg - 32px
xl - 48px
2xl - 64px

Shadows

Soft, layered shadows create depth without aggression. Multiple shadow layers at low opacity create a plush, tactile feeling.

Card Shadow
Hover Shadow
Button Shadow

Border Radius

4px
8px
12px
20px
pill

Progress Bar

Table

App NameMAURevenueStatus
Convo1,234$5,678Live
Tale2,345$6,789Beta
Grasp3,456$7,890Coming Soon

Badges

DefaultSuccessWarningError

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>
  );
}
← Back to home