feat: add ScriptPreview with live substitution and copy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
chihlasm
2026-03-13 02:09:15 -04:00
parent a88b9c5483
commit 86a9d3b977

View File

@@ -0,0 +1,56 @@
import { useState } from 'react'
import { Copy, Check } from 'lucide-react'
import { useScriptGeneratorStore } from '@/store/scriptGeneratorStore'
import { PowerShellHighlighter } from './PowerShellHighlighter'
import type { ScriptParametersSchema } from '@/types'
export function ScriptPreview() {
const selectedTemplate = useScriptGeneratorStore(s => s.selectedTemplate)
const paramValues = useScriptGeneratorStore(s => s.paramValues)
const generatedScript = useScriptGeneratorStore(s => s.generatedScript)
const [copied, setCopied] = useState(false)
if (!selectedTemplate) return null
// Compute the displayed script
let displayScript: string
if (generatedScript !== null) {
displayScript = generatedScript
} else {
// Draft mode: client-side {{key}} substitution
const schema = selectedTemplate.parameters_schema as ScriptParametersSchema
const parameters = schema?.parameters ?? []
displayScript = selectedTemplate.script_body
for (const param of parameters) {
const placeholder = `{{${param.key}}}`
const replacement = param.sensitive
? '****'
: (paramValues[param.key] ?? '')
displayScript = displayScript.replaceAll(placeholder, replacement || placeholder)
}
}
const handleCopy = async () => {
try {
await navigator.clipboard.writeText(displayScript)
setCopied(true)
setTimeout(() => setCopied(false), 2000)
} catch {
// silently fail — no error displayed
}
}
return (
<div className="relative">
<button
onClick={handleCopy}
className="absolute top-3 right-3 z-10 p-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-white/5 transition-colors"
title={copied ? 'Copied!' : 'Copy to clipboard'}
aria-label={copied ? 'Copied!' : 'Copy to clipboard'}
>
{copied ? <Check size={14} className="text-emerald-400" /> : <Copy size={14} />}
</button>
<PowerShellHighlighter script={displayScript} />
</div>
)
}