Skip to content

Latest commit

Β 

History

History
504 lines (372 loc) Β· 15.3 KB

File metadata and controls

504 lines (372 loc) Β· 15.3 KB


Coding Panda β€” NeoBrutalist Blog Platform

🐼 Coding Panda Blog

The NeoBrutalist Blog Platform That Developers Actually Want to Use

Built with thick borders, flat shadows, and zero compromises.

Next.js 15 TypeScript Tailwind CSS Supabase PWA Test Coverage License


πŸš€ Live Demo Β· πŸ“– Read the Blog Β· 🀝 Contribute Β· πŸ› Report Bug Β· ✨ Request Feature



🎯 Why Coding Panda?

Most blog templates look the same β€” generic, forgettable, lifeless.

Coding Panda is different.

It's opinionated. It's bold. It's the blog you actually remember.

😴 What Every Other Blog Looks Like

  • Generic sans-serif fonts
  • Flat, forgettable cards
  • No personality
  • "Just another blog template"
  • Static content, no CMS

🐼 What Coding Panda Looks Like

  • Archivo Black headings that punch through the screen
  • 4px flat shadows that make every element pop
  • NeoBrutalist design that people screenshot and share
  • Supabase-powered real-time content
  • 90%+ test coverage because you ship what works

⚑ Get Running in 30 Seconds

# 1. Clone & Install
git clone https://github.com/XDEV200/coding-panda-blog.git
cd coding-panda-blog
npm install

# 2. Database Setup (Supabase)
# Create a new project at supabase.com and run the schema found in:
# ./supabase/schema.sql (SQL Editor in Supabase Dashboard)

# 3. Environment Config
cp .env.example .env.local
# Update .env.local with your PROJECT_URL and ANON_KEY
# Set NEXT_PUBLIC_APP_ENV=development to use dev_ prefixed tables

# 4. Launch πŸš€
npm run dev

πŸ› οΈ Development Environment (Localhost)

To prevent polluting production data, this project uses a table prefixing strategy:

  • Localhost: Uses tables prefixed with dev_ (e.g., dev_posts, dev_tags).
  • Production: Uses original table names.

Ensure you have created the dev_ prefixed tables by duplicating the schema in your Supabase dashboard or using provided migrations.

πŸ—ƒοΈ Required Database Tables

To ensure all features work (Likes, Tags, PWA, Admin), execute the SQL in schema.sql. The essential tables are:

  • posts: Core blog content (title, slug, markdown, etc.)
  • tags: Dynamic category/tag management
  • post_interactions: Session-based likes and dislikes
  • profiles: Admin and user roles for dashboard access

πŸ—οΈ Architecture β€” Clean, Not Clever

graph TB
    subgraph Client ["πŸ–₯️ Client Layer"]
        A[Next.js 15 App Router] --> B[React 19 Components]
        B --> C[Tailwind + Neo Design Tokens]
    end

    subgraph Data ["☁️ Data Layer"]
        D[Blog Service] --> E[Supabase Client]
        E --> F[(Supabase PostgreSQL)]
    end

    subgraph Infra ["πŸ”§ Infrastructure"]
        G[PWA Service Worker]
        H[Security Headers]
        I[Image Optimization]
    end

    A --> D
    A --> G
    A --> H
    A --> I

    style Client fill:#FDE047,stroke:#0A0A0A,stroke-width:3px,color:#0A0A0A
    style Data fill:#60A5FA,stroke:#0A0A0A,stroke-width:3px,color:#0A0A0A
    style Infra fill:#4ADE80,stroke:#0A0A0A,stroke-width:3px,color:#0A0A0A
Loading

🎨 The NeoBrutalist Design System

This isn't a theme β€” it's a design language. Every pixel is intentional.

🎯 Borders

border: 2px solid #0A0A0A

Thick. Unapologetic. Every surface has them.

πŸ–€ Shadows

box-shadow: 4px 4px 0px #0A0A0A

Flat. No blur. No gradients. They move on hover.

πŸ”€ Typography

Archivo Black β€” Headings
Space Grotesk β€” Body

Heavy meets geometric. Readable at any size.

🎨 Palette

#FDE047  β€” Panda Yellow
#0A0A0A  β€” Ink Black
#FAFAFA  β€” Paper White
+ 5 accent colors

Color System

Token Hex Usage
🟑 retro-yellow #FDE047 Brand, CTAs, highlights
⚫ retro-black #0A0A0A Text, borders, shadows
βšͺ retro-white #FAFAFA Backgrounds, cards
🩷 retro-pink #F472B6 Category: Design
πŸ”΅ retro-blue #60A5FA Category: Tutorials
🟒 retro-green #4ADE80 Category: Accessibility
🟠 retro-orange #FB923C Category: Announcements
🟣 retro-purple #C084FC Category: AI/ML

