Storyblok
Storyblok Datasources Examples
Vollständige Beispiele für alle verfügbaren Datasources und deren Verwendung
📚 Alle verfügbaren Datasources
Nach dem Sync (pnpm --filter @httpjpg/tokens sync:storyblok) haben Sie folgende Datasources:
📐 Spacing & Layout
spacing-options- None, XS, Small, Medium, Large, XL, 2XL, 3XL, 4XLwidth-options- Full Width, Container, Narrowgrid-columns- 1-6 Columns, Auto Fitaspect-ratio-options- 16:9, 4:3, 1:1, 3:4, 9:16, 21:9
🎨 Colors
background-color-options- White, Black, Light Gray, Gray, Dark Gray, Primary, Accenttext-color-options- Black, White, Gray, Dark Gray, Light Gray, Primary, Accent
✏️ Typography
font-family- Sans (Body), Headline (Impact), Accent (Script), Mono (Code)font-size- Small (12px), Medium (14px), Base (16px), Large (16px), XL (18px)font-weight- Light, Normal, Medium, Semibold, Bold, Black
🎬 Animations
animation-duration- Instant, Fast (150ms), Normal (300ms), Slow (500ms), Very Slow (1s)animation-easing- Linear, Ease, Ease In, Ease Out, Ease In Out
🔧 Beispiel: Text Component in Storyblok
1. Component Schema in Storyblok erstellen
{
"name": "text",
"display_name": "Text",
"schema": {
"content": {
"type": "richtext",
"display_name": "Content"
},
"font_family": {
"type": "option",
"display_name": "Font Family",
"datasource": "font-family",
"default_value": "Sans (Body)"
},
"font_size": {
"type": "option",
"display_name": "Font Size",
"datasource": "font-size",
"default_value": "Base (16px)"
},
"font_weight": {
"type": "option",
"display_name": "Font Weight",
"datasource": "font-weight",
"default_value": "Normal (400)"
},
"text_color": {
"type": "option",
"display_name": "Text Color",
"datasource": "text-color-options",
"default_value": "Black"
},
"spacing_top": {
"type": "option",
"display_name": "Spacing Top",
"datasource": "spacing-options",
"default_value": "Medium"
},
"spacing_bottom": {
"type": "option",
"display_name": "Spacing Bottom",
"datasource": "spacing-options",
"default_value": "Medium"
}
}
}2. React Component implementieren
// packages/storyblok-ui/src/components/text/SbText.tsx
import { Paragraph } from "@httpjpg/ui";
import { storyblokEditable } from "@storyblok/react/rsc";
import { memo } from "react";
import {
mapColorToToken,
mapFontFamilyToToken,
mapFontSizeToToken,
mapFontWeightToToken,
mapSpacingToToken,
} from "../../lib/token-mapping";
import { mapSpacingToToken as mapSpacing } from "../../lib/spacing-utils";
export interface SbTextProps {
blok: {
_uid: string;
content: string;
font_family?: string;
font_size?: string;
font_weight?: string;
text_color?: string;
spacing_top?: string;
spacing_bottom?: string;
};
}
export const SbText = memo(function SbText({ blok }: SbTextProps) {
const {
content,
font_family,
font_size,
font_weight,
text_color,
spacing_top,
spacing_bottom,
} = blok;
return (
<Paragraph
{...storyblokEditable(blok)}
css={{
fontFamily: mapFontFamilyToToken(font_family),
fontSize: mapFontSizeToToken(font_size),
fontWeight: mapFontWeightToToken(font_weight),
color: mapColorToToken(text_color),
mt: mapSpacing(spacing_top),
mb: mapSpacing(spacing_bottom),
}}
>
{content}
</Paragraph>
);
});🎨 Beispiel: Animated Box Component
1. Schema in Storyblok
{
"name": "animated_box",
"display_name": "Animated Box",
"schema": {
"content": {
"type": "bloks",
"display_name": "Content"
},
"bg_color": {
"type": "option",
"display_name": "Background Color",
"datasource": "background-color-options",
"default_value": "White"
},
"padding": {
"type": "option",
"display_name": "Padding",
"datasource": "spacing-options",
"default_value": "Medium"
},
"animation_duration": {
"type": "option",
"display_name": "Animation Duration",
"datasource": "animation-duration",
"default_value": "Normal (300ms)"
},
"animation_easing": {
"type": "option",
"display_name": "Animation Easing",
"datasource": "animation-easing",
"default_value": "Ease Out"
}
}
}2. React Component
import { Box } from "@httpjpg/ui";
import { DynamicRender } from "@httpjpg/storyblok-utils";
import { storyblokEditable } from "@storyblok/react/rsc";
import { memo } from "react";
import {
mapAnimationDurationToToken,
mapAnimationEasingToToken,
mapColorToToken,
} from "../../lib/token-mapping";
import { mapSpacingToToken } from "../../lib/spacing-utils";
export const SbAnimatedBox = memo(function SbAnimatedBox({ blok }) {
return (
<Box
{...storyblokEditable(blok)}
css={{
bg: mapColorToToken(blok.bg_color),
p: mapSpacingToToken(blok.padding),
transition: `all ${mapAnimationDurationToToken(blok.animation_duration)} ${mapAnimationEasingToToken(blok.animation_easing)}`,
_hover: {
transform: "scale(1.05)",
},
}}
>
<DynamicRender data={blok.content} />
</Box>
);
});🖼️ Beispiel: Grid Component
1. Schema
{
"name": "grid",
"display_name": "Grid",
"schema": {
"items": {
"type": "bloks",
"display_name": "Grid Items"
},
"columns": {
"type": "option",
"display_name": "Columns",
"datasource": "grid-columns",
"default_value": "3 Columns"
},
"gap": {
"type": "option",
"display_name": "Gap",
"datasource": "spacing-options",
"default_value": "Medium"
},
"width": {
"type": "option",
"display_name": "Width",
"datasource": "width-options",
"default_value": "Container"
}
}
}2. Component
import { Grid } from "@httpjpg/ui";
import { DynamicRender } from "@httpjpg/storyblok-utils";
import { storyblokEditable } from "@storyblok/react/rsc";
import { mapGridColumnsToToken, mapWidthToToken } from "../../lib/token-mapping";
import { mapSpacingToToken } from "../../lib/spacing-utils";
export const SbGrid = memo(function SbGrid({ blok }) {
const columns = mapGridColumnsToToken(blok.columns);
return (
<Grid
{...storyblokEditable(blok)}
css={{
gridTemplateColumns:
columns === "auto-fit"
? "repeat(auto-fit, minmax(250px, 1fr))"
: `repeat(${columns}, 1fr)`,
gap: mapSpacingToToken(blok.gap),
maxWidth: mapWidthToToken(blok.width) === "narrow"
? "container.sm"
: mapWidthToToken(blok.width) === "container"
? "container"
: "full",
}}
>
<DynamicRender data={blok.items} />
</Grid>
);
});📋 Mapping-Übersicht
Was Redakteure sehen → Was im Code verwendet wird
| Datasource | Redakteur wählt | Code erhält |
|---|---|---|
spacing-options | "Medium" | "8" → 2rem |
background-color-options | "Primary" | "primary.500" → #F43F5E |
font-family | "Headline (Impact)" | "headline" |
font-size | "Large (16px)" | "lg" |
font-weight | "Bold (700)" | "bold" |
grid-columns | "3 Columns" | "3" |
animation-duration | "Fast (150ms)" | "150ms" |
🚀 Best Practices
✅ DO:
- Nutzen Sie Datasources für alle wiederverwendbaren Optionen
- Verwenden Sie immer die Mapping-Funktionen im Code
- Synchronisieren Sie nach Token-Änderungen
- Geben Sie aussagekräftige Labels (z.B. "Medium (14px)")
❌ DON'T:
- Keine technischen Werte direkt in Storyblok eingeben
- Keine Custom Options ohne Datasource verwenden
- Keine Hex-Codes oder px-Werte in Dropdowns
🔄 Workflow-Zusammenfassung
- Entwickler: Token in
packages/tokens/src/ändern - Entwickler:
pnpm --filter @httpjpg/tokens sync:storyblokausführen - Redakteur: Im Visual Editor aus Dropdowns wählen
- Code: Automatisches Mapping zu korrekten Token-Werten
- Result: Type-safe, konsistent, wartbar! 🎉