Files
bim_engine/demo-next/components/ControlPanel.tsx
2026-04-21 15:07:49 +08:00

225 lines
6.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import { useState } from 'react';
interface ControlPanelProps {
engineStatus: string;
isLoading: boolean;
onInitEngine: () => void;
onLoadModel: (url?: string) => void;
onSetLang: (lang: 'zh-CN' | 'en-US') => void;
onSetTheme: (theme: 'dark' | 'light') => void;
onSetCustomTheme: () => void;
onOpenTestDialog: () => void;
onOpenInfoDialog: () => void;
onOpenTreeDialog: () => void;
onToggleToolbar: (visible: boolean) => void;
onToggleLabel: (visible: boolean) => void;
onPauseRendering: () => void;
onResumeRendering: () => void;
}
export default function ControlPanel({
engineStatus,
onInitEngine,
onLoadModel,
onSetLang,
onSetTheme,
onSetCustomTheme,
onOpenTestDialog,
onOpenInfoDialog,
onOpenTreeDialog,
onToggleToolbar,
onToggleLabel,
onPauseRendering,
onResumeRendering
}: ControlPanelProps) {
const [modelUrl, setModelUrl] = useState('');
const [isToolbarVisible, setIsToolbarVisible] = useState(true);
const [isLabelVisible, setIsLabelVisible] = useState(true);
const handleToggleToolbar = () => {
const newVisible = !isToolbarVisible;
setIsToolbarVisible(newVisible);
onToggleToolbar(newVisible);
};
const handleToggleLabel = () => {
const newVisible = !isLabelVisible;
setIsLabelVisible(newVisible);
onToggleLabel(newVisible);
};
const handleLoadModel = () => {
const url = modelUrl.trim();
onLoadModel(url || undefined);
};
const getStatusColor = () => {
switch (engineStatus) {
case '已初始化':
return '#28a745';
case '初始化失败':
case '初始化错误':
case 'SDK 未加载':
return '#dc3545';
default:
return '#666';
}
};
return (
<aside
style={{
width: '320px',
background: '#fff',
borderRight: '1px solid #e0e0e0',
padding: '20px',
overflowY: 'auto',
display: 'flex',
flexDirection: 'column',
gap: '20px',
boxShadow: '2px 0 5px rgba(0, 0, 0, 0.05)',
zIndex: 10
}}
>
<h1 style={{ fontSize: '1.4rem', color: '#333', marginBottom: '10px' }}>
iFlow Engine Demo
</h1>
<p style={{ fontSize: '0.85rem', color: '#666', marginBottom: '10px' }}>
Next.js + React
</p>
<ControlGroup title="🌍 语言 (Language)">
<ButtonGroup>
<button className="btn-primary" onClick={() => onSetLang('zh-CN')}></button>
<button className="btn-primary" onClick={() => onSetLang('en-US')}>English</button>
</ButtonGroup>
</ControlGroup>
<ControlGroup title="🪟 弹窗 (Dialog)">
<ButtonGroup>
<button onClick={onOpenTestDialog}></button>
<button onClick={onOpenInfoDialog}></button>
<button onClick={onOpenTreeDialog}></button>
</ButtonGroup>
</ControlGroup>
<ControlGroup title="🛠️ 工具栏 (Toolbar)">
<ButtonGroup>
<button onClick={handleToggleToolbar}>
{isToolbarVisible ? '隐藏工具栏' : '显示工具栏'}
</button>
<button onClick={handleToggleLabel}>
{isLabelVisible ? '隐藏标签' : '显示标签'}
</button>
</ButtonGroup>
</ControlGroup>
<ControlGroup title="🎨 样式 (Theme)">
<ButtonGroup>
<button onClick={() => onSetTheme('dark')}></button>
<button onClick={() => onSetTheme('light')}></button>
<button onClick={onSetCustomTheme}></button>
</ButtonGroup>
</ControlGroup>
<ControlGroup title="🎮 3D 引擎 (Engine)">
<ButtonGroup>
<button className="btn-primary" onClick={onInitEngine}></button>
<button className="btn-primary" onClick={handleLoadModel}></button>
</ButtonGroup>
<input
type="text"
value={modelUrl}
onChange={(e) => setModelUrl(e.target.value)}
placeholder="输入模型 URL可选"
style={{
width: '100%',
padding: '6px 8px',
fontSize: '0.85rem',
border: '1px solid #ddd',
borderRadius: '4px',
fontFamily: 'Consolas, Monaco, monospace',
outline: 'none',
marginTop: '8px'
}}
/>
<ButtonGroup style={{ marginTop: '8px' }}>
<button onClick={onPauseRendering}></button>
<button onClick={onResumeRendering}></button>
</ButtonGroup>
<div style={{ marginTop: '10px', fontSize: '0.85rem', color: '#666' }}>
: <span style={{ color: getStatusColor() }}>{engineStatus}</span>
</div>
</ControlGroup>
<style jsx>{`
button {
padding: 6px 12px;
font-size: 0.9rem;
border: 1px solid #ddd;
background: #fff;
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
flex: 1 1 auto;
}
button:hover {
background: #f0f0f0;
border-color: #ccc;
}
.btn-primary {
background: #0078d4;
color: white;
border-color: #0063b1;
}
.btn-primary:hover {
background: #0063b1;
}
`}</style>
</aside>
);
}
function ControlGroup({ title, children }: { title: string; children: React.ReactNode }) {
return (
<div
style={{
background: '#f9f9f9',
padding: '15px',
borderRadius: '8px',
border: '1px solid #eee'
}}
>
<h2
style={{
fontSize: '1rem',
color: '#555',
marginBottom: '10px',
paddingBottom: '5px',
borderBottom: '2px solid #e0e0e0'
}}
>
{title}
</h2>
{children}
</div>
);
}
function ButtonGroup({ children, style }: { children: React.ReactNode; style?: React.CSSProperties }) {
return (
<div
style={{
display: 'flex',
flexWrap: 'wrap',
gap: '8px',
...style
}}
>
{children}
</div>
);
}