|
3 | 3 | import { CodebuffConfigSchema } from '@codebuff/common/json-config/constants' |
4 | 4 | import { schemaToJsonStr } from '@codebuff/common/util/zod-schema' |
5 | 5 | import { DynamicAgentTemplateSchema } from '@codebuff/common/types/dynamic-agent-template' |
| 6 | +import { useState, useRef } from 'react' |
| 7 | +import { ChevronDown, ChevronUp } from 'lucide-react' |
6 | 8 |
|
7 | 9 | import { CodeDemo } from './code-demo' |
| 10 | +import { Button } from '@/components/ui/button' |
| 11 | +import { |
| 12 | + Collapsible, |
| 13 | + CollapsibleContent, |
| 14 | + CollapsibleTrigger, |
| 15 | +} from '@/components/ui/collapsible' |
| 16 | +import { useIsMobile } from '@/hooks/use-mobile' |
| 17 | + |
| 18 | +// Configuration constant for easy adjustment |
| 19 | +const SCHEMA_TRUNCATE_LINES = 25 |
8 | 20 |
|
9 | 21 | export function SchemaDisplay() { |
10 | | - const schemaString = schemaToJsonStr(CodebuffConfigSchema, {io: 'input'}) |
| 22 | + const schemaString = schemaToJsonStr(CodebuffConfigSchema, { io: 'input' }) |
11 | 23 | return <CodeDemo language="json">{schemaString}</CodeDemo> |
12 | 24 | } |
13 | 25 |
|
14 | 26 | export function AgentTemplateSchemaDisplay() { |
15 | | - const schemaString = schemaToJsonStr(DynamicAgentTemplateSchema, {io: 'input'}) |
16 | | - return <CodeDemo language="json">{schemaString}</CodeDemo> |
| 27 | + const [isExpanded, setIsExpanded] = useState(false) |
| 28 | + const isMobile = useIsMobile() |
| 29 | + const componentRef = useRef<HTMLDivElement>(null) |
| 30 | + const schemaString = schemaToJsonStr(DynamicAgentTemplateSchema, { |
| 31 | + io: 'input', |
| 32 | + }) |
| 33 | + |
| 34 | + const lines = schemaString.split('\n') |
| 35 | + const shouldTruncate = lines.length > SCHEMA_TRUNCATE_LINES |
| 36 | + const truncatedSchema = shouldTruncate |
| 37 | + ? lines.slice(0, SCHEMA_TRUNCATE_LINES).join('\n') + '\n // ... truncated' |
| 38 | + : schemaString |
| 39 | + if (!shouldTruncate) { |
| 40 | + return <CodeDemo language="json">{schemaString}</CodeDemo> |
| 41 | + } |
| 42 | + |
| 43 | + const handleToggle = (open: boolean) => { |
| 44 | + setIsExpanded(open) |
| 45 | + // Scroll to component when collapsing |
| 46 | + if (!open && componentRef.current) { |
| 47 | + componentRef.current.scrollIntoView({ |
| 48 | + behavior: 'smooth', |
| 49 | + block: 'start', |
| 50 | + }) |
| 51 | + } |
| 52 | + } |
| 53 | + |
| 54 | + return ( |
| 55 | + <Collapsible open={isExpanded} onOpenChange={handleToggle}> |
| 56 | + <div className="relative group" ref={componentRef}> |
| 57 | + <CodeDemo language="json"> |
| 58 | + {isExpanded ? schemaString : truncatedSchema} |
| 59 | + </CodeDemo> |
| 60 | + {!isExpanded && ( |
| 61 | + <div className="absolute bottom-0 left-0 right-0 flex justify-center pb-4 bg-gradient-to-t from-muted/30 via-muted/20 to-transparent pointer-events-none"> |
| 62 | + <CollapsibleTrigger asChild> |
| 63 | + <Button |
| 64 | + variant="outline" |
| 65 | + size="sm" |
| 66 | + className={`text-xs hover:bg-white/90 bg-white/95 backdrop-blur-sm shadow-md border-gray-200 pointer-events-auto transition-opacity duration-200 text-gray-800 hover:text-gray-900 ${ |
| 67 | + isMobile ? 'opacity-100' : 'opacity-0 group-hover:opacity-100' |
| 68 | + }`} |
| 69 | + > |
| 70 | + <ChevronDown className="h-3 w-3 mr-1" /> |
| 71 | + Show full schema ({lines.length} lines) |
| 72 | + </Button> |
| 73 | + </CollapsibleTrigger> |
| 74 | + </div> |
| 75 | + )} |
| 76 | + {isExpanded && ( |
| 77 | + <div className="flex justify-center mt-2"> |
| 78 | + <CollapsibleTrigger asChild> |
| 79 | + <Button |
| 80 | + variant="outline" |
| 81 | + size="sm" |
| 82 | + className="text-xs hover:bg-muted/60" |
| 83 | + > |
| 84 | + <ChevronUp className="h-3 w-3 mr-1" /> |
| 85 | + Show less |
| 86 | + </Button> |
| 87 | + </CollapsibleTrigger> |
| 88 | + </div> |
| 89 | + )} |
| 90 | + </div> |
| 91 | + </Collapsible> |
| 92 | + ) |
17 | 93 | } |
0 commit comments