add skills
Build and Deploy / build-and-deploy (push) Successful in 2m53s

This commit is contained in:
2026-05-18 08:39:42 +02:00
parent 92a80e8759
commit 57af0b8386
53 changed files with 10190 additions and 0 deletions
@@ -0,0 +1,134 @@
# Content Reuse Patterns
Effective content models maximize reuse while minimizing duplication. Here are patterns for achieving both.
## The Content Reuse Spectrum
```
Full Duplication ←————————————————→ Full Reference
(Copy everything) (Link to one source)
```
Most real-world content sits somewhere in between.
## Pattern 1: Shared Components
Create reusable content blocks that can be embedded anywhere.
**Use case:** Testimonials, FAQs, CTAs that appear on multiple pages.
```typescript
// Standalone testimonial documents
defineType({
name: 'testimonial',
type: 'document',
fields: [
defineField({ name: 'quote', type: 'text' }),
defineField({ name: 'author', type: 'string' }),
defineField({ name: 'company', type: 'string' }),
]
})
// Reference in page builders
defineField({
name: 'pageBuilder',
type: 'array',
of: [
{ type: 'reference', to: [{ type: 'testimonial' }] }
]
})
```
## Pattern 2: Shared Field Sets
Extract common fields into reusable definitions.
**Use case:** SEO fields, social metadata, common dates.
```typescript
// Shared field definition
export const seoFields = [
defineField({ name: 'seoTitle', type: 'string' }),
defineField({ name: 'seoDescription', type: 'text' }),
defineField({ name: 'ogImage', type: 'image' }),
]
// Spread into multiple types
defineType({
name: 'page',
fields: [
defineField({ name: 'title', type: 'string' }),
...seoFields
]
})
defineType({
name: 'post',
fields: [
defineField({ name: 'title', type: 'string' }),
...seoFields
]
})
```
## Pattern 3: Taxonomy References
Centralize classification for consistent tagging.
**Use case:** Categories, tags, topics that span content types.
```typescript
// Central taxonomy
defineType({
name: 'category',
type: 'document',
fields: [
defineField({ name: 'title', type: 'string' }),
defineField({ name: 'slug', type: 'slug' }),
]
})
// Used across content types
defineField({
name: 'categories',
type: 'array',
of: [{ type: 'reference', to: [{ type: 'category' }] }]
})
```
## Pattern 4: Content Fragments
Small, reusable pieces that combine into larger content.
**Use case:** Bios, addresses, contact info.
```typescript
// Fragment type
defineType({
name: 'contactInfo',
type: 'object',
fields: [
defineField({ name: 'email', type: 'email' }),
defineField({ name: 'phone', type: 'string' }),
defineField({ name: 'address', type: 'text' }),
]
})
// Reused across types
defineType({
name: 'office',
fields: [
defineField({ name: 'name', type: 'string' }),
defineField({ name: 'contact', type: 'contactInfo' }),
]
})
```
## Anti-Pattern: Over-Abstraction
Not everything needs to be reusable. If content is only used in one place, embedding is simpler.
**Signs of over-abstraction:**
- References that are only used once
- Editors navigating multiple documents for one page
- Complex queries joining rarely-shared content
@@ -0,0 +1,89 @@
# Reference vs Embedding Content
When should content be linked (referenced) vs copied (embedded)? This decision affects reusability, query complexity, and editing workflows.
## The Trade-offs
| Aspect | Reference | Embedded Object |
|--------|-----------|-----------------|
| Reusability | ✅ Shared across documents | ❌ Copied per document |
| Single source | ✅ Update once, reflects everywhere | ❌ Must update each copy |
| Query complexity | Requires joins/expansion | Inline, simpler queries |
| Editing UX | Separate editing interface | All fields in one place |
| Independence | Can exist on its own | Only exists within parent |
## When to Reference
Use references when content:
- **Is reusable** — Same author across many articles
- **Needs central management** — Update product info once
- **Has its own lifecycle** — Published/draft independent of parent
- **Should stay in sync** — Price changes reflect everywhere
**Examples:**
- Author profiles
- Product catalog items
- Shared testimonials
- Category taxonomy
- Reusable CTAs
## When to Embed
Use embedded objects when content:
- **Is unique to this document** — Page-specific hero
- **Doesn't make sense alone** — SEO metadata
- **Should be copied, not linked** — Historical snapshot
- **Simplifies editing** — All fields in one form
**Examples:**
- SEO metadata
- Page-specific sections
- Address information
- Social links
- Configuration options
## Sanity Implementation
```typescript
// Reference: Author is reusable
defineField({
name: 'author',
type: 'reference',
to: [{ type: 'author' }]
})
// Embedded: SEO is page-specific
defineField({
name: 'seo',
type: 'object',
fields: [
defineField({ name: 'title', type: 'string' }),
defineField({ name: 'description', type: 'text' })
]
})
```
## The Hybrid Approach
Sometimes you want both: a reference for the canonical data, plus embedded overrides.
```typescript
defineField({
name: 'featuredProduct',
type: 'object',
fields: [
defineField({
name: 'product',
type: 'reference',
to: [{ type: 'product' }]
}),
defineField({
name: 'overrideTitle',
type: 'string',
description: 'Optional: Override the product title for this context'
}),
]
})
```
Query uses `coalesce(overrideTitle, product->title)`.
@@ -0,0 +1,60 @@
# Separation of Content and Presentation
The most important principle in structured content: **separate what content IS from how it LOOKS**.
## The Problem
When content is tied to presentation:
- Redesigns require content migration
- Content can't be reused across channels (web, mobile, voice)
- Editors make design decisions instead of content decisions
- A/B testing requires duplicate content
## The Principle
Model content based on **meaning and purpose**, not visual appearance.
### Bad: Presentation-Focused
```
BigHeroText → What if we want small heroes?
RedButton → What if brand colors change?
ThreeColumnLayout → What if mobile needs one column?
LeftSidebar → Position is a frontend concern
MobileImage → Device-specific content is fragile
```
### Good: Meaning-Focused
```
Headline → The main message (render however)
CallToAction → An action we want users to take
Features → A list of things (columns decided by frontend)
RelatedContent → Content relationships (position by context)
Image → One image with responsive crops
```
## Testing Your Model
Ask: "If we completely redesigned the site, would these field names still make sense?"
- `threeColumnFeatures` → ❌ Fails (what if 2 columns?)
- `features` → ✅ Works (describes the content's purpose: a list of product features)
- `blueHighlightBox` → ❌ Fails (what if we go purple?)
- `callout` → ✅ Works (describes the content's role: an attention-grabbing aside)
## Sanity Implementation
```typescript
// ❌ Avoid presentation-focused names
defineField({ name: 'bigHeroText', type: 'string' })
defineField({ name: 'fontSize', type: 'number' })
defineField({ name: 'backgroundColor', type: 'color' })
// ✅ Use meaning-focused names
defineField({ name: 'headline', type: 'string' })
defineField({ name: 'emphasis', type: 'string', options: { list: ['standard', 'prominent'] } })
defineField({ name: 'tone', type: 'string', options: { list: ['neutral', 'warning', 'success'] } })
```
The frontend translates `tone: 'warning'` to visual styles. Content stays semantic.
@@ -0,0 +1,136 @@
# Taxonomy and Classification
Organizing content with taxonomies enables filtering, navigation, and content relationships. Well-designed taxonomies scale; poorly designed ones become maintenance nightmares.
## Types of Classification
### Flat Taxonomy
Simple list of terms with no hierarchy.
**Use for:** Tags, simple categories
**Example:** Blog tags: "javascript", "react", "tutorial"
```typescript
defineType({
name: 'tag',
type: 'document',
fields: [
defineField({ name: 'title', type: 'string' }),
defineField({ name: 'slug', type: 'slug' }),
]
})
```
### Hierarchical Taxonomy
Terms with parent-child relationships.
**Use for:** Product categories, content sections
**Example:** Electronics > Phones > Smartphones
```typescript
defineType({
name: 'category',
type: 'document',
fields: [
defineField({ name: 'title', type: 'string' }),
defineField({ name: 'slug', type: 'slug' }),
defineField({
name: 'parent',
type: 'reference',
to: [{ type: 'category' }],
description: 'Parent category (leave empty for top-level)'
}),
]
})
```
### Faceted Classification
Multiple independent dimensions.
**Use for:** Complex filtering (e-commerce)
**Example:** Filter by color AND size AND price range
```typescript
// Multiple taxonomy types
defineField({ name: 'color', type: 'reference', to: [{ type: 'color' }] })
defineField({ name: 'size', type: 'reference', to: [{ type: 'size' }] })
defineField({ name: 'material', type: 'reference', to: [{ type: 'material' }] })
```
## Design Principles
### 1. Mutual Exclusivity (When Appropriate)
Categories should be distinct. If items frequently belong to multiple categories, consider tags instead.
**Categories:** One primary classification
**Tags:** Many optional classifications
### 2. User-Centric Naming
Use terms your audience uses, not internal jargon.
**Bad:** "Content Assets" (internal term)
**Good:** "Resources" or "Downloads" (user term)
### 3. Balanced Depth
Too shallow: Everything lumped together
Too deep: Users can't find anything
**Rule of thumb:** 3-4 levels max for hierarchies
### 4. Scalable Structure
Design for 10x growth. Will your structure work with 10,000 items?
## Querying Taxonomies
### Get all items in a category
```groq
*[_type == "product" && category._ref == $categoryId]
```
### Get items in category OR children
```groq
// First get all descendant category IDs
*[_type == "product" && category._ref in
*[_type == "category" && (
_id == $categoryId ||
parent._ref == $categoryId ||
parent->parent._ref == $categoryId
)]._id
]
```
### Get category tree
```groq
*[_type == "category" && !defined(parent)]{
title,
slug,
"children": *[_type == "category" && parent._ref == ^._id]{
title,
slug,
"children": *[_type == "category" && parent._ref == ^._id]{
title,
slug
}
}
}
```
## Common Mistakes
### Over-categorization
Creating a category for everything results in mostly-empty categories.
**Fix:** Start minimal, add categories as content grows.
### Inconsistent Granularity
Some categories broad ("Technology"), others narrow ("React 18 Server Components").
**Fix:** Define clear criteria for category creation.
### No Governance
Anyone can create taxonomy terms, leading to duplicates and inconsistency.
**Fix:** Limit who can create/edit taxonomy documents. Use validation.