feat: multi-wallet support - Phantom, Solflare, Backpack, Coinbase, Trust, MetaMask
This commit is contained in:
parent
d0d13c3f30
commit
b71361d7ab
2 changed files with 266 additions and 11 deletions
|
|
@ -446,3 +446,155 @@
|
|||
font-size: 0.6rem;
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
/* Wallet Modal */
|
||||
.sol-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sol-modal.hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.sol-modal-backdrop {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.sol-modal-content {
|
||||
position: relative;
|
||||
background: rgba(12, 12, 12, 0.98);
|
||||
border: 1px solid rgba(138, 43, 226, 0.3);
|
||||
border-top: 2px solid #a855f7;
|
||||
width: 90%;
|
||||
max-width: 420px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.sol-modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 1rem 1.25rem;
|
||||
border-bottom: 1px solid rgba(138, 43, 226, 0.15);
|
||||
}
|
||||
|
||||
.sol-modal-title {
|
||||
font-family: 'Orbitron', monospace;
|
||||
font-size: 0.7rem;
|
||||
color: #a855f7;
|
||||
letter-spacing: 3px;
|
||||
}
|
||||
|
||||
.sol-modal-close {
|
||||
background: transparent;
|
||||
border: 1px solid rgba(255, 255, 255, 0.15);
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
font-size: 0.75rem;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.sol-modal-close:hover {
|
||||
border-color: rgba(255, 50, 50, 0.5);
|
||||
color: rgba(255, 50, 50, 0.8);
|
||||
}
|
||||
|
||||
.sol-modal-body {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.sol-modal-footer {
|
||||
padding: 0.75rem 1.25rem;
|
||||
border-top: 1px solid rgba(138, 43, 226, 0.1);
|
||||
}
|
||||
|
||||
.sol-modal-hint {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 0.55rem;
|
||||
color: rgba(255, 255, 255, 0.25);
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
/* Wallet Options */
|
||||
.sol-wallet-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
width: 100%;
|
||||
padding: 0.85rem 1rem;
|
||||
background: rgba(20, 20, 20, 0.6);
|
||||
border: 1px solid rgba(138, 43, 226, 0.12);
|
||||
color: #ffffff;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
margin-bottom: 0.4rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.sol-wallet-option:hover {
|
||||
background: rgba(138, 43, 226, 0.1);
|
||||
border-color: rgba(138, 43, 226, 0.35);
|
||||
transform: translateX(3px);
|
||||
}
|
||||
|
||||
.sol-wallet-option.not-installed {
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
.sol-wallet-option.not-installed:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.sol-wallet-option-icon {
|
||||
font-size: 1.2rem;
|
||||
width: 28px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.sol-wallet-option-name {
|
||||
font-family: 'Orbitron', monospace;
|
||||
font-size: 0.65rem;
|
||||
letter-spacing: 2px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.sol-wallet-option-status {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 0.5rem;
|
||||
letter-spacing: 1px;
|
||||
color: #00cc44;
|
||||
}
|
||||
|
||||
.sol-wallet-option.not-installed .sol-wallet-option-status {
|
||||
color: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.sol-wallet-divider {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 0.5rem;
|
||||
color: rgba(255, 255, 255, 0.2);
|
||||
letter-spacing: 2px;
|
||||
padding: 0.75rem 1rem 0.4rem;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
||||
margin-top: 0.25rem;
|
||||
}
|
||||
|
|
|
|||
123
js/soldomains.js
123
js/soldomains.js
|
|
@ -244,10 +244,109 @@ async function doReverse() {
|
|||
}
|
||||
|
||||
// ─── WALLET ─────────────────────────────────────────────────
|
||||
let connectedProvider = null;
|
||||
|
||||
const WALLETS = [
|
||||
{ name: 'PHANTOM', icon: '👻', detect: () => window.phantom?.solana, url: 'https://phantom.app' },
|
||||
{ name: 'SOLFLARE', icon: '🔆', detect: () => window.solflare, url: 'https://solflare.com' },
|
||||
{ name: 'BACKPACK', icon: '🎒', detect: () => window.backpack, url: 'https://backpack.app' },
|
||||
{ name: 'COINBASE', icon: '🔵', detect: () => window.coinbaseSolana, url: 'https://coinbase.com/wallet' },
|
||||
{ name: 'TRUST', icon: '🛡️', detect: () => window.trustwallet?.solana, url: 'https://trustwallet.com' },
|
||||
{ name: 'METAMASK', icon: '🦊', detect: () => window.ethereum?.isSolana ? window.ethereum : null, url: 'https://metamask.io' },
|
||||
];
|
||||
|
||||
function getAvailableWallets() {
|
||||
const available = [];
|
||||
for (const w of WALLETS) {
|
||||
try {
|
||||
const provider = w.detect();
|
||||
if (provider) available.push({ ...w, provider });
|
||||
} catch(e) {}
|
||||
}
|
||||
// Fallback: check generic window.solana if no specific wallet matched
|
||||
if (available.length === 0 && window.solana) {
|
||||
available.push({ name: 'SOLANA WALLET', icon: '◈', provider: window.solana, url: '#' });
|
||||
}
|
||||
return available;
|
||||
}
|
||||
|
||||
function initWallet() {
|
||||
const btn = $('#wallet-btn');
|
||||
if (!btn) return;
|
||||
btn.addEventListener('click', toggleWallet);
|
||||
createWalletModal();
|
||||
}
|
||||
|
||||
function createWalletModal() {
|
||||
const modal = document.createElement('div');
|
||||
modal.id = 'wallet-modal';
|
||||
modal.className = 'sol-modal hidden';
|
||||
modal.innerHTML = `
|
||||
<div class="sol-modal-backdrop"></div>
|
||||
<div class="sol-modal-content">
|
||||
<div class="sol-modal-header">
|
||||
<span class="sol-modal-title">SELECT WALLET</span>
|
||||
<button class="sol-modal-close" id="modal-close">✕</button>
|
||||
</div>
|
||||
<div class="sol-modal-body" id="wallet-list"></div>
|
||||
<div class="sol-modal-footer">
|
||||
<span class="sol-modal-hint">No wallet? Install one to connect to Solana</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(modal);
|
||||
|
||||
modal.querySelector('.sol-modal-backdrop').addEventListener('click', closeModal);
|
||||
modal.querySelector('#modal-close').addEventListener('click', closeModal);
|
||||
}
|
||||
|
||||
function openModal() {
|
||||
const modal = $('#wallet-modal');
|
||||
const list = $('#wallet-list');
|
||||
const available = getAvailableWallets();
|
||||
|
||||
let html = '';
|
||||
|
||||
if (available.length > 0) {
|
||||
html += available.map(w => `
|
||||
<button class="sol-wallet-option" data-wallet="${w.name}">
|
||||
<span class="sol-wallet-option-icon">${w.icon}</span>
|
||||
<span class="sol-wallet-option-name">${w.name}</span>
|
||||
<span class="sol-wallet-option-status">DETECTED</span>
|
||||
</button>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
// Show install links for wallets not detected
|
||||
const notInstalled = WALLETS.filter(w => { try { return !w.detect(); } catch(e) { return true; } });
|
||||
if (notInstalled.length > 0) {
|
||||
html += '<div class="sol-wallet-divider">NOT INSTALLED</div>';
|
||||
html += notInstalled.map(w => `
|
||||
<a href="${w.url}" target="_blank" rel="noopener" class="sol-wallet-option not-installed">
|
||||
<span class="sol-wallet-option-icon">${w.icon}</span>
|
||||
<span class="sol-wallet-option-name">${w.name}</span>
|
||||
<span class="sol-wallet-option-status">INSTALL ↗</span>
|
||||
</a>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
list.innerHTML = html;
|
||||
|
||||
// Bind click handlers for detected wallets
|
||||
list.querySelectorAll('.sol-wallet-option:not(.not-installed)').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const name = btn.dataset.wallet;
|
||||
const wallet = available.find(w => w.name === name);
|
||||
if (wallet) connectWallet(wallet);
|
||||
});
|
||||
});
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
const modal = $('#wallet-modal');
|
||||
if (modal) modal.classList.add('hidden');
|
||||
}
|
||||
|
||||
async function toggleWallet() {
|
||||
|
|
@ -255,26 +354,29 @@ async function toggleWallet() {
|
|||
disconnectWallet();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for Phantom
|
||||
if (!window.solana || !window.solana.isPhantom) {
|
||||
const bar = $('#wallet-status');
|
||||
if (bar) bar.innerHTML = '<span style="color:rgba(255,50,50,0.8)">PHANTOM WALLET NOT DETECTED — <a href="https://phantom.app" target="_blank" style="color:#a855f7">INSTALL</a></span>';
|
||||
return;
|
||||
openModal();
|
||||
}
|
||||
|
||||
async function connectWallet(wallet) {
|
||||
try {
|
||||
const resp = await window.solana.connect();
|
||||
closeModal();
|
||||
const resp = await wallet.provider.connect();
|
||||
walletAddress = resp.publicKey.toString();
|
||||
connectedProvider = wallet;
|
||||
updateWalletUI();
|
||||
} catch(err) {
|
||||
console.error('Wallet connection failed:', err);
|
||||
const status = $('#wallet-status');
|
||||
if (status) status.innerHTML = `<span style="color:rgba(255,50,50,0.8)">CONNECTION REJECTED</span>`;
|
||||
}
|
||||
}
|
||||
|
||||
function disconnectWallet() {
|
||||
if (window.solana) window.solana.disconnect();
|
||||
if (connectedProvider && connectedProvider.provider) {
|
||||
try { connectedProvider.provider.disconnect(); } catch(e) {}
|
||||
}
|
||||
walletAddress = null;
|
||||
connectedProvider = null;
|
||||
updateWalletUI();
|
||||
}
|
||||
|
||||
|
|
@ -283,8 +385,10 @@ function updateWalletUI() {
|
|||
const btn = $('#wallet-btn');
|
||||
|
||||
if (walletAddress) {
|
||||
const wName = connectedProvider ? connectedProvider.name : 'WALLET';
|
||||
const wIcon = connectedProvider ? connectedProvider.icon : '◈';
|
||||
status.className = 'sol-wallet-status connected';
|
||||
status.innerHTML = `● CONNECTED <span class="sol-wallet-address">${truncAddr(walletAddress)}</span>`;
|
||||
status.innerHTML = `● CONNECTED VIA ${wIcon} ${wName} <span class="sol-wallet-address">${truncAddr(walletAddress)}</span>`;
|
||||
btn.className = 'sol-wallet-btn disconnect';
|
||||
btn.textContent = 'DISCONNECT';
|
||||
} else {
|
||||
|
|
@ -292,7 +396,6 @@ function updateWalletUI() {
|
|||
status.innerHTML = '○ NOT CONNECTED';
|
||||
btn.className = 'sol-wallet-btn';
|
||||
btn.textContent = 'CONNECT WALLET';
|
||||
// Clear my domains
|
||||
const panel = $('#mydomains-content');
|
||||
if (panel) panel.innerHTML = `<div class="sol-empty">CONNECT WALLET TO VIEW YOUR DOMAINS</div>`;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue