Upgrade explorer more menu into grouped tools hub

This commit is contained in:
defiQUG
2026-03-27 12:11:18 -07:00
parent 2491336b8e
commit 0f4630f443

View File

@@ -3670,29 +3670,147 @@
if ((window.location.pathname || '').replace(/^\//, '').split('/')[0] !== 'more') updatePath('/more');
var container = document.getElementById('moreContent');
if (!container) return;
var cards = [
{ href: '/bridge', icon: 'fa-bridge', title: 'Bridge', desc: 'Inspect CCIP routes, bridge endpoints, and cross-chain references.', action: 'showBridgeMonitoring();' },
{ href: '/weth', icon: 'fa-coins', title: 'WETH', desc: 'Wrap and unwrap WETH9 / WETH10 and review utility contract details.', action: 'showWETHUtilities();' },
{ href: '/liquidity', icon: 'fa-wave-square', title: 'Liquidity', desc: 'Open the public liquidity map, route matrix endpoints, partner payload templates, and fallback execution access.', action: 'showLiquidityAccess();' },
{ href: '/tokens', icon: 'fa-tag', title: 'Tokens', desc: 'Browse the indexed token list and jump into token detail pages.', action: 'showTokensList();' },
{ href: '/addresses', icon: 'fa-address-book', title: 'Addresses', desc: 'Review indexed addresses, labels, contract status, and recent activity.', action: 'showAddresses();' },
{ href: '/watchlist', icon: 'fa-star', title: 'Watchlist', desc: 'Track saved addresses and revisit them quickly.', action: 'showWatchlist();' },
{ href: '/pools', icon: 'fa-water', title: 'Pools', desc: 'Review the liquidity snapshot and config caps for public pools and reserve links.', action: 'openPoolsView();' },
{ href: '/analytics', icon: 'fa-chart-line', title: 'Analytics', desc: 'Open the Track 3 analytics hub for network and bridge insight.', action: 'showAnalytics();' },
{ href: '/operator', icon: 'fa-cog', title: 'Operator', desc: 'Open the Track 4 operator panel for deployment and maintenance tools.', action: 'showOperator();' }
var groups = [
{
key: 'tools',
title: 'Tools',
items: [
{ title: 'Input Data Decoder', icon: 'fa-file-code', status: 'Live', badgeClass: 'badge-info', desc: 'Open transaction detail pages to decode calldata, logs, and contract interactions already exposed by the explorer.', action: 'showTransactionsList();', href: '/transactions' },
{ title: 'Unit Converter', icon: 'fa-scale-balanced', status: 'Live', badgeClass: 'badge-success', desc: 'Convert wei, gwei, ether, and common Chain 138 stablecoin units with a quick in-page helper.', action: 'showUnitConverterModal();', href: '/more' },
{ title: 'CSV Export', icon: 'fa-file-csv', status: 'Live', badgeClass: 'badge-success', desc: 'Export pool state and route inventory snapshots for operator review and downstream ingestion.', action: 'showPools(); updatePath(\'/pools\'); setTimeout(function(){ if (typeof exportPoolsCSV === \"function\") exportPoolsCSV(); }, 200);', href: '/pools' },
{ title: 'Account Balance Checker', icon: 'fa-wallet', status: 'Live', badgeClass: 'badge-success', desc: 'Jump into indexed addresses to inspect balances, token inventory, internal transfers, and recent activity.', action: 'showAddresses();', href: '/addresses' }
]
},
{
key: 'explore',
title: 'Explore',
items: [
{ title: 'Gas Tracker', icon: 'fa-gas-pump', status: 'Live', badgeClass: 'badge-success', desc: 'Review live gas, block time, TPS, and chain health from the analytics and home dashboards.', action: 'showAnalytics();', href: '/analytics' },
{ title: 'DEX Tracker', icon: 'fa-chart-line', status: 'Live', badgeClass: 'badge-success', desc: 'Open liquidity discovery, PMM pool status, live route trees, and partner payload access points.', action: 'showLiquidityAccess();', href: '/liquidity' },
{ title: 'Node Tracker', icon: 'fa-server', status: 'Live', badgeClass: 'badge-success', desc: 'Inspect bridge and operator infrastructure surfaces already exposed in the Bridge and Operator panels.', action: 'showOperator();', href: '/operator' },
{ title: 'Label Cloud', icon: 'fa-tags', status: 'Live', badgeClass: 'badge-success', desc: 'Browse labeled addresses, contracts, and address activity through the explorer address index.', action: 'showAddresses();', href: '/addresses' },
{ title: 'Domain Name Lookup', icon: 'fa-magnifying-glass', status: 'Live', badgeClass: 'badge-success', desc: 'Use the smart search launcher to resolve ENS-style names, domains, addresses, hashes, and token symbols.', action: 'openSmartSearchModal(\'\');', href: '/more' }
]
},
{
key: 'services',
title: 'Services',
items: [
{ title: 'Token Approvals', icon: 'fa-shield-halved', status: 'External', badgeClass: 'badge-warning', desc: 'Jump to revoke.cash for wallet approval review. Address detail pages also expose approval shortcuts directly.', action: 'openExternalMoreLink(\'https://revoke.cash/\');', href: '#' },
{ title: 'Verified Signature', icon: 'fa-signature', status: 'Live', badgeClass: 'badge-success', desc: 'Use wallet sign-in and verified address flows already built into the explorer authentication surfaces.', action: 'showWalletModal();', href: '/more' },
{ title: 'Input Data Messages', icon: 'fa-message', status: 'Live', badgeClass: 'badge-info', desc: 'Transaction detail pages already surface decoded input data, event logs, and contract interaction context.', action: 'showTransactionsList();', href: '/transactions' },
{ title: 'Advanced Filter', icon: 'fa-filter', status: 'Live', badgeClass: 'badge-success', desc: 'Block, transaction, address, token, pool, bridge, and watchlist screens all support focused page-level filtering.', action: 'showTransactionsList();', href: '/transactions' },
{ title: 'Blockscan Chat', icon: 'fa-comments', status: 'Soon', badgeClass: 'badge-muted', desc: 'Messaging and collaborative address discussion are not exposed yet in SolaceScanScout.', disabled: true, href: '/more' }
]
}
];
var html = '<div style="display:grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1rem;">';
cards.forEach(function(card) {
html += '<a href="' + card.href + '" onclick="event.preventDefault(); ' + card.action + ' updatePath(\'' + card.href + '\'); closeNavMenu();" style="display:block; text-decoration:none; color:inherit; border:1px solid var(--border); border-radius: 14px; padding: 1rem; background: var(--light); box-shadow: 0 2px 8px rgba(0,0,0,0.04);">';
html += '<div style="display:flex; align-items:center; gap:0.75rem; margin-bottom:0.75rem;"><span style="width:2.2rem; height:2.2rem; border-radius:50%; display:inline-flex; align-items:center; justify-content:center; background: rgba(102,126,234,0.12); color: var(--primary);"><i class="fas ' + escapeHtml(card.icon) + '"></i></span><strong style="font-size:1rem;">' + escapeHtml(card.title) + '</strong></div>';
html += '<div style="color: var(--text-light); font-size: 0.92rem; line-height: 1.5;">' + escapeHtml(card.desc) + '</div>';
html += '</a>';
var html = '<div style="display:grid; grid-template-columns:minmax(240px, 0.9fr) repeat(3, minmax(220px, 1fr)); gap:1rem; align-items:start;">';
html += '<div style="border:1px solid var(--border); border-radius:18px; padding:1.25rem; background:linear-gradient(180deg, rgba(59,130,246,0.08), rgba(15,23,42,0.02)); min-height:100%;">';
html += '<div style="font-size:1.25rem; font-weight:800; margin-bottom:0.75rem;">Tools &amp; Services</div>';
html += '<div style="color:var(--text-light); line-height:1.7; margin-bottom:1rem;">Discover more of SolaceScanScout&apos;s explorer tools in one place, grouped the way users expect from Etherscan-style explorers.</div>';
html += '<div style="display:grid; gap:0.75rem;">';
html += '<div style="padding:0.85rem; border:1px solid var(--border); border-radius:14px; background:var(--muted-surface);"><div style="font-size:0.82rem; text-transform:uppercase; letter-spacing:0.08em; color:var(--text-light); margin-bottom:0.35rem;">Now live</div><div style="font-weight:700;">Route matrix, ingestion APIs, smart search, pool exports, and live Mainnet stable bridge discovery.</div></div>';
html += '<div style="padding:0.85rem; border:1px solid var(--border); border-radius:14px; background:var(--muted-surface);"><div style="font-size:0.82rem; text-transform:uppercase; letter-spacing:0.08em; color:var(--text-light); margin-bottom:0.35rem;">Good entry points</div><div style="display:flex; flex-wrap:wrap; gap:0.5rem;">';
html += '<button type="button" class="btn btn-primary" onclick="showLiquidityAccess(); updatePath(\'/liquidity\');"><i class="fas fa-wave-square"></i> Liquidity</button>';
html += '<button type="button" class="btn btn-secondary" onclick="openSmartSearchModal(\'\');"><i class="fas fa-magnifying-glass"></i> Search</button>';
html += '<button type="button" class="btn btn-secondary" onclick="showAddresses(); updatePath(\'/addresses\');"><i class="fas fa-address-book"></i> Addresses</button>';
html += '</div></div>';
html += '</div></div>';
groups.forEach(function(group) {
html += '<div style="border:1px solid var(--border); border-radius:18px; padding:1.1rem; background:var(--light); min-height:100%;">';
html += '<div style="font-size:1.1rem; font-weight:800; margin-bottom:0.85rem;">' + escapeHtml(group.title) + '</div>';
html += '<div style="display:grid; gap:0.7rem;">';
group.items.forEach(function(item) {
var disabled = !!item.disabled;
var disabledTitle = String(item.title) + ' is not exposed in the explorer yet.';
var onclick = disabled
? ('event.preventDefault(); showToast(' + JSON.stringify(disabledTitle) + ', "info");')
: (item.href === '#'
? ('event.preventDefault(); ' + item.action + ' closeNavMenu();')
: ('event.preventDefault(); ' + item.action + ' updatePath(' + JSON.stringify(item.href) + '); closeNavMenu();'));
var href = disabled ? '/more' : item.href;
html += '<a href="' + escapeAttr(href) + '" onclick="' + onclick + '" style="display:block; text-decoration:none; color:inherit; border:1px solid var(--border); border-radius:14px; padding:0.9rem; background:' + (disabled ? 'rgba(148,163,184,0.08)' : 'var(--muted-surface)') + '; opacity:' + (disabled ? '0.78' : '1') + ';">';
html += '<div style="display:flex; justify-content:space-between; gap:0.75rem; align-items:flex-start; margin-bottom:0.45rem;">';
html += '<div style="display:flex; align-items:center; gap:0.65rem; min-width:0;">';
html += '<span style="width:2rem; height:2rem; border-radius:999px; display:inline-flex; align-items:center; justify-content:center; background:rgba(59,130,246,0.12); color:var(--primary); flex:0 0 auto;"><i class="fas ' + escapeHtml(item.icon) + '"></i></span>';
html += '<strong style="line-height:1.35;">' + escapeHtml(item.title) + '</strong>';
html += '</div>';
html += '<span class="badge ' + escapeHtml(item.badgeClass || 'badge-info') + '" style="white-space:nowrap;">' + escapeHtml(item.status) + '</span>';
html += '</div>';
html += '<div style="color:var(--text-light); font-size:0.9rem; line-height:1.55;">' + escapeHtml(item.desc) + '</div>';
html += '</a>';
});
html += '</div></div>';
});
html += '</div>';
container.innerHTML = html;
}
window._showMore = renderMoreView;
window.showUnitConverterModal = function() {
var existing = document.getElementById('unitConverterModal');
if (existing) existing.remove();
var modal = document.createElement('div');
modal.id = 'unitConverterModal';
modal.style.cssText = 'position:fixed; inset:0; background:rgba(8,15,32,0.68); backdrop-filter:blur(8px); z-index:12000; display:flex; align-items:center; justify-content:center; padding:1rem;';
modal.innerHTML = '' +
'<div style="width:min(560px, 100%); border-radius:18px; border:1px solid var(--border); background:var(--background); box-shadow:0 24px 90px rgba(0,0,0,0.35); overflow:hidden;">' +
'<div style="display:flex; justify-content:space-between; align-items:center; padding:1rem 1.1rem; border-bottom:1px solid var(--border);">' +
'<div><div style="font-size:1.1rem; font-weight:800;">Unit Converter</div><div style="color:var(--text-light); font-size:0.9rem; margin-top:0.2rem;">Wei, gwei, ether, and 6-decimal stablecoin units for Chain 138.</div></div>' +
'<button type="button" class="btn btn-secondary" id="unitConverterCloseBtn"><i class="fas fa-times"></i></button>' +
'</div>' +
'<div style="padding:1rem 1.1rem; display:grid; gap:0.9rem;">' +
'<label style="display:grid; gap:0.35rem;"><span style="font-weight:700;">Amount</span><input id="unitConverterAmount" type="number" min="0" step="any" placeholder="1.0" style="padding:0.8rem 0.9rem; border:1px solid var(--border); border-radius:12px; background:var(--light); color:var(--text);"></label>' +
'<label style="display:grid; gap:0.35rem;"><span style="font-weight:700;">Unit</span><select id="unitConverterUnit" style="padding:0.8rem 0.9rem; border:1px solid var(--border); border-radius:12px; background:var(--light); color:var(--text);"><option value="ether">Ether / WETH</option><option value="gwei">Gwei</option><option value="wei">Wei</option><option value="stable">Stablecoin (6 decimals)</option></select></label>' +
'<div id="unitConverterResults" style="display:grid; gap:0.55rem;"></div>' +
'</div>' +
'</div>';
document.body.appendChild(modal);
function renderUnitConverterResults() {
var amountEl = document.getElementById('unitConverterAmount');
var unitEl = document.getElementById('unitConverterUnit');
var resultsEl = document.getElementById('unitConverterResults');
if (!amountEl || !unitEl || !resultsEl) return;
var amount = Number(amountEl.value || '0');
var unit = unitEl.value;
if (!isFinite(amount) || amount < 0) {
resultsEl.innerHTML = '<div style="color:var(--text-light);">Enter a non-negative amount to convert.</div>';
return;
}
var wei = 0;
if (unit === 'ether') wei = amount * 1e18;
else if (unit === 'gwei') wei = amount * 1e9;
else if (unit === 'wei') wei = amount;
else if (unit === 'stable') wei = amount * 1e6;
var etherValue = unit === 'stable' ? 'N/A' : (wei / 1e18).toLocaleString(undefined, { maximumFractionDigits: 18 });
var gweiValue = unit === 'stable' ? 'N/A' : (wei / 1e9).toLocaleString(undefined, { maximumFractionDigits: 9 });
var stableValue = (unit === 'stable' ? amount : wei / 1e6).toLocaleString(undefined, { maximumFractionDigits: 6 });
resultsEl.innerHTML =
'<div style="padding:0.8rem; border:1px solid var(--border); border-radius:12px; background:var(--muted-surface);"><strong>Wei:</strong> ' + escapeHtml(Math.round(wei).toString()) + '</div>' +
'<div style="padding:0.8rem; border:1px solid var(--border); border-radius:12px; background:var(--muted-surface);"><strong>Gwei:</strong> ' + escapeHtml(gweiValue) + '</div>' +
'<div style="padding:0.8rem; border:1px solid var(--border); border-radius:12px; background:var(--muted-surface);"><strong>Ether / WETH:</strong> ' + escapeHtml(etherValue) + '</div>' +
'<div style="padding:0.8rem; border:1px solid var(--border); border-radius:12px; background:var(--muted-surface);"><strong>6-decimal stable amount:</strong> ' + escapeHtml(stableValue) + '</div>';
}
var closeBtn = document.getElementById('unitConverterCloseBtn');
if (closeBtn) closeBtn.addEventListener('click', function() { modal.remove(); });
modal.addEventListener('click', function(event) {
if (event.target === modal) modal.remove();
});
var amountEl = document.getElementById('unitConverterAmount');
var unitEl = document.getElementById('unitConverterUnit');
if (amountEl) amountEl.addEventListener('input', renderUnitConverterResults);
if (unitEl) unitEl.addEventListener('change', renderUnitConverterResults);
renderUnitConverterResults();
};
window.openExternalMoreLink = function(url) {
window.open(url, '_blank', 'noopener,noreferrer');
};
async function refreshBridgeData() {
const container = document.getElementById('bridgeContent');
if (!container) return;