Personal site and blog of Muhammaddiyor Tohirov. Next.js 16 App Router, Tailwind CSS v4, MDX.
- Next.js 16.3 (Turbopack, React Compiler, typed routes, root params)
- React 19.3, TypeScript 6
- Tailwind CSS 4 with a custom pixel-accent design system (
src/assets/css/tailwind.css) - MDX via
next-mdx-remote, Shiki dual-theme code blocks next-themesfor light/dark,uz/enrouting under/[lang]
bun install
cp .env.example .env
bun run dev| Command | What it does |
|---|---|
bun run dev |
dev server |
bun run build |
production build |
bun run lint / bun run fix |
ESLint |
bun run typecheck |
next typegen + tsc |
bun run post <slug> --lang uz |
new blog post (see content/README.md) |
bun run post <slug> --note |
new short note |
src/
app/[lang]/ routes (home, blog, notes, projects + case studies, resume, uses, feed.xml)
app/api/content/ serves post assets from content/
components/ ui primitives, widgets, mdx renderer
data/ profile, projects, resume, uses (edit these)
i18n/ locales + dictionaries
lib/ content loaders (blog, notes, case studies), dither generator, og images, metadata
proxy.ts `/` → `/uz` or `/en` (cookie, then Accept-Language)
content/ MDX, one file per language: blogs/ (posts), notes/, projects/ (case studies)
scripts/ post scaffolder, Telegram announcer
- Site copy:
src/i18n/dictionaries/{uz,en}.ts - Projects, resume, uses:
src/data/*.ts - Blog posts:
content/blogs/<slug>/index.{uz,en}.mdx - Case studies:
content/projects/<project-slug>/index.{uz,en}.mdx(slug must matchsrc/data/projects.ts) - Contact links:
src/config/site.ts
- CI (
.github/workflows/ci.yml): lint + production build on every PR and on pushes tonext. - Telegram (
.github/workflows/telegram.yml): after a push tonextthat publishes a post or note (published: truein a new file, or flipped fromfalse), waits until the page is live and posts it to the channel. Edits to already published posts are not announced.- Secrets:
TELEGRAM_BOT_TOKEN,TELEGRAM_CHAT_ID(add the bot to the channel as an admin). - Variable (optional):
TELEGRAM_LANGS, defaultuz; setuz,ento announce both languages. - Manual run: Actions → Telegram → Run workflow, with the file paths (and "dry run" to preview).
- Secrets: