Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77ea4a8e67 | ||
|
|
12d4810f4c |
124
lite/build.js
124
lite/build.js
@@ -675,7 +675,7 @@ class FloatingTab {
|
|||||||
appearance: {
|
appearance: {
|
||||||
style: 'pill', // 'pill', 'square', 'circle'
|
style: 'pill', // 'pill', 'square', 'circle'
|
||||||
theme: 'auto', // 'auto', 'light', 'dark'
|
theme: 'auto', // 'auto', 'light', 'dark'
|
||||||
icon: '[LOGIN]',
|
icon: '',
|
||||||
text: 'Login',
|
text: 'Login',
|
||||||
iconOnly: false
|
iconOnly: false
|
||||||
},
|
},
|
||||||
@@ -685,11 +685,14 @@ class FloatingTab {
|
|||||||
autoSlide: true,
|
autoSlide: true,
|
||||||
persistent: false
|
persistent: false
|
||||||
},
|
},
|
||||||
|
getUserInfo: false,
|
||||||
|
getUserRelay: [],
|
||||||
...options
|
...options
|
||||||
};
|
};
|
||||||
|
|
||||||
this.isAuthenticated = false;
|
this.isAuthenticated = false;
|
||||||
this.userInfo = null;
|
this.userInfo = null;
|
||||||
|
this.userProfile = null;
|
||||||
this.container = null;
|
this.container = null;
|
||||||
this.isVisible = false;
|
this.isVisible = false;
|
||||||
|
|
||||||
@@ -790,11 +793,24 @@ class FloatingTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleAuth(authData) {
|
async _handleAuth(authData) {
|
||||||
console.log('FloatingTab: Handling authentication:', authData);
|
console.log('FloatingTab: Handling authentication:', authData);
|
||||||
this.isAuthenticated = true;
|
this.isAuthenticated = true;
|
||||||
this.userInfo = authData;
|
this.userInfo = authData;
|
||||||
|
|
||||||
|
// Fetch user profile if enabled and we have a pubkey
|
||||||
|
if (this.options.getUserInfo && authData.pubkey) {
|
||||||
|
console.log('FloatingTab: Fetching user profile for:', authData.pubkey);
|
||||||
|
try {
|
||||||
|
const profile = await this._fetchUserProfile(authData.pubkey);
|
||||||
|
this.userProfile = profile;
|
||||||
|
console.log('FloatingTab: User profile fetched:', profile);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('FloatingTab: Failed to fetch user profile:', error);
|
||||||
|
this.userProfile = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.options.behavior.hideWhenAuthenticated) {
|
if (this.options.behavior.hideWhenAuthenticated) {
|
||||||
this.hide();
|
this.hide();
|
||||||
} else {
|
} else {
|
||||||
@@ -806,6 +822,7 @@ class FloatingTab {
|
|||||||
console.log('FloatingTab: Handling logout');
|
console.log('FloatingTab: Handling logout');
|
||||||
this.isAuthenticated = false;
|
this.isAuthenticated = false;
|
||||||
this.userInfo = null;
|
this.userInfo = null;
|
||||||
|
this.userProfile = null;
|
||||||
|
|
||||||
if (this.options.behavior.hideWhenAuthenticated) {
|
if (this.options.behavior.hideWhenAuthenticated) {
|
||||||
this.show();
|
this.show();
|
||||||
@@ -873,18 +890,29 @@ class FloatingTab {
|
|||||||
|
|
||||||
// Update content
|
// Update content
|
||||||
if (this.isAuthenticated && this.options.behavior.showUserInfo) {
|
if (this.isAuthenticated && this.options.behavior.showUserInfo) {
|
||||||
const display = this.userInfo?.pubkey ?
|
let display;
|
||||||
(this.options.appearance.iconOnly ?
|
|
||||||
'[USER]' :
|
// Use profile name if available, otherwise fall back to pubkey
|
||||||
\`[USER] \${this.userInfo.pubkey.slice(0, 6)}...\`) :
|
if (this.userProfile?.name || this.userProfile?.display_name) {
|
||||||
(this.options.appearance.iconOnly ? '[AUTH]' : '[AUTH] Logged In');
|
const userName = this.userProfile.name || this.userProfile.display_name;
|
||||||
|
display = this.options.appearance.iconOnly
|
||||||
|
? userName.slice(0, 8)
|
||||||
|
: userName;
|
||||||
|
} else if (this.userInfo?.pubkey) {
|
||||||
|
// Fallback to pubkey display
|
||||||
|
display = this.options.appearance.iconOnly
|
||||||
|
? this.userInfo.pubkey.slice(0, 6)
|
||||||
|
: \`\${this.userInfo.pubkey.slice(0, 6)}...\`;
|
||||||
|
} else {
|
||||||
|
display = this.options.appearance.iconOnly ? 'User' : 'Authenticated';
|
||||||
|
}
|
||||||
|
|
||||||
this.container.textContent = display;
|
this.container.textContent = display;
|
||||||
this.container.className = 'nl-floating-tab nl-floating-tab--logged-in';
|
this.container.className = 'nl-floating-tab nl-floating-tab--logged-in';
|
||||||
} else {
|
} else {
|
||||||
const display = this.options.appearance.iconOnly ?
|
const display = this.options.appearance.iconOnly ?
|
||||||
this.options.appearance.icon :
|
this.options.appearance.icon :
|
||||||
\`\${this.options.appearance.icon} \${this.options.appearance.text}\`;
|
(this.options.appearance.icon ? \`\${this.options.appearance.icon} \${this.options.appearance.text}\` : this.options.appearance.text);
|
||||||
|
|
||||||
this.container.textContent = display;
|
this.container.textContent = display;
|
||||||
this.container.className = 'nl-floating-tab nl-floating-tab--logged-out';
|
this.container.className = 'nl-floating-tab nl-floating-tab--logged-out';
|
||||||
@@ -915,6 +943,62 @@ class FloatingTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _fetchUserProfile(pubkey) {
|
||||||
|
if (!this.options.getUserInfo) {
|
||||||
|
console.log('FloatingTab: getUserInfo disabled, skipping profile fetch');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine which relays to use
|
||||||
|
const relays = this.options.getUserRelay.length > 0
|
||||||
|
? this.options.getUserRelay
|
||||||
|
: (this.modal?.options?.relays || ['wss://relay.damus.io', 'wss://nos.lol']);
|
||||||
|
|
||||||
|
console.log('FloatingTab: Fetching profile from relays:', relays);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create a SimplePool instance for querying
|
||||||
|
const pool = new window.NostrTools.nip46.SimplePool();
|
||||||
|
|
||||||
|
// Query for kind 0 (user metadata) events
|
||||||
|
const events = await pool.querySync(relays, {
|
||||||
|
kinds: [0],
|
||||||
|
authors: [pubkey],
|
||||||
|
limit: 1
|
||||||
|
}, { timeout: 5000 });
|
||||||
|
|
||||||
|
console.log('FloatingTab: Profile query returned', events.length, 'events');
|
||||||
|
|
||||||
|
if (events.length === 0) {
|
||||||
|
console.log('FloatingTab: No profile events found');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the most recent event
|
||||||
|
const latestEvent = events.sort((a, b) => b.created_at - a.created_at)[0];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const profile = JSON.parse(latestEvent.content);
|
||||||
|
console.log('FloatingTab: Parsed profile:', profile);
|
||||||
|
|
||||||
|
// Return relevant profile fields
|
||||||
|
return {
|
||||||
|
name: profile.name || null,
|
||||||
|
display_name: profile.display_name || null,
|
||||||
|
about: profile.about || null,
|
||||||
|
picture: profile.picture || null,
|
||||||
|
nip05: profile.nip05 || null
|
||||||
|
};
|
||||||
|
} catch (parseError) {
|
||||||
|
console.warn('FloatingTab: Failed to parse profile JSON:', parseError);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('FloatingTab: Profile fetch error:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_position() {
|
_position() {
|
||||||
if (!this.container) return;
|
if (!this.container) return;
|
||||||
|
|
||||||
@@ -1076,7 +1160,7 @@ class NostrLite {
|
|||||||
appearance: {
|
appearance: {
|
||||||
style: 'pill',
|
style: 'pill',
|
||||||
theme: 'auto',
|
theme: 'auto',
|
||||||
icon: '[LOGIN]',
|
icon: '',
|
||||||
text: 'Login',
|
text: 'Login',
|
||||||
iconOnly: false
|
iconOnly: false
|
||||||
},
|
},
|
||||||
@@ -1085,7 +1169,9 @@ class NostrLite {
|
|||||||
showUserInfo: true,
|
showUserInfo: true,
|
||||||
autoSlide: true,
|
autoSlide: true,
|
||||||
persistent: false
|
persistent: false
|
||||||
}
|
},
|
||||||
|
getUserInfo: false,
|
||||||
|
getUserRelay: []
|
||||||
},
|
},
|
||||||
...options
|
...options
|
||||||
};
|
};
|
||||||
@@ -1254,13 +1340,13 @@ class WindowNostr {
|
|||||||
if (event.detail.method === 'extension') {
|
if (event.detail.method === 'extension') {
|
||||||
this.authenticatedExtension = event.detail.extension;
|
this.authenticatedExtension = event.detail.extension;
|
||||||
console.log('WindowNostr: Captured authenticated extension:', this.authenticatedExtension?.constructor?.name);
|
console.log('WindowNostr: Captured authenticated extension:', this.authenticatedExtension?.constructor?.name);
|
||||||
|
}
|
||||||
|
|
||||||
// Re-install our facade to ensure we intercept signEvent calls
|
// CRITICAL FIX: Re-install our facade for ALL authentication methods
|
||||||
// Extensions may overwrite window.nostr after authentication
|
// Extensions may overwrite window.nostr after ANY authentication, not just extension auth
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
console.log('WindowNostr: Re-installing facade after authentication');
|
console.log('WindowNostr: Re-installing facade after', this.authState?.method, 'authentication');
|
||||||
window.nostr = this;
|
window.nostr = this;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('WindowNostr: Auth state updated:', this.authState?.method);
|
console.log('WindowNostr: Auth state updated:', this.authState?.method);
|
||||||
@@ -1270,6 +1356,12 @@ class WindowNostr {
|
|||||||
this.authState = null;
|
this.authState = null;
|
||||||
this.authenticatedExtension = null;
|
this.authenticatedExtension = null;
|
||||||
console.log('WindowNostr: Auth state cleared');
|
console.log('WindowNostr: Auth state cleared');
|
||||||
|
|
||||||
|
// Re-install facade after logout to ensure we maintain control
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
console.log('WindowNostr: Re-installing facade after logout');
|
||||||
|
window.nostr = this;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
* Two-file architecture:
|
* Two-file architecture:
|
||||||
* 1. Load nostr.bundle.js (official nostr-tools bundle)
|
* 1. Load nostr.bundle.js (official nostr-tools bundle)
|
||||||
* 2. Load nostr-lite.js (this file - NOSTR_LOGIN_LITE library with CSS-only themes)
|
* 2. Load nostr-lite.js (this file - NOSTR_LOGIN_LITE library with CSS-only themes)
|
||||||
* Generated on: 2025-09-15T17:48:16.817Z
|
* Generated on: 2025-09-15T18:50:50.789Z
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Verify dependencies are loaded
|
// Verify dependencies are loaded
|
||||||
@@ -1076,26 +1076,6 @@ class Modal {
|
|||||||
button.style.background = 'var(--nl-secondary-color)';
|
button.style.background = 'var(--nl-secondary-color)';
|
||||||
};
|
};
|
||||||
|
|
||||||
const iconDiv = document.createElement('div');
|
|
||||||
// Replace emoji icons with text-based ones
|
|
||||||
const iconMap = {
|
|
||||||
'🔌': '[EXT]',
|
|
||||||
'🔑': '[KEY]',
|
|
||||||
'🌐': '[NET]',
|
|
||||||
'👁️': '[VIEW]',
|
|
||||||
'📱': '[SMS]'
|
|
||||||
};
|
|
||||||
iconDiv.textContent = iconMap[option.icon] || option.icon;
|
|
||||||
iconDiv.style.cssText = `
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-right: 16px;
|
|
||||||
width: 50px;
|
|
||||||
text-align: center;
|
|
||||||
color: var(--nl-primary-color);
|
|
||||||
font-family: var(--nl-font-family, 'Courier New', monospace);
|
|
||||||
`;
|
|
||||||
|
|
||||||
const contentDiv = document.createElement('div');
|
const contentDiv = document.createElement('div');
|
||||||
contentDiv.style.cssText = 'flex: 1; text-align: left;';
|
contentDiv.style.cssText = 'flex: 1; text-align: left;';
|
||||||
|
|
||||||
@@ -1119,7 +1099,6 @@ class Modal {
|
|||||||
contentDiv.appendChild(titleDiv);
|
contentDiv.appendChild(titleDiv);
|
||||||
contentDiv.appendChild(descDiv);
|
contentDiv.appendChild(descDiv);
|
||||||
|
|
||||||
button.appendChild(iconDiv);
|
|
||||||
button.appendChild(contentDiv);
|
button.appendChild(contentDiv);
|
||||||
this.modalBody.appendChild(button);
|
this.modalBody.appendChild(button);
|
||||||
});
|
});
|
||||||
@@ -1627,15 +1606,176 @@ class Modal {
|
|||||||
|
|
||||||
const warningDiv = document.createElement('div');
|
const warningDiv = document.createElement('div');
|
||||||
warningDiv.textContent = '⚠️ Save your secret key securely!';
|
warningDiv.textContent = '⚠️ Save your secret key securely!';
|
||||||
warningDiv.style.cssText = 'background: #fef3c7; color: #92400e; padding: 12px; border-radius: 6px; margin-bottom: 16px; font-size: 14px;';
|
warningDiv.style.cssText = 'background: #fef3c7; color: #92400e; padding: 12px; border-radius: 6px; margin-bottom: 16px; font-size: 12px;';
|
||||||
|
|
||||||
const nsecDiv = document.createElement('div');
|
// Helper function to create copy button
|
||||||
nsecDiv.innerHTML = `<strong>Your Secret Key:</strong><br><code style="word-break: break-all; background: #f3f4f6; padding: 8px; border-radius: 4px;">${nsec}</code>`;
|
const createCopyButton = (text, label) => {
|
||||||
nsecDiv.style.cssText = 'margin-bottom: 16px; font-size: 14px;';
|
const copyBtn = document.createElement('button');
|
||||||
|
copyBtn.textContent = `Copy ${label}`;
|
||||||
|
copyBtn.style.cssText = `
|
||||||
|
margin-left: 8px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 10px;
|
||||||
|
background: var(--nl-secondary-color);
|
||||||
|
color: var(--nl-primary-color);
|
||||||
|
border: 1px solid var(--nl-primary-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
|
`;
|
||||||
|
copyBtn.onclick = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
const originalText = copyBtn.textContent;
|
||||||
|
copyBtn.textContent = '✓ Copied!';
|
||||||
|
copyBtn.style.color = '#059669';
|
||||||
|
setTimeout(() => {
|
||||||
|
copyBtn.textContent = originalText;
|
||||||
|
copyBtn.style.color = 'var(--nl-primary-color)';
|
||||||
|
}, 2000);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to copy:', err);
|
||||||
|
copyBtn.textContent = '✗ Failed';
|
||||||
|
copyBtn.style.color = '#dc2626';
|
||||||
|
setTimeout(() => {
|
||||||
|
copyBtn.textContent = originalText;
|
||||||
|
copyBtn.style.color = 'var(--nl-primary-color)';
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return copyBtn;
|
||||||
|
};
|
||||||
|
|
||||||
const npubDiv = document.createElement('div');
|
// Convert pubkey to hex for verification
|
||||||
npubDiv.innerHTML = `<strong>Your Public Key:</strong><br><code style="word-break: break-all; background: #f3f4f6; padding: 8px; border-radius: 4px;">${window.NostrTools.nip19.npubEncode(pubkey)}</code>`;
|
const pubkeyHex = typeof pubkey === 'string' ? pubkey : Array.from(pubkey).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||||
npubDiv.style.cssText = 'margin-bottom: 16px; font-size: 14px;';
|
|
||||||
|
// Decode nsec to get secret key as hex
|
||||||
|
let secretKeyHex = '';
|
||||||
|
try {
|
||||||
|
const decoded = window.NostrTools.nip19.decode(nsec);
|
||||||
|
secretKeyHex = Array.from(decoded.data).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to decode nsec for hex display:', err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Secret Key Section
|
||||||
|
const nsecSection = document.createElement('div');
|
||||||
|
nsecSection.style.cssText = 'margin-bottom: 16px;';
|
||||||
|
|
||||||
|
const nsecLabel = document.createElement('div');
|
||||||
|
nsecLabel.innerHTML = '<strong>Your Secret Key (nsec):</strong>';
|
||||||
|
nsecLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
|
||||||
|
|
||||||
|
const nsecContainer = document.createElement('div');
|
||||||
|
nsecContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;';
|
||||||
|
|
||||||
|
const nsecCode = document.createElement('code');
|
||||||
|
nsecCode.textContent = nsec;
|
||||||
|
nsecCode.style.cssText = `
|
||||||
|
flex: 1;
|
||||||
|
word-break: break-all;
|
||||||
|
background: #f3f4f6;
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
display: block;
|
||||||
|
`;
|
||||||
|
|
||||||
|
nsecContainer.appendChild(nsecCode);
|
||||||
|
nsecContainer.appendChild(createCopyButton(nsec, 'nsec'));
|
||||||
|
nsecSection.appendChild(nsecLabel);
|
||||||
|
nsecSection.appendChild(nsecContainer);
|
||||||
|
|
||||||
|
// Secret Key Hex Section
|
||||||
|
if (secretKeyHex) {
|
||||||
|
const secretHexLabel = document.createElement('div');
|
||||||
|
secretHexLabel.innerHTML = '<strong>Secret Key (hex):</strong>';
|
||||||
|
secretHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
|
||||||
|
|
||||||
|
const secretHexContainer = document.createElement('div');
|
||||||
|
secretHexContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;';
|
||||||
|
|
||||||
|
const secretHexCode = document.createElement('code');
|
||||||
|
secretHexCode.textContent = secretKeyHex;
|
||||||
|
secretHexCode.style.cssText = `
|
||||||
|
flex: 1;
|
||||||
|
word-break: break-all;
|
||||||
|
background: #f3f4f6;
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
display: block;
|
||||||
|
`;
|
||||||
|
|
||||||
|
secretHexContainer.appendChild(secretHexCode);
|
||||||
|
secretHexContainer.appendChild(createCopyButton(secretKeyHex, 'hex'));
|
||||||
|
nsecSection.appendChild(secretHexLabel);
|
||||||
|
nsecSection.appendChild(secretHexContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public Key Section
|
||||||
|
const npubSection = document.createElement('div');
|
||||||
|
npubSection.style.cssText = 'margin-bottom: 16px;';
|
||||||
|
|
||||||
|
const npub = window.NostrTools.nip19.npubEncode(pubkey);
|
||||||
|
|
||||||
|
const npubLabel = document.createElement('div');
|
||||||
|
npubLabel.innerHTML = '<strong>Your Public Key (npub):</strong>';
|
||||||
|
npubLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
|
||||||
|
|
||||||
|
const npubContainer = document.createElement('div');
|
||||||
|
npubContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;';
|
||||||
|
|
||||||
|
const npubCode = document.createElement('code');
|
||||||
|
npubCode.textContent = npub;
|
||||||
|
npubCode.style.cssText = `
|
||||||
|
flex: 1;
|
||||||
|
word-break: break-all;
|
||||||
|
background: #f3f4f6;
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
display: block;
|
||||||
|
`;
|
||||||
|
|
||||||
|
npubContainer.appendChild(npubCode);
|
||||||
|
npubContainer.appendChild(createCopyButton(npub, 'npub'));
|
||||||
|
npubSection.appendChild(npubLabel);
|
||||||
|
npubSection.appendChild(npubContainer);
|
||||||
|
|
||||||
|
// Public Key Hex Section
|
||||||
|
const pubHexLabel = document.createElement('div');
|
||||||
|
pubHexLabel.innerHTML = '<strong>Public Key (hex):</strong>';
|
||||||
|
pubHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
|
||||||
|
|
||||||
|
const pubHexContainer = document.createElement('div');
|
||||||
|
pubHexContainer.style.cssText = 'display: flex; align-items: flex-start;';
|
||||||
|
|
||||||
|
const pubHexCode = document.createElement('code');
|
||||||
|
pubHexCode.textContent = pubkeyHex;
|
||||||
|
pubHexCode.style.cssText = `
|
||||||
|
flex: 1;
|
||||||
|
word-break: break-all;
|
||||||
|
background: #f3f4f6;
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
display: block;
|
||||||
|
`;
|
||||||
|
|
||||||
|
pubHexContainer.appendChild(pubHexCode);
|
||||||
|
pubHexContainer.appendChild(createCopyButton(pubkeyHex, 'hex'));
|
||||||
|
npubSection.appendChild(pubHexLabel);
|
||||||
|
npubSection.appendChild(pubHexContainer);
|
||||||
|
|
||||||
const continueButton = document.createElement('button');
|
const continueButton = document.createElement('button');
|
||||||
continueButton.textContent = 'Continue';
|
continueButton.textContent = 'Continue';
|
||||||
@@ -1644,8 +1784,8 @@ class Modal {
|
|||||||
|
|
||||||
this.modalBody.appendChild(title);
|
this.modalBody.appendChild(title);
|
||||||
this.modalBody.appendChild(warningDiv);
|
this.modalBody.appendChild(warningDiv);
|
||||||
this.modalBody.appendChild(nsecDiv);
|
this.modalBody.appendChild(nsecSection);
|
||||||
this.modalBody.appendChild(npubDiv);
|
this.modalBody.appendChild(npubSection);
|
||||||
this.modalBody.appendChild(continueButton);
|
this.modalBody.appendChild(continueButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1983,7 +2123,7 @@ class FloatingTab {
|
|||||||
appearance: {
|
appearance: {
|
||||||
style: 'pill', // 'pill', 'square', 'circle'
|
style: 'pill', // 'pill', 'square', 'circle'
|
||||||
theme: 'auto', // 'auto', 'light', 'dark'
|
theme: 'auto', // 'auto', 'light', 'dark'
|
||||||
icon: '[LOGIN]',
|
icon: '',
|
||||||
text: 'Login',
|
text: 'Login',
|
||||||
iconOnly: false
|
iconOnly: false
|
||||||
},
|
},
|
||||||
@@ -1993,11 +2133,14 @@ class FloatingTab {
|
|||||||
autoSlide: true,
|
autoSlide: true,
|
||||||
persistent: false
|
persistent: false
|
||||||
},
|
},
|
||||||
|
getUserInfo: false,
|
||||||
|
getUserRelay: [],
|
||||||
...options
|
...options
|
||||||
};
|
};
|
||||||
|
|
||||||
this.isAuthenticated = false;
|
this.isAuthenticated = false;
|
||||||
this.userInfo = null;
|
this.userInfo = null;
|
||||||
|
this.userProfile = null;
|
||||||
this.container = null;
|
this.container = null;
|
||||||
this.isVisible = false;
|
this.isVisible = false;
|
||||||
|
|
||||||
@@ -2098,11 +2241,24 @@ class FloatingTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_handleAuth(authData) {
|
async _handleAuth(authData) {
|
||||||
console.log('FloatingTab: Handling authentication:', authData);
|
console.log('FloatingTab: Handling authentication:', authData);
|
||||||
this.isAuthenticated = true;
|
this.isAuthenticated = true;
|
||||||
this.userInfo = authData;
|
this.userInfo = authData;
|
||||||
|
|
||||||
|
// Fetch user profile if enabled and we have a pubkey
|
||||||
|
if (this.options.getUserInfo && authData.pubkey) {
|
||||||
|
console.log('FloatingTab: Fetching user profile for:', authData.pubkey);
|
||||||
|
try {
|
||||||
|
const profile = await this._fetchUserProfile(authData.pubkey);
|
||||||
|
this.userProfile = profile;
|
||||||
|
console.log('FloatingTab: User profile fetched:', profile);
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('FloatingTab: Failed to fetch user profile:', error);
|
||||||
|
this.userProfile = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.options.behavior.hideWhenAuthenticated) {
|
if (this.options.behavior.hideWhenAuthenticated) {
|
||||||
this.hide();
|
this.hide();
|
||||||
} else {
|
} else {
|
||||||
@@ -2114,6 +2270,7 @@ class FloatingTab {
|
|||||||
console.log('FloatingTab: Handling logout');
|
console.log('FloatingTab: Handling logout');
|
||||||
this.isAuthenticated = false;
|
this.isAuthenticated = false;
|
||||||
this.userInfo = null;
|
this.userInfo = null;
|
||||||
|
this.userProfile = null;
|
||||||
|
|
||||||
if (this.options.behavior.hideWhenAuthenticated) {
|
if (this.options.behavior.hideWhenAuthenticated) {
|
||||||
this.show();
|
this.show();
|
||||||
@@ -2181,18 +2338,29 @@ class FloatingTab {
|
|||||||
|
|
||||||
// Update content
|
// Update content
|
||||||
if (this.isAuthenticated && this.options.behavior.showUserInfo) {
|
if (this.isAuthenticated && this.options.behavior.showUserInfo) {
|
||||||
const display = this.userInfo?.pubkey ?
|
let display;
|
||||||
(this.options.appearance.iconOnly ?
|
|
||||||
'[USER]' :
|
// Use profile name if available, otherwise fall back to pubkey
|
||||||
`[USER] ${this.userInfo.pubkey.slice(0, 6)}...`) :
|
if (this.userProfile?.name || this.userProfile?.display_name) {
|
||||||
(this.options.appearance.iconOnly ? '[AUTH]' : '[AUTH] Logged In');
|
const userName = this.userProfile.name || this.userProfile.display_name;
|
||||||
|
display = this.options.appearance.iconOnly
|
||||||
|
? userName.slice(0, 8)
|
||||||
|
: userName;
|
||||||
|
} else if (this.userInfo?.pubkey) {
|
||||||
|
// Fallback to pubkey display
|
||||||
|
display = this.options.appearance.iconOnly
|
||||||
|
? this.userInfo.pubkey.slice(0, 6)
|
||||||
|
: `${this.userInfo.pubkey.slice(0, 6)}...`;
|
||||||
|
} else {
|
||||||
|
display = this.options.appearance.iconOnly ? 'User' : 'Authenticated';
|
||||||
|
}
|
||||||
|
|
||||||
this.container.textContent = display;
|
this.container.textContent = display;
|
||||||
this.container.className = 'nl-floating-tab nl-floating-tab--logged-in';
|
this.container.className = 'nl-floating-tab nl-floating-tab--logged-in';
|
||||||
} else {
|
} else {
|
||||||
const display = this.options.appearance.iconOnly ?
|
const display = this.options.appearance.iconOnly ?
|
||||||
this.options.appearance.icon :
|
this.options.appearance.icon :
|
||||||
`${this.options.appearance.icon} ${this.options.appearance.text}`;
|
(this.options.appearance.icon ? `${this.options.appearance.icon} ${this.options.appearance.text}` : this.options.appearance.text);
|
||||||
|
|
||||||
this.container.textContent = display;
|
this.container.textContent = display;
|
||||||
this.container.className = 'nl-floating-tab nl-floating-tab--logged-out';
|
this.container.className = 'nl-floating-tab nl-floating-tab--logged-out';
|
||||||
@@ -2223,6 +2391,62 @@ class FloatingTab {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _fetchUserProfile(pubkey) {
|
||||||
|
if (!this.options.getUserInfo) {
|
||||||
|
console.log('FloatingTab: getUserInfo disabled, skipping profile fetch');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine which relays to use
|
||||||
|
const relays = this.options.getUserRelay.length > 0
|
||||||
|
? this.options.getUserRelay
|
||||||
|
: (this.modal?.options?.relays || ['wss://relay.damus.io', 'wss://nos.lol']);
|
||||||
|
|
||||||
|
console.log('FloatingTab: Fetching profile from relays:', relays);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create a SimplePool instance for querying
|
||||||
|
const pool = new window.NostrTools.nip46.SimplePool();
|
||||||
|
|
||||||
|
// Query for kind 0 (user metadata) events
|
||||||
|
const events = await pool.querySync(relays, {
|
||||||
|
kinds: [0],
|
||||||
|
authors: [pubkey],
|
||||||
|
limit: 1
|
||||||
|
}, { timeout: 5000 });
|
||||||
|
|
||||||
|
console.log('FloatingTab: Profile query returned', events.length, 'events');
|
||||||
|
|
||||||
|
if (events.length === 0) {
|
||||||
|
console.log('FloatingTab: No profile events found');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the most recent event
|
||||||
|
const latestEvent = events.sort((a, b) => b.created_at - a.created_at)[0];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const profile = JSON.parse(latestEvent.content);
|
||||||
|
console.log('FloatingTab: Parsed profile:', profile);
|
||||||
|
|
||||||
|
// Return relevant profile fields
|
||||||
|
return {
|
||||||
|
name: profile.name || null,
|
||||||
|
display_name: profile.display_name || null,
|
||||||
|
about: profile.about || null,
|
||||||
|
picture: profile.picture || null,
|
||||||
|
nip05: profile.nip05 || null
|
||||||
|
};
|
||||||
|
} catch (parseError) {
|
||||||
|
console.warn('FloatingTab: Failed to parse profile JSON:', parseError);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('FloatingTab: Profile fetch error:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_position() {
|
_position() {
|
||||||
if (!this.container) return;
|
if (!this.container) return;
|
||||||
|
|
||||||
@@ -2384,7 +2608,7 @@ class NostrLite {
|
|||||||
appearance: {
|
appearance: {
|
||||||
style: 'pill',
|
style: 'pill',
|
||||||
theme: 'auto',
|
theme: 'auto',
|
||||||
icon: '[LOGIN]',
|
icon: '',
|
||||||
text: 'Login',
|
text: 'Login',
|
||||||
iconOnly: false
|
iconOnly: false
|
||||||
},
|
},
|
||||||
@@ -2393,7 +2617,9 @@ class NostrLite {
|
|||||||
showUserInfo: true,
|
showUserInfo: true,
|
||||||
autoSlide: true,
|
autoSlide: true,
|
||||||
persistent: false
|
persistent: false
|
||||||
}
|
},
|
||||||
|
getUserInfo: false,
|
||||||
|
getUserRelay: []
|
||||||
},
|
},
|
||||||
...options
|
...options
|
||||||
};
|
};
|
||||||
@@ -2562,13 +2788,13 @@ class WindowNostr {
|
|||||||
if (event.detail.method === 'extension') {
|
if (event.detail.method === 'extension') {
|
||||||
this.authenticatedExtension = event.detail.extension;
|
this.authenticatedExtension = event.detail.extension;
|
||||||
console.log('WindowNostr: Captured authenticated extension:', this.authenticatedExtension?.constructor?.name);
|
console.log('WindowNostr: Captured authenticated extension:', this.authenticatedExtension?.constructor?.name);
|
||||||
|
}
|
||||||
|
|
||||||
// Re-install our facade to ensure we intercept signEvent calls
|
// CRITICAL FIX: Re-install our facade for ALL authentication methods
|
||||||
// Extensions may overwrite window.nostr after authentication
|
// Extensions may overwrite window.nostr after ANY authentication, not just extension auth
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
console.log('WindowNostr: Re-installing facade after authentication');
|
console.log('WindowNostr: Re-installing facade after', this.authState?.method, 'authentication');
|
||||||
window.nostr = this;
|
window.nostr = this;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('WindowNostr: Auth state updated:', this.authState?.method);
|
console.log('WindowNostr: Auth state updated:', this.authState?.method);
|
||||||
@@ -2578,6 +2804,12 @@ class WindowNostr {
|
|||||||
this.authState = null;
|
this.authState = null;
|
||||||
this.authenticatedExtension = null;
|
this.authenticatedExtension = null;
|
||||||
console.log('WindowNostr: Auth state cleared');
|
console.log('WindowNostr: Auth state cleared');
|
||||||
|
|
||||||
|
// Re-install facade after logout to ensure we maintain control
|
||||||
|
if (typeof window !== 'undefined') {
|
||||||
|
console.log('WindowNostr: Re-installing facade after logout');
|
||||||
|
window.nostr = this;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
200
lite/ui/modal.js
200
lite/ui/modal.js
@@ -280,26 +280,6 @@ class Modal {
|
|||||||
button.style.background = 'var(--nl-secondary-color)';
|
button.style.background = 'var(--nl-secondary-color)';
|
||||||
};
|
};
|
||||||
|
|
||||||
const iconDiv = document.createElement('div');
|
|
||||||
// Replace emoji icons with text-based ones
|
|
||||||
const iconMap = {
|
|
||||||
'🔌': '[EXT]',
|
|
||||||
'🔑': '[KEY]',
|
|
||||||
'🌐': '[NET]',
|
|
||||||
'👁️': '[VIEW]',
|
|
||||||
'📱': '[SMS]'
|
|
||||||
};
|
|
||||||
iconDiv.textContent = iconMap[option.icon] || option.icon;
|
|
||||||
iconDiv.style.cssText = `
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-right: 16px;
|
|
||||||
width: 50px;
|
|
||||||
text-align: center;
|
|
||||||
color: var(--nl-primary-color);
|
|
||||||
font-family: var(--nl-font-family, 'Courier New', monospace);
|
|
||||||
`;
|
|
||||||
|
|
||||||
const contentDiv = document.createElement('div');
|
const contentDiv = document.createElement('div');
|
||||||
contentDiv.style.cssText = 'flex: 1; text-align: left;';
|
contentDiv.style.cssText = 'flex: 1; text-align: left;';
|
||||||
|
|
||||||
@@ -323,7 +303,6 @@ class Modal {
|
|||||||
contentDiv.appendChild(titleDiv);
|
contentDiv.appendChild(titleDiv);
|
||||||
contentDiv.appendChild(descDiv);
|
contentDiv.appendChild(descDiv);
|
||||||
|
|
||||||
button.appendChild(iconDiv);
|
|
||||||
button.appendChild(contentDiv);
|
button.appendChild(contentDiv);
|
||||||
this.modalBody.appendChild(button);
|
this.modalBody.appendChild(button);
|
||||||
});
|
});
|
||||||
@@ -831,15 +810,176 @@ class Modal {
|
|||||||
|
|
||||||
const warningDiv = document.createElement('div');
|
const warningDiv = document.createElement('div');
|
||||||
warningDiv.textContent = '⚠️ Save your secret key securely!';
|
warningDiv.textContent = '⚠️ Save your secret key securely!';
|
||||||
warningDiv.style.cssText = 'background: #fef3c7; color: #92400e; padding: 12px; border-radius: 6px; margin-bottom: 16px; font-size: 14px;';
|
warningDiv.style.cssText = 'background: #fef3c7; color: #92400e; padding: 12px; border-radius: 6px; margin-bottom: 16px; font-size: 12px;';
|
||||||
|
|
||||||
const nsecDiv = document.createElement('div');
|
// Helper function to create copy button
|
||||||
nsecDiv.innerHTML = `<strong>Your Secret Key:</strong><br><code style="word-break: break-all; background: #f3f4f6; padding: 8px; border-radius: 4px;">${nsec}</code>`;
|
const createCopyButton = (text, label) => {
|
||||||
nsecDiv.style.cssText = 'margin-bottom: 16px; font-size: 14px;';
|
const copyBtn = document.createElement('button');
|
||||||
|
copyBtn.textContent = `Copy ${label}`;
|
||||||
|
copyBtn.style.cssText = `
|
||||||
|
margin-left: 8px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 10px;
|
||||||
|
background: var(--nl-secondary-color);
|
||||||
|
color: var(--nl-primary-color);
|
||||||
|
border: 1px solid var(--nl-primary-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
|
`;
|
||||||
|
copyBtn.onclick = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
try {
|
||||||
|
await navigator.clipboard.writeText(text);
|
||||||
|
const originalText = copyBtn.textContent;
|
||||||
|
copyBtn.textContent = '✓ Copied!';
|
||||||
|
copyBtn.style.color = '#059669';
|
||||||
|
setTimeout(() => {
|
||||||
|
copyBtn.textContent = originalText;
|
||||||
|
copyBtn.style.color = 'var(--nl-primary-color)';
|
||||||
|
}, 2000);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to copy:', err);
|
||||||
|
copyBtn.textContent = '✗ Failed';
|
||||||
|
copyBtn.style.color = '#dc2626';
|
||||||
|
setTimeout(() => {
|
||||||
|
copyBtn.textContent = originalText;
|
||||||
|
copyBtn.style.color = 'var(--nl-primary-color)';
|
||||||
|
}, 2000);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return copyBtn;
|
||||||
|
};
|
||||||
|
|
||||||
const npubDiv = document.createElement('div');
|
// Convert pubkey to hex for verification
|
||||||
npubDiv.innerHTML = `<strong>Your Public Key:</strong><br><code style="word-break: break-all; background: #f3f4f6; padding: 8px; border-radius: 4px;">${window.NostrTools.nip19.npubEncode(pubkey)}</code>`;
|
const pubkeyHex = typeof pubkey === 'string' ? pubkey : Array.from(pubkey).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||||
npubDiv.style.cssText = 'margin-bottom: 16px; font-size: 14px;';
|
|
||||||
|
// Decode nsec to get secret key as hex
|
||||||
|
let secretKeyHex = '';
|
||||||
|
try {
|
||||||
|
const decoded = window.NostrTools.nip19.decode(nsec);
|
||||||
|
secretKeyHex = Array.from(decoded.data).map(b => b.toString(16).padStart(2, '0')).join('');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to decode nsec for hex display:', err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Secret Key Section
|
||||||
|
const nsecSection = document.createElement('div');
|
||||||
|
nsecSection.style.cssText = 'margin-bottom: 16px;';
|
||||||
|
|
||||||
|
const nsecLabel = document.createElement('div');
|
||||||
|
nsecLabel.innerHTML = '<strong>Your Secret Key (nsec):</strong>';
|
||||||
|
nsecLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
|
||||||
|
|
||||||
|
const nsecContainer = document.createElement('div');
|
||||||
|
nsecContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;';
|
||||||
|
|
||||||
|
const nsecCode = document.createElement('code');
|
||||||
|
nsecCode.textContent = nsec;
|
||||||
|
nsecCode.style.cssText = `
|
||||||
|
flex: 1;
|
||||||
|
word-break: break-all;
|
||||||
|
background: #f3f4f6;
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
display: block;
|
||||||
|
`;
|
||||||
|
|
||||||
|
nsecContainer.appendChild(nsecCode);
|
||||||
|
nsecContainer.appendChild(createCopyButton(nsec, 'nsec'));
|
||||||
|
nsecSection.appendChild(nsecLabel);
|
||||||
|
nsecSection.appendChild(nsecContainer);
|
||||||
|
|
||||||
|
// Secret Key Hex Section
|
||||||
|
if (secretKeyHex) {
|
||||||
|
const secretHexLabel = document.createElement('div');
|
||||||
|
secretHexLabel.innerHTML = '<strong>Secret Key (hex):</strong>';
|
||||||
|
secretHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
|
||||||
|
|
||||||
|
const secretHexContainer = document.createElement('div');
|
||||||
|
secretHexContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;';
|
||||||
|
|
||||||
|
const secretHexCode = document.createElement('code');
|
||||||
|
secretHexCode.textContent = secretKeyHex;
|
||||||
|
secretHexCode.style.cssText = `
|
||||||
|
flex: 1;
|
||||||
|
word-break: break-all;
|
||||||
|
background: #f3f4f6;
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
display: block;
|
||||||
|
`;
|
||||||
|
|
||||||
|
secretHexContainer.appendChild(secretHexCode);
|
||||||
|
secretHexContainer.appendChild(createCopyButton(secretKeyHex, 'hex'));
|
||||||
|
nsecSection.appendChild(secretHexLabel);
|
||||||
|
nsecSection.appendChild(secretHexContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public Key Section
|
||||||
|
const npubSection = document.createElement('div');
|
||||||
|
npubSection.style.cssText = 'margin-bottom: 16px;';
|
||||||
|
|
||||||
|
const npub = window.NostrTools.nip19.npubEncode(pubkey);
|
||||||
|
|
||||||
|
const npubLabel = document.createElement('div');
|
||||||
|
npubLabel.innerHTML = '<strong>Your Public Key (npub):</strong>';
|
||||||
|
npubLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
|
||||||
|
|
||||||
|
const npubContainer = document.createElement('div');
|
||||||
|
npubContainer.style.cssText = 'display: flex; align-items: flex-start; margin-bottom: 8px;';
|
||||||
|
|
||||||
|
const npubCode = document.createElement('code');
|
||||||
|
npubCode.textContent = npub;
|
||||||
|
npubCode.style.cssText = `
|
||||||
|
flex: 1;
|
||||||
|
word-break: break-all;
|
||||||
|
background: #f3f4f6;
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
display: block;
|
||||||
|
`;
|
||||||
|
|
||||||
|
npubContainer.appendChild(npubCode);
|
||||||
|
npubContainer.appendChild(createCopyButton(npub, 'npub'));
|
||||||
|
npubSection.appendChild(npubLabel);
|
||||||
|
npubSection.appendChild(npubContainer);
|
||||||
|
|
||||||
|
// Public Key Hex Section
|
||||||
|
const pubHexLabel = document.createElement('div');
|
||||||
|
pubHexLabel.innerHTML = '<strong>Public Key (hex):</strong>';
|
||||||
|
pubHexLabel.style.cssText = 'margin-bottom: 4px; font-size: 12px; font-weight: 600;';
|
||||||
|
|
||||||
|
const pubHexContainer = document.createElement('div');
|
||||||
|
pubHexContainer.style.cssText = 'display: flex; align-items: flex-start;';
|
||||||
|
|
||||||
|
const pubHexCode = document.createElement('code');
|
||||||
|
pubHexCode.textContent = pubkeyHex;
|
||||||
|
pubHexCode.style.cssText = `
|
||||||
|
flex: 1;
|
||||||
|
word-break: break-all;
|
||||||
|
background: #f3f4f6;
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 10px;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
display: block;
|
||||||
|
`;
|
||||||
|
|
||||||
|
pubHexContainer.appendChild(pubHexCode);
|
||||||
|
pubHexContainer.appendChild(createCopyButton(pubkeyHex, 'hex'));
|
||||||
|
npubSection.appendChild(pubHexLabel);
|
||||||
|
npubSection.appendChild(pubHexContainer);
|
||||||
|
|
||||||
const continueButton = document.createElement('button');
|
const continueButton = document.createElement('button');
|
||||||
continueButton.textContent = 'Continue';
|
continueButton.textContent = 'Continue';
|
||||||
@@ -848,8 +988,8 @@ class Modal {
|
|||||||
|
|
||||||
this.modalBody.appendChild(title);
|
this.modalBody.appendChild(title);
|
||||||
this.modalBody.appendChild(warningDiv);
|
this.modalBody.appendChild(warningDiv);
|
||||||
this.modalBody.appendChild(nsecDiv);
|
this.modalBody.appendChild(nsecSection);
|
||||||
this.modalBody.appendChild(npubDiv);
|
this.modalBody.appendChild(npubSection);
|
||||||
this.modalBody.appendChild(continueButton);
|
this.modalBody.appendChild(continueButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user