placebo.mk/FRONTEND_GUIDE.md
2026-01-10 19:41:04 +01:00

8.3 KiB

Frontend Setup Complete - TanStack Router + Tailwind 4

Quick Start

cd frontend
npm run dev

Visit:

Architecture

Tech Stack

  • React 19 - UI framework
  • TanStack Router - File-based routing
  • TanStack Query - Server state management
  • Tailwind CSS 4 - CSS-first (v4 no config file)
  • Shadcn/ui - Pre-built components
  • TypeScript - Type safety

Project Structure

frontend/
├── src/
│   ├── components/
│   │   └── ui/                 # shadcn/ui components
│   │       ├── button.tsx
│   │       └── card.tsx
│   ├── lib/
│   │   ├── api.ts              # Backend API functions
│   │   ├── query-client.ts     # TanStack Query config
│   │   └── utils.ts           # cn() utility
│   ├── routes/                 # TanStack Router routes
│   │   ├── root.tsx          # Root layout
│   │   ├── index.tsx          # Home page
│   │   └── articles.tsx       # Articles list
│   ├── styles.css              # Tailwind CSS + theme
│   └── main.tsx              # App entry
├── components.json              # shadcn/ui config
├── vite.config.ts              # Vite + Tailwind CSS plugin
└── package.json

Pages & Routes

Home Page (/)

  • Welcome message about Placebo.mk
  • "Welcome" card with intro
  • "Get Started" card with feature list
  • Centered layout with max-width container

Articles Page (/articles)

  • Grid of article cards (responsive: 1/2/3 columns)
  • Each card shows:
    • Title (truncated to 2 lines)
    • Excerpt (truncated to 3 lines)
    • Content preview (truncated to 4 lines)
    • Creation date
    • View count
  • Loading state
  • Error state
  • Empty state when no articles

Root Layout

  • Header with navigation (Home, Articles links)
  • Main content area with <Outlet />
  • Footer with copyright
  • SEO meta tags
  • Tailwind CSS import

Components

Card (src/components/ui/card.tsx)

  • Card - Main container
  • CardHeader - Header section
  • CardTitle - Title (h3 element)
  • CardDescription - Description (p element)
  • CardContent - Content area
  • CardFooter - Footer area

Button (src/components/ui/button.tsx)

  • Variants: default, destructive, outline, secondary, ghost, link
  • Sizes: default, sm, lg, icon
  • Uses shadcn/ui theming system
  • Ready to use (not used yet)

Utilities

cn() Function (src/lib/utils.ts)

import { cn } from '@/lib/utils'

// Merge Tailwind classes with conditional logic
<div className={cn(
  'base-class',
  isActive && 'active-class',
  className
)}>

Styling

Tailwind CSS 4 (CSS-First)

Configuration in src/styles.css:

@import "tailwindcss";

@theme {
  --color-primary: oklch(0.647 0.22 0.23);
  --font-sans: "Inter", sans-serif;
}

Shadcn/ui Theme

CSS variables in src/styles.css:

  • --background - Background color
  • --foreground - Text color
  • --card - Card background
  • --primary - Primary brand color
  • --muted - Muted text color
  • Dark mode support with .dark class

Data Flow

API Layer (src/lib/api.ts)

  • fetchArticles() - Get all articles with filters
  • fetchArticleById() - Get single article by ID
  • fetchArticleBySlug() - Get article by slug

TanStack Query

  • Automatic caching
  • Refetch on window focus (disabled)
  • Stale time: 5 minutes
  • Retry: 1 attempt
  • Query client shared across app

Backend Integration

API Configuration

const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000/api/v1'

Environment Variables

Create frontend/.env:

VITE_API_URL=http://localhost:3000/api/v1

Adding New Pages

Method 1: File-Based Routes (Current)

Create new route file in src/routes/:

// src/routes/about.tsx
import { createFileRoute } from '@tanstack/react-router'

export const Route = createFileRoute('/about')({
  component: () => <div>About Page</div>,
})

Add to src/main.tsx:

import { aboutRoute } from './routes/about'

