{{define "layout"}}
<!doctype html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>{{.Title}}</title>
  <link rel="stylesheet" href="/ui/assets/vendor/tabler.min.css" />
  <link rel="stylesheet" href="/ui/assets/style.css?v=20260508-ia07" />
  <link rel="stylesheet" href="/ui/assets/graph_editor.css?v=20260429-ia01" />
</head>
<body data-theme="blue-dark">
  <div class="app-shell">
    <aside class="sidebar">
      <div class="brand-block">
        <div class="brand-mark">AI</div>
        <div>
          <div class="brand-title">工业安全生产视觉监测平台</div>
        </div>
      </div>
      <nav class="side-nav" aria-label="主导航">
        <a href="/ui/dashboard"><span class="nav-icon">{{icon "overview"}}</span><span>总览</span></a>
        <a href="/ui/console"><span class="nav-icon">{{icon "apply"}}</span><span>管控台</span></a>
        <a href="/ui/alarms"><span class="nav-icon">{{icon "bell"}}</span><span>告警中心</span></a>
        <a href="/ui/devices"><span class="nav-icon">{{icon "devices"}}</span><span>设备</span></a>
        <a href="/ui/monitor"><span class="nav-icon">{{icon "devices"}}</span><span>视频监控</span></a>
        <a href="/ui/face-gallery"><span class="nav-icon">{{icon "profile"}}</span><span>人脸库</span></a>
        <details class="nav-group" id="system-nav-group">
          <summary>
            <span class="nav-icon">{{icon "system"}}</span>
            <span>系统设置</span>
          </summary>
          <div class="nav-group-items">
            <a class="nav-subitem" href="/ui/system"><span class="nav-icon nav-subicon">{{icon "heartbeat"}}</span><span>系统状态</span></a>
            <a class="nav-subitem" href="/ui/diagnostics"><span class="nav-icon nav-subicon">{{icon "logs"}}</span><span>日志审计</span></a>
            <a class="nav-subitem" href="/ui/tasks"><span class="nav-icon nav-subicon">{{icon "task"}}</span><span>任务中心</span></a>
            <a class="nav-subitem expert-only" href="/ui/scene-templates"><span class="nav-icon nav-subicon">{{icon "profile"}}</span><span>场景管理</span></a>
            <a class="nav-subitem expert-only" href="/ui/recognition-units"><span class="nav-icon nav-subicon">{{icon "device"}}</span><span>视频通道</span></a>
            <a class="nav-subitem expert-only" href="/ui/device-assignments"><span class="nav-icon nav-subicon">{{icon "apply"}}</span><span>通道部署</span></a>
            <a class="nav-subitem expert-only" href="/ui/assets"><span class="nav-icon nav-subicon">{{icon "assets"}}</span><span>配置中心</span></a>
            <a class="nav-subitem expert-only" href="/ui/models"><span class="nav-icon nav-subicon">{{icon "assets"}}</span><span>模型管理</span></a>
            <a class="nav-subitem expert-only" href="/ui/resources"><span class="nav-icon nav-subicon">{{icon "template"}}</span><span>资源管理</span></a>
          </div>
        </details>
      </nav>
      <div class="sidebar-footer">
        <div class="mode-toggle" id="mode-toggle" role="switch" tabindex="0" aria-label="切换操作模式">
          <span class="mode-label mode-label-left">标准</span>
          <span class="mode-track"><span class="mode-thumb"></span></span>
          <span class="mode-label mode-label-right">专家</span>
        </div>
        <div>北京泰奥理科技有限公司</div>
        <div>&copy; {{.Year}} V{{.Version}}</div>
      </div>
    </aside>
    <div class="workspace">
      <header class="topbar">
        <div class="topbar-title">
          <h1>{{.Title}}</h1>
        </div>
        <div class="topbar-actions">
          <div class="theme-menu">
            <button type="button" class="topbar-icon-btn js-theme-menu-toggle" aria-label="主题" title="主题">
              {{icon "theme"}}
            </button>
            <div class="theme-menu-panel" hidden>
              <button type="button" data-theme-option="blue-dark">黑白暗色</button>
              <button type="button" data-theme-option="blue-light">蓝灰浅色</button>
              <button type="button" data-theme-option="graphite-gold">石墨金色</button>
            </div>
          </div>
          <a class="topbar-icon-btn" href="/ui/diagnostics" aria-label="日志审计" title="日志审计">
            {{icon "bell"}}
            <span class="topbar-dot" aria-hidden="true"></span>
          </a>
          <a class="topbar-icon-btn" href="/ui/system" aria-label="系统" title="系统">
            {{icon "system"}}
          </a>
        </div>
      </header>
      <main>
        {{if .Error}}<div class="error">{{.Error}}</div>{{end}}
        {{if .Message}}<div class="msg">{{.Message}}</div>{{end}}
        {{.ContentHTML}}
      </main>
    </div>
  </div>
  <script src="/ui/assets/vendor/tabler.min.js"></script>
  <script>
    (function () {
      const themeKey = "3588-admin-theme";
      const allowedThemes = new Set(["blue-dark", "blue-light", "graphite-gold"]);
      const themeLabels = {
        "blue-dark": "黑白暗色",
        "blue-light": "蓝灰浅色",
        "graphite-gold": "石墨金色"
      };

      function applyTheme(theme, persist) {
        const nextTheme = allowedThemes.has(theme) ? theme : "blue-dark";
        document.body.setAttribute("data-theme", nextTheme);
        const themeToggle = document.querySelector(".js-theme-menu-toggle");
        if (themeToggle) {
          const label = "当前主题：" + themeLabels[nextTheme];
          themeToggle.setAttribute("aria-label", label);
          themeToggle.setAttribute("title", label);
        }
        if (persist) {
          localStorage.setItem(themeKey, nextTheme);
        }
        document.querySelectorAll("[data-theme-option]").forEach(function (button) {
          const active = button.getAttribute("data-theme-option") === nextTheme;
          button.setAttribute("aria-pressed", active ? "true" : "false");
        });
      }

      applyTheme(localStorage.getItem("3588-admin-theme") || document.body.getAttribute("data-theme"), false);

      document.querySelectorAll("[data-theme-option]").forEach(function (themeOption) {
        themeOption.addEventListener("click", function (event) {
          event.preventDefault();
          event.stopPropagation();
          applyTheme(themeOption.getAttribute("data-theme-option"), true);
          const panel = themeOption.closest(".theme-menu-panel");
          if (panel) {
            panel.hidden = true;
          }
        });
      });

      function openThemePanel(themeToggle, panel) {
        if (panel.parentElement !== document.body) {
          document.body.appendChild(panel);
        }
        const rect = themeToggle.getBoundingClientRect();
        panel.hidden = false;
        const panelWidth = panel.offsetWidth || 132;
        const viewportPadding = 12;
        const maxLeft = Math.max(viewportPadding, window.innerWidth - panelWidth - viewportPadding);
        const preferredLeft = rect.right - panelWidth;
        const left = Math.min(Math.max(viewportPadding, preferredLeft), maxLeft);
        panel.style.top = Math.round(rect.bottom + 6) + "px";
        panel.style.left = Math.round(left) + "px";
        panel.style.right = "auto";
      }

      function suggestedFilenameFromHeader(headerValue, fallback) {
        if (!headerValue) return fallback;
        const match = /filename="?([^"]+)"?/i.exec(headerValue);
        if (!match || !match[1]) return fallback;
        return match[1];
      }

      async function saveBlobFromURL(url, defaultFilename, types, errorMessage) {
        if (window.showSaveFilePicker) {
          const response = await fetch(url, { credentials: "same-origin" });
          if (!response.ok) {
            throw new Error(errorMessage);
          }
          const blob = await response.blob();
          const filename = suggestedFilenameFromHeader(response.headers.get("Content-Disposition"), defaultFilename);
          const handle = await window.showSaveFilePicker({
            suggestedName: filename,
            types: types
          });
          const writable = await handle.createWritable();
          await writable.write(blob);
          await writable.close();
          return;
        }
        throw new Error("当前浏览器不支持选择保存目录和文件名，请使用支持文件保存对话框的浏览器。");
      }

      async function saveJSONFromURL(url, defaultFilename) {
        return saveBlobFromURL(
          url,
          defaultFilename || "config.json",
          [{
            description: "JSON 文件",
            accept: { "application/json": [".json"] }
          }],
          "导出失败"
        );
      }

      async function saveDBFromURL(url, defaultFilename) {
        return saveBlobFromURL(
          url,
          defaultFilename || "app.db",
          [{
            description: "SQLite 数据库",
            accept: { "application/octet-stream": [".db"], "application/x-sqlite3": [".db"] }
          }],
          "备份失败"
        );
      }

      document.addEventListener("click", function (event) {
        const themeToggle = event.target.closest(".js-theme-menu-toggle");
        if (themeToggle) {
          event.preventDefault();
          const panel = document.querySelector(".theme-menu-panel");
          if (panel) {
            if (panel.hidden) {
              openThemePanel(themeToggle, panel);
            } else {
              panel.hidden = true;
            }
          }
          return;
        }

        const btn = event.target.closest(".js-export-json");
        if (btn) {
          event.preventDefault();
          const url = btn.getAttribute("data-export-url");
          const filename = btn.getAttribute("data-default-filename");
          saveJSONFromURL(url, filename).catch(function (err) {
            window.alert(err && err.message ? err.message : "导出失败");
          });
          return;
        }
        const dbBtn = event.target.closest(".js-export-db");
        if (dbBtn) {
          event.preventDefault();
          const url = dbBtn.getAttribute("data-export-url");
          const filename = dbBtn.getAttribute("data-default-filename");
          saveDBFromURL(url, filename).catch(function (err) {
            window.alert(err && err.message ? err.message : "备份失败");
          });
          return;
        }

        const editToggle = event.target.closest(".js-inline-edit-toggle");
        if (editToggle) {
          event.preventDefault();
          const targetId = editToggle.getAttribute("data-target");
          const form = targetId ? document.getElementById(targetId) : null;
          const display = editToggle.closest(".editable-line");
          if (form) {
            form.hidden = false;
            if (display) display.hidden = true;
            const input = form.querySelector("input:not([type=hidden])");
            if (input) {
              input.focus();
              input.select();
            }
          }
          return;
        }

        const instanceRow = event.target.closest("[data-instance-row]");
        if (instanceRow && !event.target.closest("button, a, input, select, textarea")) {
          const index = instanceRow.getAttribute("data-instance-row");
          const activeInput = document.getElementById("active-instance-input");
          if (activeInput && index !== null) {
            activeInput.value = index;
          }
          document.querySelectorAll("[data-instance-editor]").forEach(function (panel) {
            panel.hidden = panel.getAttribute("data-instance-editor") !== index;
          });
          document.querySelectorAll("[data-instance-row]").forEach(function (row) {
            row.classList.toggle("selected", row.getAttribute("data-instance-row") === index);
          });
          return;
        }

        const profileRow = event.target.closest("[data-profile-row]");
        if (profileRow && !event.target.closest("button, a, input, select, textarea")) {
          const href = profileRow.getAttribute("data-profile-href");
          if (href) {
            window.location.href = href;
          }
          return;
        }

        const navRow = event.target.closest("[data-nav-row]");
        if (navRow && !event.target.closest("button, a, input, select, textarea")) {
          const href = navRow.getAttribute("data-nav-href");
          if (href) {
            window.location.href = href;
          }
          return;
        }

        const instanceEditorToggle = event.target.closest(".js-open-instance-editor");
        if (instanceEditorToggle) {
          event.preventDefault();
          const index = instanceEditorToggle.getAttribute("data-instance-index");
          const activeInput = document.getElementById("active-instance-input");
          if (activeInput && index !== null) {
            activeInput.value = index;
          }
          document.querySelectorAll("[data-instance-editor]").forEach(function (panel) {
            panel.hidden = panel.getAttribute("data-instance-editor") !== index;
          });
          document.querySelectorAll("[data-instance-row]").forEach(function (row) {
            row.classList.toggle("selected", row.getAttribute("data-instance-row") === index);
          });
          const targetId = instanceEditorToggle.getAttribute("data-target");
          const panel = targetId ? document.getElementById(targetId) : null;
          if (panel) {
            panel.scrollIntoView({ block: "start", behavior: "smooth" });
            const input = panel.querySelector("input:not([type=hidden]):not([readonly]), textarea, select");
            if (input) {
              input.focus();
              if (input.tagName === "INPUT" || input.tagName === "TEXTAREA") {
                input.select();
              }
            }
          }
          return;
        }

        const editCancel = event.target.closest(".js-inline-edit-cancel");
        if (editCancel) {
          event.preventDefault();
          const targetId = editCancel.getAttribute("data-target");
          const form = targetId ? document.getElementById(targetId) : null;
          if (form) {
            form.hidden = true;
            const container = form.parentElement;
            const display = container ? container.querySelector(".editable-line") : null;
            if (display) display.hidden = false;
          }
        }
      });

      const systemNavGroup = document.getElementById("system-nav-group");
      if (systemNavGroup) {
        const path = window.location.pathname || "";
        if (
          path === "/ui/system" ||
          path === "/ui/diagnostics" ||
          path === "/ui/tasks" ||
          path === "/ui/scene-templates" ||
          path === "/ui/recognition-units" ||
          path === "/ui/device-assignments" ||
          path === "/ui/assets" ||
          path === "/ui/models" ||
          path === "/ui/resources" ||
          path === "/ui/audit" ||
          path === "/ui/api"
        ) {
          systemNavGroup.open = true;
        }
      }

      var modeKey = "safesight-mode";
      function applyMode(mode, persist) {
        var nextMode = mode === "expert" ? "expert" : "standard";
        document.body.setAttribute("data-mode", nextMode);
        if (persist) {
          localStorage.setItem(modeKey, nextMode);
        }
      }
      applyMode(localStorage.getItem(modeKey) || "standard", false);
      document.getElementById("mode-toggle").addEventListener("click", function () {
        var current = document.body.getAttribute("data-mode") || "standard";
        applyMode(current === "expert" ? "standard" : "expert", true);
      });

    })();
  </script>
</body>
</html>
{{end}}
