import { Maximize2, Play } from 'lucide-react'; import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useI18n } from '@/application/i18n/I18nProvider'; import type { Snippet } from '@/domain/models'; import { DEFAULT_SCRIPT_TEMPLATE } from '@/domain/snippetScript.ts'; import { STORAGE_KEY_SCRIPT_EDITOR_HEIGHT } from '@/infrastructure/config/storageKeys.ts'; import { localStorageAdapter } from '@/infrastructure/persistence/localStorageAdapter.ts'; import { ScriptCodeEditor } from './ScriptCodeEditor'; import { ScriptMetaFields } from './ScriptMetaFields'; import { Button } from '@/components/ui/button'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; const DEFAULT_HEIGHT = 200; const MIN_HEIGHT = 120; const MAX_HEIGHT = 480; function clampHeight(height: number): number { return Math.max(MIN_HEIGHT, Math.min(MAX_HEIGHT, height)); } function readStoredHeight(): number { const stored = localStorageAdapter.readNumber(STORAGE_KEY_SCRIPT_EDITOR_HEIGHT); if (stored === null) return DEFAULT_HEIGHT; return clampHeight(stored); } function countLines(content: string): number { if (!content) return 1; let lines = 1; for (let i = 0; i < content.length; i += 1) { if (content.charCodeAt(i) === 10) lines += 1; } return lines; } export interface ScriptEditorPanelProps { snippet: Snippet; onChange: (snippet: Snippet) => void; onRun?: () => void; canRun?: boolean; onExpand?: () => void; } export const ScriptEditorPanel: React.FC = ({ snippet, onChange, onRun, canRun = false, onExpand, }) => { const { t } = useI18n(); const [height, setHeight] = useState(readStoredHeight); const dragRef = useRef<{ startY: number; startHeight: number } | null>(null); const heightRef = useRef(height); heightRef.current = height; const language = 'javascript'; const editorValue = snippet.command || DEFAULT_SCRIPT_TEMPLATE; const lineCount = countLines(editorValue); const handleResizeStart = useCallback((event: React.MouseEvent) => { event.preventDefault(); dragRef.current = { startY: event.clientY, startHeight: heightRef.current }; document.body.style.cursor = 'ns-resize'; document.body.style.userSelect = 'none'; }, []); useEffect(() => { const onMove = (event: MouseEvent) => { if (!dragRef.current) return; const delta = event.clientY - dragRef.current.startY; setHeight(clampHeight(dragRef.current.startHeight + delta)); }; const onUp = () => { if (dragRef.current) { localStorageAdapter.writeNumber(STORAGE_KEY_SCRIPT_EDITOR_HEIGHT, heightRef.current); } dragRef.current = null; document.body.style.cursor = ''; document.body.style.userSelect = ''; }; window.addEventListener('mousemove', onMove); window.addEventListener('mouseup', onUp); return () => { window.removeEventListener('mousemove', onMove); window.removeEventListener('mouseup', onUp); document.body.style.cursor = ''; document.body.style.userSelect = ''; }; }, []); return (

{t('scripts.meta.code')}

{t('scripts.editor.lineCount', { count: lineCount })}
{onRun ? ( {t('scripts.actions.runNowHint')} ) : null} {onExpand ? ( {t('scripts.actions.openEditorHint')} ) : null}
onChange({ ...snippet, command })} language={language} height={height} />
); };