content: update building-minimal-design-systems.md, deneme.md, blog-detail.ts (2026-03-11 07:00)

This commit is contained in:
Poyraz Avsever
2026-03-11 10:00:20 +03:00
parent 6e29f0fbf9
commit 2fbf1f532d
3 changed files with 252 additions and 185 deletions
@@ -0,0 +1,190 @@
---
title: "Building Minimal Design Systems"
category: "React"
date: "March 2026"
readTime: "12 min read"
author: "Poyraz Avsever"
excerpt: "A practical and detailed playbook for building a clean, scalable UI system with markdown-driven documentation, mermaid diagrams, and implementation-ready code."
coverImage: "/news/design.svg"
---
## Why Most Design Systems Become Heavy
Most teams start with good intentions and end up with too many variants, too many exceptions, and no clear usage guide.
The real problem is usually **decision sprawl**:
- Too many size and style combinations
- Inconsistent naming conventions
- Documentation that explains props, but not decisions
---
## Core Principle: Constrain First, Expand Later
Start with a strict base:
1. Typography scale
2. Spacing scale
3. Semantic colors
4. A handful of primitives
> A design system is not a component museum.
> It is an agreement that helps teams ship consistent UI quickly.
---
## Suggested Token Strategy
```json
{
"font": {
"size": { "sm": "0.875rem", "base": "1rem", "lg": "1.125rem" },
"weight": { "regular": 400, "medium": 500, "bold": 700 }
},
"space": {
"1": "0.25rem",
"2": "0.5rem",
"3": "0.75rem",
"4": "1rem",
"6": "1.5rem"
}
}
```
---
## Architecture Flow
```mermaid
flowchart LR
A[Design Tokens] --> B[Primitives]
B --> C[Composed Components]
C --> D[Page Sections]
D --> E[Product Screens]
```
---
## Example: Button Primitive
```tsx
import { cva } from "class-variance-authority";
const buttonVariants = cva(
"inline-flex items-center justify-center rounded-sm text-sm font-medium transition-colors",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground",
outline: "border border-border bg-background",
ghost: "bg-transparent"
},
size: {
sm: "h-8 px-3",
md: "h-9 px-4",
lg: "h-10 px-5"
}
},
defaultVariants: {
variant: "default",
size: "md"
}
}
);
```
Why this works:
- Variants are explicit
- Defaults are stable
- Consumers avoid ad-hoc class combinations
---
## Documentation Pattern That Scales
Instead of "prop-only docs", use this pattern for every component:
### 1) When to use
Explain context and intent.
### 2) Do / Don't
Show 2 positive and 2 negative examples.
### 3) Accessibility checklist
- Keyboard interaction
- Focus visibility
- ARIA coverage
### 4) Code examples by complexity
- Basic
- With validation
- With async state
---
## Mermaid Sequence for Contribution Workflow
```mermaid
sequenceDiagram
participant Dev as Developer
participant DS as Design System
participant App as Product App
Dev->>DS: Add primitive or variant
DS-->>Dev: Exports + docs update
Dev->>App: Integrate component
App-->>Dev: UX feedback
Dev->>DS: Refine API
```
---
## Example: Page-Level Composition
```tsx
export function BlogHeader() {
return (
<header className="space-y-2">
<Badge>React</Badge>
<h1 className="text-2xl font-bold">Building Minimal Design Systems</h1>
<p className="text-sm text-muted-foreground">
Practical notes from shipping real components.
</p>
</header>
);
}
```
---
## Common Failure Modes
| Problem | Why it happens | Better approach |
|---|---|---|
| Variant explosion | No ownership rules | Add contribution guardrails |
| Styling overrides everywhere | Weak defaults | Strengthen semantic tokens |
| Inconsistent docs | No template | Use one markdown template |
| Slow adoption | API too abstract | Show direct usage examples |
---
## Final Checklist Before Shipping a New Component
- [ ] API is minimal and explicit
- [ ] States are documented (default, hover, focus, disabled, loading)
- [ ] Keyboard support verified
- [ ] Mobile rendering verified
- [ ] Real usage example added to docs
---
## Closing Notes
A minimal design system should feel boring in the best way.
When engineers can predict behavior, teams move faster with fewer regressions.
Focus on **consistency, clarity, and constraints**.
Those three will outperform "feature-rich" component sets in the long run.
+10
View File
@@ -0,0 +1,10 @@
---
title: deneme
category: General
date: Mart 2026
readTime: 12 min read
author: Poyraz Avsever
excerpt: asdasdasdasd
coverImage: /news/design.svg
---
asdasdasdasd
+52 -185
View File
@@ -1,3 +1,7 @@
import fs from "node:fs/promises";
import path from "node:path";
import matter from "gray-matter";
export type BlogDetail = {
slug: string;
title: string;
@@ -10,202 +14,65 @@ export type BlogDetail = {
markdown: string;
};
export const BLOG_DETAILS: BlogDetail[] = [
{
slug: "building-minimal-design-systems",
title: "Building Minimal Design Systems",
category: "React",
date: "March 2026",
readTime: "12 min read",
author: "Poyraz Avsever",
excerpt:
"A practical and detailed playbook for building a clean, scalable UI system with markdown-driven documentation, mermaid diagrams, and implementation-ready code.",
coverImage: "/news/design.svg",
markdown: `
## Why Most Design Systems Become Heavy
const BLOG_CONTENT_DIR = path.join(process.cwd(), "content", "blog");
Most teams start with good intentions and end up with too many variants, too many exceptions, and no clear usage guide.
The real problem is usually **decision sprawl**:
- Too many size and style combinations
- Inconsistent naming conventions
- Documentation that explains props, but not decisions
---
## Core Principle: Constrain First, Expand Later
Start with a strict base:
1. Typography scale
2. Spacing scale
3. Semantic colors
4. A handful of primitives
> A design system is not a component museum.
> It is an agreement that helps teams ship consistent UI quickly.
---
## Suggested Token Strategy
\`\`\`json
{
"font": {
"size": { "sm": "0.875rem", "base": "1rem", "lg": "1.125rem" },
"weight": { "regular": 400, "medium": 500, "bold": 700 }
},
"space": {
"1": "0.25rem",
"2": "0.5rem",
"3": "0.75rem",
"4": "1rem",
"6": "1.5rem"
function toSafeString(value: unknown, fallback: string) {
if (typeof value !== "string") return fallback;
const trimmed = value.trim();
return trimmed || fallback;
}
function normalizeSlug(fileName: string) {
return fileName.replace(/\.md$/i, "");
}
\`\`\`
---
function mapMarkdownToBlogDetail(fileName: string, raw: string): BlogDetail {
const parsed = matter(raw);
const slug = normalizeSlug(fileName);
## Architecture Flow
\`\`\`mermaid
flowchart LR
A[Design Tokens] --> B[Primitives]
B --> C[Composed Components]
C --> D[Page Sections]
D --> E[Product Screens]
\`\`\`
---
## Example: Button Primitive
\`\`\`tsx
import { cva } from "class-variance-authority";
const buttonVariants = cva(
"inline-flex items-center justify-center rounded-sm text-sm font-medium transition-colors",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground",
outline: "border border-border bg-background",
ghost: "bg-transparent"
},
size: {
sm: "h-8 px-3",
md: "h-9 px-4",
lg: "h-10 px-5"
}
},
defaultVariants: {
variant: "default",
size: "md"
return {
slug,
title: toSafeString(parsed.data.title, slug),
category: toSafeString(parsed.data.category, "General"),
date: toSafeString(parsed.data.date, ""),
readTime: toSafeString(parsed.data.readTime, ""),
author: toSafeString(parsed.data.author, "Poyraz Avsever"),
excerpt: toSafeString(parsed.data.excerpt, ""),
coverImage: toSafeString(parsed.data.coverImage, "/news/design.svg"),
markdown: parsed.content.trim(),
};
}
export async function listBlogDetails(): Promise<BlogDetail[]> {
let files: string[] = [];
try {
files = await fs.readdir(BLOG_CONTENT_DIR);
} catch {
return [];
}
const markdownFiles = files.filter((fileName) => fileName.endsWith(".md"));
const posts = await Promise.all(
markdownFiles.map(async (fileName) => {
const targetPath = path.join(BLOG_CONTENT_DIR, fileName);
const raw = await fs.readFile(targetPath, "utf8");
return mapMarkdownToBlogDetail(fileName, raw);
}),
);
\`\`\`
Why this works:
- Variants are explicit
- Defaults are stable
- Consumers avoid ad-hoc class combinations
---
## Documentation Pattern That Scales
Instead of “prop-only docs”, use this pattern for every component:
### 1) When to use
Explain context and intent.
### 2) Do / Don't
Show 2 positive and 2 negative examples.
### 3) Accessibility checklist
- Keyboard interaction
- Focus visibility
- ARIA coverage
### 4) Code examples by complexity
- Basic
- With validation
- With async state
---
## Mermaid Sequence for Contribution Workflow
\`\`\`mermaid
sequenceDiagram
participant Dev as Developer
participant DS as Design System
participant App as Product App
Dev->>DS: Add primitive or variant
DS-->>Dev: Exports + docs update
Dev->>App: Integrate component
App-->>Dev: UX feedback
Dev->>DS: Refine API
\`\`\`
---
## Example: Page-Level Composition
\`\`\`tsx
export function BlogHeader() {
return (
<header className="space-y-2">
<Badge>React</Badge>
<h1 className="text-2xl font-bold">Building Minimal Design Systems</h1>
<p className="text-sm text-muted-foreground">
Practical notes from shipping real components.
</p>
</header>
);
return posts.sort((a, b) => a.slug.localeCompare(b.slug));
}
\`\`\`
---
export async function getBlogDetailBySlug(slug: string): Promise<BlogDetail | null> {
const safeSlug = slug.trim().toLowerCase();
if (!safeSlug) return null;
## Common Failure Modes
const targetPath = path.join(BLOG_CONTENT_DIR, `${safeSlug}.md`);
| Problem | Why it happens | Better approach |
|---|---|---|
| Variant explosion | No ownership rules | Add contribution guardrails |
| Styling overrides everywhere | Weak defaults | Strengthen semantic tokens |
| Inconsistent docs | No template | Use one markdown template |
| Slow adoption | API too abstract | Show direct usage examples |
---
## Final Checklist Before Shipping a New Component
- [ ] API is minimal and explicit
- [ ] States are documented (default, hover, focus, disabled, loading)
- [ ] Keyboard support verified
- [ ] Mobile rendering verified
- [ ] Real usage example added to docs
---
## Closing Notes
A minimal design system should feel boring in the best way.
When engineers can predict behavior, teams move faster with fewer regressions.
Focus on **consistency, clarity, and constraints**.
Those three will outperform “feature-rich” component sets in the long run.
`,
},
] as const;
export function getBlogDetailBySlug(slug: string) {
return BLOG_DETAILS.find((post) => post.slug === slug) ?? null;
try {
const raw = await fs.readFile(targetPath, "utf8");
return mapMarkdownToBlogDetail(`${safeSlug}.md`, raw);
} catch {
return null;
}
}