# Frontend Setup Complete - TanStack Router + Tailwind 4 ✅
## Quick Start
```bash
cd frontend
npm run dev
```
Visit:
- Home: http://localhost:5173/
- Articles: http://localhost:5173/articles
## 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 ``
- 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`)
```tsx
import { cn } from '@/lib/utils'
// Merge Tailwind classes with conditional logic
```
## Styling
### Tailwind CSS 4 (CSS-First)
Configuration in `src/styles.css`:
```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
```typescript
const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000/api/v1'
```
### Environment Variables
Create `frontend/.env`:
```bash
VITE_API_URL=http://localhost:3000/api/v1
```
## Adding New Pages
### Method 1: File-Based Routes (Current)
Create new route file in `src/routes/`:
```tsx
// src/routes/about.tsx
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/about')({
component: () =>
About Page
,
})
```
Add to `src/main.tsx`:
```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
### Using CLI (Recommended)
```bash
cd frontend
npx shadcn@latest add [component-name]
```
### Recommended Components
```bash
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`:
```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:
```tsx
// src/routes/root.tsx
const toggleDarkMode = () => {
document.documentElement.classList.toggle('dark')
localStorage.setItem('theme',
document.documentElement.classList.contains('dark') ? 'dark' : 'light'
)
}
// In component
```
### Typography
Edit `src/styles.css`:
```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
```bash
# 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
```bash
# Test API
curl http://localhost:3000/api/v1/articles
# Test frontend
npm run dev
# Open http://localhost:5173
```
### Type Checking
```bash
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
- [TanStack Router Docs](https://tanstack.com/router/latest)
- [Tailwind CSS 4 Docs](https://tailwindcss.com/docs/installation/using-postcss)
- [Shadcn/ui Documentation](https://ui.shadcn.com)
- [TanStack Query Docs](https://tanstack.com/query/latest)