'use client'; import { useRef, useState } from 'react'; import { useTheme } from 'next-themes'; import CodeMirror from '@uiw/react-codemirror'; import { html } from '@codemirror/lang-html'; import { Expand, Terminal } from 'lucide-react'; import Link from 'next/link'; import { Button } from '@/components/ui/button'; import { ORIGIN_ERROR_PAGE_HTML_MAX_BYTES, previewOriginErrorPageHTML, } from '@/lib/openflare/default-origin-error-page-html'; type HtmlEditorWorkspaceProps = { value: string; onChange: (value: string) => void; toolbarRight?: React.ReactNode; maxBytes?: number; preview?: (html: string) => string; footerHint?: React.ReactNode; showPreviewLink?: boolean; previewTitle?: string; }; /** * 通用 HTML 编辑器工作区:左代码 / 右实时预览横向布局,可拖拽分隔。 */ export function HtmlEditorWorkspace({ value, onChange, toolbarRight, maxBytes = ORIGIN_ERROR_PAGE_HTML_MAX_BYTES, preview = previewOriginErrorPageHTML, footerHint = ( <> {'{{status}}'}→502 · {'{{host}}'}→example.com ), showPreviewLink = true, previewTitle = '源站错误页实时预览', }: HtmlEditorWorkspaceProps) { const containerRef = useRef(null); const [editorWidthPercent, setEditorWidthPercent] = useState(48); const { resolvedTheme } = useTheme(); const cmTheme = resolvedTheme === 'dark' ? 'dark' : 'light'; const previewSrcDoc = preview(value); const htmlBytes = new TextEncoder().encode(value).length; const handleMouseDown = (e: React.MouseEvent) => { e.preventDefault(); const container = containerRef.current; if (!container) return; const rect = container.getBoundingClientRect(); const handleMouseMove = (moveEvent: MouseEvent) => { const x = moveEvent.clientX - rect.left; const pct = (x / rect.width) * 100; if (pct > 25 && pct < 75) { setEditorWidthPercent(pct); } }; const handleMouseUp = () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); }; document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); }; return (
HTML 编辑器 {htmlBytes} / {maxBytes} 字节 {value.trim() === '' ? ' · 空则使用内置默认' : ''}
{toolbarRight}
实时预览
{footerHint ?? null} {showPreviewLink ? ( ) : null}