From 060258ea2dd347d6518268afee7cff4b554db766 Mon Sep 17 00:00:00 2001 From: yangy Date: Tue, 21 Apr 2026 15:29:29 +0800 Subject: [PATCH] Enhance Vite configuration with custom input for rollup, update ConnectScreen to validate IP input before connection, and modify DeviceContext to support dynamic IP handling in LuxsinAPI. Adjust VUPage to use BASE_URL for image previews. --- client/i.html | 12 ++++++++++++ client/src/components/ConnectScreen.tsx | 6 ++++-- client/src/contexts/DeviceContext.tsx | 7 ++++--- client/src/lib/luxsinApi.ts | 15 ++++++++++++++- client/src/pages/VUPage.tsx | 2 +- vite.config.ts | 3 +++ 6 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 client/i.html diff --git a/client/i.html b/client/i.html new file mode 100644 index 0000000..ed884c3 --- /dev/null +++ b/client/i.html @@ -0,0 +1,12 @@ + + + + + + Luxsin X8 Controller + + +
+ + + diff --git a/client/src/components/ConnectScreen.tsx b/client/src/components/ConnectScreen.tsx index 5e855d4..0324cd0 100644 --- a/client/src/components/ConnectScreen.tsx +++ b/client/src/components/ConnectScreen.tsx @@ -11,9 +11,11 @@ export default function ConnectScreen() { const [inputIp, setInputIp] = useState(ip); const handleConnect = async () => { - setIp(inputIp); + const targetIp = inputIp.trim(); + if (!targetIp) return; + setIp(targetIp); setDemoMode(false); - await connect(); + await connect(false, targetIp); }; const handleDemo = async () => { diff --git a/client/src/contexts/DeviceContext.tsx b/client/src/contexts/DeviceContext.tsx index f8eac7d..d6ae6c7 100644 --- a/client/src/contexts/DeviceContext.tsx +++ b/client/src/contexts/DeviceContext.tsx @@ -20,7 +20,7 @@ interface DeviceContextType { peqState: PeqState | null; lastUpdated: Date | null; error: string | null; - connect: (forceDemo?: boolean) => Promise; + connect: (forceDemo?: boolean, connectIp?: string) => Promise; disconnect: () => void; refresh: () => Promise; api: LuxsinAPI | null; @@ -62,8 +62,9 @@ export function DeviceProvider({ children }: { children: React.ReactNode }) { lastMsgCountRef.current = state.msgCount; }, []); - const connect = useCallback(async (forceDemo?: boolean) => { + const connect = useCallback(async (forceDemo?: boolean, connectIp?: string) => { const useDemo = forceDemo !== undefined ? forceDemo : isDemoMode; + const targetIp = (connectIp ?? ip).trim(); // Demo mode — use mock data immediately, no network call if (useDemo) { setIsConnecting(true); @@ -80,7 +81,7 @@ export function DeviceProvider({ children }: { children: React.ReactNode }) { setIsConnecting(true); setError(null); try { - const newApi = new LuxsinAPI(ip); + const newApi = new LuxsinAPI(targetIp); // Fetch device info from http://{ip}/dev/info.cgi?action=syncData // The response is encoded with custom base64, needs decoding const state = await newApi.getDeviceState(); diff --git a/client/src/lib/luxsinApi.ts b/client/src/lib/luxsinApi.ts index 0262fdb..6bcb98b 100644 --- a/client/src/lib/luxsinApi.ts +++ b/client/src/lib/luxsinApi.ts @@ -165,6 +165,17 @@ export const FILTER_TYPE_LABELS = ["Low Pass", "High Pass", "Band Pass", "Notch" export const DAC_ARC_LABELS = ["ARC", "eARC"]; export const BT_STATUS_LABELS = ["Disconnected", "Playing", "Paused"]; +function resolveDeviceProtocol(): "http" | "https" { + if (typeof window !== "undefined" && window.location.protocol === "https:") { + return "https"; + } + return "http"; +} + +function normalizeDeviceHost(input: string): string { + return input.trim().replace(/^https?:\/\//i, "").replace(/\/+$/, ""); +} + // ============================================================ // API Class // ============================================================ @@ -172,7 +183,9 @@ export class LuxsinAPI { private baseUrl: string; constructor(ip: string) { - this.baseUrl = `http://${ip}`; + const host = normalizeDeviceHost(ip); + const protocol = resolveDeviceProtocol(); + this.baseUrl = `${protocol}://${host}`; } async getDeviceState(): Promise { diff --git a/client/src/pages/VUPage.tsx b/client/src/pages/VUPage.tsx index 46ac04e..6fb68b2 100644 --- a/client/src/pages/VUPage.tsx +++ b/client/src/pages/VUPage.tsx @@ -19,7 +19,7 @@ interface VUStyle { const VU_STYLES: VUStyle[] = Array.from({ length: 16 }, (_, i) => ({ index: i, name: `VU ${i + 1}`, - preview: `/vu/vu${i + 1}.png`, + preview: `${import.meta.env.BASE_URL}vu/vu${i + 1}.png`, })); export default function VUPage() { diff --git a/vite.config.ts b/vite.config.ts index a4e58ca..1735015 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -179,6 +179,9 @@ export default defineConfig({ }, }, rollupOptions: { + input: { + i: path.resolve(import.meta.dirname, "client", "i.html"), + }, output: { manualChunks(id) { if (!id.includes("node_modules")) return;