goldenChat base source add
This commit is contained in:
@@ -0,0 +1,228 @@
|
||||
import React, { useState } from 'react';
|
||||
import type { Drawing, DrawingStyle } from '../types';
|
||||
import { useDraggablePanel } from '../hooks/useDraggablePanel';
|
||||
|
||||
const PRESET_COLORS = [
|
||||
'#FF6D00','#FF5722','#EF5350','#E91E63','#9C27B0',
|
||||
'#673AB7','#3F51B5','#2196F3','#03A9F4','#00BCD4',
|
||||
'#009688','#4CAF50','#8BC34A','#CDDC39','#FFC107',
|
||||
'#FF9800','#795548','#9E9E9E','#607D8B','#FFFFFF',
|
||||
];
|
||||
|
||||
const LINE_WIDTHS = [1, 2, 3, 4] as const;
|
||||
const LINE_STYLES: { value: DrawingStyle; label: string }[] = [
|
||||
{ value: 'solid', label: '실선' },
|
||||
{ value: 'dashed', label: '파선' },
|
||||
{ value: 'dotted', label: '점선' },
|
||||
];
|
||||
|
||||
interface Props {
|
||||
drawing: Drawing;
|
||||
onSave: (updated: Drawing) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
const DrawingSettingsModal: React.FC<Props> = ({ drawing, onSave, onCancel }) => {
|
||||
const [color, setColor] = useState(drawing.color);
|
||||
const [lineWidth, setLineWidth] = useState(drawing.lineWidth);
|
||||
const [style, setStyle] = useState<DrawingStyle>(drawing.style);
|
||||
const [text, setText] = useState(drawing.text ?? '');
|
||||
|
||||
const handleSave = () => {
|
||||
onSave({
|
||||
...drawing,
|
||||
color,
|
||||
lineWidth,
|
||||
style,
|
||||
...(drawing.type === 'text' ? { text: text.trim() || drawing.text } : {}),
|
||||
});
|
||||
};
|
||||
|
||||
const {
|
||||
panelRef,
|
||||
dragging,
|
||||
onHeaderPointerDown, headerTouchStyle,
|
||||
panelStyle,
|
||||
headerCursor,
|
||||
} = useDraggablePanel({ centerOnMount: true });
|
||||
|
||||
return (
|
||||
<div
|
||||
className="dsm-overlay"
|
||||
style={{ zIndex: 1200 }}
|
||||
onMouseDown={e => { if (e.target === e.currentTarget) onCancel(); }}
|
||||
>
|
||||
<div
|
||||
ref={panelRef}
|
||||
className="dsm-dialog"
|
||||
style={{
|
||||
...panelStyle,
|
||||
minWidth: 300,
|
||||
cursor: dragging ? 'grabbing' : undefined,
|
||||
}}
|
||||
onMouseDown={e => e.stopPropagation()}
|
||||
>
|
||||
<div
|
||||
className="gc-popup-header"
|
||||
onPointerDown={onHeaderPointerDown}
|
||||
style={{ cursor: headerCursor, ...headerTouchStyle }}
|
||||
>
|
||||
<span className="gc-popup-title">드로잉 설정</span>
|
||||
<button type="button" className="gc-popup-close" onClick={onCancel} aria-label="닫기">✕</button>
|
||||
</div>
|
||||
<div className="dsm-body">
|
||||
|
||||
{/* 색상 */}
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ fontSize: 11, color: 'var(--text-muted, #6e7191)', marginBottom: 8 }}>색상</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
|
||||
{PRESET_COLORS.map(c => (
|
||||
<button
|
||||
key={c}
|
||||
onClick={() => setColor(c)}
|
||||
style={{
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: '50%',
|
||||
background: c,
|
||||
border: color === c ? '2px solid #fff' : '2px solid transparent',
|
||||
cursor: 'pointer',
|
||||
padding: 0,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{/* 커스텀 컬러 피커 */}
|
||||
<input
|
||||
type="color"
|
||||
value={color}
|
||||
onChange={e => setColor(e.target.value)}
|
||||
title="커스텀 색상"
|
||||
style={{
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: '50%',
|
||||
border: 'none',
|
||||
padding: 0,
|
||||
cursor: 'pointer',
|
||||
background: 'none',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 선 굵기 (pencil·text·measure 제외) */}
|
||||
{drawing.type !== 'text' && drawing.type !== 'measure' && (
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ fontSize: 11, color: 'var(--text-muted, #6e7191)', marginBottom: 8 }}>선 굵기</div>
|
||||
<div style={{ display: 'flex', gap: 6 }}>
|
||||
{LINE_WIDTHS.map(w => (
|
||||
<button
|
||||
key={w}
|
||||
onClick={() => setLineWidth(w)}
|
||||
style={{
|
||||
width: 34,
|
||||
height: 28,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
background: lineWidth === w ? 'var(--accent-bg, rgba(122,162,247,0.15))' : 'transparent',
|
||||
border: lineWidth === w ? '1px solid var(--accent, #7aa2f7)' : '1px solid var(--border, rgba(122,162,247,0.2))',
|
||||
borderRadius: 4,
|
||||
cursor: 'pointer',
|
||||
color: 'inherit',
|
||||
}}
|
||||
>
|
||||
<div style={{ width: 20, height: w, background: 'currentColor', borderRadius: 1 }} />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 선 스타일 (hline, vline, trendline, ray, channel 계열) */}
|
||||
{!['text', 'measure', 'pencil', 'fib', 'rect'].includes(drawing.type) && (
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ fontSize: 11, color: 'var(--text-muted, #6e7191)', marginBottom: 8 }}>선 스타일</div>
|
||||
<div style={{ display: 'flex', gap: 6 }}>
|
||||
{LINE_STYLES.map(({ value, label }) => (
|
||||
<button
|
||||
key={value}
|
||||
onClick={() => setStyle(value)}
|
||||
style={{
|
||||
flex: 1,
|
||||
height: 28,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
background: style === value ? 'var(--accent-bg, rgba(122,162,247,0.15))' : 'transparent',
|
||||
border: style === value ? '1px solid var(--accent, #7aa2f7)' : '1px solid var(--border, rgba(122,162,247,0.2))',
|
||||
borderRadius: 4,
|
||||
cursor: 'pointer',
|
||||
color: 'inherit',
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 텍스트 (text 타입만) */}
|
||||
{drawing.type === 'text' && (
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ fontSize: 11, color: 'var(--text-muted, #6e7191)', marginBottom: 8 }}>텍스트</div>
|
||||
<input
|
||||
value={text}
|
||||
onChange={e => setText(e.target.value)}
|
||||
style={{
|
||||
width: '100%',
|
||||
boxSizing: 'border-box',
|
||||
background: 'rgba(255,255,255,0.05)',
|
||||
border: '1px solid var(--border, rgba(122,162,247,0.25))',
|
||||
borderRadius: 4,
|
||||
padding: '6px 8px',
|
||||
color: 'inherit',
|
||||
fontSize: 13,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 버튼 */}
|
||||
<div className="dsm-footer">
|
||||
<button
|
||||
onClick={onCancel}
|
||||
style={{
|
||||
padding: '6px 16px',
|
||||
background: 'transparent',
|
||||
border: '1px solid var(--border, rgba(122,162,247,0.25))',
|
||||
borderRadius: 5,
|
||||
cursor: 'pointer',
|
||||
color: 'inherit',
|
||||
fontSize: 13,
|
||||
}}
|
||||
>취소</button>
|
||||
<button
|
||||
onClick={handleSave}
|
||||
style={{
|
||||
padding: '6px 16px',
|
||||
background: 'var(--accent, #7aa2f7)',
|
||||
border: 'none',
|
||||
borderRadius: 5,
|
||||
cursor: 'pointer',
|
||||
color: '#1a1b26',
|
||||
fontWeight: 600,
|
||||
fontSize: 13,
|
||||
}}
|
||||
>확인</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DrawingSettingsModal;
|
||||
Reference in New Issue
Block a user