Files
hohoff/demo/main.tsx
2026-03-03 20:46:23 +10:00

124 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { StrictMode, useState } from 'react'
import { createRoot } from 'react-dom/client'
import { useEditorStore } from '@renderer/store/editorStore'
import { MarkdownEditor } from '@renderer/components/Editor/MarkdownEditor'
import { ChatPanel } from '@renderer/components/AIChat/ChatPanel'
import { RevisionPanel } from '@renderer/components/Revisions/RevisionPanel'
import '@renderer/styles/global.css'
import '@renderer/styles/app.css'
// Mock window.api so the renderer doesn't crash in a plain browser context
;(window as unknown as Record<string, unknown>).api = {
listFiles: () => Promise.resolve([]),
readFile: () => Promise.resolve(''),
writeFile: () => Promise.resolve(),
streamAIMessage: () => Promise.resolve(),
removeAIListener: () => {},
getProjectWordCount: () => Promise.resolve(0),
saveOrder: () => Promise.resolve(),
pickAttachments: () => Promise.resolve([]),
saveRevision: () => Promise.resolve(),
listRevisions: () => Promise.resolve([]),
loadRevision: () => Promise.resolve(''),
deleteRevision: () => Promise.resolve(),
renameNode: () => Promise.resolve(''),
deleteNode: () => Promise.resolve(),
createFile: () => Promise.resolve(''),
createDir: () => Promise.resolve(''),
moveFile: () => Promise.resolve(''),
openStoryBible: () => Promise.resolve({ path: '', content: '' }),
writeStoryBible: () => Promise.resolve(''),
readSession: () => Promise.resolve({}),
writeSession: () => Promise.resolve(),
onMenuAction: () => () => {}
}
const DEMO_TEXT =
`She was seen by him walking down the cobblestone path.\n\n` +
`The old manuscript was written by an unknown author many centuries ago.\n\n` +
`The message had been delivered by the courier at dawn.`
// Compute annotation character ranges directly from the text
const a1s = DEMO_TEXT.indexOf('She was seen')
const a1e = DEMO_TEXT.indexOf('.', a1s) + 1
const a2s = DEMO_TEXT.indexOf('The old manuscript')
const a2e = DEMO_TEXT.indexOf('.', a2s) + 1
const a3s = DEMO_TEXT.indexOf('The message')
const a3e = DEMO_TEXT.indexOf('.', a3s) + 1
// Pre-seed store before React renders so all three effects fire correctly on mount
const store = useEditorStore.getState()
store.setActiveFile('demo.md', DEMO_TEXT)
store.setAnnotations([
{
id: 'ann-1',
type: 'passive_voice',
from: a1s,
to: a1e,
matchedText: 'was seen by',
message: 'Passive voice weakens the narrative tension here — placing the subject in an active role would make the sentence more immediate and visceral, which is essential for gothic prose where atmosphere must feel alive and urgent\u2026',
suggestion: 'He saw her walking down the cobblestone path.'
},
{
id: 'ann-2',
type: 'passive_voice',
from: a2s,
to: a2e,
matchedText: 'was written by',
message: 'Passive construction distances the reader from the action; consider foregrounding the actor to strengthen the historical atmosphere.',
suggestion: 'An unknown author wrote the old manuscript many centuries ago.'
},
{
id: 'ann-3',
type: 'style',
from: a3s,
to: a3e,
matchedText: 'had been delivered by',
message: 'Wordy passive construction: "had been delivered by"',
suggestion: 'The courier delivered the message at dawn.'
}
])
function DemoApp(): JSX.Element {
const { revisionPanelOpen, toggleRevisionPanel } = useEditorStore()
return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%', background: 'var(--bg-base)' }}>
{/* Titlebar same markup as App.tsx */}
<div className="app-titlebar">
<span className="app-titlebar-title">Hohoff Editor</span>
<div className="app-titlebar-right">
<div className="app-layout-toggle">
<button className="app-layout-toggle-seg active" />
<div className="app-layout-toggle-seg app-layout-toggle-seg--mid" />
<button className="app-layout-toggle-seg active" />
</div>
<div className="app-titlebar-icon-group">
<button
className={`app-titlebar-theme-btn app-titlebar-revision-btn${revisionPanelOpen ? ' active' : ''}`}
onClick={toggleRevisionPanel}
title="Revision history"
></button>
<button className="app-titlebar-theme-btn" title="Toggle theme"></button>
</div>
</div>
</div>
{/* Editor content below */}
<div style={{ flex: 1, display: 'flex', minHeight: 0 }}>
<div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', position: 'relative' }}>
<MarkdownEditor />
{revisionPanelOpen && <RevisionPanel />}
</div>
<div style={{ width: '300px', flexShrink: 0 }}>
<ChatPanel />
</div>
</div>
</div>
)
}
createRoot(document.getElementById('root')!).render(
<StrictMode>
<DemoApp />
</StrictMode>
)