diff --git a/apps/admin/app/dashboard/system/tos.tsx b/apps/admin/app/dashboard/system/tos.tsx index 7d0fb42..a15b90b 100644 --- a/apps/admin/app/dashboard/system/tos.tsx +++ b/apps/admin/app/dashboard/system/tos.tsx @@ -5,11 +5,9 @@ import { MarkdownEditor } from '@repo/ui/editor'; import { toast } from '@shadcn/ui/lib/sonner'; import { useQuery } from '@tanstack/react-query'; import { useTranslations } from 'next-intl'; -import { useTheme } from 'next-themes'; export default function Tos() { const t = useTranslations('system.tos'); - const { resolvedTheme } = useTheme(); const { data, refetch, isFetched } = useQuery({ queryKey: ['getTosConfig'], queryFn: async () => { diff --git a/packages/ui/src/editor/json.tsx b/packages/ui/src/editor/json.tsx index ad703d8..279f10e 100644 --- a/packages/ui/src/editor/json.tsx +++ b/packages/ui/src/editor/json.tsx @@ -34,7 +34,7 @@ export function JSONEditor(props: JSONEditorProps) { props.value && typeof props.value === 'string' ? value : JSON.parse(value), ); } catch (e) { - console.error('Invalid JSON input:', e); + console.log('Invalid JSON input:', e); } } }} diff --git a/packages/ui/src/editor/monaco-editor.tsx b/packages/ui/src/editor/monaco-editor.tsx index 8706562..9774def 100644 --- a/packages/ui/src/editor/monaco-editor.tsx +++ b/packages/ui/src/editor/monaco-editor.tsx @@ -1,12 +1,11 @@ -'use client'; - import { type OnMount } from '@monaco-editor/react'; import { Button } from '@shadcn/ui/button'; import { cn } from '@shadcn/ui/lib/utils'; import { useSize } from 'ahooks'; import { EyeIcon, EyeOff, FullscreenIcon, MinimizeIcon } from 'lucide-react'; import dynamic from 'next/dynamic'; -import { useRef, useState } from 'react'; +import { useEffect, useRef, useState } from 'react'; + const Editor = dynamic(() => import('@monaco-editor/react'), { ssr: false }); export interface MonacoEditorProps { @@ -22,8 +21,16 @@ export interface MonacoEditorProps { className?: string; } +function debounce void>(func: T, delay: number) { + let timeoutId: ReturnType; + return function (...args: Parameters) { + clearTimeout(timeoutId); + timeoutId = setTimeout(() => func(...args), delay); + }; +} + export function MonacoEditor({ - value, + value: propValue, onChange, onBlur, title = 'Editor Title', @@ -34,22 +41,44 @@ export function MonacoEditor({ language = 'markdown', className, }: MonacoEditorProps) { + const [internalValue, setInternalValue] = useState(propValue); const [isFullscreen, setIsFullscreen] = useState(false); const [isPreviewVisible, setIsPreviewVisible] = useState(false); - const toggleFullscreen = () => setIsFullscreen(!isFullscreen); - const togglePreview = () => setIsPreviewVisible(!isPreviewVisible); + const ref = useRef(null); + const size = useSize(ref); + + useEffect(() => { + setInternalValue(propValue); + }, [propValue]); + + const debouncedOnChange = useRef( + debounce((newValue: string | undefined) => { + if (onChange) { + onChange(newValue); + } + }, 300), + ).current; const handleEditorDidMount: OnMount = (editor, monaco) => { if (onMount) onMount(editor, monaco); + + editor.onDidChangeModelContent(() => { + const newValue = editor.getValue(); + setInternalValue(newValue); + debouncedOnChange(newValue); + }); + editor.onDidBlurEditorWidget(() => { if (onBlur) { onBlur(editor.getValue()); } }); }; - const ref = useRef(null); - const size = useSize(ref); + + const toggleFullscreen = () => setIsFullscreen(!isFullscreen); + const togglePreview = () => setIsPreviewVisible(!isPreviewVisible); + return (
@@ -86,8 +115,11 @@ export function MonacoEditor({ > { + setInternalValue(newValue); + debouncedOnChange(newValue); + }} onMount={handleEditorDidMount} className='' options={{ @@ -122,7 +154,7 @@ export function MonacoEditor({ }); }} /> - {!value && placeholder && ( + {!internalValue?.trim() && placeholder && (
             {render && isPreviewVisible && (
-              
{render(value)}
+
{render(internalValue)}
)}