282 lines
14 KiB
JavaScript
282 lines
14 KiB
JavaScript
/** @type {import('tailwindcss').Config} */
|
|
|
|
/* ──────────────────────────────────────────────────────────────────────────
|
|
* Makelore Tailwind design tokens
|
|
* ──────────────────────────────────────────────────────────────────────────
|
|
*
|
|
* This config layers Makelore's own visual language on top of shadcn/ui:
|
|
*
|
|
* 1. fontFamily — All three stacks (sans / serif / mono) are pinned
|
|
* explicitly so we never silently inherit Tailwind's evolving defaults.
|
|
* This locks the rendering on macOS, Windows, and Linux to the same
|
|
* glyph sources we ship to designers.
|
|
*
|
|
* 2. fontSize — We only *add* missing rungs to Tailwind's default scale.
|
|
* All new tokens come from the orphan pixel values (10/11/13/17/40px)
|
|
* that occurred most often in the codebase. Naming is semantic
|
|
* (`meta`, `tiny`, `subtitle`, `2xs`, `stat`) so a future density
|
|
* change only touches this file.
|
|
*
|
|
* 3. colors — On top of shadcn's semantic tokens (primary / destructive /
|
|
* ...) we add three Makelore-private groups:
|
|
* - brand : Makelore orange used for primary CTAs
|
|
* - skill : orange highlight for inline /skill chips in chat
|
|
* - surface.{modal,input,sidebar}: white and neutral layers for the
|
|
* single light product theme.
|
|
*
|
|
* 4. Naming — All Makelore-private tokens live under their own top-level
|
|
* key (`brand`, `skill`, `surface`) instead of being merged into
|
|
* the root `colors` namespace, so they're trivially distinguishable
|
|
* from shadcn semantic tokens.
|
|
*
|
|
* Usage references:
|
|
* - Sizes : see fontSize block below
|
|
* - Colors : see colors block below
|
|
* - CSS variables: src/styles/globals.css
|
|
*
|
|
* ────────────────────────────────────────────────────────────────────────── */
|
|
|
|
module.exports = {
|
|
darkMode: ['class'],
|
|
content: [
|
|
'./index.html',
|
|
'./src/**/*.{js,ts,jsx,tsx}',
|
|
],
|
|
theme: {
|
|
container: {
|
|
center: true,
|
|
padding: '2rem',
|
|
screens: {
|
|
'2xl': '1400px',
|
|
},
|
|
},
|
|
extend: {
|
|
/* ──────────────────────────────────────────────────────────────
|
|
* fontFamily
|
|
* ──────────────────────────────────────────────────────────────
|
|
*
|
|
* All three stacks are pinned explicitly to remove dependency on
|
|
* Tailwind's default fontFamily values. The intent:
|
|
*
|
|
* - sans : the everyday UI body / control font. Apple-first
|
|
* on macOS (-apple-system), then BlinkMacSystemFont
|
|
* so Chromium on macOS picks the same metrics, then
|
|
* Segoe UI for Windows, Roboto for Linux/Android,
|
|
* and finally the four Apple/Segoe/Noto color emoji
|
|
* fonts so emoji never fall back to a serif.
|
|
*
|
|
* - serif : compatibility alias for the platform display stack.
|
|
* The product now uses one system sans family so page
|
|
* hierarchy stays coherent across modules.
|
|
*
|
|
* - mono : standard developer-font stack. Used for IDs, paths,
|
|
* tokens, timestamps, code blocks, CLI output etc.
|
|
* We pin this so behaviour is identical to Tailwind's
|
|
* current default but immune to upstream changes.
|
|
* ────────────────────────────────────────────────────────────── */
|
|
fontFamily: {
|
|
sans: [
|
|
'-apple-system',
|
|
'BlinkMacSystemFont',
|
|
'"Segoe UI"',
|
|
'Roboto',
|
|
'"Helvetica Neue"',
|
|
'Arial',
|
|
'"Noto Sans"',
|
|
'sans-serif',
|
|
'"Apple Color Emoji"',
|
|
'"Segoe UI Emoji"',
|
|
'"Segoe UI Symbol"',
|
|
'"Noto Color Emoji"',
|
|
],
|
|
serif: [
|
|
'-apple-system',
|
|
'BlinkMacSystemFont',
|
|
'"SF Pro Display"',
|
|
'"PingFang SC"',
|
|
'"Segoe UI"',
|
|
'Roboto',
|
|
'sans-serif',
|
|
],
|
|
mono: [
|
|
'ui-monospace',
|
|
'SFMono-Regular',
|
|
'"SF Mono"',
|
|
'Menlo',
|
|
'Monaco',
|
|
'Consolas',
|
|
'"Liberation Mono"',
|
|
'"Courier New"',
|
|
'monospace',
|
|
],
|
|
},
|
|
|
|
/* ──────────────────────────────────────────────────────────────
|
|
* fontSize
|
|
* ──────────────────────────────────────────────────────────────
|
|
*
|
|
* Naming is by visual *role*, not pixel count, so a future density
|
|
* change only edits the values here. Makelore's full size ladder
|
|
* (combining Tailwind defaults + Makelore additions, smallest first):
|
|
*
|
|
* ┌──────────────┬──────────┬─────────────┬──────────────────────────────┐
|
|
* │ Token │ FontSize │ LineHeight │ Primary use │
|
|
* ├──────────────┼──────────┼─────────────┼──────────────────────────────┤
|
|
* │ 2xs (new) │ 10px │ 14px │ micro labels, chip suffixes │
|
|
* │ tiny (new) │ 11px │ 16px │ ultra-small captions, tips │
|
|
* │ xs (TW) │ 12px │ 16px │ secondary helpers, badges │
|
|
* │ meta (new) │ 13px │ 18px │ form/button/modal description│
|
|
* │ sm (TW) │ 14px │ 20px │ body (Label / CardDescription│
|
|
* │ base (TW) │ 16px │ 24px │ rare; Textarea fallback only │
|
|
* │ subtitle(new)│ 17px │ 24px │ subtitle right under page H1 │
|
|
* │ lg (TW) │ 18px │ 28px │ Sheet / Confirm titles │
|
|
* │ xl (TW) │ 20px │ 28px │ Setup steps, large emoji │
|
|
* │ 2xl (TW) │ 24px │ 32px │ CardTitle │
|
|
* │ 3xl (TW) │ 30px │ 36px │ section H2 (serif) │
|
|
* │ 4xl (TW) │ 36px │ 40px │ Chat empty-state H1 │
|
|
* │ stat (new) │ 40px │ 1 │ dashboard hero numbers │
|
|
* │ 5xl (TW) │ 48px │ 1 │ page H1 (narrow viewport) │
|
|
* │ 6xl (TW) │ 60px │ 1 │ page H1 (md and up) │
|
|
* └──────────────┴──────────┴─────────────┴──────────────────────────────┘
|
|
*
|
|
* Tailwind defaults marked (TW) are intentionally untouched so
|
|
* shadcn components keep their original rendering.
|
|
* ────────────────────────────────────────────────────────────── */
|
|
fontSize: {
|
|
'2xs': ['10px', { lineHeight: '14px' }],
|
|
tiny: ['11px', { lineHeight: '16px' }],
|
|
meta: ['13px', { lineHeight: '18px' }],
|
|
subtitle: ['17px', { lineHeight: '24px' }],
|
|
// Display-size token used only by the Cron dashboard hero counters.
|
|
// line-height: 1 (unitless) keeps the number tightly aligned with
|
|
// the icon next to it, which is why we don't reuse 4xl/5xl here.
|
|
stat: ['40px', { lineHeight: '1' }],
|
|
},
|
|
|
|
/* ──────────────────────────────────────────────────────────────
|
|
* colors
|
|
* ──────────────────────────────────────────────────────────────
|
|
*
|
|
* Three groups:
|
|
* A. shadcn standard semantic tokens — read via `hsl(var(--xxx))`
|
|
* from globals.css. Kept fully compatible.
|
|
* B. Makelore brand tokens (brand / skill) — CSS-variable-backed
|
|
* values for the product's single light visual theme.
|
|
* C. Makelore surface tokens (surface.{modal,input,sidebar}) — use
|
|
* `hsl(var(--surface-xxx) / <alpha-value>)` so the alpha
|
|
* modifier still works (e.g. `bg-surface-sidebar/60`). The
|
|
* actual values live in globals.css so every surface follows the
|
|
* same white and neutral visual system.
|
|
*
|
|
* Examples:
|
|
* - bg-brand → primary CTA
|
|
* - hover:bg-brand-hover → CTA hover
|
|
* - bg-skill-bg/14 → skill-chip backdrop in chat input
|
|
* - text-skill-fg → skill-chip text
|
|
* - bg-surface-modal → large rounded modal panels
|
|
* - bg-surface-input → input fields / code panes
|
|
* - bg-surface-sidebar/60 → translucent left rail
|
|
* ────────────────────────────────────────────────────────────── */
|
|
colors: {
|
|
// ── A. shadcn semantic tokens (do NOT rename — Radix/shadcn
|
|
// components read these names directly) ──
|
|
border: 'hsl(var(--border))',
|
|
input: 'hsl(var(--input))',
|
|
ring: 'hsl(var(--ring))',
|
|
background: 'hsl(var(--background))',
|
|
foreground: 'hsl(var(--foreground))',
|
|
primary: {
|
|
DEFAULT: 'hsl(var(--primary))',
|
|
foreground: 'hsl(var(--primary-foreground))',
|
|
},
|
|
secondary: {
|
|
DEFAULT: 'hsl(var(--secondary))',
|
|
foreground: 'hsl(var(--secondary-foreground))',
|
|
},
|
|
destructive: {
|
|
DEFAULT: 'hsl(var(--destructive))',
|
|
foreground: 'hsl(var(--destructive-foreground))',
|
|
},
|
|
muted: {
|
|
DEFAULT: 'hsl(var(--muted))',
|
|
foreground: 'hsl(var(--muted-foreground))',
|
|
},
|
|
accent: {
|
|
DEFAULT: 'hsl(var(--accent))',
|
|
foreground: 'hsl(var(--accent-foreground))',
|
|
soft: 'hsl(var(--accent-soft) / <alpha-value>)',
|
|
strong: 'hsl(var(--accent-strong))',
|
|
},
|
|
popover: {
|
|
DEFAULT: 'hsl(var(--popover))',
|
|
foreground: 'hsl(var(--popover-foreground))',
|
|
},
|
|
card: {
|
|
DEFAULT: 'hsl(var(--card))',
|
|
foreground: 'hsl(var(--card-foreground))',
|
|
},
|
|
|
|
// ── B. Makelore brand tokens ────────────────────────────────────
|
|
// Makelore brand orange used for primary CTAs.
|
|
brand: {
|
|
DEFAULT: 'hsl(var(--brand))',
|
|
hover: 'hsl(var(--brand-hover))',
|
|
soft: 'hsl(var(--brand-soft) / <alpha-value>)',
|
|
quiet: 'hsl(var(--brand-quiet))',
|
|
},
|
|
|
|
// Highlight orange for inline /skill chips in the chat input.
|
|
// The chip combines bg + text + text-shadow to produce a glow
|
|
// effect, so we expose three separate tokens (bg, light fg,
|
|
// dark fg) instead of a 50/100/.../900 ramp — this palette is
|
|
// intentionally not extensible.
|
|
skill: {
|
|
bg: 'hsl(var(--brand))', // chip backdrop (used at /14 or /18)
|
|
fg: 'hsl(var(--brand))', // chip text (light mode)
|
|
'fg-dark': '#F8A58E', // compatibility value for legacy dark classes
|
|
},
|
|
|
|
// ── C. Makelore layered surfaces ────────────────────────────────
|
|
// We use `<alpha-value>` placeholders so Tailwind auto-emits
|
|
// `bg-surface-xxx/{alpha}` rules. Concrete pixel values live in
|
|
// globals.css for the single light product theme.
|
|
surface: {
|
|
modal: 'hsl(var(--surface-modal) / <alpha-value>)',
|
|
input: 'hsl(var(--surface-input) / <alpha-value>)',
|
|
sidebar: 'hsl(var(--surface-sidebar) / <alpha-value>)',
|
|
subtle: 'hsl(var(--surface-subtle) / <alpha-value>)',
|
|
tertiary: 'hsl(var(--surface-tertiary) / <alpha-value>)',
|
|
},
|
|
},
|
|
boxShadow: {
|
|
soft: '0 1px 2px hsl(220 20% 16% / 0.035), 0 12px 30px hsl(220 20% 16% / 0.045)',
|
|
float: '0 18px 44px hsl(220 20% 16% / 0.10)',
|
|
focus: '0 0 0 4px hsl(var(--ring) / 0.14)',
|
|
},
|
|
transitionTimingFunction: {
|
|
spring: 'cubic-bezier(0.22, 1, 0.36, 1)',
|
|
},
|
|
borderRadius: {
|
|
lg: 'var(--radius)',
|
|
md: 'calc(var(--radius) - 2px)',
|
|
sm: 'calc(var(--radius) - 4px)',
|
|
},
|
|
keyframes: {
|
|
'accordion-down': {
|
|
from: { height: '0' },
|
|
to: { height: 'var(--radix-accordion-content-height)' },
|
|
},
|
|
'accordion-up': {
|
|
from: { height: 'var(--radix-accordion-content-height)' },
|
|
to: { height: '0' },
|
|
},
|
|
},
|
|
animation: {
|
|
'accordion-down': 'accordion-down 0.2s ease-out',
|
|
'accordion-up': 'accordion-up 0.2s ease-out',
|
|
},
|
|
},
|
|
},
|
|
plugins: [require('tailwindcss-animate')],
|
|
};
|