Skip to content

patricio0312rev/dev-blog

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

blog.patriciomarroquin.dev โ€“ Personal Developer Blog

A modern, fast developer blog built with Astro, React, TypeScript, Tailwind 4, and an AI-powered content pipeline.

TypeScript Astro React Tailwind Vercel


โœจ Features

  • ๐ŸŒ— Dark / Light mode

    • Respects system preference (prefers-color-scheme)
    • Manual toggle powered by a data-theme attribute
  • ๐Ÿ“ฐ MDX-powered blog

    • Articles live in src/content/articles/*.mdx
    • Custom BlogPost.astro layout with consistent typography and spacing
    • Reading time, publication meta, tags, and category badges
  • ๐Ÿ”Š Reading experience upgrades

    • Reading progress bar (top of the article)
    • Estimated reading time
    • Text-to-speech mode: โ€œListen / Stop listeningโ€ button that reads:
      • Title
      • Description
      • Full article body
  • ๐Ÿง‘โ€๐Ÿ’ป Beautiful code blocks

    • Shiki-based syntax highlighting via Astroโ€™s markdown pipeline
    • Custom CodeBlock.astro wrapper for MDX
    • โ€œTraffic lightโ€ header + language label + Copy button
    • Optional filename="yourfile.tsx" meta support in code fences
  • ๐Ÿ“… Content calendar

    • src/pages/calendar.astro + ContentCalendarPage.tsx
    • Reads monthly plans from content-plans/*.json
    • Shows:
      • Planned vs Published articles
      • Category color dots (๐Ÿ”ฅ Trending, ๐Ÿ“š Tutorial, ๐Ÿ”ฌ Deep Dive)
      • Upcoming articles list
    • Published entries link directly to /blog/[slug]
  • ๐Ÿค– AI-powered content pipeline

    • Monthly content plan generator (JSON under content-plans/)
    • Daily article generator (MDX under src/content/articles/)
    • Uses OpenAIโ€™s Responses API
    • GitHub Actions open PRs so content can be reviewed before publishing
  • ๐Ÿ” Full-text search (Pagefind)

    • Static search index generated after each build
    • Client-side search modal (SearchModal.tsx) with:
      • Debounced queries
      • Keyboard navigation (โ†‘ / โ†“ / โ†ต / ESC)
      • Recent searches stored in localStorage
    • Results show title, excerpt, category badge, and tags
  • ๐ŸŒ Production ready

    • Astro static site generation
    • Deployed on Vercel
    • Vercel Web Analytics enabled
    • SEO-friendly structure + sitemap

๐Ÿš€ Quick Start

This project uses pnpm.

# Install dependencies
pnpm install

# Start development server
pnpm dev

# Build for production (static output)
pnpm build

# Preview the production build
pnpm preview

Linting (if configured)

pnpm lint

๐Ÿค– Content Automation

Two scripts handle content planning and generation.

1) Generate monthly content plan

Creates/updates a JSON file in content-plans/YYYY-MM.json with a schedule of articles for the month (category, title, slug, angle, outline, etc.).

pnpm generate:plan
  • Looks at the current month (e.g. "2025-12")
  • Keeps existing months; doesnโ€™t overwrite unrelated data
  • Used by the Content Calendar page

2) Generate todayโ€™s article from the plan

Reads the monthโ€™s plan, finds todayโ€™s entry, and generates a full MDX article file (with frontmatter + body):

pnpm generate:article
  • Output: src/content/articles/YYYY-MM-DD-slug-from-plan.mdx

  • Uses:

    • Your outlined sections
    • Code ideas
    • Media ideas (images/diagrams)
  • Enforces:

    • Real, useful content (not fluff)

    • Multiple code snippets

    • Optional filename="..." in code fences for better code block headers

    • Final signature:

      Until next time, happy coding ๐Ÿ‘จโ€๐Ÿ’ป  
      โ€“ Juan Patricio ๐Ÿ’œ

โš ๏ธ These scripts require OPENAI_API_KEY in your .env.


๐Ÿ” GitHub Actions (Automation Overview)

(File names are suggestions; adjust if you named them differently.)

.github/workflows/content-plan.yml

  • Runs: monthly, on the 1st (e.g. 0 9 1 * *)
  • Does:
    • Checks out the repo
    • Runs pnpm generate:plan
    • Commits the updated content-plans/YYYY-MM.json
    • Opens a PR with a conventional commit-style message, e.g.:
      • feat(content): add content plan for 2025-12

.github/workflows/generate-article.yml

  • Runs: daily around midday (UTC / chosen TZ)
  • Does:
    • Checks out the repo
    • Runs pnpm generate:article
    • If a new article is generated:
      • Commits the MDX file under src/content/articles/
      • Opens a PR, e.g.:
        • feat(article): add post for 2025-12-06

This keeps you in the loop: AI proposes, you review & merge.


๐Ÿ” Full-text Search

Search is powered by Pagefind and runs entirely on the client.

How it works

  • After astro build, a post-build script runs:

    pnpm build
    # -> astro build
    # -> node scripts/build-search-index.mjs
  • scripts/build-search-index.mjs:

    • Detects the correct static output directory:

      • Uses .vercel/output/static when deployed on Vercel (Astro + Vercel adapter)
      • Falls back to dist when running locally
    • Runs Pagefind against that directory:

      npx pagefind --site "<output-dir>"
    • Generates the search bundle and index under /pagefind (including pagefind.js), alongside other static assets.

Frontend integration (SearchModal.tsx)

  • The search modal dynamically loads the Pagefind client at runtime:

    const pagefind = await import(/* @vite-ignore */ "/pagefind/pagefind.js");
  • It performs pagefind.search(query) and maps each result to:

    • url
    • title
    • excerpt (HTML stripped to plain text)
    • meta.category
    • meta.tags
    • meta.publish_date
  • UX features:

    • Debounced search requests
    • Keyboard navigation (โ†‘ / โ†“ / โ†ต / ESC)
    • Loading and โ€œno resultsโ€ states
    • Recent searches stored in localStorage with a โ€œClearโ€ option
    • Result cards showing title, excerpt, category badge, and tags

