feat: светлая тема как основная + переключатель тем

- CSS-переменные --bg, --surface, --ink, --mute, --accent для обеих тем
- darkMode: 'class' в Tailwind config
- ThemeToggle компонент с Sun/Moon, сохраняет выбор в localStorage
- Inline-скрипт в layout.js защищает от FOUC (FlashOfUnstyledContent)
- Авто-определение по prefers-color-scheme как fallback
- not-found.js: красивая 404 страница вместо дефолтной Next
- Обновлены все компоненты и страницы — Header, Footer, ArticleCard, page.js, blog, tag, about
This commit is contained in:
Alexey Pavlov
2026-05-31 09:07:44 +03:00
parent d8d1affcc8
commit a16bf812e4
12 changed files with 231 additions and 75 deletions
+7 -4
View File
@@ -1,6 +1,6 @@
import Header from '@/components/Header'; import Header from '@/components/Header';
import Footer from '@/components/Footer'; import Footer from '@/components/Footer';
import { Sparkles, Cpu, BookOpen, Zap } from 'lucide-react'; import { Sparkles } from 'lucide-react';
export const metadata = { title: 'О проекте' }; export const metadata = { title: 'О проекте' };
@@ -9,13 +9,16 @@ export default function AboutPage() {
<> <>
<Header /> <Header />
<main className="container-narrow pt-12 pb-16"> <main className="container-narrow pt-12 pb-16">
<div className="inline-flex items-center gap-2 text-xs text-accent bg-accent/10 border border-accent/20 px-3 py-1.5 rounded-full mb-6"> <div
className="inline-flex items-center gap-2 text-xs accent px-3 py-1.5 rounded-full mb-6"
style={{ background: 'rgb(var(--accent) / 0.1)', border: '1px solid rgb(var(--accent) / 0.2)' }}
>
<Sparkles className="w-3.5 h-3.5" /> О ZeroPost <Sparkles className="w-3.5 h-3.5" /> О ZeroPost
</div> </div>
<h1 className="text-4xl sm:text-5xl font-bold leading-tight mb-6"> <h1 className="text-4xl sm:text-5xl font-bold leading-tight mb-6 ink">
Эксперимент: блог, который ведёт ИИ Эксперимент: блог, который ведёт ИИ
</h1> </h1>
<div className="prose prose-invert prose-lg max-w-none"> <div className="prose prose-lg max-w-none">
<p> <p>
ZeroPost это два связанных проекта: <strong>публичный блог</strong>, который ты сейчас читаешь, и <strong>сервис</strong> для ведения Telegram-каналов с помощью ИИ. ZeroPost это два связанных проекта: <strong>публичный блог</strong>, который ты сейчас читаешь, и <strong>сервис</strong> для ведения Telegram-каналов с помощью ИИ.
</p> </p>
+7 -8
View File
@@ -30,7 +30,6 @@ export default async function ArticlePage({ params }) {
const article = await getArticle(slug); const article = await getArticle(slug);
if (!article) notFound(); if (!article) notFound();
// Убираю H1 из контента — он уже идёт в заголовке страницы
const contentWithoutH1 = article.content.replace(/^#\s+.+$/m, '').trim(); const contentWithoutH1 = article.content.replace(/^#\s+.+$/m, '').trim();
const html = renderMarkdown(contentWithoutH1); const html = renderMarkdown(contentWithoutH1);
@@ -38,7 +37,7 @@ export default async function ArticlePage({ params }) {
<> <>
<Header /> <Header />
<article className="container-narrow pt-10 pb-16"> <article className="container-narrow pt-10 pb-16">
<Link href="/" className="btn-ghost text-sm mb-6 -ml-2"> <Link href="/" className="btn btn-ghost text-sm mb-6 -ml-2">
<ArrowLeft className="w-4 h-4" /> Все статьи <ArrowLeft className="w-4 h-4" /> Все статьи
</Link> </Link>
@@ -48,11 +47,11 @@ export default async function ArticlePage({ params }) {
))} ))}
</div> </div>
<h1 className="font-serif text-3xl sm:text-5xl font-bold leading-tight mb-5 tracking-tight"> <h1 className="font-serif text-3xl sm:text-5xl font-bold leading-tight mb-5 tracking-tight ink">
{article.title} {article.title}
</h1> </h1>
<div className="flex items-center gap-4 text-sm text-mute pb-8 mb-8 border-b border-border/60"> <div className="flex items-center gap-4 text-sm mute pb-8 mb-8 border-b-soft">
<span>{article.author}</span> <span>{article.author}</span>
<span>·</span> <span>·</span>
<span>{formatDate(article.published_at)}</span> <span>{formatDate(article.published_at)}</span>
@@ -67,13 +66,13 @@ export default async function ArticlePage({ params }) {
</div> </div>
<div <div
className="prose prose-invert prose-lg max-w-none font-serif prose-headings:font-sans" className="prose prose-lg max-w-none font-serif prose-headings:font-sans"
dangerouslySetInnerHTML={{ __html: html }} dangerouslySetInnerHTML={{ __html: html }}
/> />
<div className="mt-16 pt-8 border-t border-border/60 text-center"> <div className="mt-16 pt-8 border-t-soft text-center">
<p className="text-mute mb-4">Хочешь такой же блог или канал в Telegram?</p> <p className="mute mb-4">Хочешь такой же блог или канал в Telegram?</p>
<a href="https://app.zeropost.ru" className="btn-primary"> <a href="https://app.zeropost.ru" className="btn btn-primary">
Открыть ZeroPost Открыть ZeroPost
</a> </a>
</div> </div>
+81 -7
View File
@@ -2,18 +2,92 @@
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
/* === Theme tokens === */
:root {
--bg: 250 250 249; /* почти белый, тёплый */
--surface: 255 255 255; /* карточки */
--surface-2: 245 245 244; /* приглушённый фон */
--border: 231 229 228;
--ink: 28 25 23; /* основной текст */
--mute: 120 113 108; /* приглушённый текст */
--accent: 16 185 129; /* emerald-500 */
--accent-2: 5 150 105; /* emerald-600 */
--accent-soft: 209 250 229; /* emerald-100 */
}
.dark {
--bg: 10 10 10;
--surface: 20 20 20;
--surface-2: 28 28 28;
--border: 42 42 42;
--ink: 229 231 235;
--mute: 156 163 175;
--accent: 16 185 129;
--accent-2: 52 211 153;
--accent-soft: 6 78 59;
}
@layer base { @layer base {
html { @apply bg-bg text-ink; } html {
background: rgb(var(--bg));
color: rgb(var(--ink));
}
body { @apply font-sans antialiased; } body { @apply font-sans antialiased; }
::selection { @apply bg-accent/30; } ::selection { background: rgb(var(--accent) / 0.25); }
} }
@layer components { @layer components {
.btn { @apply inline-flex items-center justify-center gap-2 px-4 py-2 rounded-lg font-medium transition-colors disabled:opacity-50 disabled:cursor-not-allowed; } .btn {
.btn-primary { @apply btn bg-accent text-black hover:bg-accent2; } @apply inline-flex items-center justify-center gap-2 px-4 py-2 rounded-lg font-medium transition-all disabled:opacity-50 disabled:cursor-not-allowed;
.btn-ghost { @apply btn text-mute hover:bg-surface hover:text-white; } }
.btn-primary {
background: rgb(var(--accent));
color: white;
}
.btn-primary:hover { background: rgb(var(--accent-2)); }
.btn-ghost {
color: rgb(var(--mute));
}
.btn-ghost:hover {
background: rgb(var(--surface-2));
color: rgb(var(--ink));
}
.container-narrow { @apply max-w-3xl mx-auto px-4; } .container-narrow { @apply max-w-3xl mx-auto px-4; }
.container-wide { @apply max-w-6xl mx-auto px-4; } .container-wide { @apply max-w-6xl mx-auto px-4; }
.article-card { @apply bg-surface border border-border rounded-2xl p-6 hover:border-accent/40 transition-colors; }
.tag { @apply inline-block text-xs px-2.5 py-1 rounded-full bg-surface2 text-mute hover:bg-surface hover:text-white transition-colors; } .article-card {
background: rgb(var(--surface));
border: 1px solid rgb(var(--border));
@apply rounded-2xl p-6 transition-all duration-200;
}
.article-card:hover {
border-color: rgb(var(--accent) / 0.4);
transform: translateY(-2px);
box-shadow: 0 10px 25px -10px rgb(0 0 0 / 0.08);
}
.dark .article-card:hover {
box-shadow: 0 10px 25px -10px rgb(0 0 0 / 0.5);
}
.tag {
display: inline-block;
@apply text-xs px-2.5 py-1 rounded-full transition-colors;
background: rgb(var(--surface-2));
color: rgb(var(--mute));
}
.tag:hover {
background: rgb(var(--accent-soft));
color: rgb(var(--accent-2));
}
.surface { background: rgb(var(--surface)); }
.surface-2 { background: rgb(var(--surface-2)); }
.ink { color: rgb(var(--ink)); }
.mute { color: rgb(var(--mute)); }
.accent { color: rgb(var(--accent)); }
.border-soft { border-color: rgb(var(--border)); }
.border-b-soft { border-bottom: 1px solid rgb(var(--border)); }
.border-t-soft { border-top: 1px solid rgb(var(--border)); }
} }
+13 -1
View File
@@ -14,10 +14,22 @@ export const metadata = {
}, },
}; };
// Защита от FOUC: ставим тему до первого рендера
const themeInitScript = `
(function() {
try {
var saved = localStorage.getItem('theme');
var theme = saved || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
if (theme === 'dark') document.documentElement.classList.add('dark');
} catch(e) {}
})();
`;
export default function RootLayout({ children }) { export default function RootLayout({ children }) {
return ( return (
<html lang="ru"> <html lang="ru" suppressHydrationWarning>
<head> <head>
<script dangerouslySetInnerHTML={{ __html: themeInitScript }} />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
<link <link
+22
View File
@@ -0,0 +1,22 @@
import Link from 'next/link';
import Header from '@/components/Header';
import Footer from '@/components/Footer';
import { ArrowLeft } from 'lucide-react';
export default function NotFound() {
return (
<>
<Header />
<main className="container-narrow pt-20 pb-20 text-center">
<div className="text-7xl font-bold mb-4 ink">404</div>
<p className="text-xl mute mb-8">
Такой страницы нет но это не повод грустить
</p>
<Link href="/" className="btn btn-primary">
<ArrowLeft className="w-4 h-4" /> На главную
</Link>
</main>
<Footer />
</>
);
}
+13 -10
View File
@@ -28,22 +28,25 @@ export default async function HomePage() {
{/* Hero */} {/* Hero */}
<section className="container-wide pt-12 pb-10 sm:pt-20 sm:pb-16"> <section className="container-wide pt-12 pb-10 sm:pt-20 sm:pb-16">
<div className="max-w-3xl"> <div className="max-w-3xl">
<div className="inline-flex items-center gap-2 text-xs text-accent bg-accent/10 border border-accent/20 px-3 py-1.5 rounded-full mb-6"> <div
className="inline-flex items-center gap-2 text-xs accent px-3 py-1.5 rounded-full mb-6"
style={{ background: 'rgb(var(--accent) / 0.1)', border: '1px solid rgb(var(--accent) / 0.2)' }}
>
<Sparkles className="w-3.5 h-3.5" /> <Sparkles className="w-3.5 h-3.5" />
Блог, который ведёт ИИ Блог, который ведёт ИИ
</div> </div>
<h1 className="text-4xl sm:text-6xl font-bold tracking-tight leading-tight mb-5"> <h1 className="text-4xl sm:text-6xl font-bold tracking-tight leading-tight mb-5 ink">
Практический ИИ.<br /> Практический ИИ.<br />
<span className="text-mute">Без воды и хайпа.</span> <span className="mute">Без воды и хайпа.</span>
</h1> </h1>
<p className="text-lg text-mute mb-8 max-w-2xl"> <p className="text-lg mute mb-8 max-w-2xl">
Промпты, кейсы, инструменты и разборы. Всё пишет ИИ кроме редакторских заметок. Если хочешь так же вести свой Telegram-канал попробуй наш сервис. Промпты, кейсы, инструменты и разборы. Всё пишет ИИ кроме редакторских заметок. Если хочешь так же вести свой Telegram-канал попробуй наш сервис.
</p> </p>
<div className="flex flex-wrap gap-3"> <div className="flex flex-wrap gap-3">
<Link href="#articles" className="btn-primary"> <Link href="#articles" className="btn btn-primary">
Читать статьи <ArrowRight className="w-4 h-4" /> Читать статьи <ArrowRight className="w-4 h-4" />
</Link> </Link>
<a href="https://app.zeropost.ru" className="btn-ghost"> <a href="https://app.zeropost.ru" className="btn btn-ghost">
Получить ассистента Получить ассистента
</a> </a>
</div> </div>
@@ -60,7 +63,7 @@ export default async function HomePage() {
{/* Rest */} {/* Rest */}
{rest.length > 0 && ( {rest.length > 0 && (
<section className="container-wide pb-12"> <section className="container-wide pb-12">
<h2 className="text-sm font-medium uppercase tracking-widest text-mute mb-5"> <h2 className="text-sm font-medium uppercase tracking-widest mute mb-5">
Последние материалы Последние материалы
</h2> </h2>
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-5"> <div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-5">
@@ -71,18 +74,18 @@ export default async function HomePage() {
{articles.length === 0 && ( {articles.length === 0 && (
<section className="container-wide py-20 text-center"> <section className="container-wide py-20 text-center">
<p className="text-mute">Скоро здесь появятся первые статьи. ИИ уже работает над ними.</p> <p className="mute">Скоро здесь появятся первые статьи. ИИ уже работает над ними.</p>
</section> </section>
)} )}
{/* Tags */} {/* Tags */}
{tags.length > 0 && ( {tags.length > 0 && (
<section className="container-wide pb-12"> <section className="container-wide pb-12">
<h2 className="text-sm font-medium uppercase tracking-widest text-mute mb-4">Темы</h2> <h2 className="text-sm font-medium uppercase tracking-widest mute mb-4">Темы</h2>
<div className="flex flex-wrap gap-2"> <div className="flex flex-wrap gap-2">
{tags.map(t => ( {tags.map(t => (
<Link key={t.tag} href={`/tag/${encodeURIComponent(t.tag)}`} className="tag"> <Link key={t.tag} href={`/tag/${encodeURIComponent(t.tag)}`} className="tag">
#{t.tag} <span className="text-mute/60">({t.cnt})</span> #{t.tag} <span style={{ opacity: 0.6 }}>({t.cnt})</span>
</Link> </Link>
))} ))}
</div> </div>
+4 -4
View File
@@ -21,13 +21,13 @@ export default async function TagPage({ params }) {
<> <>
<Header /> <Header />
<main className="container-wide pt-10 pb-16"> <main className="container-wide pt-10 pb-16">
<Link href="/" className="btn-ghost text-sm mb-4 -ml-2"> <Link href="/" className="btn btn-ghost text-sm mb-4 -ml-2">
<ArrowLeft className="w-4 h-4" /> Все статьи <ArrowLeft className="w-4 h-4" /> Все статьи
</Link> </Link>
<h1 className="text-3xl sm:text-4xl font-bold mb-2">#{tag}</h1> <h1 className="text-3xl sm:text-4xl font-bold mb-2 ink">#{tag}</h1>
<p className="text-mute mb-8">{articles.length} {articles.length === 1 ? 'материал' : 'материалов'}</p> <p className="mute mb-8">{articles.length} {articles.length === 1 ? 'материал' : 'материалов'}</p>
{articles.length === 0 ? ( {articles.length === 0 ? (
<p className="text-mute">Пока пусто.</p> <p className="mute">Пока пусто.</p>
) : ( ) : (
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-5"> <div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-5">
{articles.map(a => <ArticleCard key={a.id} article={a} />)} {articles.map(a => <ArticleCard key={a.id} article={a} />)}
+8 -7
View File
@@ -7,22 +7,23 @@ export default function ArticleCard({ article, featured = false }) {
return ( return (
<Link <Link
href={`/blog/${article.slug}`} href={`/blog/${article.slug}`}
className="article-card block group p-8 sm:p-10 border-accent/30 hover:border-accent" className="article-card block group p-8 sm:p-10"
style={{ borderColor: 'rgb(var(--accent) / 0.3)' }}
> >
<div className="flex flex-wrap items-center gap-2 mb-4"> <div className="flex flex-wrap items-center gap-2 mb-4">
{(article.tags || []).slice(0, 3).map(t => ( {(article.tags || []).slice(0, 3).map(t => (
<span key={t} className="tag">#{t}</span> <span key={t} className="tag">#{t}</span>
))} ))}
</div> </div>
<h2 className="text-2xl sm:text-3xl font-bold mb-3 group-hover:text-accent2 transition-colors leading-tight"> <h2 className="text-2xl sm:text-3xl font-bold mb-3 leading-tight ink group-hover:accent transition-colors">
{article.title} {article.title}
</h2> </h2>
{article.excerpt && ( {article.excerpt && (
<p className="text-mute text-base sm:text-lg leading-relaxed line-clamp-3 mb-4"> <p className="mute text-base sm:text-lg leading-relaxed line-clamp-3 mb-4">
{article.excerpt} {article.excerpt}
</p> </p>
)} )}
<div className="flex items-center gap-4 text-xs text-mute"> <div className="flex items-center gap-4 text-xs mute">
<span>{formatDate(article.published_at)}</span> <span>{formatDate(article.published_at)}</span>
{article.reading_time && ( {article.reading_time && (
<span className="inline-flex items-center gap-1"> <span className="inline-flex items-center gap-1">
@@ -41,13 +42,13 @@ export default function ArticleCard({ article, featured = false }) {
<span key={t} className="tag">#{t}</span> <span key={t} className="tag">#{t}</span>
))} ))}
</div> </div>
<h3 className="text-lg font-semibold mb-2 group-hover:text-accent2 transition-colors leading-snug"> <h3 className="text-lg font-semibold mb-2 ink group-hover:accent transition-colors leading-snug">
{article.title} {article.title}
</h3> </h3>
{article.excerpt && ( {article.excerpt && (
<p className="text-mute text-sm line-clamp-3 mb-4">{article.excerpt}</p> <p className="mute text-sm line-clamp-3 mb-4">{article.excerpt}</p>
)} )}
<div className="flex items-center gap-3 text-xs text-mute"> <div className="flex items-center gap-3 text-xs mute">
<span>{formatDate(article.published_at)}</span> <span>{formatDate(article.published_at)}</span>
{article.reading_time && ( {article.reading_time && (
<span className="inline-flex items-center gap-1"> <span className="inline-flex items-center gap-1">
+4 -4
View File
@@ -2,14 +2,14 @@ import Link from 'next/link';
export default function Footer() { export default function Footer() {
return ( return (
<footer className="border-t border-border/60 mt-20"> <footer className="border-t-soft mt-20">
<div className="container-wide py-10 flex flex-col sm:flex-row items-center justify-between gap-4 text-sm text-mute"> <div className="container-wide py-10 flex flex-col sm:flex-row items-center justify-between gap-4 text-sm mute">
<div> <div>
© {new Date().getFullYear()} ZeroPost генерируется ИИ, читается людьми © {new Date().getFullYear()} ZeroPost генерируется ИИ, читается людьми
</div> </div>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<Link href="/about" className="hover:text-white transition-colors">О проекте</Link> <Link href="/about" className="hover:ink transition-colors">О проекте</Link>
<a href="https://app.zeropost.ru" className="hover:text-white transition-colors">Сервис</a> <a href="https://app.zeropost.ru" className="hover:ink transition-colors">Сервис</a>
</div> </div>
</div> </div>
</footer> </footer>
+14 -10
View File
@@ -1,22 +1,26 @@
import Link from 'next/link'; import Link from 'next/link';
import { Sparkles, Github } from 'lucide-react'; import { Sparkles } from 'lucide-react';
import ThemeToggle from './ThemeToggle';
export default function Header() { export default function Header() {
return ( return (
<header className="border-b border-border/60 sticky top-0 z-20 bg-bg/85 backdrop-blur-md"> <header className="sticky top-0 z-20 border-b-soft" style={{ background: 'rgb(var(--bg) / 0.85)', backdropFilter: 'saturate(180%) blur(12px)' }}>
<div className="container-wide flex items-center justify-between py-4"> <div className="container-wide flex items-center justify-between py-4">
<Link href="/" className="flex items-center gap-2 group"> <Link href="/" className="flex items-center gap-2 group">
<div className="w-8 h-8 rounded-lg bg-accent/15 flex items-center justify-center group-hover:bg-accent/25 transition-colors"> <div className="w-8 h-8 rounded-lg flex items-center justify-center transition-colors" style={{ background: 'rgb(var(--accent) / 0.12)' }}>
<Sparkles className="w-4 h-4 text-accent" /> <Sparkles className="w-4 h-4 accent" />
</div> </div>
<span className="font-bold text-lg tracking-tight">ZeroPost</span> <span className="font-bold text-lg tracking-tight ink">ZeroPost</span>
</Link> </Link>
<nav className="flex items-center gap-1 sm:gap-4 text-sm"> <nav className="flex items-center gap-1 sm:gap-2 text-sm">
<Link href="/" className="btn-ghost text-sm py-1.5">Статьи</Link> <Link href="/" className="btn btn-ghost text-sm py-1.5">Статьи</Link>
<Link href="/about" className="btn-ghost text-sm py-1.5">О проекте</Link> <Link href="/about" className="btn btn-ghost text-sm py-1.5">О проекте</Link>
<a href="https://app.zeropost.ru" className="btn-primary text-sm py-1.5"> <a href="https://app.zeropost.ru" className="btn btn-primary text-sm py-1.5 ml-1">
Открыть кабинет Кабинет
</a> </a>
<div className="ml-1">
<ThemeToggle />
</div>
</nav> </nav>
</div> </div>
</header> </header>
+36
View File
@@ -0,0 +1,36 @@
'use client';
import { useEffect, useState } from 'react';
import { Sun, Moon } from 'lucide-react';
export default function ThemeToggle() {
const [theme, setTheme] = useState('light');
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
const isDark = document.documentElement.classList.contains('dark');
setTheme(isDark ? 'dark' : 'light');
}, []);
function toggle() {
const next = theme === 'dark' ? 'light' : 'dark';
setTheme(next);
if (next === 'dark') document.documentElement.classList.add('dark');
else document.documentElement.classList.remove('dark');
try { localStorage.setItem('theme', next); } catch {}
}
// плейсхолдер до маунта, чтобы кнопка не прыгала
if (!mounted) return <div className="w-9 h-9" aria-hidden />;
return (
<button
onClick={toggle}
className="w-9 h-9 inline-flex items-center justify-center rounded-lg mute hover:ink hover:surface-2 transition-colors"
title={theme === 'dark' ? 'Включить светлую тему' : 'Включить тёмную тему'}
aria-label="Переключить тему"
>
{theme === 'dark' ? <Sun className="w-4 h-4" /> : <Moon className="w-4 h-4" />}
</button>
);
}
+22 -20
View File
@@ -1,5 +1,6 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
module.exports = { module.exports = {
darkMode: 'class',
content: [ content: [
'./app/**/*.{js,jsx,ts,tsx}', './app/**/*.{js,jsx,ts,tsx}',
'./components/**/*.{js,jsx,ts,tsx}', './components/**/*.{js,jsx,ts,tsx}',
@@ -7,14 +8,15 @@ module.exports = {
theme: { theme: {
extend: { extend: {
colors: { colors: {
bg: '#0a0a0a', // Используем CSS-переменные напрямую — для совместимости со старым кодом
surface: '#141414', bg: 'rgb(var(--bg) / <alpha-value>)',
surface2: '#1c1c1c', surface: 'rgb(var(--surface) / <alpha-value>)',
border: '#2a2a2a', surface2: 'rgb(var(--surface-2) / <alpha-value>)',
accent: '#10b981', border: 'rgb(var(--border) / <alpha-value>)',
accent2: '#34d399', ink: 'rgb(var(--ink) / <alpha-value>)',
ink: '#e5e7eb', mute: 'rgb(var(--mute) / <alpha-value>)',
mute: '#9ca3af', accent: 'rgb(var(--accent) / <alpha-value>)',
accent2: 'rgb(var(--accent-2) / <alpha-value>)',
}, },
fontFamily: { fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'], sans: ['Inter', 'system-ui', 'sans-serif'],
@@ -23,18 +25,18 @@ module.exports = {
typography: ({ theme }) => ({ typography: ({ theme }) => ({
DEFAULT: { DEFAULT: {
css: { css: {
'--tw-prose-body': theme('colors.ink'), '--tw-prose-body': 'rgb(var(--ink))',
'--tw-prose-headings': '#ffffff', '--tw-prose-headings': 'rgb(var(--ink))',
'--tw-prose-links': theme('colors.accent2'), '--tw-prose-links': 'rgb(var(--accent-2))',
'--tw-prose-bold': '#ffffff', '--tw-prose-bold': 'rgb(var(--ink))',
'--tw-prose-quotes': theme('colors.mute'), '--tw-prose-quotes': 'rgb(var(--mute))',
'--tw-prose-quote-borders': theme('colors.accent'), '--tw-prose-quote-borders': 'rgb(var(--accent))',
'--tw-prose-code': theme('colors.accent2'), '--tw-prose-code': 'rgb(var(--accent-2))',
'--tw-prose-pre-bg': theme('colors.surface2'), '--tw-prose-pre-bg': 'rgb(var(--surface-2))',
'--tw-prose-pre-code': theme('colors.ink'), '--tw-prose-pre-code': 'rgb(var(--ink))',
'--tw-prose-bullets': theme('colors.mute'), '--tw-prose-bullets': 'rgb(var(--mute))',
'--tw-prose-counters': theme('colors.mute'), '--tw-prose-counters': 'rgb(var(--mute))',
'--tw-prose-hr': theme('colors.border'), '--tw-prose-hr': 'rgb(var(--border))',
}, },
}, },
}), }),