<!doctype html>
<!--
  Copyright © 2025-26 l5yth & contributors

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<html lang="en" data-theme="dark">
<head>
  <meta name="color-scheme" content="dark light">
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width,initial-scale=1" />
  <% meta_title_html = Rack::Utils.escape_html(meta_title) %>
  <% meta_name_html = Rack::Utils.escape_html(meta_name) %>
  <% meta_description_html = Rack::Utils.escape_html(meta_description) %>
  <% request_path = request.path.to_s.empty? ? "/" : request.path %>
  <% canonical_base = (defined?(public_base_url) ? public_base_url : request.base_url) %>
  <% canonical_url = "#{canonical_base}#{request_path}" %>
  <% canonical_html = Rack::Utils.escape_html(canonical_url) %>
  <% default_meta_image_url = "#{canonical_base}/og-image.png" %>
  <% page_meta_image_url = (defined?(meta_image_url) && meta_image_url && !meta_image_url.empty?) ? meta_image_url : (defined?(og_image_url) ? og_image_url : default_meta_image_url) %>
  <% page_meta_image_runtime = (page_meta_image_url == default_meta_image_url) %>
  <% page_meta_image_html = Rack::Utils.escape_html(page_meta_image_url) %>
  <% page_meta_image_alt_html = Rack::Utils.escape_html("#{meta_name} preview") %>
  <% page_meta_noindex = defined?(meta_noindex) && meta_noindex %>
  <title><%= meta_title_html %></title>
  <meta name="application-name" content="<%= meta_name_html %>" />
  <meta name="apple-mobile-web-app-title" content="<%= meta_name_html %>" />
  <meta name="description" content="<%= meta_description_html %>" />
  <% if page_meta_noindex %>
  <meta name="robots" content="noindex,nofollow" />
  <% end %>
  <link rel="canonical" href="<%= canonical_html %>" />
  <meta property="og:title" content="<%= meta_title_html %>" />
  <meta property="og:site_name" content="<%= meta_name_html %>" />
  <meta property="og:description" content="<%= meta_description_html %>" />
  <meta property="og:type" content="website" />
  <meta property="og:url" content="<%= canonical_html %>" />
  <meta property="og:image" content="<%= page_meta_image_html %>" />
  <meta property="og:image:alt" content="<%= page_meta_image_alt_html %>" />
  <% if page_meta_image_runtime %>
  <meta property="og:image:width" content="1200" />
  <meta property="og:image:height" content="630" />
  <meta property="og:image:type" content="image/png" />
  <% end %>
  <meta name="twitter:card" content="summary_large_image" />
  <meta name="twitter:title" content="<%= meta_title_html %>" />
  <meta name="twitter:description" content="<%= meta_description_html %>" />
  <meta name="twitter:image" content="<%= page_meta_image_html %>" />
  <meta name="twitter:image:alt" content="<%= page_meta_image_alt_html %>" />
  <link rel="icon" type="image/png" sizes="256x256" href="/favicon.png" />
  <link rel="icon" type="image/svg+xml" sizes="any" href="/potatomesh-logo.svg" />
  <link rel="alternate icon" type="image/x-icon" href="/favicon.ico" />
  <% if (defined?(current_view_mode) ? current_view_mode : nil).to_s == "dashboard" %>
  <script type="application/ld+json">
    <%= JSON.generate({
          "@context" => "https://schema.org",
          "@type" => "WebSite",
          "name" => meta_name,
          "url" => canonical_base,
          "description" => meta_description,
        }) %>
  </script>
  <% end %>
  <%# Import map versions the entire served JS module graph (SPEC AV3); must
      precede any module load so relative imports resolve to the busted URLs. %>
  <script type="importmap"><%= asset_import_map_json %></script>
  <link rel="stylesheet" href="<%= asset_url("/assets/styles/base.css") %>" />
  <script src="<%= asset_url("/assets/js/theme.js") %>" defer></script>
  <script src="<%= asset_url("/assets/js/background.js") %>" defer></script>

  <!-- Leaflet CSS/JS (CDN) -->
  <link
    rel="stylesheet"
    href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
    integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
    crossorigin=""
  />
  <script
    src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
    integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
    crossorigin=""
  ></script>
</head>
<% body_classes = ["dark"]
   view_mode = (defined?(current_view_mode) && current_view_mode) ? current_view_mode.to_sym : :dashboard
   page_view = view_mode.to_s.start_with?("page_")
   full_screen_view = !(%i[dashboard charts federation].include?(view_mode) || page_view)
   body_classes << "view-#{view_mode}"
   shell_classes = ["page-shell"]
   shell_classes << "page-shell--full-screen" if full_screen_view
   main_classes = ["page-main"]
   main_classes << "page-main--dashboard" if view_mode == :dashboard
   main_classes << "page-main--full-screen" if full_screen_view
   show_header = true
   show_footer = !full_screen_view || %i[charts federation].include?(view_mode) || page_view
   footer_slim = %i[charts federation].include?(view_mode) || page_view
   show_filter_input = !(%i[node_detail charts federation].include?(view_mode) || page_view)
   show_meta_row = !(%i[node_detail charts federation].include?(view_mode) || page_view)
   nodes_nav_href = "/nodes"
   nodes_nav_active = %i[nodes node_detail].include?(view_mode)
   federation_nav_enabled = !private_mode && federation_enabled
   announcement_markup = announcement_html %>
