feat: 主布局 + 左侧模式面板

This commit is contained in:
2026-06-17 00:21:19 +08:00
parent 3186502edb
commit 8aacd3bea2
5 changed files with 103 additions and 5 deletions
+51 -5
View File
@@ -1,9 +1,55 @@
export default function App() { import { QrProvider, useQrState } from './store/qrContext';
import ModePanel from './components/ModePanel';
import QrPreview from './components/QrPreview';
import ExportPanel from './components/ExportPanel';
import HistoryList from './components/HistoryList';
function AppLayout() {
return ( return (
<div className="h-screen flex items-center justify-center bg-gray-50 dark:bg-gray-950"> <div className="h-screen flex flex-col bg-gray-50 dark:bg-gray-950">
<h1 className="text-2xl font-bold text-gray-700 dark:text-gray-300"> {/* 顶部标题栏 */}
🀫 QRGen GUI <div className="h-10 flex items-center px-4 bg-white/80 dark:bg-gray-900/80 backdrop-blur-xl border-b border-gray-200 dark:border-gray-800">
</h1> <span className="text-sm font-semibold text-gray-700 dark:text-gray-300">
🀫 QRGen
</span>
</div>
{/* 三栏主体 */}
<div className="flex-1 flex overflow-hidden">
<ModePanel />
<div className="flex-1 flex items-center justify-center p-4">
<QrPreview />
</div>
<div className="w-56 flex flex-col border-l border-gray-200 dark:border-gray-800 p-3 gap-3 bg-white/60 dark:bg-gray-900/60 backdrop-blur-sm">
<ExportPanel />
<div className="flex-1 overflow-hidden">
<HistoryList />
</div>
</div>
</div>
{/* 底部输入区 */}
<div className="h-24 border-t border-gray-200 dark:border-gray-800 bg-white/80 dark:bg-gray-900/80 backdrop-blur-xl p-3">
<BottomInput />
</div>
</div> </div>
); );
} }
function BottomInput() {
const { state } = useQrState();
return (
<div className="flex items-center justify-center h-full text-gray-400 text-sm">
: {state.mode}
</div>
);
}
export default function App() {
return (
<QrProvider>
<AppLayout />
</QrProvider>
);
}
@@ -0,0 +1,8 @@
export default function ExportPanel() {
return (
<div className="flex flex-col gap-2">
<div className="text-xs font-semibold text-gray-400 uppercase tracking-wider"></div>
<div className="text-xs text-gray-400">...</div>
</div>
);
}
@@ -0,0 +1,8 @@
export default function HistoryList() {
return (
<div className="flex flex-col h-full">
<div className="text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2">📋 </div>
<p className="text-xs text-gray-400 text-center py-4"></p>
</div>
);
}
@@ -0,0 +1,27 @@
import { useQrState } from '../store/qrContext';
import { MODES, MODE_LABELS } from '../types';
export default function ModePanel() {
const { state, dispatch } = useQrState();
return (
<div className="w-48 border-r border-gray-200 dark:border-gray-800 p-3 flex flex-col gap-1 bg-white/60 dark:bg-gray-900/60 backdrop-blur-sm">
<div className="text-xs font-semibold text-gray-400 uppercase tracking-wider mb-2 px-2">
</div>
{MODES.map(mode => (
<button
key={mode}
onClick={() => dispatch({ type: 'SET_MODE', payload: mode })}
className={`px-3 py-2 rounded-lg text-left text-sm transition-all ${
state.mode === mode
? 'bg-gradient-to-r from-blue-500 to-cyan-500 text-white shadow-md shadow-blue-500/20'
: 'text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800'
}`}
>
{MODE_LABELS[mode]}
</button>
))}
</div>
);
}
@@ -0,0 +1,9 @@
export default function QrPreview() {
return (
<div className="flex flex-col items-center justify-center gap-3 text-gray-400">
<div className="w-48 h-48 border-2 border-dashed border-gray-300 dark:border-gray-700 rounded-2xl flex items-center justify-center">
<span className="text-sm"> QR </span>
</div>
</div>
);
}