| name | component-patterns |
| description | React component patterns, styling conventions, and animation standards for CJS2026 UI development |
Component Patterns
When to Activate
Use this skill when the agent needs to:
- Create new React components
- Add animations to existing components
- Apply consistent styling
- Understand the design system
- Build dashboard widgets or admin tabs
Design System Overview
CJS2026 uses a "Sketch & Parchment" aesthetic with these foundations:
Color Palette
// Primary colors
text-brand-teal // #2A9D8F - Primary brand
text-brand-ink // #2C3E50 - Primary text
bg-brand-cream // #F5F0E6 - Primary background
bg-brand-parchment // #EDE8DC - Secondary sections
text-brand-cardinal // #C84B31 - 10th anniversary accent
// Opacity variants for hierarchy
text-brand-ink/70 // Secondary text
text-brand-ink/50 // Subtle text
Typography
font-heading // Playfair Display (serif) - Headlines
font-body // Source Sans 3 (sans) - Body text
font-accent // Caveat (handwritten) - Decorative
Component Templates
Standard Page Component
import { motion } from 'framer-motion';
import Navbar from '../components/Navbar';
import Footer from '../components/Footer';
export default function PageName() {
return (
<div className="min-h-screen bg-brand-cream">
<Navbar />
<main className="pt-24 pb-16">
<div className="max-w-4xl mx-auto px-4">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
>
<h1 className="font-heading text-4xl md:text-5xl text-brand-ink mb-8">
Page Title
</h1>
<div className="card-sketch p-8">
{/* Content */}
</div>
</motion.div>
</div>
</main>
<Footer />
</div>
);
}
Dashboard Widget Card
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.3 }} // Increment for stagger
className="card-sketch p-6"
>
<div className="flex items-center justify-between mb-4">
<h3 className="font-heading text-xl text-brand-ink">
Widget Title
</h3>
<span className="text-brand-teal">
<IconComponent className="h-5 w-5" />
</span>
</div>
<div className="space-y-3">
{/* Widget content */}
</div>
<button className="btn-primary w-full mt-4">
Action
</button>
</motion.div>
Admin Tab Content
const renderTabContent = () => (
<div className="space-y-6">
<h2 className="font-admin-heading text-2xl font-bold text-admin-ink dark:text-white">
Tab Title
</h2>
{/* Stats row */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className={cardClass}>
<div className="text-3xl font-bold text-admin-teal">123</div>
<div className="text-sm text-gray-500">Metric Label</div>
</div>
</div>
{/* Main content */}
<div className={cardClass}>
{/* ... */}
</div>
</div>
);
Animation Patterns
Entrance Animation
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6 }}
>
Scroll-Triggered Animation
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
Staggered Children
{items.map((item, index) => (
<motion.div
key={item.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: index * 0.1 }}
>
{/* Item content */}
</motion.div>
))}
Card Styles
Public Site Card
<div className="card-sketch p-6">
{/* Automatic double-border shadow effect */}
{/* Hover: lift animation */}
</div>
Admin Panel Card
const cardClass = `rounded-lg border ${
theme === 'ink'
? 'bg-gray-800 border-gray-700'
: 'bg-white border-gray-200'
} p-6`;
<div className={cardClass}>
{/* Theme-aware styling */}
</div>
Button Styles
Primary Button
<button className="btn-primary">
Click Me
</button>
// Or manually:
<button className="px-6 py-3 bg-brand-teal text-white font-body font-semibold
rounded-lg border-2 border-brand-teal-dark
shadow-[3px_3px_0_var(--teal-dark)]
hover:translate-x-[-2px] hover:translate-y-[-2px]
hover:shadow-[5px_5px_0_var(--teal-dark)]
transition-all duration-200">
Context Usage
import { useAuth } from '../contexts/AuthContext';
function Component() {
const {
currentUser,
userProfile,
saveSession,
unsaveSession,
isSessionSaved
} = useAuth();
// Check registration for feature gating
const hasFullAccess = userProfile?.role === 'admin' ||
['registered', 'confirmed'].includes(userProfile?.registrationStatus);
}
Responsive Patterns
// Grid responsive
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
// Text responsive
<h1 className="text-2xl md:text-4xl lg:text-5xl">
// Show/hide by breakpoint
<div className="hidden lg:block"> {/* Desktop only */}
<div className="lg:hidden"> {/* Mobile only */}
Integration Points
- cjs-architecture - For understanding component hierarchy
- cms-content-pipeline - For CMS-controlled content in components
Guidelines
- Use
card-sketchclass for public-facing cards - Use theme-aware
cardClassfor admin components - Apply Framer Motion for all entrance animations
- Increment delay values for staggered animations
- Use
font-headingfor titles,font-bodyfor content - Always include mobile breakpoints in responsive designs