const routeTree = rootRoute.addChildren([indexRoute, articlesRoute, aboutRoute])

Method 2: Using TanStack Router

Create routes dynamically in existing route files.

Adding Shadcn/ui Components

cd frontend
npx shadcn@latest add [component-name]
npx shadcn@latest add badge      # Article tags
npx shadcn@latest add input      # Search box
npx shadcn@latest add dialog     # Article detail modal
npx shadcn@latest add tabs       # Content organization
npx shadcn@latest add separator  # Visual separation
npx shadcn@latest add skeleton   # Loading placeholder
npx shadcn@latest add pagination # Article list navigation
npx shadcn@latest add dropdown-menu # Menus and filters
npx shadcn@latest add select     # Dropdown selectors

Customization

Changing Brand Colors

Edit src/styles.css:

@theme {
  --color-primary: oklch(0.7 0.5 0.2);  /* Your brand color */
  --font-sans: "Your Font", sans-serif;
}

Dark Mode

Add toggle button to header:

// src/routes/root.tsx
const toggleDarkMode = () => {
  document.documentElement.classList.toggle('dark')
  localStorage.setItem('theme',
    document.documentElement.classList.contains('dark') ? 'dark' : 'light'
  )
}

// In component
<button onClick={toggleDarkMode}>Toggle Theme</button>

Typography

Edit src/styles.css:

@theme {
  --font-sans: "Your Custom Font", sans-serif;
}

@layer base {
  * {
    @apply font-sans;
  }
}

Troubleshooting

Routes Not Loading

  1. Check route files exist in src/routes/
  2. Check exports: export const Route = createFileRoute(...)
  3. Check route tree in src/main.tsx
  4. Restart dev server

Styles Not Applying

  1. Check src/styles.css has Tailwind directives
  2. Check vite.config.ts has tailwindcss() plugin
  3. Restart dev server
  4. Hard refresh browser (Ctrl+Shift+R)

Component Imports Failing

  1. Check tsconfig.json has @/ paths
  2. Check import paths are correct: @/components/ui/component
  3. Restart TypeScript server (VSCode: Cmd+Shift+P)

Data Not Fetching

  1. Check backend is running: http://localhost:3000
  2. Check .env file exists and has correct API URL
  3. Check browser network tab for failed requests
  4. Check CORS in backend (backend/src/main.ts)

TypeScript Errors

  1. Run: npm run type-check
  2. Restart TypeScript server (VSCode)
  3. Clear Vite cache: rm -rf node_modules/.vite

Performance Tips

  1. Code Splitting: Use lazy() for large components
  2. Image Optimization: Add loading="lazy" to article images
  3. Query Caching: TanStack Query caches automatically
  4. Bundle Size: Run npm run build and check size

Development Workflow

Adding New Article

  1. Create article in Strapi CMS: http://localhost:1337/admin
  2. Publish article
  3. Sync to backend: curl -X POST http://localhost:3000/api/v1/webhooks/strapi/sync/all
  4. Refresh frontend to see new article

Running All Services

# Terminal 1 - Backend
cd backend
npm run start:dev

# Terminal 2 - Frontend
cd frontend
npm run dev

# Terminal 3 - Strapi CMS (optional)
cd cms/cms
npm run develop

Testing

Manual Testing

# Test API
curl http://localhost:3000/api/v1/articles

# Test frontend
npm run dev
# Open http://localhost:5173

Type Checking

cd frontend
npm run type-check

Next Steps

  1. Add article detail page with $id parameter
  2. Add search input for filtering articles
  3. Add category/tag filtering
  4. Add pagination for article lists
  5. Add dark mode toggle
  6. Add "about" page with site information
  7. Add "contact" page or form
  8. Add article comments system
  9. Add social sharing buttons
  10. Add analytics for article views

Files to Edit

File Purpose
src/styles.css Theme colors, fonts, CSS variables
vite.config.ts Vite plugins, path aliases
components.json shadcn/ui configuration
tsconfig.json TypeScript paths
.env Environment variables

Resources