-
Notifications
You must be signed in to change notification settings - Fork 0
Key Reusuable Components and Code Patterns
phawatboom edited this page Sep 23, 2025
·
1 revision
-
Highly flexible with multiple variants using
class-variance-authority -
Polymorphic: Works as both
<button>and<Link>based onhrefprop -
Variants:
primary,outline,secondary,ghost -
Sizes:
sm,md,lg -
Colors:
cream,abyss,algae,grass - Usage: Perfect for CTAs, navigation, forms
- Smart image optimization with automatic size selection
- Built-in placeholders and error handling
- CMS integration with Payload Media types
- Responsive image loading with custom loader
- Usage: All image displays throughout the site
- Payload CMS integration for rich text content
- Prose styling with Tailwind typography
- Usage: Blog posts, descriptions, CMS content
- Domain-specific for river grading system
- Color-coded difficulty levels (Grade 1-6)
- Usage: River difficulty indicators
- Loading states with animation
- Consistent styling across the app
- Usage: Content loading placeholders
- Leaflet integration with React
- Multi-marker support with popups
- Auto-fitting bounds for multiple coordinates
- Mobile-responsive map interactions
- Usage: River locations, event venues
Modular card architecture with separate concerns:
- TripsCard.tsx - Main container
-
TripsCardContent.tsx- Text content -
TripsCardImage.tsx- Image display -
TripsCardDate.tsx- Date formatting -
TripsCardLocation.tsx- Location display -
TripsCardButtons.tsx- Action buttons
This pattern is perfect for replication across other content types!
// Combines clsx and tailwind-merge for optimal class handling
cn('base-class', condition && 'conditional-class', className)-
formatDate()- Single date formatting (NZ locale) -
formatDateRange()- Smart date range formatting - Timezone aware (Pacific/Auckland)
-
getPlainText()- Extracts text from rich content - Payload CMS integration helpers
- Consistent API for data fetching
- TypeScript typed responses
- Error handling built-in
- Reusable patterns for different content types
Example pattern:
export async function getContent(options?: QueryOptions) {
const { docs: content } = await payload.find({
collection: 'content',
...options
})
return { content }
}- Page Component (page.tsx) - Data fetching
-
Page Component (
_components/PageName.tsx) - UI logic - Sub-components - Specific sections
- Header/Navbar - Global navigation
- Footer - Site-wide footer
- Consistent spacing and responsive design
--abyss: oklch(27.35% 0.017 189.89); /* Dark blue */
--grass: oklch(66.38% 0.088 132.22); /* Green */
--cream: oklch(94.49% 0.013 97.45); /* Light cream */
--water: oklch(79.98% 0.038 187.93); /* Light blue */
--algae: oklch(74.26% 0.113 127.26); /* Light green */
--seafoam: oklch(89.92% 0.0193 162.89); /* Very light blue */- Heading: Rubik Mono One (monospace)
- Body: Rubik (sans-serif)
- Handwritten: Caveat (cursive)
- Display: Unbounded (sans-serif)
- Button Component - Use everywhere for consistency
- Card Architecture - Apply TripsCard pattern to other content
- PayloadImage - All image handling
- cn() utility - Every component for class management
- Date formatters - All date displays
- Query pattern - All data fetching
- Page structure - Consistent across all routes
When creating new pages, leverage these existing patterns:
- Copy the TripsCard modular approach for other card types
- Use Button component for all interactive elements
- Follow the page β _components structure
- Utilize existing utilities (cn, date formatters, etc.)
- Maintain color palette consistency
- Use PayloadImage for all media display