From 75f6270462a20fc7a1925f5dae0c3f161a112aaf Mon Sep 17 00:00:00 2001 From: Devon-White Date: Tue, 16 Jun 2026 07:38:40 -0400 Subject: [PATCH 1/4] feat(docs): add the Voice Widget (rows design) to the TTS pages A TTS voice browser embedded in the docs: a bordered list of two-line rows (name over muted meta) with play-to-audition and copy-config, scoped under .vw.vw-rows and following the docs' light/dark brand tokens. - fern/components/voice-widget: the widget (index.tsx) over a shared data/helper engine (engine.tsx) + types; styles in styles.css. Loading state is a row-shaped skeleton built on the generic skeleton primitive. - Registered via docs.yml experimental.mdx-components + css. - Embedded on all 11 TTS pages (provider-locked on each provider page, groupBy="none" on the index). Supersedes the earlier stacked PRs #392 (parent), #407 (card refinements), and #409 (rows). The competing card design was dropped per the design decision to ship the rows layout; only the rows widget and its self-contained stylesheet remain. --- .gitignore | 3 +- fern/components/index.tsx | 8 + fern/components/skeleton/index.tsx | 50 ++ fern/components/skeleton/styles.css | 25 + fern/components/tsconfig.json | 19 + fern/components/voice-widget/engine.tsx | 220 +++++++++ fern/components/voice-widget/index.tsx | 453 ++++++++++++++++++ fern/components/voice-widget/styles.css | 251 ++++++++++ fern/components/voice-widget/types.ts | 51 ++ fern/docs.yml | 4 + .../pages/calling/voice/TTS/azure.mdx | 6 + .../pages/calling/voice/TTS/cartesia.mdx | 6 + .../pages/calling/voice/TTS/deepgram.mdx | 6 + .../pages/calling/voice/TTS/elevenlabs.mdx | 6 + .../pages/calling/voice/TTS/google.mdx | 8 + .../pages/calling/voice/TTS/index.mdx | 11 + .../pages/calling/voice/TTS/inworld.mdx | 6 + .../pages/calling/voice/TTS/minimax.mdx | 6 + .../pages/calling/voice/TTS/openai.mdx | 6 + .../pages/calling/voice/TTS/polly.mdx | 8 + .../platform/pages/calling/voice/TTS/rime.mdx | 6 + package.json | 4 +- yarn.lock | 34 +- 23 files changed, 1194 insertions(+), 3 deletions(-) create mode 100644 fern/components/index.tsx create mode 100644 fern/components/skeleton/index.tsx create mode 100644 fern/components/skeleton/styles.css create mode 100644 fern/components/tsconfig.json create mode 100644 fern/components/voice-widget/engine.tsx create mode 100644 fern/components/voice-widget/index.tsx create mode 100644 fern/components/voice-widget/styles.css create mode 100644 fern/components/voice-widget/types.ts diff --git a/.gitignore b/.gitignore index 8bbf8e72f5..61594e6e47 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,5 @@ dist .docs-review # Internal process artifacts (superpowers / brainstorming specs) -docs/superpowers/ \ No newline at end of file +docs/superpowers/ +.superpowers/ \ No newline at end of file diff --git a/fern/components/index.tsx b/fern/components/index.tsx new file mode 100644 index 0000000000..289efdaf69 --- /dev/null +++ b/fern/components/index.tsx @@ -0,0 +1,8 @@ +// Barrel for docs MDX components. Each component lives in its own subdirectory as an index.tsx +// for organization. MDX pages import this barrel as a file path — +// `import { VoiceWidget } from "@/components/index"` — because Fern's resolver only resolves file +// paths, not directories (and not directory→index). For the same reason the re-exports below use +// explicit `/index` file paths rather than bare directory paths. `export *` pulls in each +// component's public surface (components + types) without enumerating them. +export * from "./voice-widget/index"; +export * from "./skeleton/index"; diff --git a/fern/components/skeleton/index.tsx b/fern/components/skeleton/index.tsx new file mode 100644 index 0000000000..c59f770bdc --- /dev/null +++ b/fern/components/skeleton/index.tsx @@ -0,0 +1,50 @@ +import type { CSSProperties } from "react"; + +// Reusable loading-skeleton primitive for custom MDX components that fetch data at runtime. +// Compose a few of these to mimic the shape of the content that's loading. Pairs with this folder's +// styles.css (loaded via docs.yml `css:` — Fern's component bundler doesn't process CSS imports). +// Theme-aware (light/dark) through Fern's grayscale vars. +// +// import { Skeleton, SkeletonText } from "@/components/index"; +// if (!data) return ; + +export interface SkeletonProps { + /** CSS width — number (px) or any CSS length (e.g. "60%"). */ + width?: string | number; + /** CSS height — number (px) or any CSS length. Default: 14. */ + height?: string | number; + /** Border radius override — number (px) or any CSS length (e.g. "50%" for a circle). */ + radius?: string | number; + className?: string; + style?: CSSProperties; +} + +export function Skeleton({ width, height = 14, radius, className, style }: SkeletonProps) { + return ( +