krz/brand-bench
A dynamic brand documentation generator with Ollama integration.
clone: git clone https://gitbay.org/krz/brand-bench.git
main: src/components/PreviewPanel.tsx · raw
1import type { BrandInputs, BrandOutputs, LockedSections } from '../types';
2import { BrandDoc } from './BrandDoc';
3import { CopyButton } from './CopyButton';
4import { toMarkdown, toJSON, toHTML, downloadFile } from '../lib/export';
5
6interface Props {
7 inputs: BrandInputs;
8 outputs: BrandOutputs | null;
9 locked: LockedSections;
10 onToggleLock: (section: keyof LockedSections) => void;
11 onEdit: <K extends keyof BrandOutputs>(key: K, value: BrandOutputs[K]) => void;
12 isGenerating: boolean;
13 generateMode?: 'template' | string;
14 generateError?: string | null;
15 onGenerate?: () => void;
16}
17
18export function PreviewPanel({ inputs, outputs, locked, onToggleLock, onEdit, isGenerating, generateMode, generateError, onGenerate }: Props) {
19 const handleExportMd = () => {
20 if (!outputs) return;
21 downloadFile(toMarkdown(inputs, outputs), `${inputs.name || 'brand'}-package.md`, 'text/markdown');
22 };
23
24 const handleExportJson = () => {
25 if (!outputs) return;
26 downloadFile(toJSON(inputs, outputs), `${inputs.name || 'brand'}-package.json`, 'application/json');
27 };
28
29 const handleExportHtml = () => {
30 if (!outputs) return;
31 downloadFile(toHTML(inputs, outputs), `${inputs.name || 'brand'}-guidelines.html`, 'text/html');
32 };
33
34 const fullMarkdown = outputs ? toMarkdown(inputs, outputs) : '';
35
36 return (
37 <div className="preview-panel">
38 <div className="preview-toolbar">
39 <div className="preview-toolbar-left">
40 <span className="preview-doc-label">
41 {outputs ? 'Brand Package' : 'Preview'}
42 </span>
43 {outputs && (
44 <span style={{ fontSize: 11, color: 'var(--text-4)' }}>
45 · {new Date().toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}
46 </span>
47 )}
48 </div>
49 {outputs && (
50 <div className="preview-toolbar-right">
51 <CopyButton text={fullMarkdown} label="Copy all" />
52 </div>
53 )}
54 </div>
55
56 {generateError && (
57 <div className="generate-error">
58 <span className="generate-error-icon">⚠</span>
59 <span className="generate-error-msg">{generateError}</span>
60 {onGenerate && (
61 <button className="generate-error-retry btn btn-ghost" onClick={onGenerate}>
62 Try template instead
63 </button>
64 )}
65 </div>
66 )}
67
68 <div className="preview-scroll">
69 {isGenerating ? (
70 <div className="empty-state">
71 <div className="empty-state-title" style={{ color: 'var(--text-3)' }}>
72 {generateMode && generateMode !== 'template'
73 ? `Thinking with ${generateMode}…`
74 : 'Generating…'}
75 </div>
76 {generateMode && generateMode !== 'template' && (
77 <div className="empty-state-sub">This may take 15–60 seconds depending on your hardware</div>
78 )}
79 </div>
80 ) : outputs ? (
81 <BrandDoc
82 inputs={inputs}
83 outputs={outputs}
84 locked={locked}
85 onToggleLock={onToggleLock}
86 onEdit={onEdit}
87 />
88 ) : (
89 <div className="empty-state">
90 <div className="empty-state-title">No package generated yet</div>
91 <div className="empty-state-sub">Fill in the project details and click Generate</div>
92 </div>
93 )}
94 </div>
95
96 {outputs && (
97 <div className="export-bar">
98 <span className="export-bar-left">
99 Export
100 </span>
101 <div className="export-bar-right">
102 <button className="btn" onClick={handleExportMd}>
103 Export Markdown
104 </button>
105 <button className="btn" onClick={handleExportJson}>
106 Export JSON
107 </button>
108 <button className="btn" onClick={handleExportHtml}>
109 Export HTML
110 </button>
111 </div>
112 </div>
113 )}
114 </div>
115 );
116}