All searching happens client-side on top of the static HTML generated by Astro, so the site remains fast, statically hosted, and independent of external search services.


๐Ÿ“ Project Structure

High-level overview of the Astro + React + MDX setup.

src/
โ”œโ”€โ”€ components/
โ”‚   โ”œโ”€โ”€ ui/                    # Reusable UI primitives
โ”‚   โ”‚   โ”œโ”€โ”€ Button.tsx
โ”‚   โ”‚   โ”œโ”€โ”€ Tag.tsx
โ”‚   โ”‚   โ”œโ”€โ”€ CodeContainer.tsx  # React version (for non-MDX usage)
โ”‚   โ”‚   โ””โ”€โ”€ ThemeToggle.tsx
โ”‚   โ”œโ”€โ”€ articles/
โ”‚   โ”‚   โ”œโ”€โ”€ ArticleCard.tsx
โ”‚   โ”‚   โ””โ”€โ”€ ArticleCategoryBadge.tsx
โ”‚   โ””โ”€โ”€ layout/
โ”‚       โ”œโ”€โ”€ Navbar.tsx
โ”‚       โ”œโ”€โ”€ MobileNav.tsx
โ”‚       โ””โ”€โ”€ Footer.tsx
โ”œโ”€โ”€ content/
โ”‚   โ””โ”€โ”€ articles/              # MDX blog posts
โ”‚       โ”œโ”€โ”€ 2025-12-06-react-19-....mdx
โ”‚       โ””โ”€โ”€ ...
โ”œโ”€โ”€ layouts/
โ”‚   โ”œโ”€โ”€ BaseLayout.astro       # Shared shell for pages
โ”‚   โ””โ”€โ”€ BlogPost.astro         # Article layout (reading UX, TTS, etc.)
โ”œโ”€โ”€ pages/
โ”‚   โ”œโ”€โ”€ index.astro            # Home / landing
โ”‚   โ”œโ”€โ”€ blog/
โ”‚   โ”‚   โ”œโ”€โ”€ index.astro        # Blog index
โ”‚   โ”‚   โ””โ”€โ”€ [slug].astro       # Article detail route
โ”‚   โ””โ”€โ”€ calendar.astro         # Content calendar page
โ”œโ”€โ”€ views/
โ”‚   โ”œโ”€โ”€ HomePage.tsx           # React "view" components
โ”‚   โ”œโ”€โ”€ BlogIndexPage.tsx
โ”‚   โ”œโ”€โ”€ ArticleListPage.tsx
โ”‚   โ””โ”€โ”€ ContentCalendarPage.tsx
โ”œโ”€โ”€ hooks/
โ”‚   โ”œโ”€โ”€ useReadingProgress.ts  # Scroll โ†’ progress bar value
โ”‚   โ””โ”€โ”€ useTheme.tsx           # ThemeProvider + useTheme
โ”œโ”€โ”€ utils/
โ”‚   โ”œโ”€โ”€ index.ts               # cn(), formatDate(), etc.
โ”‚   โ””โ”€โ”€ calendar.ts            # getMonthMatrix(), helpers for calendar
โ”œโ”€โ”€ styles/
โ”‚   โ””โ”€โ”€ global.css             # Tailwind base + custom prose styles
โ”œโ”€โ”€ types/
โ”‚   โ””โ”€โ”€ index.d.ts             # Article & calendar types
โ””โ”€โ”€ env.d.ts                   # Astro env typing

