diff --git a/src/meshcore_hub/web/static/css/app.css b/src/meshcore_hub/web/static/css/app.css
index 5eeb635..aa7df99 100644
--- a/src/meshcore_hub/web/static/css/app.css
+++ b/src/meshcore_hub/web/static/css/app.css
@@ -23,8 +23,8 @@
--color-nodes: oklch(0.65 0.24 265); /* violet */
--color-adverts: oklch(0.7 0.17 330); /* magenta */
--color-messages: oklch(0.75 0.18 180); /* teal */
- --color-map: oklch(0.72 0.19 142); /* green */
- --color-members: oklch(0.75 0.15 75); /* amber */
+ --color-map: oklch(0.8 0.17 80); /* yellow (matches btn-warning) */
+ --color-members: oklch(0.72 0.17 50); /* orange */
}
/* ==========================================================================
diff --git a/src/meshcore_hub/web/static/js/spa/pages/node-detail.js b/src/meshcore_hub/web/static/js/spa/pages/node-detail.js
index e276b7b..7c91748 100644
--- a/src/meshcore_hub/web/static/js/spa/pages/node-detail.js
+++ b/src/meshcore_hub/web/static/js/spa/pages/node-detail.js
@@ -199,17 +199,20 @@ ${heroHtml}
cleanupFns.push(() => map.remove());
}
- // Initialize QR code
- if (typeof QRCode !== 'undefined') {
- const typeMap = { chat: 1, repeater: 2, room: 3, sensor: 4 };
- const typeNum = typeMap[(node.adv_type || '').toLowerCase()] || 1;
- const url = 'meshcore://contact/add?name=' + encodeURIComponent(displayName) + '&public_key=' + node.public_key + '&type=' + typeNum;
- new QRCode(document.getElementById('qr-code'), {
- text: url, width: 140, height: 140,
- colorDark: '#000000', colorLight: '#ffffff',
- correctLevel: QRCode.CorrectLevel.L,
- });
- }
+ // Initialize QR code (defer to next frame so layout settles after map init)
+ requestAnimationFrame(() => {
+ const qrEl = document.getElementById('qr-code');
+ if (qrEl && typeof QRCode !== 'undefined') {
+ const typeMap = { chat: 1, repeater: 2, room: 3, sensor: 4 };
+ const typeNum = typeMap[(node.adv_type || '').toLowerCase()] || 1;
+ const url = 'meshcore://contact/add?name=' + encodeURIComponent(displayName) + '&public_key=' + node.public_key + '&type=' + typeNum;
+ new QRCode(qrEl, {
+ text: url, width: 140, height: 140,
+ colorDark: '#000000', colorLight: '#ffffff',
+ correctLevel: QRCode.CorrectLevel.L,
+ });
+ }
+ });
return () => {
cleanupFns.forEach(fn => fn());
diff --git a/src/meshcore_hub/web/templates/_macros.html b/src/meshcore_hub/web/templates/_macros.html
deleted file mode 100644
index a994ef9..0000000
--- a/src/meshcore_hub/web/templates/_macros.html
+++ /dev/null
@@ -1,47 +0,0 @@
-{# Reusable macros for templates #}
-
-{#
- Pagination macro
-
- Parameters:
- - page: Current page number
- - total_pages: Total number of pages
- - params: Dict of query parameters to preserve (e.g., {"search": "foo", "limit": 50})
-#}
-{% macro pagination(page, total_pages, params={}) %}
-{% if total_pages > 1 %}
-{% set query_parts = [] %}
-{% for key, value in params.items() %}
-{% if value is not none and value != '' %}
-{% set _ = query_parts.append(key ~ '=' ~ value) %}
-{% endif %}
-{% endfor %}
-{% set base_query = query_parts|join('&') %}
-{% set query_prefix = '&' if base_query else '' %}
-
-
- {% if page > 1 %}
-
Previous
- {% else %}
-
Previous
- {% endif %}
-
- {% for p in range(1, total_pages + 1) %}
- {% if p == page %}
-
{{ p }}
- {% elif p == 1 or p == total_pages or (p >= page - 2 and p <= page + 2) %}
-
{{ p }}
- {% elif p == 2 or p == total_pages - 1 %}
-
...
- {% endif %}
- {% endfor %}
-
- {% if page < total_pages %}
-
Next
- {% else %}
-
Next
- {% endif %}
-
-
-{% endif %}
-{% endmacro %}
diff --git a/src/meshcore_hub/web/templates/admin/access_denied.html b/src/meshcore_hub/web/templates/admin/access_denied.html
deleted file mode 100644
index 1e0b91e..0000000
--- a/src/meshcore_hub/web/templates/admin/access_denied.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{% extends "base.html" %}
-{% from "macros/icons.html" import icon_lock %}
-
-{% block title %}Access Denied - {{ network_name }}{% endblock %}
-
-{% block content %}
-
-
- {{ icon_lock("h-24 w-24 mx-auto text-error opacity-50 mb-6") }}
-
Access Denied
-
You don't have permission to access the admin area.
-
Please contact the network administrator if you believe this is an error.
-
-
-
-{% endblock %}
diff --git a/src/meshcore_hub/web/templates/admin/index.html b/src/meshcore_hub/web/templates/admin/index.html
deleted file mode 100644
index ad821a8..0000000
--- a/src/meshcore_hub/web/templates/admin/index.html
+++ /dev/null
@@ -1,57 +0,0 @@
-{% extends "base.html" %}
-{% from "macros/icons.html" import icon_user, icon_email, icon_users, icon_tag %}
-
-{% block title %}Admin - {{ network_name }}{% endblock %}
-
-{% block content %}
-
-
-
-
- {% if auth_username or auth_user %}
-
- {{ icon_user("h-4 w-4") }}
- {{ auth_username or auth_user }}
-
- {% endif %}
- {% if auth_email %}
-
- {{ icon_email("h-4 w-4") }}
- {{ auth_email }}
-
- {% endif %}
-
-
-
-
-{% endblock %}
diff --git a/src/meshcore_hub/web/templates/admin/members.html b/src/meshcore_hub/web/templates/admin/members.html
deleted file mode 100644
index 1364f8b..0000000
--- a/src/meshcore_hub/web/templates/admin/members.html
+++ /dev/null
@@ -1,277 +0,0 @@
-{% extends "base.html" %}
-{% from "macros/icons.html" import icon_success, icon_error, icon_alert %}
-
-{% block title %}Admin: Members - {{ network_name }}{% endblock %}
-
-{% block content %}
-
-
-
-{% if message %}
-
- {{ icon_success("stroke-current shrink-0 h-6 w-6") }}
- {{ message }}
-
-{% endif %}
-
-{% if error %}
-
- {{ icon_error("stroke-current shrink-0 h-6 w-6") }}
- {{ error }}
-
-{% endif %}
-
-
-
-
-
-
Network Members ({{ members|length }})
- Add Member
-
-
- {% if members %}
-
-
-
-
- Member ID
- Name
- Callsign
- Contact
- Actions
-
-
-
- {% for member in members %}
-
- {{ member.member_id }}
- {{ member.name }}
-
- {% if member.callsign %}
- {{ member.callsign }}
- {% else %}
- -
- {% endif %}
-
- {{ member.contact or '-' }}
-
-
-
- Edit
-
-
- Delete
-
-
-
-
- {% endfor %}
-
-
-
- {% else %}
-
-
No members configured yet.
-
Click "Add Member" to create the first member.
-
- {% endif %}
-
-
-
-
-
-
-
- close
-
-
-
-
-
-
-
Edit Member
-
-
-
-
-
-
- Cancel
- Save Changes
-
-
-
-
- close
-
-
-
-
-
-
-
Delete Member
-
-
-
- Are you sure you want to delete member ?
-
-
- {{ icon_alert("stroke-current shrink-0 h-6 w-6") }}
- This action cannot be undone.
-
-
-
- Cancel
- Delete
-
-
-
-
- close
-
-
-{% endblock %}
-
-{% block extra_scripts %}
-
-{% endblock %}
diff --git a/src/meshcore_hub/web/templates/admin/node_tags.html b/src/meshcore_hub/web/templates/admin/node_tags.html
deleted file mode 100644
index 4886e7f..0000000
--- a/src/meshcore_hub/web/templates/admin/node_tags.html
+++ /dev/null
@@ -1,419 +0,0 @@
-{% extends "base.html" %}
-{% from "macros/icons.html" import icon_success, icon_error, icon_alert, icon_info, icon_tag %}
-
-{% block title %}Admin: Node Tags - {{ network_name }}{% endblock %}
-
-{% block content %}
-
-
-
-{% if message %}
-
- {{ icon_success("stroke-current shrink-0 h-6 w-6") }}
- {{ message }}
-
-{% endif %}
-
-{% if error %}
-
- {{ icon_error("stroke-current shrink-0 h-6 w-6") }}
- {{ error }}
-
-{% endif %}
-
-
-
-
-
Select Node
-
-
-
- Node
-
-
- -- Select a node --
- {% for node in nodes %}
-
- {{ node.name or 'Unnamed' }} ({{ node.public_key[:8] }}...{{ node.public_key[-4:] }})
-
- {% endfor %}
-
-
- Load Tags
-
-
-
-
-{% if selected_public_key and selected_node %}
-
-
-
-
-
-
{% if selected_node.adv_type and selected_node.adv_type|lower == 'chat' %}💬{% elif selected_node.adv_type and selected_node.adv_type|lower == 'repeater' %}📡{% elif selected_node.adv_type and selected_node.adv_type|lower == 'room' %}🪧{% else %}📍{% endif %}
-
-
{{ selected_node.name or 'Unnamed Node' }}
-
{{ selected_public_key }}
-
-
-
- {% if tags %}
-
Copy All
-
Delete All
- {% endif %}
-
View Node
-
-
-
-
-
-
-
-
-
Tags ({{ tags|length }})
-
- {% if tags %}
-
-
-
-
- Key
- Value
- Type
- Updated
- Actions
-
-
-
- {% for tag in tags %}
-
- {{ tag.key }}
- {{ tag.value or '-' }}
-
- {{ tag.value_type }}
-
- {{ tag.updated_at|localdate }}
-
-
-
- Edit
-
-
- Move
-
-
- Delete
-
-
-
-
- {% endfor %}
-
-
-
- {% else %}
-
-
No tags found for this node.
-
Add a new tag below.
-
- {% endif %}
-
-
-
-
-
-
-
Add New Tag
-
-
-
-
-
- Key
-
-
-
-
-
-
- Value
-
-
-
-
-
-
- Type
-
-
- string
- number
- boolean
-
-
-
-
-
-
-
- Add Tag
-
-
-
-
-
-
-
-
-
Edit Tag
-
-
-
-
-
-
- Key
-
-
-
-
-
-
- Value
-
-
-
-
-
-
- Type
-
-
- string
- number
- boolean
-
-
-
-
- Cancel
- Save Changes
-
-
-
-
- close
-
-
-
-
-
-
-
Move Tag to Another Node
-
-
-
-
-
-
- Tag Key
-
-
-
-
-
-
- Destination Node
-
-
- -- Select destination node --
- {% for node in nodes %}
- {% if node.public_key != selected_public_key %}
-
- {{ node.name or 'Unnamed' }} ({{ node.public_key[:8] }}...{{ node.public_key[-4:] }})
-
- {% endif %}
- {% endfor %}
-
-
-
-
- {{ icon_alert("stroke-current shrink-0 h-6 w-6") }}
- This will move the tag from the current node to the destination node.
-
-
-
- Cancel
- Move Tag
-
-
-
-
- close
-
-
-
-
-
-
-
Delete Tag
-
-
-
-
- Are you sure you want to delete the tag " "?
-
-
- {{ icon_alert("stroke-current shrink-0 h-6 w-6") }}
- This action cannot be undone.
-
-
-
- Cancel
- Delete
-
-
-
-
- close
-
-
-
-
-
-
-
Copy All Tags to Another Node
-
-
-
- Copy all {{ tags|length }} tag(s) from {{ selected_node.name or 'Unnamed' }} to another node.
-
-
-
- Destination Node
-
-
- -- Select destination node --
- {% for node in nodes %}
- {% if node.public_key != selected_public_key %}
-
- {{ node.name or 'Unnamed' }} ({{ node.public_key[:8] }}...{{ node.public_key[-4:] }})
-
- {% endif %}
- {% endfor %}
-
-
-
-
- {{ icon_info("stroke-current shrink-0 h-6 w-6") }}
- Tags that already exist on the destination node will be skipped. Original tags remain on this node.
-
-
-
- Cancel
- Copy Tags
-
-
-
-
- close
-
-
-
-
-
-
-
Delete All Tags
-
-
-
- Are you sure you want to delete all {{ tags|length }} tag(s) from {{ selected_node.name or 'Unnamed' }} ?
-
-
- {{ icon_alert("stroke-current shrink-0 h-6 w-6") }}
- This action cannot be undone. All tags will be permanently deleted.
-
-
-
- Cancel
- Delete All Tags
-
-
-
-
- close
-
-
-
-{% elif selected_public_key and not selected_node %}
-
- {{ icon_alert("stroke-current shrink-0 h-6 w-6") }}
- Node not found: {{ selected_public_key }}
-
-{% else %}
-
-
- {{ icon_tag("h-16 w-16 mx-auto mb-4 opacity-30") }}
-
Select a Node
-
Choose a node from the dropdown above to view and manage its tags.
-
-
-{% endif %}
-{% endblock %}
-
-{% block extra_scripts %}
-
-{% endblock %}
diff --git a/src/meshcore_hub/web/templates/advertisements.html b/src/meshcore_hub/web/templates/advertisements.html
deleted file mode 100644
index 4e6737d..0000000
--- a/src/meshcore_hub/web/templates/advertisements.html
+++ /dev/null
@@ -1,165 +0,0 @@
-{% extends "base.html" %}
-{% from "_macros.html" import pagination %}
-{% from "macros/icons.html" import icon_alert %}
-
-{% block title %}Advertisements - {{ network_name }}{% endblock %}
-
-{% block content %}
-
-
Advertisements
-
- {% if timezone and timezone != 'UTC' %}{{ timezone }} {% endif %}
- {{ total }} total
-
-
-
-{% if api_error %}
-
- {{ icon_alert("stroke-current shrink-0 h-6 w-6") }}
- Could not fetch data from API: {{ api_error }}
-
-{% endif %}
-
-
-
-
-
-
-
- Search
-
-
-
- {% if nodes %}
-
-
- Node
-
-
- All Nodes
- {% for node in nodes %}
- {% set ns = namespace(tag_name=none) %}
- {% for tag in node.tags or [] %}
- {% if tag.key == 'name' %}
- {% set ns.tag_name = tag.value %}
- {% endif %}
- {% endfor %}
- {{ ns.tag_name or node.name or node.public_key[:12] + '...' }}
- {% endfor %}
-
-
- {% endif %}
- {% if members %}
-
-
- Member
-
-
- All Members
- {% for member in members %}
- {{ member.name }}{% if member.callsign %} ({{ member.callsign }}){% endif %}
- {% endfor %}
-
-
- {% endif %}
-
-
-
-
-
-
-
-
-
-
-
-{{ pagination(page, total_pages, {"search": search, "public_key": public_key, "member_id": member_id, "limit": limit}) }}
-{% endblock %}
diff --git a/src/meshcore_hub/web/templates/base.html b/src/meshcore_hub/web/templates/base.html
deleted file mode 100644
index f62d5ce..0000000
--- a/src/meshcore_hub/web/templates/base.html
+++ /dev/null
@@ -1,126 +0,0 @@
-{% from "macros/icons.html" import icon_home, icon_dashboard, icon_nodes, icon_advertisements, icon_messages, icon_map, icon_members, icon_page, icon_menu %}
-
-
-
-
-
- {% block title %}{{ network_name }}{% endblock %}
-
-
- {% set default_description = (network_name ~ " - " ~ network_welcome_text) if network_welcome_text else (network_name ~ " - MeshCore off-grid LoRa mesh network dashboard.") %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {% block extra_head %}{% endblock %}
-
-
-
-
-
-
-
- {% block content %}{% endblock %}
-
-
-
-
-
-
-
-
- {% block extra_scripts %}{% endblock %}
-
-
diff --git a/src/meshcore_hub/web/templates/dashboard.html b/src/meshcore_hub/web/templates/dashboard.html
deleted file mode 100644
index f11ee90..0000000
--- a/src/meshcore_hub/web/templates/dashboard.html
+++ /dev/null
@@ -1,195 +0,0 @@
-{% extends "base.html" %}
-{% from "macros/icons.html" import icon_nodes, icon_advertisements, icon_messages, icon_alert, icon_channel %}
-
-{% block title %}Dashboard - {{ network_name }}{% endblock %}
-
-{% block content %}
-
-
Dashboard
-
-
-{% if api_error %}
-
- {{ icon_alert("stroke-current shrink-0 h-6 w-6") }}
- Could not fetch data from API: {{ api_error }}
-
-{% endif %}
-
-
-
-
-
-
- {{ icon_nodes("h-8 w-8") }}
-
-
Total Nodes
-
{{ stats.total_nodes }}
-
All discovered nodes
-
-
-
-
-
- {{ icon_advertisements("h-8 w-8") }}
-
-
Advertisements
-
{{ stats.advertisements_7d }}
-
Last 7 days
-
-
-
-
-
- {{ icon_messages("h-8 w-8") }}
-
-
Messages
-
{{ stats.messages_7d }}
-
Last 7 days
-
-
-
-
-
-
-
-
-
- {{ icon_nodes("h-5 w-5") }}
- Total Nodes
-
-
Over time (last 7 days)
-
-
-
-
-
-
-
-
-
-
- {{ icon_advertisements("h-5 w-5") }}
- Advertisements
-
-
Per day (last 7 days)
-
-
-
-
-
-
-
-
-
-
- {{ icon_messages("h-5 w-5") }}
- Messages
-
-
Per day (last 7 days)
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ icon_advertisements("h-6 w-6") }}
- Recent Advertisements
-
- {% if stats.recent_advertisements %}
-
-
-
-
- Node
- Type
- Received
-
-
-
- {% for ad in stats.recent_advertisements %}
-
-
-
- {{ ad.friendly_name or ad.name or ad.public_key[:12] + '...' }}
-
- {% if ad.friendly_name or ad.name %}
- {{ ad.public_key[:12] }}...
- {% endif %}
-
-
- {% if ad.adv_type and ad.adv_type|lower == 'chat' %}
- 💬
- {% elif ad.adv_type and ad.adv_type|lower == 'repeater' %}
- 📡
- {% elif ad.adv_type and ad.adv_type|lower == 'room' %}
- 🪧
- {% elif ad.adv_type %}
- 📍
- {% else %}
- -
- {% endif %}
-
- {{ ad.received_at|localtimeonly }}
-
- {% endfor %}
-
-
-
- {% else %}
-
No advertisements recorded yet.
- {% endif %}
-
-
-
-
- {% if stats.channel_messages %}
-
-
-
- {{ icon_channel("h-6 w-6") }}
- Recent Channel Messages
-
-
- {% for channel, messages in stats.channel_messages.items() %}
-
-
- CH{{ channel }}
- Channel {{ channel }}
-
-
- {% for msg in messages %}
-
- {{ msg.received_at|localtimeonly_short }}
- {{ msg.text }}
-
- {% endfor %}
-
-
- {% endfor %}
-
-
-
- {% endif %}
-
-
-{% endblock %}
-
-{% block extra_scripts %}
-
-
-
-{% endblock %}
diff --git a/src/meshcore_hub/web/templates/errors/404.html b/src/meshcore_hub/web/templates/errors/404.html
deleted file mode 100644
index 2922b8d..0000000
--- a/src/meshcore_hub/web/templates/errors/404.html
+++ /dev/null
@@ -1,32 +0,0 @@
-{% extends "base.html" %}
-{% from "macros/icons.html" import icon_home, icon_nodes %}
-
-{% block title %}Page Not Found - {{ network_name }}{% endblock %}
-
-{% block content %}
-
-
-
-
404
-
Page Not Found
-
- {% if detail %}
- {{ detail }}
- {% else %}
- The page you're looking for doesn't exist or has been moved.
- {% endif %}
-
-
-
-
-
-{% endblock %}
diff --git a/src/meshcore_hub/web/templates/home.html b/src/meshcore_hub/web/templates/home.html
deleted file mode 100644
index af31afb..0000000
--- a/src/meshcore_hub/web/templates/home.html
+++ /dev/null
@@ -1,198 +0,0 @@
-{% extends "base.html" %}
-{% from "macros/icons.html" import icon_dashboard, icon_map, icon_nodes, icon_advertisements, icon_messages, icon_page, icon_info, icon_chart, icon_globe, icon_github %}
-
-{% block title %}{{ network_name }}{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
-
-
-
{{ network_name }}
- {% if network_city and network_country %}
-
{{ network_city }}, {{ network_country }}
- {% endif %}
-
-
- {% if network_welcome_text %}
-
{{ network_welcome_text }}
- {% else %}
-
- Welcome to the {{ network_name }} mesh network dashboard.
- Monitor network activity, view connected nodes, and explore message history.
-
- {% endif %}
-
-
-
-
-
-
-
-
-
- {{ icon_nodes("h-8 w-8") }}
-
-
Total Nodes
-
{{ stats.total_nodes }}
-
All discovered nodes
-
-
-
-
-
- {{ icon_advertisements("h-8 w-8") }}
-
-
Advertisements
-
{{ stats.advertisements_7d }}
-
Last 7 days
-
-
-
-
-
- {{ icon_messages("h-8 w-8") }}
-
-
Messages
-
{{ stats.messages_7d }}
-
Last 7 days
-
-
-
-
-
-
-
-
-
- {{ icon_info("h-6 w-6") }}
- Network Info
-
-
- {% if network_radio_config %}
- {% if network_radio_config.profile %}
-
- Profile:
- {{ network_radio_config.profile }}
-
- {% endif %}
- {% if network_radio_config.frequency %}
-
- Frequency:
- {{ network_radio_config.frequency }}
-
- {% endif %}
- {% if network_radio_config.bandwidth %}
-
- Bandwidth:
- {{ network_radio_config.bandwidth }}
-
- {% endif %}
- {% if network_radio_config.spreading_factor %}
-
- Spreading Factor:
- {{ network_radio_config.spreading_factor }}
-
- {% endif %}
- {% if network_radio_config.coding_rate %}
-
- Coding Rate:
- {{ network_radio_config.coding_rate }}
-
- {% endif %}
- {% if network_radio_config.tx_power %}
-
- TX Power:
- {{ network_radio_config.tx_power }}
-
- {% endif %}
- {% endif %}
- {% if network_location and network_location != (0.0, 0.0) %}
-
- Location:
- {{ "%.4f"|format(network_location[0]) }}, {{ "%.4f"|format(network_location[1]) }}
-
- {% endif %}
-
-
-
-
-
-
-
-
Our local off-grid mesh network is made possible by
-
-
-
-
Connecting people and things, without using the internet
-
-
-
-
-
-
-
-
- {{ icon_chart("h-6 w-6") }}
- Network Activity
-
-
Activity per day (last 7 days)
-
-
-
-
-
-
-{% endblock %}
-
-{% block extra_scripts %}
-
-
-
-{% endblock %}
diff --git a/src/meshcore_hub/web/templates/macros/icons.html b/src/meshcore_hub/web/templates/macros/icons.html
deleted file mode 100644
index 8c88135..0000000
--- a/src/meshcore_hub/web/templates/macros/icons.html
+++ /dev/null
@@ -1,143 +0,0 @@
-{% macro icon_dashboard(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_map(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_nodes(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_advertisements(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_messages(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_home(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_members(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_page(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_info(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_alert(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_chart(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_refresh(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_menu(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_github(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_external_link(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_globe(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_error(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_channel(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_success(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_lock(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_user(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_email(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_tag(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
-
-{% macro icon_users(class="h-5 w-5") %}
-
-
-
-{% endmacro %}
diff --git a/src/meshcore_hub/web/templates/map.html b/src/meshcore_hub/web/templates/map.html
deleted file mode 100644
index 5463c92..0000000
--- a/src/meshcore_hub/web/templates/map.html
+++ /dev/null
@@ -1,91 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}Map - {{ network_name }}{% endblock %}
-
-{% block content %}
-
-
Map
-
- {% if timezone and timezone != 'UTC' %}{{ timezone }} {% endif %}
- Loading...
-
-
-
-
-
-
-
-
-
-
- Show
-
-
- All Nodes
- Infrastructure Only
-
-
-
-
- Node Type
-
-
- All Types
- Chat
- Repeater
- Room
-
-
-
-
- Member
-
-
- All Members
-
-
-
-
-
- Show Labels
-
-
-
-
Clear Filters
-
-
-
-
-
-
-
-
-
-
-
Nodes are placed on the map based on GPS coordinates from node reports or manual tags.
-
-{% endblock %}
-
-{% block extra_scripts %}
-
-
-{% endblock %}
diff --git a/src/meshcore_hub/web/templates/members.html b/src/meshcore_hub/web/templates/members.html
deleted file mode 100644
index 593e896..0000000
--- a/src/meshcore_hub/web/templates/members.html
+++ /dev/null
@@ -1,104 +0,0 @@
-{% extends "base.html" %}
-{% from "macros/icons.html" import icon_info %}
-
-{% block title %}Members - {{ network_name }}{% endblock %}
-
-{% block content %}
-
-
Members
- {{ members|length }} members
-
-
-{% if members %}
-
- {% for member in members %}
-
-
-
- {{ member.name }}
- {% if member.callsign %}
- {{ member.callsign }}
- {% endif %}
-
-
- {% if member.description %}
-
{{ member.description }}
- {% endif %}
-
- {% if member.contact %}
-
- Contact: {{ member.contact }}
-
- {% endif %}
-
- {% if member.nodes %}
-
- {% endif %}
-
-
- {% endfor %}
-
-{% else %}
-
- {{ icon_info("stroke-current shrink-0 h-6 w-6") }}
-
-
No members configured
-
To display network members, create a members.yaml file in your seed directory.
-
-
-
-
-
-
Members File Format
-
Create a YAML file at $SEED_HOME/members.yaml with the following structure:
-
members:
- - member_id: johndoe
- name: John Doe
- callsign: AB1CD
- role: Network Admin
- description: Manages the main repeater node.
- contact: john@example.com
- - member_id: janesmith
- name: Jane Smith
- role: Member
- description: Regular user in the downtown area.
-
- Run meshcore-hub collector seed to import members.
- To associate nodes with members, add a member_id tag to nodes in node_tags.yaml.
-
-
-
-{% endif %}
-{% endblock %}
diff --git a/src/meshcore_hub/web/templates/messages.html b/src/meshcore_hub/web/templates/messages.html
deleted file mode 100644
index 882928e..0000000
--- a/src/meshcore_hub/web/templates/messages.html
+++ /dev/null
@@ -1,149 +0,0 @@
-{% extends "base.html" %}
-{% from "_macros.html" import pagination %}
-{% from "macros/icons.html" import icon_alert %}
-
-{% block title %}Messages - {{ network_name }}{% endblock %}
-
-{% block content %}
-
-
Messages
-
- {% if timezone and timezone != 'UTC' %}{{ timezone }} {% endif %}
- {{ total }} total
-
-
-
-{% if api_error %}
-
- {{ icon_alert("stroke-current shrink-0 h-6 w-6") }}
- Could not fetch data from API: {{ api_error }}
-
-{% endif %}
-
-
-
-
-
-
-
- Type
-
-
- All Types
- Direct
- Channel
-
-
-
-
-
-
-
-
-
- {% for msg in messages %}
-
-
-
-
-
- {% if msg.message_type == 'channel' %}📻{% else %}👤{% endif %}
-
-
-
- {% if msg.message_type == 'channel' %}
- Public
- {% else %}
- {% if msg.sender_tag_name or msg.sender_name %}
- {{ msg.sender_tag_name or msg.sender_name }}
- {% else %}
- {{ (msg.pubkey_prefix or '-')[:12] }}
- {% endif %}
- {% endif %}
-
-
- {{ msg.received_at|localtime_short }}
-
-
-
-
- {% if msg.receivers and msg.receivers|length >= 1 %}
-
- {% for recv in msg.receivers %}
-
📡
- {% endfor %}
-
- {% elif msg.received_by %}
-
📡
- {% endif %}
-
-
-
{{ msg.text or '-' }}
-
-
- {% else %}
-
No messages found.
- {% endfor %}
-
-
-
-
-
-
-
- Type
- Time
- From
- Message
- Receivers
-
-
-
- {% for msg in messages %}
-
-
- {% if msg.message_type == 'channel' %}📻{% else %}👤{% endif %}
-
-
- {{ msg.received_at|localtime }}
-
-
- {% if msg.message_type == 'channel' %}
- Public
- {% else %}
- {% if msg.sender_tag_name or msg.sender_name %}
- {{ msg.sender_tag_name or msg.sender_name }}
- {% else %}
- {{ (msg.pubkey_prefix or '-')[:12] }}
- {% endif %}
- {% endif %}
-
- {{ msg.text or '-' }}
-
- {% if msg.receivers and msg.receivers|length >= 1 %}
-
- {% for recv in msg.receivers %}
-
📡
- {% endfor %}
-
- {% elif msg.received_by %}
- 📡
- {% else %}
- -
- {% endif %}
-
-
- {% else %}
-
- No messages found.
-
- {% endfor %}
-
-
-
-
-{{ pagination(page, total_pages, {"message_type": message_type, "limit": limit}) }}
-{% endblock %}
diff --git a/src/meshcore_hub/web/templates/node_detail.html b/src/meshcore_hub/web/templates/node_detail.html
deleted file mode 100644
index 3a2269b..0000000
--- a/src/meshcore_hub/web/templates/node_detail.html
+++ /dev/null
@@ -1,280 +0,0 @@
-{% extends "base.html" %}
-{% from "macros/icons.html" import icon_alert, icon_error %}
-
-{% block title %}{% if node %}{{ node.name or ('Node ' ~ public_key[:8] ~ '...') }} - {{ network_name }}{% else %}Node Not Found - {{ network_name }}{% endif %}{% endblock %}
-
-{% block extra_head %}
-
-{% endblock %}
-
-{% block content %}
-
-
- Home
- Nodes
- {% if node %}
- {% set ns = namespace(tag_name=none) %}
- {% for tag in node.tags or [] %}
- {% if tag.key == 'name' %}
- {% set ns.tag_name = tag.value %}
- {% endif %}
- {% endfor %}
- {{ ns.tag_name or node.name or public_key[:12] + '...' }}
- {% else %}
- Not Found
- {% endif %}
-
-
-
-{% if api_error %}
-
- {{ icon_alert("stroke-current shrink-0 h-6 w-6") }}
- Could not fetch data from API: {{ api_error }}
-
-{% endif %}
-
-{% if node %}
-{# Get display name from tag or node.name #}
-{% set ns = namespace(tag_name=none) %}
-{% for tag in node.tags or [] %}
- {% if tag.key == 'name' %}
- {% set ns.tag_name = tag.value %}
- {% endif %}
-{% endfor %}
-{% set display_name = ns.tag_name or node.name or 'Unnamed Node' %}
-
-{# Get coordinates from node model first, then fall back to tags (bug fix) #}
-{% set ns_coords = namespace(lat=node.lat, lon=node.lon) %}
-{% if not ns_coords.lat or not ns_coords.lon %}
- {% for tag in node.tags or [] %}
- {% if tag.key == 'lat' and not ns_coords.lat %}
- {% set ns_coords.lat = tag.value|float %}
- {% elif tag.key == 'lon' and not ns_coords.lon %}
- {% set ns_coords.lon = tag.value|float %}
- {% endif %}
- {% endfor %}
-{% endif %}
-{% set has_coords = ns_coords.lat is not none and ns_coords.lon is not none %}
-
-{# Node type emoji #}
-{% set type_emoji = '📍' %}
-{% if node.adv_type %}
- {% if node.adv_type|lower == 'chat' %}
- {% set type_emoji = '💬' %}
- {% elif node.adv_type|lower == 'repeater' %}
- {% set type_emoji = '📡' %}
- {% elif node.adv_type|lower == 'room' %}
- {% set type_emoji = '🪧' %}
- {% endif %}
-{% endif %}
-
-
-
- {{ type_emoji }}
- {{ display_name }}
-
-
-
-{% if has_coords %}
-
-{% else %}
-
-
-
-
-
Scan to add as contact
-
-
-{% endif %}
-
-
-
-
-
-
-
Public Key
- {{ node.public_key }}
-
-
-
-
-
- First seen:
- {{ node.first_seen|localtime }}
-
-
- Last seen:
- {{ node.last_seen|localtime }}
-
- {% if has_coords %}
-
- Location:
- {{ ns_coords.lat }}, {{ ns_coords.lon }}
-
- {% endif %}
-
-
-
-
-
-
-
-
-
Recent Advertisements
- {% if advertisements %}
-
- {% else %}
-
No advertisements recorded.
- {% endif %}
-
-
-
-
-
-
-
Tags
- {% if node.tags %}
-
-
-
-
- Key
- Value
- Type
-
-
-
- {% for tag in node.tags %}
-
- {{ tag.key }}
- {{ tag.value }}
- {{ tag.value_type or 'string' }}
-
- {% endfor %}
-
-
-
- {% else %}
-
No tags defined.
- {% endif %}
- {% if admin_enabled and is_authenticated %}
-
- {% endif %}
-
-
-
-
-{% else %}
-
- {{ icon_error("stroke-current shrink-0 h-6 w-6") }}
- Node not found: {{ public_key }}
-
-Back to Nodes
-{% endif %}
-{% endblock %}
-
-{% block extra_scripts %}
-{% if node %}
-{% set ns_qr = namespace(tag_name=none) %}
-{% for tag in node.tags or [] %}
- {% if tag.key == 'name' %}
- {% set ns_qr.tag_name = tag.value %}
- {% endif %}
-{% endfor %}
-
-
-
-{# Get coordinates from node model first, then fall back to tags #}
-{% set ns_map = namespace(lat=node.lat, lon=node.lon, name=none) %}
-{% if not ns_map.lat or not ns_map.lon %}
- {% for tag in node.tags or [] %}
- {% if tag.key == 'lat' and not ns_map.lat %}
- {% set ns_map.lat = tag.value|float %}
- {% elif tag.key == 'lon' and not ns_map.lon %}
- {% set ns_map.lon = tag.value|float %}
- {% endif %}
- {% endfor %}
-{% endif %}
-{% for tag in node.tags or [] %}
- {% if tag.key == 'name' %}
- {% set ns_map.name = tag.value %}
- {% endif %}
-{% endfor %}
-{% if ns_map.lat and ns_map.lon %}
-
-
-{% endif %}
-{% endif %}
-{% endblock %}
diff --git a/src/meshcore_hub/web/templates/nodes.html b/src/meshcore_hub/web/templates/nodes.html
deleted file mode 100644
index 878b984..0000000
--- a/src/meshcore_hub/web/templates/nodes.html
+++ /dev/null
@@ -1,179 +0,0 @@
-{% extends "base.html" %}
-{% from "_macros.html" import pagination %}
-{% from "macros/icons.html" import icon_alert %}
-
-{% block title %}Nodes - {{ network_name }}{% endblock %}
-
-{% block content %}
-
-
Nodes
-
- {% if timezone and timezone != 'UTC' %}{{ timezone }} {% endif %}
- {{ total }} total
-
-
-
-{% if api_error %}
-
- {{ icon_alert("stroke-current shrink-0 h-6 w-6") }}
- Could not fetch data from API: {{ api_error }}
-
-{% endif %}
-
-
-
-
-
-
-
- Search
-
-
-
-
-
- Type
-
-
- All Types
- Chat
- Repeater
- Room
-
-
- {% if members %}
-
-
- Member
-
-
- All Members
- {% for member in members %}
- {{ member.name }}{% if member.callsign %} ({{ member.callsign }}){% endif %}
- {% endfor %}
-
-
- {% endif %}
-
-
-
-
-
-
-
-
-
-
-
-{{ pagination(page, total_pages, {"search": search, "adv_type": adv_type, "member_id": member_id, "limit": limit}) }}
-{% endblock %}
diff --git a/src/meshcore_hub/web/templates/page.html b/src/meshcore_hub/web/templates/page.html
deleted file mode 100644
index 93bd3a0..0000000
--- a/src/meshcore_hub/web/templates/page.html
+++ /dev/null
@@ -1,15 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}{{ page.title }} - {{ network_name }}{% endblock %}
-
-{% block meta_description %}{{ page.title }} - {{ network_name }}{% endblock %}
-
-{% block content %}
-
-
-
- {{ page.content_html | safe }}
-
-
-
-{% endblock %}