From b85869886aa22bb9f8a4d901efe19877a459b604 Mon Sep 17 00:00:00 2001 From: william garrity Date: Tue, 3 Feb 2026 22:07:11 -0500 Subject: [PATCH 1/6] feat(RecordButton): Complete rewrite with enhanced visual design and states ## Major Changes ### Component Architecture (RecordButton.tsx) - Complete rewrite based on modern v0.app reference design - 6 distinct states: idle, recording, processing, disabled, error, success - 4 visual variants with updated color schemes: - default: Red/pink gradient with glow effects - outline: Subtle border with amber/orange recording state - ghost: Transparent with emerald/green recording state - minimal: Clean, understated with blue/indigo recording state - 3 sizes: sm (40px), md (48px), lg (56px) - Animated waveform bars component for recording visualization - Pulse ring animation during recording state - Duration display support while recording - Transcription state integration for AI applications - Both controlled and uncontrolled recording modes - Built-in MediaRecorder support with callbacks ### Stories & Documentation (RecordButton. ## Major Changes ### Component Architecture (RecordButton.tsx) - Complete rewrite based on modern v0.app reference design - 6 distinct states: idle, tch ### Component - - Complete rewrite based on modern v0.app reta- 6 distinct states: idle, recording, processing, disablegr- 4 visual variants with updated color schemes: - default: Red/pink gralt - default: Red/pink gradient with glow effec e - outline: Subtle border with amber/orange reng - ghost: Transparent with emerald/green recording state al - minimal: Clean, understated with blue/indigo recordird- 3 sizize, TranscriptionState, TranscriptionResult - Clean named- Animated waveform bars component for ree - Pulse ring animation during recording state - Duration dispti- Duration display support while recording -lating animation for recording state bars --- .../RecordButton/RecordButton.stories.tsx | 1353 +++++++---------- src/components/RecordButton/RecordButton.tsx | 835 ++++++---- src/components/RecordButton/index.ts | 3 +- src/styles/base.css | 18 + 4 files changed, 1112 insertions(+), 1097 deletions(-) diff --git a/src/components/RecordButton/RecordButton.stories.tsx b/src/components/RecordButton/RecordButton.stories.tsx index 131b9d22..8ec6f627 100644 --- a/src/components/RecordButton/RecordButton.stories.tsx +++ b/src/components/RecordButton/RecordButton.stories.tsx @@ -1,6 +1,12 @@ import type { Meta, StoryObj } from '@storybook/react'; import * as React from 'react'; -import { RecordButton, type TranscriptionState } from './RecordButton'; +import { + RecordButton, + type RecordButtonState, + type RecordButtonVariant, + type RecordButtonSize, + type TranscriptionState, +} from './RecordButton'; import { Input } from '../Input'; import { Textarea } from '../Textarea'; @@ -127,161 +133,311 @@ function useMockStreamingTranscription() { } // ============================================================================ -// Transcription Textarea Component +// State Card Component // ============================================================================ -interface TranscriptionTextareaProps { - value: string; - onChange: (value: string) => void; - placeholder?: string; - transcriptionState: TranscriptionState; - streamingText?: string; - rows?: number; - className?: string; +function StateCard({ + state, + label, + description, + variant = 'default', + size = 'md', + showWaveform, + showPulse, +}: { + state: RecordButtonState; + label: string; + description: string; + variant?: RecordButtonVariant; + size?: RecordButtonSize; + showWaveform?: boolean; + showPulse?: boolean; +}) { + return ( +
+ +
+

{label}

+

+ {description} +

+
+
+ ); } -/** - * A textarea that handles transcription states gracefully. - * Shows appropriate UI for transcribing, streaming, and idle states. - */ -function TranscriptionTextarea({ - value, - onChange, - placeholder = 'Type or record a message...', - transcriptionState, - streamingText, - rows = 3, - className, -}: TranscriptionTextareaProps) { - const isTranscribing = transcriptionState === 'transcribing'; - const isStreaming = transcriptionState === 'streaming'; - const isProcessing = isTranscribing || isStreaming; - - // Display streaming text when available, otherwise show value - const displayValue = isStreaming && streamingText ? streamingText : value; - - // Determine placeholder based on state - const getPlaceholder = () => { - if (isTranscribing) return 'Transcribing your audio...'; - if (isStreaming) return ''; - return placeholder; +// ============================================================================ +// Variant Row Component +// ============================================================================ + +function VariantRow({ + variant, + label, +}: { + variant: RecordButtonVariant; + label: string; +}) { + const states: RecordButtonState[] = [ + 'idle', + 'recording', + 'processing', + 'disabled', + 'error', + 'success', + ]; + + return ( +
+
+ {label} + + variant="{variant}" + +
+
+ {states.map((state) => ( +
+ + {state} +
+ ))} +
+
+ ); +} + +// ============================================================================ +// Interactive Demo Component +// ============================================================================ + +function InteractiveDemo() { + const [state, setState] = React.useState('idle'); + const timerRef = React.useRef(null); + + const handleClick = () => { + if (state === 'idle') { + // Start recording + setState('recording'); + } else if (state === 'recording') { + // Stop recording, start processing + setState('processing'); + + // Simulate processing time + timerRef.current = setTimeout(() => { + setState('success'); + + // Reset to idle after showing success + timerRef.current = setTimeout(() => { + setState('idle'); + }, 1500); + }, 2000); + } }; + React.useEffect(() => { + return () => { + if (timerRef.current) { + clearTimeout(timerRef.current); + } + }; + }, []); + return ( -
-