diff --git a/src/features/command-palette/constants/markdown-actions.tsx b/src/features/command-palette/constants/markdown-actions.tsx index 03593299..85ba7194 100644 --- a/src/features/command-palette/constants/markdown-actions.tsx +++ b/src/features/command-palette/constants/markdown-actions.tsx @@ -15,6 +15,7 @@ interface MarkdownActionsParams { isVirtual?: boolean, diffData?: any, isMarkdownPreview?: boolean, + isHtmlPreview?: boolean, sourceFilePath?: string, ) => string; onClose: () => void; @@ -50,6 +51,7 @@ export const createMarkdownActions = (params: MarkdownActionsParams): Action[] = true, // isVirtual undefined, // diffData true, // isMarkdownPreview + false, // isHtmlPreview activeBuffer.path, // sourceFilePath ); onClose(); diff --git a/src/features/editor/components/code-editor.tsx b/src/features/editor/components/code-editor.tsx index f3766e19..d4937d05 100644 --- a/src/features/editor/components/code-editor.tsx +++ b/src/features/editor/components/code-editor.tsx @@ -15,6 +15,7 @@ import { HoverTooltip } from "../lsp/hover-tooltip"; import { MarkdownPreview } from "../markdown/markdown-preview"; import { ScrollDebugOverlay } from "./debug/scroll-debug-overlay"; import { Editor } from "./editor"; +import { HtmlPreview } from "./html/html-preview"; import { EditorStylesheet } from "./stylesheet"; import Breadcrumb from "./toolbar/breadcrumb"; import FindBar from "./toolbar/find-bar"; @@ -58,6 +59,7 @@ const CodeEditor = ({ className }: CodeEditorProps) => { const onChange = activeBuffer ? handleContentChange : () => {}; const showMarkdownPreview = activeBuffer?.isMarkdownPreview || false; + const showHtmlPreview = activeBuffer?.isHtmlPreview || false; // Initialize refs in store useEffect(() => { @@ -279,6 +281,8 @@ const CodeEditor = ({ className }: CodeEditorProps) => {
{showMarkdownPreview ? ( + ) : showHtmlPreview ? ( + ) : ( b.id === activeBufferId); + + // If this is a preview buffer, find the source buffer + const sourceBuffer = activeBuffer?.sourceFilePath + ? buffers.find((b) => b.path === activeBuffer.sourceFilePath) + : activeBuffer; + + const [iframeContent, setIframeContent] = useState(""); + const containerRef = useRef(null); + + // Memoize the asset URL for the directory + const assetBaseUrl = useMemo(() => { + if (!sourceBuffer?.path) return ""; + + // Get directory path + const lastSlashIndex = sourceBuffer.path.lastIndexOf("/"); + const dirPath = + lastSlashIndex !== -1 ? sourceBuffer.path.substring(0, lastSlashIndex) : sourceBuffer.path; + + // Convert to Tauri asset URL + // convertFileSrc handles the protocol logic (e.g. asset:// or http://asset.localhost) + const url = convertFileSrc(dirPath); + + // Ensure it ends with slash for correct base resolution + return url.endsWith("/") ? url : `${url}/`; + }, [sourceBuffer?.path]); + + useEffect(() => { + if (!sourceBuffer) return; + + let content = sourceBuffer.content; + + // Inject tag to allow relative links (CSS/JS/Images) to work + if (assetBaseUrl) { + const baseTag = ``; + + // Try to inject in head + if (content.includes("")) { + content = content.replace("", `\n${baseTag}`); + } else if (content.includes("")) { + content = content.replace("", `\n${baseTag}`); + } else { + // No head/html tags, just prepend + content = `${baseTag}\n${content}`; + } + } + + // Add script to handle errors and console logs if needed in future + // For now keeping it simple with just content rendering + setIframeContent(content); + }, [sourceBuffer?.content, assetBaseUrl]); + + if (!sourceBuffer) { + return ( +
+ No active buffer +
+ ); + } + + return ( +
+