Shadow Hierarchy

neo        β†’  4px 4px 0px  β†’  Default state
neo-lg     β†’  6px 6px 0px  β†’  Featured cards
neo-xl     β†’  8px 8px 0px  β†’  Hero elements
neo-hover  β†’  2px 2px 0px  β†’  Active/pressed state

🧩 Component Library

Every component follows the Neo design system. No ad-hoc styles.

components/
β”œβ”€β”€ ui/
β”‚   β”œβ”€β”€ Badge.tsx          # 7 color-coded category pills
β”‚   β”œβ”€β”€ Button.tsx         # 3 variants Γ— 3 sizes with shadow animations
β”‚   └── ThemeToggle.tsx    # Light/dark mode with smooth transitions
β”œβ”€β”€ blog/
β”‚   β”œβ”€β”€ BlogCard.tsx       # Standard + featured layouts
β”‚   β”œβ”€β”€ BlogGrid.tsx       # Responsive grid with featured-first row
β”‚   └── CategoryFilter.tsx # aria-pressed filter buttons
└── layout/
    β”œβ”€β”€ Navbar.tsx          # Sticky yellow navbar with dynamic theme
    └── Footer.tsx          # Dark footer with dynamic year

πŸ—‚οΈ Full Project Structure

coding-panda-blog/
β”œβ”€β”€ πŸ“ app/                          # Next.js 15 App Router
β”‚   β”œβ”€β”€ layout.tsx                   # Root layout β€” PWA metadata, ThemeProvider
β”‚   β”œβ”€β”€ globals.css                  # Design tokens + Google Fonts
β”‚   β”œβ”€β”€ page.tsx                     # Blog listing with live category filtering
β”‚   β”œβ”€β”€ not-found.tsx                # Custom 404 page
β”‚   β”œβ”€β”€ [slug]/page.tsx              # Dynamic blog post route (SSG)
β”‚   └── api/blogs/route.ts           # REST API: GET /api/blogs?category=X
β”‚
β”œβ”€β”€ πŸ“ components/                   # UI component library
β”‚   β”œβ”€β”€ ThemeProvider.tsx             # next-themes wrapper
β”‚   β”œβ”€β”€ ui/                          # Atomic design components
β”‚   β”œβ”€β”€ blog/                        # Blog-specific components
β”‚   └── layout/                      # App shell (Navbar, Footer)
β”‚
β”œβ”€β”€ πŸ“ lib/                          # Business logic
β”‚   β”œβ”€β”€ posts.ts                     # Data access layer (async, Supabase-backed)
β”‚   └── utils.ts                     # Pure utilities: cn, formatDate, slugify, truncate
β”‚
β”œβ”€β”€ πŸ“ services/                     # Service layer
β”‚   └── blogService.ts               # Supabase CRUD operations
β”‚
β”œβ”€β”€ πŸ“ types/                        # TypeScript interfaces
β”‚   └── blog.ts                      # BlogPost, BlogCategory
β”‚
β”œβ”€β”€ πŸ“ public/                       # Static assets
β”‚   β”œβ”€β”€ manifest.json                # PWA manifest
β”‚   β”œβ”€β”€ sw.js                        # Service worker (auto-generated)
β”‚   └── icons/                       # App icons (192, 512, apple-touch)
β”‚
└── πŸ“ __tests__/                    # Test suite (90%+ coverage)
    β”œβ”€β”€ lib/                         # Unit tests for utilities & data
    β”œβ”€β”€ components/                  # Component render & interaction tests
    β”œβ”€β”€ services/                    # Service layer tests
    └── app/                         # Page & API route tests

πŸ›‘οΈ Security β€” Not an Afterthought

Every request is hardened with production-grade security headers:

Header Value Why
X-Content-Type-Options nosniff Prevents MIME-type sniffing attacks
X-Frame-Options DENY Blocks clickjacking via iframes
X-XSS-Protection 1; mode=block Legacy XSS filter activation
Referrer-Policy strict-origin-when-cross-origin Controls referrer data leakage
Permissions-Policy camera=(), microphone=(), geolocation=() Disables unnecessary browser APIs
poweredByHeader false Hides Next.js fingerprint

All external links use rel="noopener noreferrer". No information leaks.


β™Ώ Accessibility β€” WCAG 2.1 AA

This blog is built for everyone, not just sighted mouse-users:

  • βœ… Semantic HTML β€” header, nav, main, article, footer
  • βœ… ARIA landmarks β€” Every navigation region is labeled
  • βœ… aria-pressed β€” Category filter buttons communicate state
  • βœ… aria-live="polite" β€” Post count updates announced to screen readers
  • βœ… Focus-visible rings β€” Every interactive element has keyboard focus styles
  • βœ… Color contrast β€” All text meets WCAG AA contrast ratios
  • βœ… Reduced motion β€” Animations respect prefers-reduced-motion

πŸ“± PWA β€” Install It. Use It Offline.

Coding Panda works as a Progressive Web App out of the box:

Feature Implementation
πŸ”Œ Offline Support NetworkFirst caching via Workbox
πŸ“² Installable Full manifest.json with icons
⚑ App Shortcuts Home page shortcut in manifest
🎨 Theme Color #FDE047 matches the Panda Yellow brand
πŸ”„ Auto-update skipWaiting + register: true

πŸ§ͺ Testing β€” 90%+ Coverage or It Doesn't Ship

We don't guess. We test. Every component, every function, every edge case.

# Run the full test suite with coverage
npm test

# Watch mode for development
npm run test:watch

# CI mode with enforced thresholds
npm run test:ci

Coverage Thresholds

Metric Threshold
Lines β‰₯ 90%
Functions β‰₯ 90%
Statements β‰₯ 90%
Branches β‰₯ 85%

What We Test

Layer Tests What's Covered
lib/utils.ts 20 tests All pure functions, edge cases, type coercion
lib/posts.ts 18 tests Data integrity, async operations, error paths
UI Components 40+ tests Render, variants, a11y attributes, interactions
Blog Components 20+ tests Grid layouts, filtering, featured cards
Pages 10+ tests State management, loading states, aria-live
API Routes 8+ tests Status codes, filtering, cache headers, schema

πŸ”Œ API Reference

GET /api/blogs

Returns all posts, sorted by date (newest first).

GET /api/blogs?category=tutorials

Filter by category. Available categories: design, tutorials, accessibility, announcements.

Response:

{
  "posts": [
    {
      "slug": "building-neobrutalist-components",
      "title": "Building NeoBrutalist Components",
      "excerpt": "A deep dive into thick borders and flat shadows...",
      "category": "tutorials",
      "tags": ["react", "css", "design-system"],
      "readTime": 5,
      "featured": true
    }
  ],
  "total": 1
}

🧰 Tech Stack Deep-Dive

Technology Version Why This?
Next.js 15 App Router, RSC, image optimization, SSG
React 19 Latest hooks, server components support
TypeScript 5.7 Type safety across every layer
Tailwind CSS 3.4 Design tokens as config, JIT compilation
Supabase 2.x PostgreSQL + real-time subscriptions + auth
next-pwa 5.6 Zero-config PWA with Workbox
next-themes 0.4 Flicker-free dark mode
Lucide React 0.473 Consistent, tree-shakeable icons
date-fns 4.1 Modular date formatting
Jest 29 Fast, reliable test runner
Testing Library 16 User-centric component tests

πŸš€ Extending Coding Panda

Adding a Blog Post

Blog posts are stored in Supabase and fetched via the blogService. Add a row to the posts table with:

{
  slug: "your-post-slug",
  title: "Your Post Title",
  excerpt: "A brief description...",
  content: "Full markdown content...",
  category: "tutorials",
  tags: ["react", "nextjs"],
  readTime: 5,
  coverColor: "#60A5FA",
  featured: false
}

Adding a Category

  1. Add posts with the new category string in Supabase
  2. Add a colour mapping in components/ui/Badge.tsx β†’ CATEGORY_VARIANT_MAP
  3. The CategoryFilter auto-discovers categories from the data

Swapping the Backend

The blogService.ts is the only file that talks to Supabase. Swap it for any backend:

blogService.ts  β†’  Your CMS / REST API / GraphQL / local MDX
     ↓
  lib/posts.ts  β†’  Same API, same types, zero component changes
     ↓
  Components    β†’  They never know the difference

πŸ“œ Available Scripts

Command Description
npm run dev Start dev server with HMR
npm run build Production build + PWA service worker
npm start Start production server
npm test Run all tests with coverage report
npm run test:watch Tests in watch mode
npm run test:ci CI tests with enforced 90% threshold
npm run lint ESLint

🀝 Contributing

We love contributors! Whether you're fixing a bug, suggesting a feature, or improving documentation, your help is welcome.

Please read our Contributing Guide to get started with the development process and understand our engineering standards.

All contributors are expected to follow our Code of Conduct.

Quick Start for Contributors

  1. Fork the repo
  2. Create your feature branch (git checkout -b feature/awesome-feature)
  3. Commit your changes (git commit -m 'feat: add awesome feature')
  4. Push to the branch (git push origin feature/awesome-feature)
  5. Open a Pull Request

πŸ“„ License

This project is licensed under the MIT License β€” see the LICENSE file for details.




Built with πŸ–€ by XDEV200

If this project helped you, consider giving it a ⭐ β€” it means more than you think.


Star History Chart