Initial commit: 提交控制器版本2核心代码
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
/* ============================================================
|
||||
IO PAGE — Input / Output Selection
|
||||
Design: Reference luxsin_x8_输入输出.jpg
|
||||
- Circular icon buttons in a grid (3 cols)
|
||||
- Active = cyan fill + glow
|
||||
- Inactive = dark gray circle
|
||||
============================================================ */
|
||||
import { useDevice } from "@/contexts/DeviceContext";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ChevronLeft } from "lucide-react";
|
||||
import { useLocation } from "wouter";
|
||||
|
||||
interface IOOption {
|
||||
index: number;
|
||||
label: string;
|
||||
icon: React.ReactNode;
|
||||
}
|
||||
|
||||
const InputIcon = ({ d }: { d: string }) => (
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-7 h-7">
|
||||
<path d={d} />
|
||||
</svg>
|
||||
);
|
||||
|
||||
const INPUT_OPTIONS: IOOption[] = [
|
||||
{
|
||||
index: 0, label: "USB-B",
|
||||
icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-7 h-7"><rect x="8" y="6" width="8" height="12" rx="1.5"/><line x1="10" y1="6" x2="10" y2="4"/><line x1="14" y1="6" x2="14" y2="4"/></svg>
|
||||
},
|
||||
{
|
||||
index: 1, label: "USB-C",
|
||||
icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-7 h-7"><rect x="5" y="9" width="14" height="6" rx="3"/></svg>
|
||||
},
|
||||
{
|
||||
index: 2, label: "同轴",
|
||||
icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-7 h-7"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3" fill="currentColor" stroke="none"/></svg>
|
||||
},
|
||||
{
|
||||
index: 3, label: "光纤",
|
||||
icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-7 h-7"><rect x="7" y="7" width="10" height="10" rx="1"/><line x1="12" y1="3" x2="12" y2="7"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
|
||||
},
|
||||
{
|
||||
index: 4, label: "蓝牙",
|
||||
icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-7 h-7"><polyline points="6.5 6.5 17.5 17.5 12 23 12 1 17.5 6.5 6.5 17.5"/></svg>
|
||||
},
|
||||
{
|
||||
index: 5, label: "IIS",
|
||||
icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-7 h-7"><rect x="3" y="8" width="18" height="10" rx="1.5"/><line x1="7" y1="8" x2="7" y2="18"/><line x1="12" y1="8" x2="12" y2="18"/><line x1="17" y1="8" x2="17" y2="18"/></svg>
|
||||
},
|
||||
];
|
||||
|
||||
const OUTPUT_OPTIONS: IOOption[] = [
|
||||
{
|
||||
index: 0, label: "XLR",
|
||||
icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-7 h-7"><circle cx="12" cy="12" r="8"/><circle cx="9" cy="10" r="1.5" fill="currentColor" stroke="none"/><circle cx="15" cy="10" r="1.5" fill="currentColor" stroke="none"/><circle cx="12" cy="15" r="1.5" fill="currentColor" stroke="none"/></svg>
|
||||
},
|
||||
{
|
||||
index: 1, label: "RCA",
|
||||
icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-7 h-7"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3" fill="currentColor" stroke="none"/></svg>
|
||||
},
|
||||
{
|
||||
index: 2, label: "耳机",
|
||||
icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-7 h-7"><path d="M3 18v-6a9 9 0 0 1 18 0v6"/><path d="M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3z"/><path d="M3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z"/></svg>
|
||||
},
|
||||
{
|
||||
index: 3, label: "XLR/RCA",
|
||||
icon: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" className="w-7 h-7"><circle cx="8" cy="12" r="5"/><circle cx="16" cy="12" r="5"/><circle cx="8" cy="12" r="1.5" fill="currentColor" stroke="none"/><circle cx="16" cy="12" r="1.5" fill="currentColor" stroke="none"/></svg>
|
||||
},
|
||||
];
|
||||
|
||||
function IOCircleButton({
|
||||
option, active, onSelect,
|
||||
}: { option: IOOption; active: boolean; onSelect: () => void }) {
|
||||
return (
|
||||
<button onClick={onSelect} className="flex flex-col items-center gap-2.5">
|
||||
<div
|
||||
className={cn(
|
||||
"w-[68px] h-[68px] rounded-full flex items-center justify-center transition-all duration-200",
|
||||
active
|
||||
? "text-black"
|
||||
: "text-white/55 border border-white/10"
|
||||
)}
|
||||
style={active ? {
|
||||
background: "#00FFF6",
|
||||
boxShadow: "0 0 24px rgba(0,255,246,0.55), 0 0 8px rgba(0,255,246,0.3)",
|
||||
} : {
|
||||
background: "rgba(44,44,46,0.9)",
|
||||
}}
|
||||
>
|
||||
{option.icon}
|
||||
</div>
|
||||
<span className={cn("text-[13px] font-medium", active ? "text-[#00FFF6]" : "text-white/45")}>
|
||||
{option.label}
|
||||
</span>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
export default function IOPage() {
|
||||
const [, setLocation] = useLocation();
|
||||
const { deviceState, setInput, setOutput } = useDevice();
|
||||
|
||||
const currentInput = deviceState?.input ?? 1;
|
||||
const currentOutput = deviceState?.output ?? 2;
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-black">
|
||||
<div className="page-header">
|
||||
<button onClick={() => setLocation("/")} className="mr-4 text-white/60 active:text-white transition-colors">
|
||||
<ChevronLeft size={24} />
|
||||
</button>
|
||||
<h1 className="flex-1 text-center text-[17px] font-semibold text-white">输入输出</h1>
|
||||
<div className="w-8" />
|
||||
</div>
|
||||
|
||||
<div className="px-4 pb-32 pt-4 space-y-6">
|
||||
<div>
|
||||
<p className="text-[22px] font-bold text-white mb-4 px-1">Input</p>
|
||||
<div className="ios-list-group p-5">
|
||||
<div className="grid grid-cols-3 gap-x-2 gap-y-6">
|
||||
{INPUT_OPTIONS.map((opt) => (
|
||||
<IOCircleButton key={opt.index} option={opt} active={currentInput === opt.index}
|
||||
onSelect={() => setInput(opt.index)} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p className="text-[22px] font-bold text-white mb-4 px-1">Output</p>
|
||||
<div className="ios-list-group p-5">
|
||||
<div className="grid grid-cols-3 gap-x-2 gap-y-6">
|
||||
{OUTPUT_OPTIONS.map((opt) => (
|
||||
<IOCircleButton key={opt.index} option={opt} active={currentOutput === opt.index}
|
||||
onSelect={() => setOutput(opt.index)} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user