Split SnippetViewer.tsx (158 LOC) into 2 focused components

Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-01-17 22:02:12 +00:00
parent 5a419e764a
commit 12fabfdab2
3 changed files with 171 additions and 110 deletions

View File

@@ -2,18 +2,12 @@ import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
} from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { Copy, Pencil, Check, SplitVertical } from '@phosphor-icons/react'
import { Snippet } from '@/lib/types'
import { MonacoEditor } from '@/components/features/snippet-editor/MonacoEditor'
import { ReactPreview } from '@/components/features/snippet-editor/ReactPreview'
import { PythonOutput } from '@/components/features/python-runner/PythonOutput'
import { cn } from '@/lib/utils'
import { useState } from 'react'
import { strings, appConfig, LANGUAGE_COLORS } from '@/lib/config'
import { appConfig } from '@/lib/config'
import { SnippetViewerHeader } from './SnippetViewerHeader'
import { SnippetViewerContent } from './SnippetViewerContent'
interface SnippetViewerProps {
snippet: Snippet | null
@@ -47,110 +41,24 @@ export function SnippetViewer({ snippet, open, onOpenChange, onEdit, onCopy }: S
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[95vw] sm:max-h-[95vh] h-[95vh] overflow-hidden flex flex-col p-0">
<DialogHeader className="px-6 pt-6 pb-4 pr-14 border-b border-border">
<div className="flex items-start justify-between gap-4">
<div className="flex-1 min-w-0 space-y-2">
<div className="flex items-center gap-3">
<DialogTitle className="text-2xl font-bold truncate">
{snippet.title}
</DialogTitle>
<Badge
variant="outline"
className={cn(
"shrink-0 border font-medium text-xs px-2 py-1",
LANGUAGE_COLORS[snippet.language] || LANGUAGE_COLORS['Other']
)}
>
{snippet.language}
</Badge>
</div>
{snippet.description && (
<p className="text-sm text-muted-foreground">
{snippet.description}
</p>
)}
<p className="text-xs text-muted-foreground">
{strings.snippetViewer.lastUpdated}: {new Date(snippet.updatedAt).toLocaleString()}
</p>
</div>
<div className="flex gap-2 shrink-0">
{canPreview && (
<Button
variant={showPreview ? "default" : "outline"}
size="sm"
onClick={() => setShowPreview(!showPreview)}
className="gap-2"
>
<SplitVertical className="h-4 w-4" />
{showPreview ? strings.snippetViewer.buttons.hidePreview : strings.snippetViewer.buttons.showPreview}
</Button>
)}
<Button
variant="outline"
size="sm"
onClick={handleCopy}
className="gap-2"
>
{isCopied ? (
<>
<Check className="h-4 w-4" weight="bold" />
{strings.snippetViewer.buttons.copied}
</>
) : (
<>
<Copy className="h-4 w-4" />
{strings.snippetViewer.buttons.copy}
</>
)}
</Button>
<Button
variant="outline"
size="sm"
onClick={handleEdit}
className="gap-2"
>
<Pencil className="h-4 w-4" />
{strings.snippetViewer.buttons.edit}
</Button>
</div>
</div>
<SnippetViewerHeader
snippet={snippet}
isCopied={isCopied}
canPreview={canPreview}
showPreview={showPreview}
onCopy={handleCopy}
onEdit={handleEdit}
onTogglePreview={() => setShowPreview(!showPreview)}
/>
</DialogHeader>
<div className="flex-1 overflow-hidden flex">
{canPreview && showPreview ? (
<>
<div className="flex-1 overflow-hidden border-r border-border">
<MonacoEditor
value={snippet.code}
onChange={() => {}}
language={snippet.language}
height="100%"
readOnly={true}
/>
</div>
<div className="flex-1 overflow-hidden">
{isPython ? (
<PythonOutput code={snippet.code} />
) : (
<ReactPreview
code={snippet.code}
language={snippet.language}
functionName={snippet.functionName}
inputParameters={snippet.inputParameters}
/>
)}
</div>
</>
) : (
<div className="flex-1 overflow-hidden">
<MonacoEditor
value={snippet.code}
onChange={() => {}}
language={snippet.language}
height="100%"
readOnly={true}
/>
</div>
)}
<SnippetViewerContent
snippet={snippet}
canPreview={canPreview}
showPreview={showPreview}
isPython={isPython}
/>
</div>
</DialogContent>
</Dialog>

View File

@@ -0,0 +1,58 @@
import { Snippet } from '@/lib/types'
import { MonacoEditor } from '@/components/features/snippet-editor/MonacoEditor'
import { ReactPreview } from '@/components/features/snippet-editor/ReactPreview'
import { PythonOutput } from '@/components/features/python-runner/PythonOutput'
interface SnippetViewerContentProps {
snippet: Snippet
canPreview: boolean
showPreview: boolean
isPython: boolean
}
export function SnippetViewerContent({
snippet,
canPreview,
showPreview,
isPython,
}: SnippetViewerContentProps) {
if (canPreview && showPreview) {
return (
<>
<div className="flex-1 overflow-hidden border-r border-border">
<MonacoEditor
value={snippet.code}
onChange={() => {}}
language={snippet.language}
height="100%"
readOnly={true}
/>
</div>
<div className="flex-1 overflow-hidden">
{isPython ? (
<PythonOutput code={snippet.code} />
) : (
<ReactPreview
code={snippet.code}
language={snippet.language}
functionName={snippet.functionName}
inputParameters={snippet.inputParameters}
/>
)}
</div>
</>
)
}
return (
<div className="flex-1 overflow-hidden">
<MonacoEditor
value={snippet.code}
onChange={() => {}}
language={snippet.language}
height="100%"
readOnly={true}
/>
</div>
)
}

View File

@@ -0,0 +1,95 @@
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { Copy, Pencil, Check, SplitVertical } from '@phosphor-icons/react'
import { Snippet } from '@/lib/types'
import { cn } from '@/lib/utils'
import { strings, LANGUAGE_COLORS } from '@/lib/config'
interface SnippetViewerHeaderProps {
snippet: Snippet
isCopied: boolean
canPreview: boolean
showPreview: boolean
onCopy: () => void
onEdit: () => void
onTogglePreview: () => void
}
export function SnippetViewerHeader({
snippet,
isCopied,
canPreview,
showPreview,
onCopy,
onEdit,
onTogglePreview,
}: SnippetViewerHeaderProps) {
return (
<div className="flex items-start justify-between gap-4">
<div className="flex-1 min-w-0 space-y-2">
<div className="flex items-center gap-3">
<h2 className="text-2xl font-bold truncate">
{snippet.title}
</h2>
<Badge
variant="outline"
className={cn(
"shrink-0 border font-medium text-xs px-2 py-1",
LANGUAGE_COLORS[snippet.language] || LANGUAGE_COLORS['Other']
)}
>
{snippet.language}
</Badge>
</div>
{snippet.description && (
<p className="text-sm text-muted-foreground">
{snippet.description}
</p>
)}
<p className="text-xs text-muted-foreground">
{strings.snippetViewer.lastUpdated}: {new Date(snippet.updatedAt).toLocaleString()}
</p>
</div>
<div className="flex gap-2 shrink-0">
{canPreview && (
<Button
variant={showPreview ? "default" : "outline"}
size="sm"
onClick={onTogglePreview}
className="gap-2"
>
<SplitVertical className="h-4 w-4" />
{showPreview ? strings.snippetViewer.buttons.hidePreview : strings.snippetViewer.buttons.showPreview}
</Button>
)}
<Button
variant="outline"
size="sm"
onClick={onCopy}
className="gap-2"
>
{isCopied ? (
<>
<Check className="h-4 w-4" weight="bold" />
{strings.snippetViewer.buttons.copied}
</>
) : (
<>
<Copy className="h-4 w-4" />
{strings.snippetViewer.buttons.copy}
</>
)}
</Button>
<Button
variant="outline"
size="sm"
onClick={onEdit}
className="gap-2"
>
<Pencil className="h-4 w-4" />
{strings.snippetViewer.buttons.edit}
</Button>
</div>
</div>
)
}