Buckets:
evalstate/sandbox-testing-2 / hf-mcp-server /packages /app /src /web /components /GradioWidgetApp.tsx
| import { useMemo } from 'react'; | |
| import { useWidgetProps, useMaxHeight, useTheme } from '../hooks'; | |
| interface GradioToolOutput { | |
| url?: string; | |
| spaceName?: string; | |
| [key: string]: unknown; | |
| } | |
| const LOADING_ANIMATIONS = { | |
| 'huggy-pop': { | |
| url: 'https://chunte-hfba.static.hf.space/images/modern%20Huggies/Huggy%20Pop.gif', | |
| scale: 'scale-250', | |
| }, | |
| vibing: { | |
| url: 'https://chunte-hfba.static.hf.space/images/modern%20Huggies/Vibing%20Huggy.gif', | |
| scale: 'scale-100', | |
| }, | |
| doodle: { | |
| url: 'https://chunte-hfba.static.hf.space/images/modern%20Huggies/Doodle%20Huggy.gif', | |
| scale: 'scale-90', | |
| }, | |
| }; | |
| export function GradioWidgetApp() { | |
| // Use the new hooks from openai-apps-sdk patterns | |
| const toolOutput = useWidgetProps<GradioToolOutput>(); | |
| const maxHeight = useMaxHeight(); | |
| const theme = useTheme(); | |
| // Select loading animation with weighted randomness (60% Huggy Pop, 30% Vibing, 10% Doodle) | |
| const loadingAnimation = useMemo(() => { | |
| const rand = Math.random() * 100; | |
| if (rand < 60) return LOADING_ANIMATIONS['huggy-pop']; | |
| if (rand < 90) return LOADING_ANIMATIONS.vibing; | |
| return LOADING_ANIMATIONS.doodle; | |
| }, []); | |
| // Determine content type based on URL | |
| const isAudioUrl = toolOutput?.url?.match(/\.wav$/i); | |
| const isImageUrl = toolOutput?.url?.match(/\.(jpg|jpeg|png|gif|webp|svg)$/i); | |
| // Calculate container style based on display mode and max height | |
| const containerStyle = maxHeight | |
| ? { maxHeight: `${maxHeight}px`, minHeight: `${Math.min(maxHeight, 480)}px` } | |
| : { minHeight: '100vh' }; | |
| // Determine theme-based classes | |
| const isDark = theme === 'dark'; | |
| const bgGradient = isDark | |
| ? 'bg-gradient-to-b from-neutral-900 to-neutral-800' | |
| : 'bg-gradient-to-b from-gray-50 to-gray-100'; | |
| const cardBg = isDark ? 'bg-neutral-800' : 'bg-white'; | |
| const textPrimary = isDark ? 'text-gray-100' : 'text-gray-800'; | |
| const textSecondary = isDark ? 'text-gray-400' : 'text-gray-600'; | |
| const textTertiary = isDark ? 'text-gray-500' : 'text-gray-500'; | |
| return ( | |
| <div className={`flex flex-col items-center justify-center p-4 ${bgGradient}`} style={containerStyle}> | |
| <div className="max-w-2xl w-full"> | |
| {!toolOutput ? ( | |
| <> | |
| {/* Show random Huggy animation while loading */} | |
| <div className="flex justify-center mb-6"> | |
| <div className="w-32 h-32 overflow-hidden flex items-center justify-center"> | |
| <img | |
| src={loadingAnimation.url} | |
| alt="Hugging Face" | |
| className={`w-full h-full object-cover ${loadingAnimation.scale}`} | |
| /> | |
| </div> | |
| </div> | |
| <div className="text-center"> | |
| <p className={textSecondary}>Loading...</p> | |
| </div> | |
| </> | |
| ) : isAudioUrl && toolOutput.url ? ( | |
| <div className={`${cardBg} rounded-lg shadow-lg p-6`}> | |
| <div className="flex items-center gap-3 mb-4"> | |
| <img | |
| src="https://huggingface.co/datasets/huggingface/brand-assets/resolve/main/hf-logo.svg" | |
| alt="Hugging Face" | |
| className="h-8 object-contain" | |
| /> | |
| {toolOutput.spaceName ? ( | |
| <a | |
| href={`https://huggingface.co/spaces/${toolOutput.spaceName}`} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className={`text-xl font-semibold ${textPrimary} hover:underline`} | |
| > | |
| {toolOutput.spaceName} | |
| </a> | |
| ) : ( | |
| <h2 className={`text-xl font-semibold ${textPrimary}`}>Audio Player</h2> | |
| )} | |
| </div> | |
| <audio controls className="w-full" src={toolOutput.url}> | |
| Your browser does not support the audio element. | |
| </audio> | |
| <p className={`text-sm ${textTertiary} mt-2 break-all`}>{toolOutput.url}</p> | |
| </div> | |
| ) : isImageUrl && toolOutput.url ? ( | |
| <div className={`${cardBg} rounded-lg shadow-lg p-6`}> | |
| <div className="flex items-center gap-3 mb-4"> | |
| <img | |
| src="https://huggingface.co/datasets/huggingface/brand-assets/resolve/main/hf-logo.svg" | |
| alt="Hugging Face" | |
| className="h-8 object-contain" | |
| /> | |
| {toolOutput.spaceName ? ( | |
| <a | |
| href={`https://huggingface.co/spaces/${toolOutput.spaceName}`} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className={`text-xl font-semibold ${textPrimary} hover:underline`} | |
| > | |
| {toolOutput.spaceName} | |
| </a> | |
| ) : ( | |
| <h2 className={`text-xl font-semibold ${textPrimary}`}>Image Viewer</h2> | |
| )} | |
| </div> | |
| <div className="flex justify-center items-center"> | |
| <img | |
| src={toolOutput.url} | |
| alt="Generated content" | |
| className="max-w-full h-auto rounded-lg" | |
| style={{ | |
| maxHeight: maxHeight ? `${maxHeight - 200}px` : '600px', | |
| objectFit: 'contain', | |
| }} | |
| onError={(e) => { | |
| const target = e.target as HTMLImageElement; | |
| target.style.display = 'none'; | |
| const errorMsg = target.nextElementSibling; | |
| if (errorMsg) { | |
| (errorMsg as HTMLElement).style.display = 'block'; | |
| } | |
| }} | |
| /> | |
| <p className="text-sm text-red-500 mt-2 hidden">Failed to load image</p> | |
| </div> | |
| <p className={`text-sm ${textTertiary} mt-4 break-all text-center`}>{toolOutput.url}</p> | |
| </div> | |
| ) : ( | |
| <div className={`${cardBg} rounded-lg shadow-lg p-6 text-center`}> | |
| <p className={textSecondary}> | |
| {toolOutput.url ? 'Content available but no preview available for this type.' : 'No content to display.'} | |
| </p> | |
| {toolOutput.url && !isAudioUrl && !isImageUrl && ( | |
| <p className={`text-sm ${textSecondary} mt-2 break-all`}>{toolOutput.url}</p> | |
| )} | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| } | |
Xet Storage Details
- Size:
- 5.63 kB
- Xet hash:
- 5cea572452963cbab2aa6f3f037ed245ee8248cfb66a8c640a6f41cce3078818
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.