mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-06-30 17:12:58 +08:00
feat(file-viewer): add html preview tab
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { EditorView } from '@codemirror/view';
|
||||
import { unifiedMergeView } from '@codemirror/merge';
|
||||
import type { Extension } from '@codemirror/state';
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { usePaletteOps } from '../../../contexts/PaletteOpsContext';
|
||||
import { useCodeEditorDocument } from '../hooks/useCodeEditorDocument';
|
||||
import { useCodeEditorSettings } from '../hooks/useCodeEditorSettings';
|
||||
@@ -11,6 +12,7 @@ import type { CodeEditorFile } from '../types/types';
|
||||
import { createMinimapExtension, createScrollToFirstChunkExtension, getLanguageExtensions } from '../utils/editorExtensions';
|
||||
import { getEditorStyles } from '../utils/editorStyles';
|
||||
import { createEditorToolbarPanelExtension } from '../utils/editorToolbarPanel';
|
||||
|
||||
import CodeEditorFooter from './subcomponents/CodeEditorFooter';
|
||||
import CodeEditorHeader from './subcomponents/CodeEditorHeader';
|
||||
import CodeEditorLoadingState from './subcomponents/CodeEditorLoadingState';
|
||||
@@ -73,6 +75,29 @@ export default function CodeEditor({
|
||||
return extension === 'md' || extension === 'markdown';
|
||||
}, [file.name]);
|
||||
|
||||
const isHtmlPreviewFile = useMemo(() => {
|
||||
const extension = file.name.split('.').pop()?.toLowerCase();
|
||||
return extension === 'html' || extension === 'htm';
|
||||
}, [file.name]);
|
||||
|
||||
const openHtmlPreview = useCallback(() => {
|
||||
const previewWindow = window.open('', '_blank');
|
||||
if (!previewWindow) return;
|
||||
|
||||
previewWindow.opener = null;
|
||||
previewWindow.document.title = file.name;
|
||||
previewWindow.document.body.style.margin = '0';
|
||||
|
||||
const iframe = previewWindow.document.createElement('iframe');
|
||||
iframe.title = file.name;
|
||||
iframe.sandbox.add('allow-forms', 'allow-modals', 'allow-popups', 'allow-scripts');
|
||||
iframe.style.cssText = 'position:fixed;inset:0;width:100%;height:100%;border:0;background:white';
|
||||
|
||||
iframe.srcdoc = content;
|
||||
|
||||
previewWindow.document.body.appendChild(iframe);
|
||||
}, [content, file.name]);
|
||||
|
||||
const minimapExtension = useMemo(
|
||||
() => (
|
||||
createMinimapExtension({
|
||||
@@ -224,10 +249,12 @@ export default function CodeEditor({
|
||||
isSidebar={isSidebar}
|
||||
isFullscreen={isFullscreen}
|
||||
isMarkdownFile={isMarkdownFile}
|
||||
isHtmlPreviewFile={isHtmlPreviewFile}
|
||||
markdownPreview={markdownPreview}
|
||||
saving={saving}
|
||||
saveSuccess={saveSuccess}
|
||||
onToggleMarkdownPreview={() => setMarkdownPreview((previous) => !previous)}
|
||||
onOpenHtmlPreview={openHtmlPreview}
|
||||
onOpenSettings={() => paletteOps.openSettings('appearance')}
|
||||
onDownload={handleDownload}
|
||||
onSave={handleSave}
|
||||
@@ -237,6 +264,7 @@ export default function CodeEditor({
|
||||
showingChanges: t('header.showingChanges'),
|
||||
editMarkdown: t('actions.editMarkdown'),
|
||||
previewMarkdown: t('actions.previewMarkdown'),
|
||||
previewHtml: t('actions.previewHtml', 'Open HTML preview in new tab'),
|
||||
settings: t('toolbar.settings'),
|
||||
download: t('actions.download'),
|
||||
save: t('actions.save'),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Code2, Download, Eye, Maximize2, Minimize2, Save, Settings as SettingsIcon, X } from 'lucide-react';
|
||||
|
||||
import type { CodeEditorFile } from '../../types/types';
|
||||
|
||||
type CodeEditorHeaderProps = {
|
||||
@@ -6,10 +7,12 @@ type CodeEditorHeaderProps = {
|
||||
isSidebar: boolean;
|
||||
isFullscreen: boolean;
|
||||
isMarkdownFile: boolean;
|
||||
isHtmlPreviewFile: boolean;
|
||||
markdownPreview: boolean;
|
||||
saving: boolean;
|
||||
saveSuccess: boolean;
|
||||
onToggleMarkdownPreview: () => void;
|
||||
onOpenHtmlPreview: () => void;
|
||||
onOpenSettings: () => void;
|
||||
onDownload: () => void;
|
||||
onSave: () => void;
|
||||
@@ -19,6 +22,7 @@ type CodeEditorHeaderProps = {
|
||||
showingChanges: string;
|
||||
editMarkdown: string;
|
||||
previewMarkdown: string;
|
||||
previewHtml: string;
|
||||
settings: string;
|
||||
download: string;
|
||||
save: string;
|
||||
@@ -35,10 +39,12 @@ export default function CodeEditorHeader({
|
||||
isSidebar,
|
||||
isFullscreen,
|
||||
isMarkdownFile,
|
||||
isHtmlPreviewFile,
|
||||
markdownPreview,
|
||||
saving,
|
||||
saveSuccess,
|
||||
onToggleMarkdownPreview,
|
||||
onOpenHtmlPreview,
|
||||
onOpenSettings,
|
||||
onDownload,
|
||||
onSave,
|
||||
@@ -82,6 +88,17 @@ export default function CodeEditorHeader({
|
||||
</button>
|
||||
)}
|
||||
|
||||
{isHtmlPreviewFile && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onOpenHtmlPreview}
|
||||
className="flex items-center justify-center rounded-md p-1.5 text-gray-600 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-white"
|
||||
title={labels.previewHtml}
|
||||
>
|
||||
<Eye className="h-4 w-4" />
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={onOpenSettings}
|
||||
|
||||
Reference in New Issue
Block a user