Di Gusto Components
Developer reference for all React Native components in the Di Gusto platform. Built with Expo, React Native Paper, and IBM Plex Sans. This library powers the immersive Italian storytelling experience.
Core Components
The Di Gusto wordmark rendered in IBM Plex Sans Bold, optionally accompanied by the animated SpiroLogo icon. Supports multiple size presets, color variants, layout modes, and an animated cycling tagline. Wraps in a Pressable when onPress is provided.
| Prop | Type | Default | Description |
|---|---|---|---|
| size | 'sm' | 'md' | 'lg' | 'xl' | 'lg' | Size preset controlling wordmark font size (20/28/40/56px) and icon scale. |
| variant | 'default' | 'light' | 'dark' | 'primary' | 'default' | Color variant. light = white, dark = #09090b, primary = theme orange, default = theme onBackground. |
| mode | 'full' | 'wordmark' | 'full' | full renders SpiroLogo icon + wordmark. wordmark renders text only. |
| version | 'v1' | 'v2' | 'v2' | Animation version of the SpiroLogo. v1 = breathe, v2 = morph keyframe sequence. |
| tagline | boolean | false | Show tagline text below the wordmark. |
| taglineText | string | 'Where Taste and Culture Meet' | Static tagline text (used when animatedTagline is false). |
| wordmark | string | 'Di Gusto' | Override the wordmark text. |
| animatedTagline | boolean | false | Cycles through slogan words (Entertainment, Storytelling, …) with fade animation. Requires tagline={true}. |
| morphCycles | number | undefined (∞) | Number of SpiroLogo morph animation cycles before stopping. |
| showBeta | boolean | false | Render a small uppercase BETA label next to the wordmark. |
| layout | 'stacked' | 'inline' | 'stacked' | Container direction. stacked centers vertically, inline places icon and text in a row. |
| shadow | boolean | false | Add text shadow for readability over images or video backgrounds. |
| onPress | () => void | undefined | Press handler — wraps logo in a Pressable. Typically navigates to the home/play screen. |
| style | ViewStyle | undefined | Additional styles applied to the outer container View. |
Animated spirograph icon computed from epitrochoid mathematics (R, r, d parameters). No hardcoded SVG path data — the pattern is generated entirely from code. Supports spin, progressive draw, breathe, and morph-keyframe animations. On web, canvas-based rendering bypasses React reconciliation for smooth 60fps animation.
| Prop | Type | Default | Description |
|---|---|---|---|
| size | number | 32 | Width and height of the rendered SVG/canvas in pixels. |
| color | string | '#ec4899' | Stroke color of the spirograph path. |
| outerRadius | number | 139 | Outer circle radius R in the epitrochoid formula. |
| innerRadius | number | 58 | Inner circle radius r in the epitrochoid formula. |
| penDistance | number | 147 | Pen arm distance d from the inner circle center. |
| opacity | number | 0.8 | Stroke opacity (0–1). |
| lineWidth | number | 0.1 | Stroke line width in SVG units. |
| spin | boolean | false | Continuously rotate the spirograph. |
| spinDuration | number | 8000 | Duration of one full rotation in milliseconds. |
| draw | boolean | false | Progressive draw animation on mount (web SVG dashoffset). |
| drawDuration | number | 2000 | Draw animation duration in ms. |
| breathe | boolean | false | Animate outer radius down to breatheMin and back in a cosine cycle. |
| breatheDuration | number | 6000 | Full breathe cycle duration in ms. |
| breatheMin | number | 20 | Minimum outer radius during breathe animation. |
| breatheCount | number | undefined (∞) | Number of breathe cycles before stopping on the final full-radius frame. |
| morph | boolean | false | Enable keyframe morph animation. Requires morphKeyframes. |
| morphKeyframes | SpiroKeyframe[] | undefined | Array of keyframe states to interpolate between. Each has R, r, d, lineWidth, fill, alternate, pulseScale, duration. |
| morphDuration | number | 3000 | Default duration per keyframe transition (ms). Each keyframe can override with its own duration. |
| morphCycles | number | undefined (∞) | Number of full morph cycles before stopping on the first keyframe. |
| alternateWeights | boolean | false | Render alternating thick/thin lobe stroke weights for a more intricate look. |
| thinRatio | number | 0.35 | Stroke width ratio for thin lobes when alternateWeights is enabled. |
| style | any | undefined | Style passed to the outer wrapper (View on native, div on web). |
Circular initial-based avatar with optional gradient background and auteur level badge. Displays 1–2 characters in a colored circle. The optional level prop (1–3) renders a small colored badge at the bottom-right: gray (Audience), amber (Director), orange (Auteur).
| Prop | Type | Default | Description |
|---|---|---|---|
| labelrequired | string | — | 1 or 2 characters to display. Automatically uppercased. Single char = larger font (48% of size), two chars = 38%. |
| size | number | 48 | Diameter of the circle in pixels. |
| color | AvatarColor | 'orange' | Background color. Accepts a preset key (orange, indigo, pink, emerald, amber, sky, rose, violet) or any CSS color string. |
| gradient | [string, string] | null | undefined | Two-stop gradient colors. When provided, overrides solid color. Rendered as a LinearGradient (top-left to bottom-right). |
| level | number | undefined | Auteur level 1–3. Renders a colored circle badge at bottom-right. Values outside 1–3 are ignored. |
Slide-in notification anchored to the bottom-right of the screen. 300px wide, slides in from the right edge, pauses for reading, then slides back out. Supports four semantic variants with corresponding icons and color themes.
| Prop | Type | Default | Description |
|---|---|---|---|
| visiblerequired | boolean | — | Controls whether the toast is shown. Triggers slide-in when changed to true. |
| messagerequired | string | — | The notification text. Capped at 2 lines. |
| onDismissrequired | () => void | — | Called after the auto-dismiss animation completes. |
| variant | 'success' | 'info' | 'warning' | 'error' | 'success' | Semantic variant controlling icon (Check/Info/AlertTriangle/X) and color theme. |
| icon | LucideIcon | variant default | Override the default variant icon with any Lucide icon component. |
| duration | number | 4000 | Milliseconds the toast stays visible before sliding out. |
Compact chip showing the user's live token balance with an odometer-style rolling digit animation. Tapping opens a fullscreen cinematic modal with a video background. Two video states based on balance: deficit (<100 tokens) shows the film crew urging the user to earn; surplus (≥100) shows a celebration. Balance changes trigger a pulse animation and floating delta indicator.
| Prop | Type | Default | Description |
|---|---|---|---|
| refreshKey | number | 0 | Increment this value to trigger a token balance refresh from the server. |
| onPress | () => void | undefined | Override the built-in modal with a custom press handler. |
| compact | boolean | false | Compact display mode for tight layout spaces. |
Layout Components
Standard authenticated-screen chrome providing a fixed header, scrollable content area constrained to 1200px max-width, optional footer, and optional floating action button. The outer viewport uses a dark zinc gradient. Content and footer slots accept any React node, enabling composition with TopNav, Footer, and other layout components.
| Prop | Type | Default | Description |
|---|---|---|---|
| headerrequired | ReactNode | — | Header component fixed above scroll content. Typically <TopNav />. |
| childrenrequired | ReactNode | — | Main scrollable content rendered inside the content area. |
| footer | ReactNode | undefined | Optional footer pinned below the scroll content. Typically <Footer />. |
| fab | ReactNode | undefined | Floating action button positioned at bottom-right of the content area. |
| contentPadding | number | 16 | Padding applied to the scrollable content area in pixels. |
| scrollEnabled | boolean | true | Set to false for screens using FlatList or other self-scrolling content. |
| onRefresh | () => void | undefined | Pull-to-refresh callback. No-op on web. |
| refreshing | boolean | false | Whether the refresh indicator is visible. |
| backgroundColor | string | zinc gradient | Override the outer viewport background color. |
Full-screen modal with animated backdrop, optional header (title + close button), scrollable content, and optional footer. Supports ESC to close on web, backdrop-press to close, and configurable animation duration. Used as the foundation for all modals in the app including NavMenu (desktop) and AuteurLevelModal.
| Prop | Type | Default | Description |
|---|---|---|---|
| visiblerequired | boolean | — | Controls modal visibility. Triggers fade animation. |
| onCloserequired | () => void | — | Called when the modal should close (close button, backdrop press, or ESC key). |
| childrenrequired | ReactNode | — | Main modal content rendered in the scrollable area. |
| title | string | undefined | Optional title shown in the modal header. |
| footer | ReactNode | undefined | Optional content pinned to the bottom of the modal. |
| showCloseButton | boolean | true | Show the close (×) button in the header. |
| closeOnBackdrop | boolean | true | Close modal when the backdrop is pressed. |
| closeOnEsc | boolean | true | Close on ESC key press (web only). |
| scrollEnabled | boolean | true | Set false for non-scrolling content (e.g. FlatList). |
| contentPadding | number | 24 | Padding applied to the scrollable content container. |
| backgroundColor | string | theme.colors.background | Override the modal container background color. |
| animationDuration | number | 250 | Fade animation duration in milliseconds. |
Two-panel responsive layout: content panel + media panel. Side-by-side on wide screens (≥768px), stacked on narrow with media on top. Media panel supports image, video, solid color, gradient, or a playlist of videos with smooth CrossfadeVideo transitions. Optional background audio with mute toggle, crossfade between playlist tracks.
| Prop | Type | Default | Description |
|---|---|---|---|
| childrenrequired | ReactNode | — | Content rendered in the content panel. |
| mediarequired | SplitScreenMedia | SplitScreenMedia[] | — | Media configuration. Pass an array for a playlist. Types: image, video, color, gradient. |
| contentSide | 'left' | 'right' | 'left' | Which side content appears on in wide mode. In narrow mode media is always on top. |
| mediaShuffleStart | boolean | true | Start playlist at a random index. |
| breakpoint | number | 768 | Viewport width (px) at which layout switches from stacked to side-by-side. |
| ratio | [number, number] | [1, 1] | Flex ratio [content, media] in wide mode. |
| mediaOverlay | { color?: string; opacity?: number } | undefined | Semi-transparent overlay on the media panel for contrast/darkening. |
| mediaContent | ReactNode | (media, index) => ReactNode | undefined | Content overlaid on top of the media panel (branding, captions). Centered and auto-sized. |
| contentPadding | number | 0 | Padding for the content panel. Let children handle their own padding by default. |
| showMediaOnNarrow | boolean | true | Show media panel on narrow/mobile screens. |
| narrowMediaRatio | number | 0.4 | Media panel flex ratio relative to content in narrow mode. |
| audio | SplitScreenAudio | SplitScreenAudio[] | undefined | Background audio. Starts muted with a toggle icon in the media panel corner. Crossfades between playlist tracks. |
| onVideoEnd | () => void | undefined | Called when a non-looping video finishes (fires per video in playlists before auto-advance). |
Common Components
Accessible tooltip wrapper that shows a label on hover (web) or long-press (native). Wraps any pressable child and displays the tooltip label in a small dark popover above or below the target element.
| Prop | Type | Default | Description |
|---|---|---|---|
| titlerequired | string | — | Tooltip label text displayed on hover/long-press. |
| childrenrequired | ReactNode | — | The element that triggers the tooltip. |
Vertically-oriented sidebar label used to annotate sections of the UI with rotated text. Typically used in split layouts to label the media panel or content zones.
| Prop | Type | Default | Description |
|---|---|---|---|
| labelrequired | string | — | Text to display in the vertical sidebar label. |
| side | 'left' | 'right' | 'left' | Which side of the container the label is anchored to. |
Loading spinner that cycles through multiple visual styles ("variety") to keep long-loading states visually interesting. Wraps React Native's ActivityIndicator with Di Gusto brand colors.
| Prop | Type | Default | Description |
|---|---|---|---|
| size | 'small' | 'large' | number | 'large' | Spinner size. |
| color | string | theme primary | Spinner color override. |
| style | ViewStyle | undefined | Additional container styles. |
Story Components
Cinematic scene identifier label displaying act/scene numbers and a custom label. Supports a glass-morphism variant for use over video backgrounds. Optionally accepts children for additional descriptive text below the primary label.
| Prop | Type | Default | Description |
|---|---|---|---|
| scenerequired | number | — | Scene number. |
| actrequired | number | — | Act number. |
| labelrequired | string | — | Primary label text (e.g. "★ 1,250 TOKENS"). |
| variant | 'default' | 'glass' | 'default' | glass uses backdrop-blur for overlay on video/images. |
| children | ReactNode | undefined | Additional descriptive content rendered below the label. |
Badge component displaying story and act metadata. Used to mark story cards, scene headers, and timeline entries with their Act/Scene identifier in the Di Gusto cinematic style.
| Prop | Type | Default | Description |
|---|---|---|---|
| act | number | 1 | Act number displayed in the badge. |
| scene | number | 1 | Scene number displayed in the badge. |
| variant | 'default' | 'compact' | 'default' | Size variant. compact for tight card contexts. |
| style | ViewStyle | undefined | Additional container styles. |
Italian vocabulary flashcard displayed during story transitions or as interstitials. Shows the Italian word prominently with pronunciation guide and English translation. Styled with warm gold tones to match the Di Gusto aesthetic.
| Prop | Type | Default | Description |
|---|---|---|---|
| wordrequired | string | — | Italian vocabulary word. |
| pronunciation | string | undefined | Phonetic pronunciation guide. |
| translationrequired | string | — | English translation. |
| context | string | undefined | Story context or example sentence using the word. |
| style | ViewStyle | undefined | Additional container styles. |
Card component that highlights a featured ingredient from the current story. Shows ingredient name, origin, flavor profile, and a brief culinary description. Used in story scenes where food culture intersects with the narrative.
| Prop | Type | Default | Description |
|---|---|---|---|
| ingredientrequired | string | — | Ingredient name. |
| origin | string | undefined | Geographic origin (e.g. "Tuscany, Italy"). |
| descriptionrequired | string | — | Culinary description and flavor notes. |
| imageUrl | string | undefined | Optional hero image URL for the ingredient. |
| style | ViewStyle | undefined | Additional container styles. |
Patience / loading interstitial shown while AI story generation is in progress. Displays an animated waiting state with Italian-themed copy and a progress indicator. Keeps users engaged during the 15–30 second story generation window.
| Prop | Type | Default | Description |
|---|---|---|---|
| message | string | 'Creating your story…' | Loading message displayed below the animation. |
| progress | number | undefined | Optional progress value 0–1 for a progress bar. |
| style | ViewStyle | undefined | Additional container styles. |
Italian-themed patience screen — a more cinematic variant of BePatient featuring Italian idioms, scenic imagery, and character-driven copy. Used for longer wait states where a richer experience is appropriate (e.g. first story generation).
| Prop | Type | Default | Description |
|---|---|---|---|
| onReady | () => void | undefined | Called when the patience screen determines the user is ready to proceed. |
| minDisplayMs | number | 3000 | Minimum time in ms to display before calling onReady. |
| style | ViewStyle | undefined | Additional container styles. |
Media Components
Smart HTML video player with viewport detection — pauses when scrolled out of view and resumes when back in view (IntersectionObserver on web). Supports autoplay, mute, loop, object-fit, and an onEnded callback.
| Prop | Type | Default | Description |
|---|---|---|---|
| srcrequired | string | — | Video source URL. |
| autoPlay | boolean | false | Start playing immediately when in viewport. |
| muted | boolean | true | Mute the video (required for autoplay in most browsers). |
| loop | boolean | false | Loop the video playback. |
| objectFit | 'cover' | 'contain' | 'fill' | 'cover' | CSS object-fit for the video element. |
| style | ViewStyle | undefined | Styles applied to the video container. |
| onEnded | () => void | undefined | Called when video playback ends. |
Video player with smooth crossfade transitions between a playlist of clips. Preloads the next clip for seamless transitions. Used internally by SplitScreen for video playlists and can be used standalone for story scene sequences.
| Prop | Type | Default | Description |
|---|---|---|---|
| scenesrequired | CrossfadeScene[] | — | Array of scenes with id, url, and optional posterUrl. |
| startIndex | number | 0 | Index of the first scene to play. |
| muted | boolean | true | Mute all video clips. |
| loop | boolean | true | Loop the entire playlist after the last scene. |
| viewport | boolean | true | Pause when scrolled out of viewport. |
| crossfadeDuration | number | 1000 | Crossfade transition duration in ms. |
| onSceneChange | (index: number) => void | undefined | Called when the active scene changes. |
Fullscreen video modal overlay. Tapping the backdrop or pressing ESC dismisses the modal. Used for previewing story clips, showcasing ingredients, and cinematic reveals.
| Prop | Type | Default | Description |
|---|---|---|---|
| visiblerequired | boolean | — | Controls modal visibility. |
| srcrequired | string | — | Video source URL. |
| onCloserequired | () => void | — | Called when the modal is dismissed. |
| autoPlay | boolean | true | Start playing when modal opens. |
| poster | string | undefined | Poster image shown before video loads. |
Modal Components
In-app purchase modal for acquiring token credits. Displays current balance, available token pack options with pricing, and handles the purchase flow. Called from TokenBalanceChip when the user needs more tokens to start a story.
| Prop | Type | Default | Description |
|---|---|---|---|
| visiblerequired | boolean | — | Controls modal visibility. |
| onDismissrequired | () => void | — | Called when the modal is dismissed without purchase. |
| currentBalancerequired | number | — | User's current token balance displayed in the modal header. |
| onPurchaseComplete | () => void | undefined | Called after a successful purchase completes. |
Modal showing the user's current auteur/creator level progression — Audience (1), Director (2), or Auteur (3) — along with token stats, lifetime earnings, and what's unlocked at each tier. Opened from the avatar pill in TopNav.
| Prop | Type | Default | Description |
|---|---|---|---|
| visiblerequired | boolean | — | Controls modal visibility. |
| onCloserequired | () => void | — | Called when the modal is dismissed. |
| level | 1 | 2 | 3 | 1 | Current auteur level. |
| tokenBalance | number | 0 | Current token balance shown in the stats section. |
| lifetimeTokens | number | 0 | Lifetime tokens earned shown in the stats section. |
Auth Components
Authentication gate wrapper that conditionally renders children only when the user is authenticated. Redirects unauthenticated users to the sign-in screen. Optionally accepts a fallback component to show while the auth state is loading.
| Prop | Type | Default | Description |
|---|---|---|---|
| childrenrequired | ReactNode | — | Content to render when authenticated. |
| fallback | ReactNode | <VarietySpinner /> | Content to render while auth state is loading. |
| redirectTo | string | 'SignIn' | Screen name to navigate to if not authenticated. |
React class component error boundary that catches rendering errors in the component tree below it. Renders a fallback UI instead of crashing the entire app. Logs errors to the console and optionally to external error tracking.
| Prop | Type | Default | Description |
|---|---|---|---|
| childrenrequired | ReactNode | — | Component tree to wrap with error boundary protection. |
| fallback | ReactNode | error message UI | Fallback UI to render when an error is caught. |
| onError | (error: Error, info: ErrorInfo) => void | undefined | Called when an error is caught, useful for error reporting services. |