`
✅ Use `max-w-6xl mx-auto` for centered content
✅ Use `space-y-6` for vertical spacing
✅ Cards for section containers
✅ Tabs for multi-section pages
### 5. Icons
✅ Import from lucide-react
✅ Use consistent size: `h-4 w-4` for buttons, `h-6 w-6` for headers
✅ Add text-primary to header icons
### 6. Finnish UI Text
✅ Page titles and descriptions in Finnish when user-facing
✅ Error messages in Finnish
✅ Admin navigation in Finnish
✅ Code/technical terms can be in English
## Common UI Components
| Component | Import Path | Use For |
|-----------|-------------|---------|
| Card | @ui/card | Section containers |
| Tabs | @ui/tabs | Multi-section pages |
| Table | @ui/table | Data lists |
| Form | @ui/form | Input forms with validation |
| Button | @ui/button | Actions |
| Badge | @ui/badge | Status indicators |
| Input | @ui/input | Text inputs |
| Switch | @ui/switch | Boolean toggles |
| Select | @ui/select | Dropdowns |
| Dialog | @ui/dialog | Modals |
| AlertDialog | @ui/alert-dialog | Confirmations |
| Alert | @ui/alert | Notices and warnings |
## AdminHeader Props
```typescript
interface AdminHeaderProps {
title: string; // Page title (Finnish)
description?: string; // Optional subtitle
icon?: React.ReactNode; // Optional icon element
showBackButton?: boolean; // Show back to admin (default: true)
showSidebarTrigger?: boolean; // Show sidebar toggle (default: true)
}
```
## Dashboard Card Props
```typescript
interface AdminCardProps {
title: string; // Card title (Finnish)
description: string; // Card description (Finnish)
icon: React.ElementType; // Lucide icon component
path: string; // Navigation path
stats?: Array<{ // Optional statistics
label: string;
value: string | number;
}>;
isLoading?: boolean; // Show skeleton for stats
isExternal?: boolean; // Open in new window
}
```
## Token Management
### Important Admin Features
- **Authentication Tokens**: Manage Supabase keys, Turnstile tokens
- **OAuth Providers**: Google, Apple (planned)
- **Integration Tokens**: OpenAI, ElevenLabs API keys
- **Direct Dashboard Links**: Quick access to external services
- **Copy-to-clipboard**: Environment variable names
- **Regeneration Guidelines**: When and how to rotate keys
- **Security Warnings**: Sensitive key indicators
### Token Card Pattern
```typescript
{token.name}
{token.isSensitive && (
Sensitive
)}
{/* Environment variable with copy button */}
{/* Location info */}
{/* Usage badges */}
{/* Dashboard links */}
{/* Regeneration info */}
```
## Related Files
### Key Admin Files
- `apps/raamattu-nyt/src/pages/AdminDashboardPage.tsx` - Dashboard hub
- `apps/raamattu-nyt/src/pages/AdminAuthTokensPage.tsx` - Token management example
- `apps/raamattu-nyt/src/components/admin/AdminHeader.tsx` - Header component
- `apps/raamattu-nyt/src/App.tsx` - Route definitions
### Documentation
- `Docs/07-ADMIN-GUIDE.md` - Admin features overview
- `Docs/12-AUTHENTICATION.md` - Auth system details
- `Docs/context/supabase-map.md` - Database schema reference
## Common Patterns
### Stats Query Pattern
```typescript
const { data: itemCount, isLoading } = useQuery({
queryKey: ["admin-item-count"],
queryFn: async () => {
const { count } = await supabase
.from("items")
.select("*", { count: "exact", head: true });
return count || 0;
},
enabled: isAdmin, // Only fetch if admin
});
```
### RPC Call Pattern
```typescript
const { data } = await supabase.rpc("get_admin_stats", {
p_limit: 1000,
});
```
### Conditional Rendering
```typescript
{stats && stats.length > 0 && (
{isLoading ? (
) : (
stats.map((stat, i) => (
{stat.value}
{stat.label}
))
)}
)}
```
## Tips
1. **Keep components focused**: One component per file, single responsibility
2. **Extract complex logic**: Move business logic to separate functions/hooks
3. **Type everything**: Use TypeScript interfaces for all data structures
4. **Test queries first**: Verify Supabase queries in SQL editor before implementing
5. **Handle empty states**: Always show something when data is empty
6. **Loading states matter**: Use skeletons for stats, spinners for content
7. **Error boundaries**: Wrap risky operations in try-catch
8. **Invalidate smartly**: Only invalidate affected queries after mutations
9. **Consistent naming**: Use Finnish for UI, English for code
10. **Document complex logic**: Add comments for non-obvious implementations