dcyfr-component-patterns
Guide DCYFR component structure with PageLayout, barrel exports, and metadata
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
What I do
I ensure DCYFR components follow established architectural patterns:
- 90% PageLayout usage - Default layout for standard pages
- Barrel exports only - No direct file imports
- Metadata generation - Proper SEO metadata on all pages
- Import strategy - Consistent import patterns across codebase
When to use me
✅ Use this skill when:
- Creating new pages or components
- Refactoring existing components to follow DCYFR patterns
- Deciding which layout to use (PageLayout vs ArticleLayout vs ArchiveLayout)
- Setting up barrel exports for new component directories
❌ Don't use this skill for:
- Testing patterns (use dcyfr-testing skill)
- API route patterns (use dcyfr-api-patterns skill)
Core Rules (NON-NEGOTIABLE)
1. PageLayout (90% Rule)
Use PageLayout for 90% of pages
// ✅ CORRECT: PageLayout for standard pages
import { PageLayout } from "@/components/layouts";
export default function AboutPage() {
return (
<PageLayout>
<div className={`mx-auto ${CONTAINER_WIDTHS.standard}`}>
Content
</div>
</PageLayout>
);
}
Exceptions (10%):
-
ArticleLayout- For blog posts and articles -
ArchiveLayout- For filterable lists (blog archive, work items)
2. Barrel Exports Only
// ✅ CORRECT: Import from barrel export
import { PostCard, CategoryBadge } from "@/components/blog";
// ❌ WRONG: Direct file imports
import { PostCard } from "@/components/blog/post-card";
import { CategoryBadge } from "@/components/blog/category-badge";
Barrel export structure:
// src/components/blog/index.ts
export { PostCard } from "./post-card";
export { CategoryBadge } from "./category-badge";
export { BlogFilter } from "./blog-filter";
3. Metadata Generation
Every page must export metadata:
import { createPageMetadata } from "@/lib/metadata";
export const metadata = createPageMetadata({
title: "Page Title",
description: "Page description for SEO",
path: "/path",
});
Available helpers:
-
createPageMetadata()- Standard pages -
createArticleMetadata()- Blog posts -
createRichMetadata()- Complex metadata with images
Decision Trees
Which Layout?
START: Creating a new page
Is it a blog post?
├─ YES → Use ArticleLayout
│
Is it a filterable list (blog archive, work items)?
├─ YES → Use ArchiveLayout
│
Otherwise → Use PageLayout (default)
Which Container Width?
START: Choosing container width
Is it a blog post?
├─ YES → CONTAINER_WIDTHS.prose (optimal reading width)
│
Is it a wide layout (dashboard, gallery)?
├─ YES → CONTAINER_WIDTHS.wide
│
Otherwise → CONTAINER_WIDTHS.standard (default)
Common Patterns
New Page Template
import { PageLayout } from "@/components/layouts";
import { createPageMetadata } from "@/lib/metadata";
import { CONTAINER_WIDTHS, SPACING, TYPOGRAPHY } from "@/lib/design-tokens";
export const metadata = createPageMetadata({
title: "Page Title",
description: "Page description",
path: "/page-path",
});
export default function NewPage() {
return (
<PageLayout>
<div className={`mx-auto ${CONTAINER_WIDTHS.standard}`}>
<h1 className={TYPOGRAPHY.h1.standard}>
Page Heading
</h1>
<div className={`mt-${SPACING.content}`}>
Content
</div>
</div>
</PageLayout>
);
}
New Component with Barrel Export
# 1. Create component file
# src/components/blog/new-component.tsx
# 2. Add to barrel export
# src/components/blog/index.ts
export { NewComponent } from "./new-component";
# 3. Import from barrel
import { NewComponent } from "@/components/blog";
Validation
# Check component patterns
npm run lint
# Full quality check
npm run check
# OpenCode-specific validation
npm run check:opencode
ESLint Rules
-
import/no-restricted-paths- Enforces barrel exports -
@dcyfr/component-patterns/require-page-layout- Validates layout usage
Related Documentation
-
Full component patterns:
.github/agents/patterns/COMPONENT_PATTERNS.md -
Layout decision tree:
docs/ai/decision-trees.md -
Templates:
docs/templates/NEW_PAGE.tsx.md
Approval Gates
Component pattern violations are STRICT (hard block):
- ❌ Direct imports fail ESLint
- ❌ Missing metadata fails build
- ✅ Must follow patterns before merging
PageLayout preference is FLEXIBLE (warning only):
- ⚠️ Reviewed during PR
- ⚠️ Must justify exceptions (ArticleLayout, ArchiveLayout)
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-01-26
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!