Darya is a private, content-first publishing engine built around a single idea: writing a post should be a content change, not a code change. A Markdown file is dropped into the content folder, pushed, and it is live within minutes. There is no database, no external CMS, and no build step that regenerates a manifest by hand.
The name comes from the Persian word for sea, chosen for a platform meant to feel calm, deliberate, and easy to navigate. This is a closed, exclusive publication with a single author. It is not open for contributions, issues, or pull requests, and this document exists purely to describe how the system is built.
- Design Philosophy
- Color System
- Typography
- Architecture
- Content Pipeline
- Publishing Workflow
- Testing
- Tech Stack
- Project Structure
- Continuous Integration
- Localization
- Key Design Principles
Every visual decision in Darya answers to three principles, carried directly from the site's own design system.
| Principle | What it means in practice |
|---|---|
| Attention | An element that does not clarify something gets removed. No decoration for its own sake. |
| Honesty | Surfaces are flat, never deceptive. No gradient exists to mask a weak design decision. |
| Silence | Whitespace is part of the message. Low density, controlled contrast, a single action color. |
The result is a reading surface designed to disappear, so the writing is the only thing that holds attention.
Darya's palette is built from five roles rather than a list of pleasant colors: a neutral canvas for reading, an ink for content, and exactly one action color used to direct attention. Gold appears only as a secondary accent and never competes with the primary color. There are no gradients anywhere in the system; every surface is flat and consistent across both light and dark mode.
| Token | Role | Light | Dark | Usage |
|---|---|---|---|---|
| Void | Primary background | #faf9f6 |
#080810 |
The neutral canvas. Deliberately ivory rather than pure white, so long reading sessions stay comfortable. |
| Panel | Secondary surface | #f2f0ea |
#0d0d18 |
Card and image backgrounds, separated from the page without a hard border. |
| Ink | Primary text | #232019 |
#f0eef8 |
Warm charcoal rather than pure black, for sufficient contrast without eye fatigue. |
| Rose | Brand and action color | #b3312b |
#d85a50 |
The only action color on the site: active links, the primary button, article titles, attention markers. Used sparingly and precisely. |
| Gold | Secondary accent | #a9822f |
#c9a96e |
Reserved for second-tier emphasis such as ruled quotes and marginal notes, never as a section's primary color. |
Two type families, two distinct jobs. Noto Naskh Arabic carries headlines and the emotional beats of the text, where rhythm and character outweigh rapid legibility. Vazirmatn carries body copy, navigation, and interface elements, set in a light weight for long paragraphs so the eye does not tire.
| Role | Sample | Size | Typeface |
|---|---|---|---|
| Hero | یادداشتهایی درباره هوش مصنوعی | clamp(3rem, 7.5vw, 6.5rem) |
Noto Naskh Arabic · 400 |
| Page H1 | اینجا برای نگاهکردن آهسته ساخته شده است | clamp(2.4rem, 6vw, 4.4rem) |
Noto Naskh Arabic · 400 |
| Section H2 | چرا اینجا نوشته میشود | clamp(1.35rem, 3.5vw, 1.7rem) |
Noto Naskh Arabic · 500 |
| Body copy | نوشتن، شکلی از توجهکردن است | clamp(0.95rem, 2vw, 1.05rem) |
Vazirmatn · 300 |
| Label / metadata | یک دفترچه شخصی · از ۱۴۰۳ | 0.72rem – 0.85rem |
Vazirmatn · 300–400 |
Motion follows the same restraint. Most transitions use cubic-bezier(0.16, 1, 0.3, 1), with a gentler overshoot curve reserved for small interactions like buttons. No animation is added purely for spectacle; every motion either aids legibility or confirms an action.
Darya is organized into four layers, each with a single responsibility. Content flows downward through parsing and typing before it ever reaches a rendered page, which keeps the UI layer entirely free of parsing or fetching logic.
Layer 1, Content. Plain text: site configuration, Markdown posts, and cover images. Nothing here is generated, and nothing here requires a database.
Layer 2, Services. Domain logic that turns raw text into structured data: a content service acting as repository and cache, a frontmatter parser for post metadata, a Markdown parser that converts the post body into typed blocks, and a Jalali date formatter that handles both calendar systems and estimated read time.
Layer 3, Models. Typed, immutable domain objects, namely Post and SiteConfig, giving the rest of the application a stable shape to work with regardless of how the underlying text was authored.
Layer 4, UI. Pages and components that consume typed data exclusively. No component parses Markdown, fetches raw files, or manipulates the DOM directly.
This is the concrete path a single post takes from a saved file to a rendered page.
- Markdown file. A post is authored as a single
.mdfile with a frontmatter header and a Markdown body. - Vite glob. The file is discovered automatically at build time through
import.meta.glob, with nothing manually imported or registered. - Parse. The frontmatter parser and Markdown parser convert raw text into structured blocks.
- Post instance. The parsed data becomes a typed, immutable
Postobject, sorted by date alongside the rest of the catalog. - Rendered. The post appears both as a card on the listing page and as a full post page, with zero manual wiring.
Adding a post means dropping a file into the posts folder and pushing. There is no posts.json to regenerate, no route to register, and no import statement to add anywhere in the codebase.
A first class admin interface lives at /admin, authenticated through GitHub OAuth, sharing the same build and the same design system as the public site rather than existing as a separate tool.
Cover images are named after the post's slug rather than a random suffix, so re-uploading a cover always overwrites the same file instead of leaving orphaned copies behind. A background cleanup sweep runs after every save or delete, comparing each post's declared cover against everything actually committed, and removes anything left unreferenced.
A small, fast test suite backs the parts of the system that are easiest to break silently: the shape of the content itself, and the handful of places that write directly into the page rather than rendering through a component.
- Unit tests (Vitest, jsdom, Testing Library) cover the document-head logic in isolation, asserting that page title, description, and related tags are written correctly and cleaned up correctly as a reader moves between routes.
- Content integrity tests run the same
ContentServicethe app uses at runtime and assert on the result: every post has a unique slug, a valid date, a non-empty title and excerpt, and a cover image that actually exists on disk.
npm run test runs the suite once; npm run test:watch keeps it running while editing. npm run verify chains lint, tests, and a production build together, the same sequence CI runs.
| Concern | Choice |
|---|---|
| Build tool | Vite |
| UI layer | React 18 |
| Language | TypeScript, strict mode |
| Routing | React Router, client side, with a GitHub Pages 404 redirect fallback |
| Content format | Markdown with frontmatter |
| Content discovery | import.meta.glob at build time |
| Date handling | Jalali and Gregorian calendar formatting |
| Testing | Vitest, jsdom, Testing Library |
| Admin authentication | GitHub OAuth |
| Admin persistence | GitHub REST API, direct commits |
| Hosting | GitHub Pages |
| CI/CD | GitHub Actions |
daryablog.github.io/
├── src/
│ ├── content/
│ │ ├── site.json # site wide configuration
│ │ └── posts/ # one .md file per post
│ ├── services/
│ │ ├── ContentService.*
│ │ ├── FrontmatterParser.*
│ │ ├── MarkdownParser.*
│ │ └── JalaliDateFormatter.*
│ ├── models/
│ │ ├── Post.*
│ │ └── SiteConfig.*
│ ├── components/ # PostCard, MarkdownBody, SiteNav, and friends
│ ├── admin/
│ │ ├── components/ # editor UI, image fields
│ │ ├── context/ # auth and toast providers
│ │ ├── lib/ # GitHub API, auth, image processing, media cleanup
│ │ └── pages/ # login, post list, post editor, settings
│ ├── pages/ # HomePage, PostPage, AboutPage
│ └── test/
│ └── setup.* # jsdom + Testing Library setup
└── public/
└── images/ # post cover images
Every push to main runs through a single pipeline: install, lint with zero warnings tolerated, run tests, type-check, build, then deploy to GitHub Pages. Nothing reaches production without passing the same checks that run locally.
checkout → install (npm ci) → lint → test → type-check → build → upload → deploy
Persian is treated as a first class concern rather than an afterthought. The interface reads right to left throughout, and dates are rendered using the Jalali calendar alongside standard formatting, reflecting how both calendar systems coexist in everyday Persian language contexts.
- Content as code. Posts are plain text, reviewed and versioned exactly like source code.
- No hidden state. No database, no generated manifest that can silently drift from the actual content.
- Typed boundaries. Once content passes through the services layer, every downstream consumer works with typed, predictable objects instead of raw strings.
- Dumb components on purpose. UI components render data. They do not fetch it, parse it, or transform it.
- One action color. Rose is the only color used to direct attention, anywhere in the interface.
- Localization is not an afterthought. Calendar and date formatting are handled centrally rather than duplicated across components.
Darya is a private, single author publication. This repository is not open for external contributions.