Upgrade explorer more menu into grouped tools hub
This commit is contained in:
@@ -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 & Services</div>';
|
||||
html += '<div style="color:var(--text-light); line-height:1.7; margin-bottom:1rem;">Discover more of SolaceScanScout'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;
|
||||
|
||||
Reference in New Issue
Block a user