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;
|
font-size: 0.6rem;
|
||||||
color: rgba(255, 255, 255, 0.3);
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
125
js/soldomains.js
125
js/soldomains.js
|
|
@ -244,10 +244,109 @@ async function doReverse() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── WALLET ─────────────────────────────────────────────────
|
// ─── 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() {
|
function initWallet() {
|
||||||
const btn = $('#wallet-btn');
|
const btn = $('#wallet-btn');
|
||||||
if (!btn) return;
|
if (!btn) return;
|
||||||
btn.addEventListener('click', toggleWallet);
|
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() {
|
async function toggleWallet() {
|
||||||
|
|
@ -255,26 +354,29 @@ async function toggleWallet() {
|
||||||
disconnectWallet();
|
disconnectWallet();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
openModal();
|
||||||
|
}
|
||||||
|
|
||||||
// Check for Phantom
|
async function connectWallet(wallet) {
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const resp = await window.solana.connect();
|
closeModal();
|
||||||
|
const resp = await wallet.provider.connect();
|
||||||
walletAddress = resp.publicKey.toString();
|
walletAddress = resp.publicKey.toString();
|
||||||
|
connectedProvider = wallet;
|
||||||
updateWalletUI();
|
updateWalletUI();
|
||||||
} catch(err) {
|
} catch(err) {
|
||||||
console.error('Wallet connection failed:', 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() {
|
function disconnectWallet() {
|
||||||
if (window.solana) window.solana.disconnect();
|
if (connectedProvider && connectedProvider.provider) {
|
||||||
|
try { connectedProvider.provider.disconnect(); } catch(e) {}
|
||||||
|
}
|
||||||
walletAddress = null;
|
walletAddress = null;
|
||||||
|
connectedProvider = null;
|
||||||
updateWalletUI();
|
updateWalletUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -283,8 +385,10 @@ function updateWalletUI() {
|
||||||
const btn = $('#wallet-btn');
|
const btn = $('#wallet-btn');
|
||||||
|
|
||||||
if (walletAddress) {
|
if (walletAddress) {
|
||||||
|
const wName = connectedProvider ? connectedProvider.name : 'WALLET';
|
||||||
|
const wIcon = connectedProvider ? connectedProvider.icon : '◈';
|
||||||
status.className = 'sol-wallet-status connected';
|
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.className = 'sol-wallet-btn disconnect';
|
||||||
btn.textContent = 'DISCONNECT';
|
btn.textContent = 'DISCONNECT';
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -292,7 +396,6 @@ function updateWalletUI() {
|
||||||
status.innerHTML = '○ NOT CONNECTED';
|
status.innerHTML = '○ NOT CONNECTED';
|
||||||
btn.className = 'sol-wallet-btn';
|
btn.className = 'sol-wallet-btn';
|
||||||
btn.textContent = 'CONNECT WALLET';
|
btn.textContent = 'CONNECT WALLET';
|
||||||
// Clear my domains
|
|
||||||
const panel = $('#mydomains-content');
|
const panel = $('#mydomains-content');
|
||||||
if (panel) panel.innerHTML = `<div class="sol-empty">CONNECT WALLET TO VIEW YOUR DOMAINS</div>`;
|
if (panel) panel.innerHTML = `<div class="sol-empty">CONNECT WALLET TO VIEW YOUR DOMAINS</div>`;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue