feat(n7web): sync N7 scene cards and optimize runtime

This commit is contained in:
Miayui
2026-09-17 11:04:05 +08:00
parent 75ce391312
commit 7d196db02b
31 changed files with 2924 additions and 126 deletions
+26 -18
View File
@@ -1265,6 +1265,7 @@
pollTimer: null,
deviceFrame: null,
deviceFingerprint: "",
deviceRenderDirty: true,
activeDevice: null,
pinnedDevice: null,
previewClearTimer: null,
@@ -1523,9 +1524,13 @@
</label>`;
}
function renderSyncedDevices() {
function renderSyncedDevices({ force = false } = {}) {
const grid = $("#v2DeviceSyncGrid");
if (!grid) return;
if (!grid) return false;
if (!force && !panelVisible("devices")) {
displaySync.deviceRenderDirty = true;
return false;
}
grid.innerHTML = syncedDevices.map((device) => {
const rows = deviceReadoutRows(device);
const waiting = rows.some(([, value]) => value === "-");
@@ -1553,7 +1558,9 @@
$(`.v2-synced-device[data-device="${displaySync.activeDevice}"]`)?.classList.add("active");
}
displaySync.deviceFingerprint = JSON.stringify(syncedDevices.map((device) => [device.id, deviceReadoutRows(device)]));
displaySync.deviceRenderDirty = false;
window.lucide?.createIcons({ attrs: { "aria-hidden": "true" } });
return true;
}
function storeDeviceControlDraft(input) {
@@ -1641,11 +1648,17 @@
}
function scheduleSyncedDeviceRender() {
if (!panelVisible("devices")) {
displaySync.deviceRenderDirty = true;
return;
}
if (displaySync.deviceFrame) return;
displaySync.deviceFrame = requestAnimationFrame(() => {
displaySync.deviceFrame = null;
const fingerprint = JSON.stringify(syncedDevices.map((device) => [device.id, deviceReadoutRows(device)]));
if (fingerprint === displaySync.deviceFingerprint && $("#v2DeviceSyncGrid")?.childElementCount) return;
if (!displaySync.deviceRenderDirty
&& fingerprint === displaySync.deviceFingerprint
&& $("#v2DeviceSyncGrid")?.childElementCount) return;
renderSyncedDevices();
if (displaySync.activeDevice) presentTwinDevice(displaySync.activeDevice, {
pinned: Boolean(displaySync.pinnedDevice),
@@ -1748,7 +1761,11 @@
rightRail.toggleAttribute("inert", collapsed);
rightRail.dataset.openPanels = openPanels.join(" ") || "none";
}
if (key === "devices" && visible) renderSyncedDevices({ force: true });
window.lucide?.createIcons({ attrs: { "aria-hidden": "true" } });
window.dispatchEvent(new CustomEvent("cognitive-agent:side-panel-visibility", {
detail: { panel: key, visible: Boolean(visible) },
}));
window.dispatchEvent(new Event("resize"));
}
@@ -2550,19 +2567,10 @@
}
buildTwinDeviceInteractions();
cabinBand.classList.add("v2-source-state-only");
new MutationObserver(scheduleSyncedDeviceRender).observe(cabinBand, {
attributes: true,
childList: true,
characterData: true,
subtree: true,
});
const stateBand = $(".state-band");
if (stateBand) new MutationObserver(scheduleSyncedDeviceRender).observe(stateBand, {
attributes: true,
childList: true,
characterData: true,
subtree: true,
});
window.addEventListener(
"cognitive-agent:vehicle-state-rendered",
scheduleSyncedDeviceRender,
);
}
setSidePanelVisibility("devices", false);
setSidePanelVisibility("extensions", false);
@@ -2983,8 +2991,8 @@
});
window.addEventListener("cognitive-agent:vehicle-feedback-state", () => {
syncRuntimePresentation();
renderSyncedDevices();
if (displaySync.activeDevice) {
scheduleSyncedDeviceRender();
if (panelVisible("devices") && displaySync.activeDevice) {
presentTwinDevice(displaySync.activeDevice, {
pinned: Boolean(displaySync.pinnedDevice),
selectSeat: false,