Thereโ€™s also:

content-plans/
โ””โ”€โ”€ YYYY-MM.json               # AI-generated content plan per month

scripts/
โ”œโ”€โ”€ generate-content-plan.mjs        # pnpm generate:plan
โ””โ”€โ”€ generate-article-from-plan.mjs   # pnpm generate:article

๐Ÿ› ๏ธ Tech Stack

Technology Purpose
Astro Static site generator / HTML-first framework
React 19 Interactive islands and UI components
TypeScript Type safety
Tailwind CSS 4 Utility-first styling (via @tailwindcss/vite)
Shiki Syntax highlighting for MDX code blocks
Lucide React Icon set for UI + calendar legend
Vercel Hosting + analytics
OpenAI Responses API Content planning & article generation
Pagefind Static full-text search over generated HTML

๐ŸŽจ Design System

Colors

  • Primary: Sky (sky-500)
  • Neutrals: Zinc palette
  • Categories:
    • ๐Ÿ”ฅ Trending: Orange
    • ๐Ÿ“š Tutorial: Sky Blue
    • ๐Ÿ”ฌ Deep Dive: Purple
  • Status:
    • โœ… Published: Emerald badge
    • โณ Coming soon: Neutral gray badge

Typography

  • Sans: Plus Jakarta Sans
  • Mono: JetBrains Mono

๐Ÿงฉ Code Blocks in MDX

Code blocks in MDX are rendered by CodeBlock.astro and Shiki.

Example with filename:

```ts filename="Profile.server.tsx"
// Profile.server.tsx
import { fetchUserProfile } from "../lib/api";

export default async function Profile() {
  const user = await fetchUserProfile();
  return (
    <div>
      <h2>{user.name}</h2>
      <p>{user.bio}</p>
    </div>
  );
}
```

- `language` is picked from the fence (`ts`, `tsx`, etc.)
- `filename` is parsed from the meta string and displayed in the header
- The copy button uses a delegated click handler + `navigator.clipboard`

---

## ๐Ÿ“ Content Types

```ts
export type ArticleCategory = "trending" | "tutorial" | "deep-dive";

export interface Article {
  slug: string;                // e.g. "react-19-biggest-features-i-am-excited-about"
  title: string;
  description: string;
  category: ArticleCategory;
  tags: string[];
  date: string;                // ISO date, e.g. "2025-12-06"
}

export interface CalendarArticle extends Article {
  status: "planned" | "published";
}

On the calendar page:

  • Published articles:
    • Green โ€œPublishedโ€ badge
    • Clickable card โ†’ navigates to /blog/[slug]
  • Planned articles:
    • Gray โ€œComing soonโ€ badge
    • Non-clickable card

๐ŸŒ— Theme System

Dark mode is handled via data-theme on <html> plus a small React provider:

type Theme = "light" | "dark";

interface ThemeContextValue {
  theme: Theme;
  toggleTheme: () => void;
}

Flow:

  1. Check localStorage for a saved theme.
  2. Otherwise, read window.matchMedia("(prefers-color-scheme: dark)").
  3. Apply data-theme="light" | "dark" on <html>.
  4. Persist user choice when toggled.

๐Ÿ”ฎ Roadmap

  • MDX support for article content
  • Migrate to Astro for SSG and SEO
  • Content calendar view
  • AI-generated monthly plan + daily article script
  • RSS feed generation
  • Full-text search (Pagefind)
  • Comments (Giscus)
  • Related articles recommendations
  • View counter per article
  • Search filters (by category / tag)

๐Ÿ“„ License

This project is licensed under the MIT License. See the LICENSE file for details.

MIT ยฉ Juan Patricio Marroquรญn


Built with โ˜• and ๐Ÿ’œ from Lima, Peru.

About

Personal dev blog using React + Astro & Open AI generation

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published