Customization: packet type colors (ADVERT, GRP_TXT, etc.)

Added global window.TYPE_COLORS in roles.js. Live.js and audio-lab.js
now reference the global. Customizer shows packet type colors with
emoji + descriptions. Changes sync to TYPE_COLORS in real-time.
Saved/restored via localStorage alongside node colors.
This commit is contained in:
you
2026-03-23 01:29:56 +00:00
parent 5e81ad6c87
commit feceadf432
5 changed files with 83 additions and 7 deletions
+1 -1
View File
@@ -10,7 +10,7 @@
let speedMult = 1;
let highlightTimers = [];
const TYPE_COLORS = {
const TYPE_COLORS = window.TYPE_COLORS || {
ADVERT: '#f59e0b', GRP_TXT: '#10b981', TXT_MSG: '#6366f1',
TRACE: '#8b5cf6', REQ: '#ef4444', RESPONSE: '#3b82f6',
ACK: '#6b7280', PATH: '#ec4899', ANON_REQ: '#f97316', UNKNOWN: '#6b7280'
+71 -1
View File
@@ -63,6 +63,10 @@
sensor: '#d97706',
observer: '#8b5cf6'
},
typeColors: {
ADVERT: '#22c55e', GRP_TXT: '#3b82f6', TXT_MSG: '#f59e0b', ACK: '#6b7280',
REQUEST: '#a855f7', RESPONSE: '#06b6d4', TRACE: '#ec4899', PATH: '#14b8a6'
},
home: {
heroTitle: 'MeshCore Analyzer',
heroSubtitle: 'Find your nodes to start monitoring them.',
@@ -170,6 +174,24 @@
const NODE_EMOJI = { repeater: '◆', companion: '●', room: '■', sensor: '▲', observer: '★' };
const TYPE_LABELS = {
ADVERT: 'ADVERT', GRP_TXT: 'GRP_TXT', TXT_MSG: 'TXT_MSG', ACK: 'ACK',
REQUEST: 'REQUEST', RESPONSE: 'RESPONSE', TRACE: 'TRACE', PATH: 'PATH'
};
const TYPE_HINTS = {
ADVERT: 'Node advertisements — map, feed, packet list',
GRP_TXT: 'Group/channel messages — map, feed, channels',
TXT_MSG: 'Direct messages — map, feed',
ACK: 'Acknowledgments — packet list',
REQUEST: 'Requests — packet list, feed',
RESPONSE: 'Responses — packet list',
TRACE: 'Traceroute — map, traces page',
PATH: 'Path packets — packet list'
};
const TYPE_EMOJI = {
ADVERT: '📡', GRP_TXT: '💬', TXT_MSG: '✉️', ACK: '✓', REQUEST: '❓', RESPONSE: '📨', TRACE: '🔍', PATH: '🛤️'
};
// Current state
let state = {};
@@ -182,6 +204,7 @@
theme: Object.assign({}, DEFAULTS.theme, cfg.theme || {}),
themeDark: Object.assign({}, DEFAULTS.themeDark, cfg.themeDark || {}),
nodeColors: Object.assign({}, DEFAULTS.nodeColors, cfg.nodeColors || {}),
typeColors: Object.assign({}, DEFAULTS.typeColors, cfg.typeColors || {}),
home: {
heroTitle: (cfg.home && cfg.home.heroTitle) || DEFAULTS.home.heroTitle,
heroSubtitle: (cfg.home && cfg.home.heroSubtitle) || DEFAULTS.home.heroSubtitle,
@@ -376,8 +399,24 @@
(val !== def ? '<button class="cust-reset-btn" data-reset-node="' + key + '">Reset</button>' : '') +
'</div>';
}
var typeRows = '';
for (var tkey in TYPE_LABELS) {
var tval = state.typeColors[tkey];
var tdef = DEFAULTS.typeColors[tkey];
typeRows += '<div class="cust-color-row">' +
'<div><label>' + (TYPE_EMOJI[tkey] || '') + ' ' + TYPE_LABELS[tkey] + '</label>' +
'<div class="cust-hint">' + (TYPE_HINTS[tkey] || '') + '</div></div>' +
'<input type="color" data-type-color="' + tkey + '" value="' + tval + '">' +
'<span class="cust-node-dot" style="background:' + tval + '" data-tdot="' + tkey + '"></span>' +
'<span class="cust-hex" data-thex="' + tkey + '">' + tval + '</span>' +
(tval !== tdef ? '<button class="cust-reset-btn" data-reset-type="' + tkey + '">Reset</button>' : '') +
'</div>';
}
return '<div class="cust-panel' + (activeTab === 'nodes' ? ' active' : '') + '" data-panel="nodes">' +
'<p class="cust-section-title">Node Role Colors</p>' + rows + '</div>';
'<p class="cust-section-title">Node Role Colors</p>' + rows +
'<hr style="border:none;border-top:1px solid var(--border);margin:16px 0">' +
'<p class="cust-section-title">Packet Type Colors</p>' + typeRows +
'</div>';
}
function renderHome() {
@@ -451,6 +490,13 @@
}
if (Object.keys(nc).length) out.nodeColors = nc;
// Packet type colors
var tc = {};
for (var tck in DEFAULTS.typeColors) {
if (state.typeColors[tck] !== DEFAULTS.typeColors[tck]) tc[tck] = state.typeColors[tck];
}
if (Object.keys(tc).length) out.typeColors = tc;
// Home
var hm = {};
if (state.home.heroTitle !== DEFAULTS.home.heroTitle) hm.heroTitle = state.home.heroTitle;
@@ -599,6 +645,27 @@
});
});
// Packet type color pickers
container.querySelectorAll('input[data-type-color]').forEach(function (inp) {
inp.addEventListener('input', function () {
var key = inp.dataset.typeColor;
state.typeColors[key] = inp.value;
if (window.TYPE_COLORS) window.TYPE_COLORS[key] = inp.value;
var dot = container.querySelector('[data-tdot="' + key + '"]');
if (dot) dot.style.background = inp.value;
var hex = container.querySelector('[data-thex="' + key + '"]');
if (hex) hex.textContent = inp.value;
});
});
container.querySelectorAll('[data-reset-type]').forEach(function (btn) {
btn.addEventListener('click', function () {
var key = btn.dataset.resetType;
state.typeColors[key] = DEFAULTS.typeColors[key];
if (window.TYPE_COLORS) window.TYPE_COLORS[key] = DEFAULTS.typeColors[key];
render(container);
});
});
// Steps
container.querySelectorAll('[data-step-field]').forEach(function (inp) {
inp.addEventListener('input', function () {
@@ -786,6 +853,9 @@
}
}
}
if (userTheme.typeColors && window.TYPE_COLORS) {
Object.assign(window.TYPE_COLORS, userTheme.typeColors);
}
}
} catch {}
});
+4 -4
View File
@@ -81,7 +81,7 @@
<main id="app" role="main"></main>
<script src="vendor/qrcode.js"></script>
<script src="roles.js?v=1774325000"></script>
<script src="roles.js?v=1774229396"></script>
<script src="region-filter.js?v=1774325000"></script>
<script src="hop-resolver.js?v=1774223973"></script>
<script src="hop-display.js?v=1774221932"></script>
@@ -95,12 +95,12 @@
<script src="analytics.js?v=1774126708" onerror="console.error('Failed to load:', this.src)"></script>
<script src="audio.js?v=1774208460" onerror="console.error('Failed to load:', this.src)"></script>
<script src="audio-v1-constellation.js?v=1774207165" onerror="console.error('Failed to load:', this.src)"></script>
<script src="audio-lab.js?v=1774208460" onerror="console.error('Failed to load:', this.src)"></script>
<script src="live.js?v=1774218049" onerror="console.error('Failed to load:', this.src)"></script>
<script src="audio-lab.js?v=1774229396" onerror="console.error('Failed to load:', this.src)"></script>
<script src="live.js?v=1774229396" onerror="console.error('Failed to load:', this.src)"></script>
<script src="observers.js?v=1774290000" onerror="console.error('Failed to load:', this.src)"></script>
<script src="observer-detail.js?v=1774219440" onerror="console.error('Failed to load:', this.src)"></script>
<script src="node-analytics.js?v=1774126708" onerror="console.error('Failed to load:', this.src)"></script>
<script src="perf.js?v=1773985649" onerror="console.error('Failed to load:', this.src)"></script>
<script src="customize.js?v=1774229133" onerror="console.error('Failed to load:', this.src)"></script>
<script src="customize.js?v=1774229396" onerror="console.error('Failed to load:', this.src)"></script>
</body>
</html>
+1 -1
View File
@@ -36,7 +36,7 @@
// ROLE_COLORS loaded from shared roles.js (includes 'unknown')
const TYPE_COLORS = {
const TYPE_COLORS = window.TYPE_COLORS || {
ADVERT: '#22c55e', GRP_TXT: '#3b82f6', TXT_MSG: '#f59e0b', ACK: '#6b7280',
REQUEST: '#a855f7', RESPONSE: '#06b6d4', TRACE: '#ec4899', PATH: '#14b8a6'
};
+6
View File
@@ -14,6 +14,12 @@
sensor: '#d97706', observer: '#8b5cf6', unknown: '#6b7280'
};
window.TYPE_COLORS = {
ADVERT: '#22c55e', GRP_TXT: '#3b82f6', TXT_MSG: '#f59e0b', ACK: '#6b7280',
REQUEST: '#a855f7', RESPONSE: '#06b6d4', TRACE: '#ec4899', PATH: '#14b8a6',
UNKNOWN: '#6b7280'
};
window.ROLE_LABELS = {
repeater: 'Repeaters', companion: 'Companions', room: 'Room Servers',
sensor: 'Sensors', observer: 'Observers'