diff --git a/src/app/App.tsx b/src/app/App.tsx index b1a389e..550b6bd 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -6,6 +6,7 @@ import { CaptureDialog } from "./CaptureDialog"; import { Diagnostics, LogitechDetails } from "./Diagnostics"; import { InterfaceSettings } from "./InterfaceSettings"; import { PendingBar } from "./PendingBar"; +import { KeychronNapeLayers } from "./KeychronNapeLayers"; import { Profiles } from "./Profiles"; import { Sidebar } from "./Sidebar"; import { Superstrike } from "./Superstrike"; @@ -155,6 +156,7 @@ function Workspace({ ].filter((node) => node !== null); const showProfiles = show(has.profiles, ["profiles"]); + const showNapeLayers = show(has.keychronNapeLayers, ["profiles"]); const showSuperstrike = show(has.superstrike, ["buttons"]); const showLogitechDetails = show(has.logitechDetails, ["advanced"]); const showMxMaster = on(tab, ["advanced"]) @@ -163,7 +165,8 @@ function Workspace({ const showOverview = on(tab, ["overview"]); const anyPanel = performance.length > 0 || advanced.length > 0 || lighting.length > 0 - || showProfiles || showSuperstrike || showLogitechDetails || showMxMaster || showDiagnostics || showOverview; + || showProfiles || showNapeLayers || showSuperstrike || showLogitechDetails || showMxMaster + || showDiagnostics || showOverview; const slotsAvailable = snapshot.profile.slotsAvailable; const stagesAvailable = Boolean(status.ui?.dpiStageEditor) @@ -188,6 +191,7 @@ function Workspace({ ) : null} {showProfiles ? : null} + {showNapeLayers ? : null} {performance.length > 0 ? (
({ + display: "flex", + gap: ".55rem", + alignItems: "center", + padding: ".45rem .6rem", + border: `1px solid ${open ? "#4a4a52" : "#26262a"}`, + borderRadius: "7px", + background: open ? "#1b1b1f" : "#141416", +}); + +const OPEN_BUTTON_STYLE: CSSProperties = { + display: "flex", + gap: ".55rem", + alignItems: "center", + flex: 1, + minWidth: 0, + textAlign: "left", + background: "none", + border: 0, + padding: 0, + cursor: "pointer", +}; + +const ICON_BUTTON_STYLE = (disabled: boolean, active = false): CSSProperties => ({ + display: "flex", + padding: ".3rem", + border: `1px solid ${active ? "#4a4a52" : "#3a3a3f"}`, + borderRadius: "5px", + background: "#19191c", + cursor: disabled ? "not-allowed" : "pointer", + opacity: disabled ? 0.4 : 1, +}); + +const KEY_ROWS = [ + { col: 2, number: "1", name: "01" }, + { col: 3, number: "2", name: "02" }, + { col: 0, number: "3", name: "03" }, + { col: 1, number: "4", name: "04" }, + { col: 4, number: "5", name: "M1" }, + { col: 5, number: "6", name: "M2" }, +] as const; + +function pendingKey(layer: number, target: NapeAssignmentControl): string { + if (target.kind === "orientation") return `nape-${layer}-orientation`; + return target.kind === "key" + ? `nape-${layer}-col-${target.col}` + : `nape-${layer}-wheel-${target.clockwise ? "cw" : "ccw"}`; +} + +function stagedFor( + staged: readonly StagedNapeAssignment[], + layer: number, + target: NapeAssignmentControl, +): StagedNapeAssignment | undefined { + return staged.find((entry) => { + if (entry.layer !== layer) return false; + if (entry.control.kind === "orientation" && target.kind === "orientation") return true; + if (entry.control.kind === "key" && target.kind === "key") return entry.control.col === target.col; + if (entry.control.kind === "wheel" && target.kind === "wheel") { + return entry.control.clockwise === target.clockwise; + } + return false; + }); +} + +function AssignmentSelect({ + layer, + target, + action, + keycode, + staged, + disabled, +}: { + layer: number; + target: NapeAssignmentControl; + action: string; + keycode: number; + staged: StagedNapeAssignment | undefined; + disabled: boolean; +}): ReactNode { + const value = staged?.action ?? action; + return ( + + +