mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-05-12 08:42:38 +02:00
feat: render html files in knowledge view via sandboxed iframe
This commit is contained in:
parent
eb6a7ac466
commit
9014c79f2c
5 changed files with 481 additions and 0 deletions
|
|
@ -13,6 +13,7 @@ import { ChatInputWithMentions, type StagedAttachment } from './components/chat-
|
|||
import { ChatMessageAttachments } from '@/components/chat-message-attachments'
|
||||
import { GraphView, type GraphEdge, type GraphNode } from '@/components/graph-view';
|
||||
import { BasesView, type BaseConfig, DEFAULT_BASE_CONFIG } from '@/components/bases-view';
|
||||
import { HtmlFileViewer } from '@/components/html-file-viewer';
|
||||
import { useDebounce } from './hooks/use-debounce';
|
||||
import { SidebarContentPanel } from '@/components/sidebar-content';
|
||||
import { SuggestedTopicsView } from '@/components/suggested-topics-view';
|
||||
|
|
@ -1424,6 +1425,11 @@ function App() {
|
|||
}
|
||||
const requestId = (fileLoadRequestIdRef.current += 1)
|
||||
const pathToLoad = selectedPath
|
||||
// For HTML files, clear stale content immediately so the viewer shows
|
||||
// its loading state instead of rendering the previous file's bytes.
|
||||
if (pathToLoad.toLowerCase().endsWith('.html') || pathToLoad.toLowerCase().endsWith('.htm')) {
|
||||
setFileContent('')
|
||||
}
|
||||
let cancelled = false
|
||||
;(async () => {
|
||||
try {
|
||||
|
|
@ -4819,6 +4825,10 @@ function App() {
|
|||
/>
|
||||
)}
|
||||
</div>
|
||||
) : selectedPath?.toLowerCase().endsWith('.html') || selectedPath?.toLowerCase().endsWith('.htm') ? (
|
||||
<div className="flex-1 min-h-0 overflow-hidden">
|
||||
<HtmlFileViewer html={fileContent} path={selectedPath} />
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex-1 overflow-auto p-4">
|
||||
<pre className="text-sm font-mono text-foreground whitespace-pre-wrap">
|
||||
|
|
|
|||
38
apps/x/apps/renderer/src/components/html-file-viewer.tsx
Normal file
38
apps/x/apps/renderer/src/components/html-file-viewer.tsx
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import { Loader2Icon } from 'lucide-react'
|
||||
|
||||
interface HtmlFileViewerProps {
|
||||
html: string
|
||||
path: string
|
||||
}
|
||||
|
||||
export function HtmlFileViewer({ html, path }: HtmlFileViewerProps) {
|
||||
const [iframeLoaded, setIframeLoaded] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
setIframeLoaded(false)
|
||||
}, [path, html])
|
||||
|
||||
const showSpinner = !html || !iframeLoaded
|
||||
|
||||
return (
|
||||
<div className="relative h-full w-full">
|
||||
{html && (
|
||||
<iframe
|
||||
key={path}
|
||||
srcDoc={html}
|
||||
sandbox="allow-scripts"
|
||||
className="h-full w-full border-0 bg-white"
|
||||
title="HTML preview"
|
||||
onLoad={() => setIframeLoaded(true)}
|
||||
/>
|
||||
)}
|
||||
{showSpinner && (
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-center gap-3 bg-background text-muted-foreground">
|
||||
<Loader2Icon className="size-6 animate-spin" />
|
||||
<p className="text-sm">Rendering preview…</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue