Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b59bf17372 | ||
|
|
3b1eb7f951 |
60
README.md
60
README.md
@@ -1,2 +1,62 @@
|
|||||||
Nostr_Login_Lite
|
Nostr_Login_Lite
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
## Floating Tab API
|
||||||
|
|
||||||
|
Configure persistent floating tab for login/logout:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
await NOSTR_LOGIN_LITE.init({
|
||||||
|
floatingTab: {
|
||||||
|
enabled: true,
|
||||||
|
hPosition: 0.95, // 0.0-1.0 or '95%' from left
|
||||||
|
vPosition: 0.5, // 0.0-1.0 or '50%' from top
|
||||||
|
appearance: {
|
||||||
|
style: 'pill', // 'pill', 'square', 'circle', 'minimal'
|
||||||
|
theme: 'auto', // 'auto', 'light', 'dark'
|
||||||
|
icon: '🔐',
|
||||||
|
text: 'Login'
|
||||||
|
},
|
||||||
|
behavior: {
|
||||||
|
hideWhenAuthenticated: false,
|
||||||
|
showUserInfo: true,
|
||||||
|
autoSlide: true
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
slideDirection: 'auto' // 'auto', 'left', 'right', 'up', 'down'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Control methods:
|
||||||
|
```javascript
|
||||||
|
NOSTR_LOGIN_LITE.showFloatingTab();
|
||||||
|
NOSTR_LOGIN_LITE.hideFloatingTab();
|
||||||
|
NOSTR_LOGIN_LITE.updateFloatingTab(options);
|
||||||
|
NOSTR_LOGIN_LITE.destroyFloatingTab();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Embedded Modal API
|
||||||
|
|
||||||
|
Embed login interface directly into page element:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Initialize library first
|
||||||
|
await NOSTR_LOGIN_LITE.init({
|
||||||
|
methods: {
|
||||||
|
extension: true,
|
||||||
|
local: true,
|
||||||
|
readonly: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Embed into container
|
||||||
|
const modal = NOSTR_LOGIN_LITE.embed('#login-container', {
|
||||||
|
title: 'Login',
|
||||||
|
showHeader: true,
|
||||||
|
seamless: false // true = no borders/shadows, blends into page
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Container can be CSS selector or DOM element. Modal renders inline without backdrop overlay.
|
||||||
|
|||||||
56
examples/embedded.html
Normal file
56
examples/embedded.html
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Embedded NOSTR_LOGIN_LITE</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 40px;
|
||||||
|
background: white;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 400px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#login-container {
|
||||||
|
/* No styling - let embedded modal blend seamlessly */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div id="login-container"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="../lite/nostr.bundle.js"></script>
|
||||||
|
<script src="../lite/nostr-lite.js"></script>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
|
await window.NOSTR_LOGIN_LITE.init({
|
||||||
|
methods: {
|
||||||
|
extension: true,
|
||||||
|
local: true,
|
||||||
|
readonly: true,
|
||||||
|
connect: true,
|
||||||
|
remote: true,
|
||||||
|
otp: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.NOSTR_LOGIN_LITE.embed('#login-container', {
|
||||||
|
seamless: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -271,9 +271,31 @@
|
|||||||
extension: true,
|
extension: true,
|
||||||
local: true,
|
local: true,
|
||||||
readonly: true,
|
readonly: true,
|
||||||
remote: true, // Enables "Nostr Connect" (NIP-46)
|
connect: true, // Enables "Nostr Connect" (NIP-46)
|
||||||
|
remote: true, // Also needed for "Nostr Connect" compatibility
|
||||||
otp: true // Enables "DM/OTP"
|
otp: true // Enables "DM/OTP"
|
||||||
},
|
},
|
||||||
|
floatingTab: {
|
||||||
|
enabled: true,
|
||||||
|
hPosition: 0.80, // 95% from left
|
||||||
|
vPosition: 0.01, // 50% from top (center)
|
||||||
|
appearance: {
|
||||||
|
style: 'minimal',
|
||||||
|
theme: 'auto',
|
||||||
|
icon: '',
|
||||||
|
text: 'Login',
|
||||||
|
iconOnly: false
|
||||||
|
},
|
||||||
|
behavior: {
|
||||||
|
hideWhenAuthenticated: false,
|
||||||
|
showUserInfo: true,
|
||||||
|
autoSlide: false,
|
||||||
|
persistent: false
|
||||||
|
},
|
||||||
|
animation: {
|
||||||
|
slideDirection: 'right' // Slide to the right when hiding
|
||||||
|
}
|
||||||
|
},
|
||||||
debug: true
|
debug: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -205,22 +205,44 @@ The following features are planned but not yet implemented:
|
|||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
To work on the source files:
|
⚠️ **CRITICAL: DO NOT EDIT `nostr-lite.js` DIRECTLY!**
|
||||||
|
|
||||||
|
The `nostr-lite.js` file is **auto-generated** by the build script. All changes must be made in the build script itself.
|
||||||
|
|
||||||
|
### Build Process
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Edit individual components
|
# The main library source code is in:
|
||||||
lite/core/nip46-client.js
|
lite/build.js # ← Edit this file for library changes
|
||||||
lite/ui/modal.js
|
|
||||||
lite/nostr-login-lite.js
|
|
||||||
|
|
||||||
# Run bundler to create distribution
|
# To make changes:
|
||||||
node lite/bundler.js
|
1. Edit lite/build.js # Contains all source code
|
||||||
|
2. cd lite && node build.js # Regenerates nostr-lite.js
|
||||||
|
3. Test your changes in examples/
|
||||||
|
|
||||||
# Start dev server (from project root)
|
# NEVER edit these files directly (they get overwritten):
|
||||||
|
lite/nostr-lite.js # ← Auto-generated, don't edit!
|
||||||
|
|
||||||
|
# Separate components that can be edited:
|
||||||
|
lite/ui/modal.js # Modal UI component
|
||||||
|
themes/default/theme.css # Default theme
|
||||||
|
themes/dark/theme.css # Dark theme
|
||||||
|
```
|
||||||
|
|
||||||
|
### Development Workflow
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Make changes to source
|
||||||
|
nano lite/build.js
|
||||||
|
|
||||||
|
# 2. Rebuild bundle
|
||||||
|
cd lite && node build.js
|
||||||
|
|
||||||
|
# 3. Start dev server (from project root)
|
||||||
python3 -m http.server 8000
|
python3 -m http.server 8000
|
||||||
|
|
||||||
# Open test page
|
# 4. Test changes
|
||||||
open http://localhost:8000/examples/simple-demo.html
|
open http://localhost:8000/examples/modal.html
|
||||||
```
|
```
|
||||||
|
|
||||||
### Local Bundle Setup
|
### Local Bundle Setup
|
||||||
|
|||||||
1069
lite/build.js
1069
lite/build.js
File diff suppressed because it is too large
Load Diff
1640
lite/nostr-lite.js
1640
lite/nostr-lite.js
File diff suppressed because it is too large
Load Diff
200
lite/ui/modal.js
200
lite/ui/modal.js
@@ -4,11 +4,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class Modal {
|
class Modal {
|
||||||
constructor(options) {
|
constructor(options = {}) {
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.container = null;
|
this.container = null;
|
||||||
this.isVisible = false;
|
this.isVisible = false;
|
||||||
this.currentScreen = null;
|
this.currentScreen = null;
|
||||||
|
this.isEmbedded = !!options.embedded;
|
||||||
|
this.embeddedContainer = options.embedded;
|
||||||
|
|
||||||
// Initialize modal container and styles
|
// Initialize modal container and styles
|
||||||
this._initModal();
|
this._initModal();
|
||||||
@@ -17,7 +19,18 @@ class Modal {
|
|||||||
_initModal() {
|
_initModal() {
|
||||||
// Create modal container
|
// Create modal container
|
||||||
this.container = document.createElement('div');
|
this.container = document.createElement('div');
|
||||||
this.container.id = 'nl-modal';
|
this.container.id = this.isEmbedded ? 'nl-modal-embedded' : 'nl-modal';
|
||||||
|
|
||||||
|
if (this.isEmbedded) {
|
||||||
|
// Embedded mode: inline positioning, no overlay
|
||||||
|
this.container.style.cssText = `
|
||||||
|
position: relative;
|
||||||
|
display: none;
|
||||||
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
|
width: 100%;
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
// Modal mode: fixed overlay
|
||||||
this.container.style.cssText = `
|
this.container.style.cssText = `
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -27,22 +40,38 @@ class Modal {
|
|||||||
background: rgba(0, 0, 0, 0.75);
|
background: rgba(0, 0, 0, 0.75);
|
||||||
display: none;
|
display: none;
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
`;
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
// Create modal content
|
// Create modal content
|
||||||
const modalContent = document.createElement('div');
|
const modalContent = document.createElement('div');
|
||||||
|
if (this.isEmbedded) {
|
||||||
|
// Embedded content: no centering margin, full width
|
||||||
modalContent.style.cssText = `
|
modalContent.style.cssText = `
|
||||||
position: relative;
|
position: relative;
|
||||||
background: white;
|
background: var(--nl-secondary-color);
|
||||||
|
color: var(--nl-primary-color);
|
||||||
|
width: 100%;
|
||||||
|
border-radius: var(--nl-border-radius, 15px);
|
||||||
|
border: var(--nl-border-width) solid var(--nl-primary-color);
|
||||||
|
overflow: hidden;
|
||||||
|
`;
|
||||||
|
} else {
|
||||||
|
// Modal content: centered with margin
|
||||||
|
modalContent.style.cssText = `
|
||||||
|
position: relative;
|
||||||
|
background: var(--nl-secondary-color);
|
||||||
|
color: var(--nl-primary-color);
|
||||||
width: 90%;
|
width: 90%;
|
||||||
max-width: 400px;
|
max-width: 400px;
|
||||||
margin: 50px auto;
|
margin: 50px auto;
|
||||||
border-radius: 12px;
|
border-radius: var(--nl-border-radius, 15px);
|
||||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
border: var(--nl-border-width) solid var(--nl-primary-color);
|
||||||
max-height: 600px;
|
max-height: 600px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
`;
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
const modalHeader = document.createElement('div');
|
const modalHeader = document.createElement('div');
|
||||||
@@ -51,6 +80,8 @@ class Modal {
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
background: transparent;
|
||||||
|
border-bottom: none;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const modalTitle = document.createElement('h2');
|
const modalTitle = document.createElement('h2');
|
||||||
@@ -59,17 +90,24 @@ class Modal {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #1f2937;
|
color: var(--nl-primary-color);
|
||||||
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
modalHeader.appendChild(modalTitle);
|
||||||
|
|
||||||
|
// Only add close button for non-embedded modals
|
||||||
|
// Embedded modals shouldn't have a close button because there's no way to reopen them
|
||||||
|
if (!this.isEmbedded) {
|
||||||
const closeButton = document.createElement('button');
|
const closeButton = document.createElement('button');
|
||||||
closeButton.innerHTML = '×';
|
closeButton.innerHTML = '×';
|
||||||
closeButton.onclick = () => this.close();
|
closeButton.onclick = () => this.close();
|
||||||
closeButton.style.cssText = `
|
closeButton.style.cssText = `
|
||||||
background: none;
|
background: var(--nl-secondary-color);
|
||||||
border: none;
|
border: var(--nl-border-width) solid var(--nl-primary-color);
|
||||||
|
border-radius: var(--nl-border-radius);
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
color: #6b7280;
|
color: var(--nl-primary-color);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
@@ -77,13 +115,19 @@ class Modal {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-radius: 6px;
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
`;
|
`;
|
||||||
closeButton.onmouseover = () => closeButton.style.background = '#f3f4f6';
|
closeButton.onmouseover = () => {
|
||||||
closeButton.onmouseout = () => closeButton.style.background = 'none';
|
closeButton.style.borderColor = 'var(--nl-accent-color)';
|
||||||
|
closeButton.style.background = 'var(--nl-secondary-color)';
|
||||||
|
};
|
||||||
|
closeButton.onmouseout = () => {
|
||||||
|
closeButton.style.borderColor = 'var(--nl-primary-color)';
|
||||||
|
closeButton.style.background = 'var(--nl-secondary-color)';
|
||||||
|
};
|
||||||
|
|
||||||
modalHeader.appendChild(modalTitle);
|
|
||||||
modalHeader.appendChild(closeButton);
|
modalHeader.appendChild(closeButton);
|
||||||
|
}
|
||||||
|
|
||||||
// Body
|
// Body
|
||||||
this.modalBody = document.createElement('div');
|
this.modalBody = document.createElement('div');
|
||||||
@@ -91,38 +135,52 @@ class Modal {
|
|||||||
padding: 24px;
|
padding: 24px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
|
background: transparent;
|
||||||
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
modalContent.appendChild(modalHeader);
|
modalContent.appendChild(modalHeader);
|
||||||
modalContent.appendChild(this.modalBody);
|
modalContent.appendChild(this.modalBody);
|
||||||
this.container.appendChild(modalContent);
|
this.container.appendChild(modalContent);
|
||||||
|
|
||||||
// Add to body
|
// Add to appropriate parent
|
||||||
|
if (this.isEmbedded && this.embeddedContainer) {
|
||||||
|
// Append to specified container for embedding
|
||||||
|
if (typeof this.embeddedContainer === 'string') {
|
||||||
|
const targetElement = document.querySelector(this.embeddedContainer);
|
||||||
|
if (targetElement) {
|
||||||
|
targetElement.appendChild(this.container);
|
||||||
|
} else {
|
||||||
|
console.error('NOSTR_LOGIN_LITE: Embedded container not found:', this.embeddedContainer);
|
||||||
document.body.appendChild(this.container);
|
document.body.appendChild(this.container);
|
||||||
|
}
|
||||||
|
} else if (this.embeddedContainer instanceof HTMLElement) {
|
||||||
|
this.embeddedContainer.appendChild(this.container);
|
||||||
|
} else {
|
||||||
|
console.error('NOSTR_LOGIN_LITE: Invalid embedded container');
|
||||||
|
document.body.appendChild(this.container);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Add to body for modal mode
|
||||||
|
document.body.appendChild(this.container);
|
||||||
|
}
|
||||||
|
|
||||||
// Click outside to close
|
// Click outside to close (only for modal mode)
|
||||||
|
if (!this.isEmbedded) {
|
||||||
this.container.onclick = (e) => {
|
this.container.onclick = (e) => {
|
||||||
if (e.target === this.container) {
|
if (e.target === this.container) {
|
||||||
this.close();
|
this.close();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Update theme
|
// Update theme
|
||||||
this.updateTheme();
|
this.updateTheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTheme() {
|
updateTheme() {
|
||||||
const isDark = this.options?.darkMode;
|
// The theme will automatically update through CSS custom properties
|
||||||
const modalContent = this.container.querySelector(':nth-child(1)');
|
// No manual styling needed - the CSS variables handle everything
|
||||||
const title = this.container.querySelector('h2');
|
|
||||||
|
|
||||||
if (isDark) {
|
|
||||||
modalContent.style.background = '#1f2937';
|
|
||||||
title.style.color = 'white';
|
|
||||||
} else {
|
|
||||||
modalContent.style.background = 'white';
|
|
||||||
title.style.color = '#1f2937';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open(opts = {}) {
|
open(opts = {}) {
|
||||||
@@ -205,26 +263,41 @@ class Modal {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
background: ${this.options?.darkMode ? '#374151' : 'white'};
|
background: var(--nl-secondary-color);
|
||||||
border: 1px solid ${this.options?.darkMode ? '#4b5563' : '#d1d5db'};
|
color: var(--nl-primary-color);
|
||||||
border-radius: 8px;
|
border: var(--nl-border-width) solid var(--nl-primary-color);
|
||||||
|
border-radius: var(--nl-border-radius);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
`;
|
`;
|
||||||
button.onmouseover = () => {
|
button.onmouseover = () => {
|
||||||
button.style.boxShadow = '0 4px 6px -1px rgba(0, 0, 0, 0.1)';
|
button.style.borderColor = 'var(--nl-accent-color)';
|
||||||
|
button.style.background = 'var(--nl-secondary-color)';
|
||||||
};
|
};
|
||||||
button.onmouseout = () => {
|
button.onmouseout = () => {
|
||||||
button.style.boxShadow = 'none';
|
button.style.borderColor = 'var(--nl-primary-color)';
|
||||||
|
button.style.background = 'var(--nl-secondary-color)';
|
||||||
};
|
};
|
||||||
|
|
||||||
const iconDiv = document.createElement('div');
|
const iconDiv = document.createElement('div');
|
||||||
iconDiv.textContent = option.icon;
|
// Replace emoji icons with text-based ones
|
||||||
|
const iconMap = {
|
||||||
|
'🔌': '[EXT]',
|
||||||
|
'🔑': '[KEY]',
|
||||||
|
'🌐': '[NET]',
|
||||||
|
'👁️': '[VIEW]',
|
||||||
|
'📱': '[SMS]'
|
||||||
|
};
|
||||||
|
iconDiv.textContent = iconMap[option.icon] || option.icon;
|
||||||
iconDiv.style.cssText = `
|
iconDiv.style.cssText = `
|
||||||
font-size: 24px;
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
margin-right: 16px;
|
margin-right: 16px;
|
||||||
width: 24px;
|
width: 50px;
|
||||||
text-align: center;
|
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');
|
||||||
@@ -235,14 +308,16 @@ class Modal {
|
|||||||
titleDiv.style.cssText = `
|
titleDiv.style.cssText = `
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
color: ${this.options?.darkMode ? 'white' : '#1f2937'};
|
color: var(--nl-primary-color);
|
||||||
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const descDiv = document.createElement('div');
|
const descDiv = document.createElement('div');
|
||||||
descDiv.textContent = option.description;
|
descDiv.textContent = option.description;
|
||||||
descDiv.style.cssText = `
|
descDiv.style.cssText = `
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: ${this.options?.darkMode ? '#9ca3af' : '#6b7280'};
|
color: #666666;
|
||||||
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
contentDiv.appendChild(titleDiv);
|
contentDiv.appendChild(titleDiv);
|
||||||
@@ -446,11 +521,22 @@ class Modal {
|
|||||||
|
|
||||||
const title = document.createElement('h3');
|
const title = document.createElement('h3');
|
||||||
title.textContent = 'Choose Browser Extension';
|
title.textContent = 'Choose Browser Extension';
|
||||||
title.style.cssText = 'margin: 0 0 16px 0; font-size: 18px; font-weight: 600;';
|
title.style.cssText = `
|
||||||
|
margin: 0 0 16px 0;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--nl-primary-color);
|
||||||
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
|
`;
|
||||||
|
|
||||||
const description = document.createElement('p');
|
const description = document.createElement('p');
|
||||||
description.textContent = `Found ${extensions.length} Nostr extensions. Choose which one to use:`;
|
description.textContent = `Found ${extensions.length} Nostr extensions. Choose which one to use:`;
|
||||||
description.style.cssText = 'margin-bottom: 20px; color: #6b7280; font-size: 14px;';
|
description.style.cssText = `
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: #666666;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
|
`;
|
||||||
|
|
||||||
this.modalBody.appendChild(title);
|
this.modalBody.appendChild(title);
|
||||||
this.modalBody.appendChild(description);
|
this.modalBody.appendChild(description);
|
||||||
@@ -465,21 +551,23 @@ class Modal {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
background: ${this.options?.darkMode ? '#374151' : 'white'};
|
background: var(--nl-secondary-color);
|
||||||
border: 1px solid ${this.options?.darkMode ? '#4b5563' : '#d1d5db'};
|
color: var(--nl-primary-color);
|
||||||
border-radius: 8px;
|
border: var(--nl-border-width) solid var(--nl-primary-color);
|
||||||
|
border-radius: var(--nl-border-radius);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
button.onmouseover = () => {
|
button.onmouseover = () => {
|
||||||
button.style.boxShadow = '0 4px 6px -1px rgba(0, 0, 0, 0.1)';
|
button.style.borderColor = 'var(--nl-accent-color)';
|
||||||
button.style.transform = 'translateY(-1px)';
|
button.style.background = 'var(--nl-secondary-color)';
|
||||||
};
|
};
|
||||||
button.onmouseout = () => {
|
button.onmouseout = () => {
|
||||||
button.style.boxShadow = 'none';
|
button.style.borderColor = 'var(--nl-primary-color)';
|
||||||
button.style.transform = 'none';
|
button.style.background = 'var(--nl-secondary-color)';
|
||||||
};
|
};
|
||||||
|
|
||||||
const iconDiv = document.createElement('div');
|
const iconDiv = document.createElement('div');
|
||||||
@@ -499,15 +587,16 @@ class Modal {
|
|||||||
nameDiv.style.cssText = `
|
nameDiv.style.cssText = `
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
color: ${this.options?.darkMode ? 'white' : '#1f2937'};
|
color: var(--nl-primary-color);
|
||||||
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const pathDiv = document.createElement('div');
|
const pathDiv = document.createElement('div');
|
||||||
pathDiv.textContent = ext.name;
|
pathDiv.textContent = ext.name;
|
||||||
pathDiv.style.cssText = `
|
pathDiv.style.cssText = `
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: ${this.options?.darkMode ? '#9ca3af' : '#6b7280'};
|
color: #666666;
|
||||||
font-family: monospace;
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
contentDiv.appendChild(nameDiv);
|
contentDiv.appendChild(nameDiv);
|
||||||
@@ -1041,23 +1130,24 @@ class Modal {
|
|||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
border: none;
|
border: var(--nl-border-width) solid var(--nl-primary-color);
|
||||||
border-radius: 8px;
|
border-radius: var(--nl-border-radius);
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
|
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
if (type === 'primary') {
|
if (type === 'primary') {
|
||||||
return baseStyle + `
|
return baseStyle + `
|
||||||
background: #3b82f6;
|
background: var(--nl-secondary-color);
|
||||||
color: white;
|
color: var(--nl-primary-color);
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
return baseStyle + `
|
return baseStyle + `
|
||||||
background: #6b7280;
|
background: #cccccc;
|
||||||
color: white;
|
color: var(--nl-primary-color);
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user