diff --git a/packages/docs/src/components/Playground/DynamicPlayground.tsx b/packages/docs/src/components/Playground/DynamicPlayground.tsx index 7fbb0ca11..96bba3975 100644 --- a/packages/docs/src/components/Playground/DynamicPlayground.tsx +++ b/packages/docs/src/components/Playground/DynamicPlayground.tsx @@ -10,7 +10,12 @@ import { lazy, Suspense, useEffect, useState } from 'react'; import { QueryParamProvider } from 'use-query-params'; import { WindowHistoryAdapter } from 'use-query-params/adapters/window'; import * as stylex from '@stylexjs/stylex'; -import { vars } from '@/theming/vars.stylex'; +import { vars, playgroundVars } from '@/theming/vars.stylex'; + +const shimmer = stylex.keyframes({ + '0%': { backgroundPosition: '200% 0' }, + '100%': { backgroundPosition: '-200% 0' }, +}); export function ClientOnly({ children, @@ -52,16 +57,178 @@ export function Playground() { } function PlaygroundPlaceholder() { - // TODO: Add a better placeholder with a shimmer version of the playground layout - return
Loading...
; + return ( +
+
+
+
+ + +
+
+ +
+
+
+
+ ); +} + +function SkeletonEditorPanel({ + tabCount, + lineCount, +}: { + tabCount: number; + lineCount: number; +}) { + const lineWidths = [ + '80%', + '55%', + '70%', + '40%', + '85%', + '60%', + '50%', + '75%', + '35%', + ]; + return ( +
+
+ {Array.from({ length: tabCount }).map((_, i) => ( +
+ ))} +
+
+ {Array.from({ length: lineCount }).map((_, i) => ( +
+ ))} +
+
+ ); +} + +function SkeletonPreviewPanel() { + return ( +
+
+
+
+
+
+
+
+ ); } const styles = stylex.create({ placeholder: { + boxSizing: 'border-box', + width: '100%', + height: `calc(100dvh - ${vars['--fd-nav-height']})`, + padding: 10, + containerType: 'inline-size', + }, + frame: { + boxSizing: 'border-box', + width: '100%', + height: '100%', + overflow: 'hidden', + borderColor: playgroundVars['--pg-border'], + borderStyle: 'solid', + borderWidth: 1, + borderRadius: 20, + }, + row: { display: 'flex', + flexDirection: { default: 'row', '@container (width < 768px)': 'column' }, + width: '100%', + height: '100%', + }, + column: { + display: 'flex', + flexGrow: 1, + flexBasis: 0, + flexDirection: 'column', + minWidth: 0, + minHeight: 0, + }, + panel: { + position: 'relative', + display: 'flex', + flexGrow: 1, + flexShrink: 0, + flexBasis: 42, + flexDirection: 'column', + overflow: 'hidden', + backgroundColor: playgroundVars['--pg-panel-surface'], + boxShadow: `0 0 0 1px ${playgroundVars['--pg-panel-shadow']}`, + }, + previewPanel: { + backgroundColor: playgroundVars['--pg-preview'], + }, + panelHeader: { + display: 'flex', + flexShrink: 0, + gap: 10, alignItems: 'center', - justifyContent: 'center', width: '100%', - height: `calc(100dvh - ${vars['--fd-nav-height']})`, + height: 44, + paddingInline: 16, + backgroundColor: playgroundVars['--pg-header-surface'], + borderBottomColor: vars['--color-fd-border'], + borderBottomStyle: 'solid', + borderBottomWidth: 1, + }, + tabPill: { + width: 64, + height: 16, + borderRadius: 4, + }, + headerLabel: { + width: 72, + height: 14, + borderRadius: 4, + }, + panelBody: { + display: 'flex', + flexGrow: 1, + flexDirection: 'column', + gap: 12, + padding: 18, + overflow: 'hidden', + }, + codeLine: { + height: 10, + borderRadius: 4, + }, + previewBody: { + display: 'flex', + flexGrow: 1, + padding: 18, + }, + previewBlock: { + flexGrow: 1, + width: '100%', + borderRadius: 8, + }, + shimmer: { + backgroundColor: vars['--color-fd-muted'], + backgroundImage: `linear-gradient(90deg, transparent 0%, ${vars['--color-fd-accent']} 50%, transparent 100%)`, + backgroundRepeat: 'no-repeat', + backgroundSize: '200% 100%', + animationName: shimmer, + animationDuration: '1.6s', + animationTimingFunction: 'linear', + animationIterationCount: 'infinite', }, });