feat: add neon color picker for wallet management
- Replace muted Tailwind palette with 16-color neon palette - Add clickable color dot in sidebar that opens a popup swatch grid - Allow color override for all wallets (including embedded) - Fix getColorForWallet to respect localStorage override - Fix duplicate renameWallet in wallets.js - Update Dockerfile to serve ESM modules via nginx
This commit is contained in:
93
index.html
93
index.html
@ -47,6 +47,37 @@ window.WalletManager = WalletManager;
|
||||
.wallet-filter-toggle { appearance: none; width: 12px; height: 12px; border-radius: 2px; border: 1px solid rgba(255,255,255,0.2); cursor: pointer; position: relative; transition: all 0.2s; }
|
||||
.wallet-filter-toggle:checked { background: var(--wallet-color); border-color: transparent; box-shadow: 0 0 8px color-mix(in srgb, var(--wallet-color) 40%, transparent); }
|
||||
|
||||
.wallet-color-dot {
|
||||
width: 16px; height: 16px; border-radius: 50%; cursor: pointer;
|
||||
flex-shrink: 0; transition: transform 0.15s, box-shadow 0.15s;
|
||||
}
|
||||
.wallet-color-dot:hover {
|
||||
transform: scale(1.25); box-shadow: 0 0 10px var(--wallet-color);
|
||||
}
|
||||
|
||||
.color-picker-overlay {
|
||||
position: fixed; inset: 0; z-index: 70; display: none; background: rgba(0,0,0,0.5);
|
||||
}
|
||||
.color-picker-overlay.open { display: block; }
|
||||
.color-picker-popup {
|
||||
position: absolute; background: #090D14; border: 1px solid #1A1F2C;
|
||||
border-radius: 12px; padding: 12px; box-shadow: 0 16px 40px rgba(0,0,0,0.7);
|
||||
display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;
|
||||
z-index: 80; width: 210px;
|
||||
}
|
||||
.color-picker-swatch {
|
||||
width: 36px; height: 36px; border-radius: 50%; cursor: pointer;
|
||||
transition: transform 0.15s, box-shadow 0.15s;
|
||||
border: 2px solid transparent;
|
||||
}
|
||||
.color-picker-swatch:hover {
|
||||
transform: scale(1.2); border-color: rgba(255,255,255,0.3);
|
||||
box-shadow: 0 0 12px var(--swatch-color);
|
||||
}
|
||||
.color-picker-swatch.selected {
|
||||
border-color: #fff; box-shadow: 0 0 14px var(--swatch-color);
|
||||
}
|
||||
|
||||
.ledger-header { display: flex; align-items: center; }
|
||||
.ledger-title-col { width: 260px; flex-shrink: 0; }
|
||||
.col-timestamp { width: 140px; flex-shrink: 0; }
|
||||
@ -117,6 +148,9 @@ window.WalletManager = WalletManager;
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Color Picker Popup -->
|
||||
<div id="color-picker-overlay" class="color-picker-overlay" onclick="closeColorPicker()"></div>
|
||||
|
||||
<!-- Main Dashboard -->
|
||||
<div class="max-w-7xl mx-auto">
|
||||
<!-- Top Nav Bar -->
|
||||
@ -338,7 +372,7 @@ window.WalletManager = WalletManager;
|
||||
const orangeBrandColor = '#FF7A00';
|
||||
const blueBrandColor = '#3b82f6';
|
||||
const API_BASE = window.location.origin;
|
||||
const WALLET_COLORS = ['#f7931a','#58a6ff','#22c55e','#f472b6','#a78bfa','#fb923c','#14b8a6','#8b5cf6','#facc15','#ec4899'];
|
||||
const WALLET_COLORS = ['#F7931A','#FF007F','#39FF14','#00FFFF','#CCFF00','#9D00FF','#FF0033','#00FFCC','#FF00FF','#007FFF','#DEFF0A','#FF5E00','#8A2BE2','#00FF66','#FF1493','#7B00FF'];
|
||||
const TOKENS = {"cbBTC": {"decimals": 8, "priceSymbol": "BTC"}, "WETH": {"decimals": 18, "priceSymbol": "WETH"}, "USDC": {"decimals": 6, "priceSymbol": "USDC"}};
|
||||
|
||||
/* Embedded data for hardcoded wallets */
|
||||
@ -388,10 +422,10 @@ function findEmbeddedId(address) {
|
||||
/* Assigned color index for dynamic wallets */
|
||||
let _colorIdx = 0;
|
||||
function getColorForWallet(address) {
|
||||
const embedded = findEmbeddedId(address);
|
||||
if (embedded && walletsMetadata[embedded].color) return walletsMetadata[embedded].color;
|
||||
const c = localStorage.getItem('cbbtc_color_' + address);
|
||||
if (c) return c;
|
||||
const embedded = findEmbeddedId(address);
|
||||
if (embedded && walletsMetadata[embedded].color) return walletsMetadata[embedded].color;
|
||||
const color = WALLET_COLORS[_colorIdx % WALLET_COLORS.length];
|
||||
_colorIdx++;
|
||||
localStorage.setItem('cbbtc_color_' + address, color);
|
||||
@ -399,8 +433,6 @@ function getColorForWallet(address) {
|
||||
}
|
||||
|
||||
function setColorForWallet(address, color) {
|
||||
const embedded = findEmbeddedId(address);
|
||||
if (embedded) return; /* embedded wallets have fixed colors */
|
||||
localStorage.setItem('cbbtc_color_' + address, color);
|
||||
renderAll();
|
||||
}
|
||||
@ -417,6 +449,55 @@ function getNextColor(address) {
|
||||
return WALLET_COLORS[nextIdx];
|
||||
}
|
||||
|
||||
/* Color Picker */
|
||||
let _colorPickerTargetAddr = null;
|
||||
|
||||
function openColorPicker(event, address) {
|
||||
event.stopPropagation();
|
||||
_colorPickerTargetAddr = address;
|
||||
const overlay = document.getElementById('color-picker-overlay');
|
||||
const popup = document.getElementById('color-picker-popup');
|
||||
|
||||
if (popup) popup.remove();
|
||||
|
||||
const newPopup = document.createElement('div');
|
||||
newPopup.id = 'color-picker-popup';
|
||||
newPopup.className = 'color-picker-popup';
|
||||
newPopup.style.left = event.clientX + 'px';
|
||||
newPopup.style.top = event.clientY + 'px';
|
||||
const currentColor = getColorForWallet(address);
|
||||
WALLET_COLORS.forEach((c, i) => {
|
||||
const swatch = document.createElement('div');
|
||||
swatch.className = 'color-picker-swatch' + (c.toLowerCase() === currentColor.toLowerCase() ? ' selected' : '');
|
||||
swatch.style.setProperty('--swatch-color', c);
|
||||
swatch.style.background = c;
|
||||
swatch.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
selectColor(c);
|
||||
closeColorPicker();
|
||||
});
|
||||
newPopup.appendChild(swatch);
|
||||
});
|
||||
document.body.appendChild(newPopup);
|
||||
const rect = newPopup.getBoundingClientRect();
|
||||
if (rect.right > window.innerWidth) newPopup.style.left = (event.clientX - rect.width) + 'px';
|
||||
if (rect.bottom > window.innerHeight) newPopup.style.top = (event.clientY - rect.height) + 'px';
|
||||
overlay.classList.add('open');
|
||||
}
|
||||
|
||||
function closeColorPicker() {
|
||||
document.getElementById('color-picker-overlay').classList.remove('open');
|
||||
const popup = document.getElementById('color-picker-popup');
|
||||
if (popup) popup.remove();
|
||||
_colorPickerTargetAddr = null;
|
||||
}
|
||||
|
||||
function selectColor(color) {
|
||||
if (_colorPickerTargetAddr) {
|
||||
setColorForWallet(_colorPickerTargetAddr, color);
|
||||
}
|
||||
}
|
||||
|
||||
/* Wallet filter state — stores UNCHECKED addresses. Empty = all checked. */
|
||||
function getWalletFilter() {
|
||||
return JSON.parse(localStorage.getItem('cbbtc_ledger_wallets') || '[]');
|
||||
@ -503,7 +584,7 @@ function renderSidebar() {
|
||||
const nick = w.nickname || shortAddr;
|
||||
html += '<div class="flex items-center justify-between bg-[#05070B] border border-[#1A1F2C]/40 rounded-lg px-3 py-2.5">' +
|
||||
'<div class="flex items-center gap-2.5 min-w-0 flex-1">' +
|
||||
'<div onclick="cycleWalletColor(\'' + w.address + '\')" class="wallet-filter-toggle cursor-pointer flex-shrink-0" style="--wallet-color:' + color + ';" title="Click to change color"></div>' +
|
||||
'<div onclick="openColorPicker(event, \'' + w.address + '\')" class="wallet-color-dot" style="--wallet-color:' + color + ';background:' + color + ';" title="Click to change color"></div>' +
|
||||
'<div class="min-w-0 flex-1">' +
|
||||
'<input class="rename-nick-input bg-transparent text-sm font-medium text-white truncate border border-transparent focus:border-[#FF7A00]/50 rounded px-1 outline-none transition block w-full" value="' + nick + '" data-addr="' + w.address + '" data-chain="' + w.chain + '" onblur="handleRenameNickname(this)" onkeydown="if(event.key===\'Enter\')this.blur()">' +
|
||||
'<div class="text-[10px] text-gray-500 font-mono truncate">' + shortAddr + '</div>' +
|
||||
|
||||
Reference in New Issue
Block a user