<body
  class="<%= body_classes.join(" ") %>"
  data-app-config="<%= Rack::Utils.escape_html(app_config_json) %>"
  data-theme="<%= initial_theme %>"
  data-private-mode="<%= private_mode ? "true" : "false" %>"
>
  <div class="<%= shell_classes.join(" ") %>">
    <% if show_header %>
      <% if announcement_markup && !announcement_markup.empty? %>
        <div class="announcement-banner" role="status" aria-live="polite">
          <p class="announcement-banner__content"><%= announcement_markup %></p>
        </div>
      <% end %>
      <header class="site-header">
        <div class="site-header__left">
          <h1 class="site-title">
            <a href="/" class="site-title__link">
              <img src="/potatomesh-logo.svg" alt="" aria-hidden="true" />
              <span class="site-title-text"><%= site_name %></span>
            </a>
          </h1>
          <% if federation_nav_enabled %>
            <div class="header-federation">
              <div class="instance-selector">
                <label class="visually-hidden" for="instanceSelect">Select a region</label>
                <select id="instanceSelect" class="instance-select" aria-label="Select instance region">
                  <option value=""><%= Rack::Utils.escape_html("Select region ...") %></option>
                </select>
              </div>
            </div>
          <% end %>
        </div>
        <div class="site-header__right">
          <nav class="site-nav" aria-label="Primary">
            <a href="/" class="site-nav__link<%= view_mode == :dashboard ? " is-active" : "" %>"<%= view_mode == :dashboard ? ' aria-current="page"' : "" %>>Dashboard</a>
            <a href="/map" class="site-nav__link<%= view_mode == :map ? " is-active" : "" %>"<%= view_mode == :map ? ' aria-current="page"' : "" %>>Map</a>
            <a href="/chat" class="site-nav__link<%= view_mode == :chat ? " is-active" : "" %>"<%= view_mode == :chat ? ' aria-current="page"' : "" %>>Chat</a>
            <a href="<%= nodes_nav_href %>" class="site-nav__link<%= nodes_nav_active ? " is-active" : "" %>"<%= nodes_nav_active ? ' aria-current="page"' : "" %>>Nodes</a>
            <a href="/charts" class="site-nav__link<%= view_mode == :charts ? " is-active" : "" %>"<%= view_mode == :charts ? ' aria-current="page"' : "" %>><img src="/assets/img/meshtastic.svg" alt="" width="13" height="13" class="protocol-icon protocol-icon--meshtastic nav-protocol-icon" aria-hidden="true" loading="lazy" decoding="async" /> Charts</a>
            <% if federation_nav_enabled %>
              <a href="/federation" class="site-nav__link js-federation-nav<%= view_mode == :federation ? " is-active" : "" %>" data-federation-label="Federation"<%= view_mode == :federation ? ' aria-current="page"' : "" %>>Federation</a>
            <% end %>
            <% static_pages.each do |sp| %>
              <% sp_active = view_mode.to_s == "page_#{sp.slug}" %>
              <a href="/pages/<%= Rack::Utils.escape_path(sp.slug) %>" class="site-nav__link<%= sp_active ? " is-active" : "" %>"<%= sp_active ? ' aria-current="page"' : "" %>><%= Rack::Utils.escape_html(sp.title) %></a>
            <% end %>
          </nav>
          <button
            id="mobileMenuToggle"
            class="icon-button menu-toggle"
            type="button"
            aria-label="Open navigation menu"
            aria-expanded="false"
            aria-controls="mobileMenu"
          >
            <span aria-hidden="true">☰</span>
          </button>
        </div>
      </header>
      <div id="mobileMenu" class="mobile-menu" hidden>
        <div class="mobile-menu__backdrop" data-mobile-menu-close></div>
        <div class="mobile-menu__panel" role="dialog" aria-modal="true" aria-labelledby="mobileMenuTitle" tabindex="-1">
          <div class="mobile-menu__header">
            <h2 id="mobileMenuTitle" class="mobile-menu__title">Menu</h2>
            <button class="icon-button mobile-menu__close" type="button" data-mobile-menu-close aria-label="Close navigation menu">
              <span aria-hidden="true">×</span>
            </button>
          </div>
          <nav class="mobile-nav" aria-label="Mobile">
            <a href="/" class="mobile-nav__link<%= view_mode == :dashboard ? " is-active" : "" %>"<%= view_mode == :dashboard ? ' aria-current="page"' : "" %>>Dashboard</a>
            <a href="/map" class="mobile-nav__link<%= view_mode == :map ? " is-active" : "" %>"<%= view_mode == :map ? ' aria-current="page"' : "" %>>Map</a>
            <a href="/chat" class="mobile-nav__link<%= view_mode == :chat ? " is-active" : "" %>"<%= view_mode == :chat ? ' aria-current="page"' : "" %>>Chat</a>
            <a href="<%= nodes_nav_href %>" class="mobile-nav__link<%= nodes_nav_active ? " is-active" : "" %>"<%= nodes_nav_active ? ' aria-current="page"' : "" %>>Nodes</a>
            <a href="/charts" class="mobile-nav__link<%= view_mode == :charts ? " is-active" : "" %>"<%= view_mode == :charts ? ' aria-current="page"' : "" %>><img src="/assets/img/meshtastic.svg" alt="" width="13" height="13" class="protocol-icon protocol-icon--meshtastic nav-protocol-icon" aria-hidden="true" loading="lazy" decoding="async" /> Charts</a>
            <% if federation_nav_enabled %>
              <a href="/federation" class="mobile-nav__link js-federation-nav<%= view_mode == :federation ? " is-active" : "" %>" data-federation-label="Federation"<%= view_mode == :federation ? ' aria-current="page"' : "" %>>Federation</a>
            <% end %>
            <% static_pages.each do |sp| %>
              <% sp_active = view_mode.to_s == "page_#{sp.slug}" %>
              <a href="/pages/<%= Rack::Utils.escape_path(sp.slug) %>" class="mobile-nav__link<%= sp_active ? " is-active" : "" %>"<%= sp_active ? ' aria-current="page"' : "" %>><%= Rack::Utils.escape_html(sp.title) %></a>
            <% end %>
          </nav>
        </div>
      </div>
    <% end %>

    <% if show_meta_row %>
      <div id="metaRow" class="meta-controls">
        <% if show_filter_input %>
          <div class="filter-input">
            <input type="text" id="filterInput" placeholder="Filter nodes" />
            <button type="button" id="filterClear" class="filter-clear" aria-label="Clear filter" hidden>&times;</button>
          </div>
        <% end %>
        <button id="protocolToggleMeshcore" type="button" class="icon-button protocol-toggle-btn" aria-label="Hide MeshCore nodes" aria-pressed="false" title="Toggle MeshCore node visibility" hidden>
          <img src="/assets/img/meshcore.svg" alt="" width="20" height="20" aria-hidden="true" class="protocol-toggle-icon" loading="lazy" decoding="async" />
        </button>
        <button id="protocolToggleMeshtastic" type="button" class="icon-button protocol-toggle-btn" aria-label="Hide Meshtastic nodes" aria-pressed="false" title="Toggle Meshtastic node visibility" hidden>
          <img src="/assets/img/meshtastic.svg" alt="" width="20" height="20" aria-hidden="true" class="protocol-toggle-icon" loading="lazy" decoding="async" />
        </button>
        <span id="footerActiveNodes" class="meta-active-nodes"></span>
        <button id="refreshBtn" type="button" title="Fetch latest data now">Refresh</button>
        <button id="autorefreshToggle" type="button" aria-label="Pause auto-refresh" aria-pressed="false" title="Pause or resume automatic data refresh">⏸</button>
        <span id="status" class="refresh-timestamp" aria-live="polite"></span>
      </div>
    <% end %>

    <div id="nodeDetailOverlay" class="node-detail-overlay" hidden>
      <div class="node-detail-overlay__dialog" role="dialog" aria-modal="true" aria-labelledby="nodeDetailOverlayHeader" tabindex="-1">
        <h2 id="nodeDetailOverlayHeader" class="visually-hidden">Node details</h2>
        <button type="button" class="node-detail-overlay__close" aria-label="Close node details">&times;</button>
        <div class="node-detail-overlay__content" aria-live="polite">
          <p class="node-detail-overlay__status">Select a node to view details.</p>
        </div>
      </div>
    </div>

    <main class="<%= main_classes.join(" ") %>">
      <%= yield %>
    </main>

    <% if show_footer %>
      <%= erb :"shared/_footer", locals: { site_name: site_name, version: version, contact_link: contact_link, contact_link_url: contact_link_url, slim: footer_slim } %>
    <% end %>
  </div>

  <template id="shortInfoOverlayTemplate">
    <div class="short-info-overlay" role="dialog" aria-modal="false">
      <button type="button" class="short-info-close" aria-label="Close node details">×</button>
      <div class="short-info-content"></div>
    </div>
  </template>

  <script>
    const CHAT_ENABLED = <%= private_mode ? "false" : "true" %>;
    const current_view_mode = '<%= view_mode %>';
  </script>
  <script type="module" src="<%= asset_url("/assets/js/app/index.js") %>"></script>
</body>
</html>
