Fully functioning theme system. Bugs fixed
This commit is contained in:
@@ -205,22 +205,44 @@ The following features are planned but not yet implemented:
|
||||
|
||||
## 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
|
||||
# Edit individual components
|
||||
lite/core/nip46-client.js
|
||||
lite/ui/modal.js
|
||||
lite/nostr-login-lite.js
|
||||
# The main library source code is in:
|
||||
lite/build.js # ← Edit this file for library changes
|
||||
|
||||
# Run bundler to create distribution
|
||||
node lite/bundler.js
|
||||
# To make changes:
|
||||
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
|
||||
|
||||
# Open test page
|
||||
open http://localhost:8000/examples/simple-demo.html
|
||||
# 4. Test changes
|
||||
open http://localhost:8000/examples/modal.html
|
||||
```
|
||||
|
||||
### Local Bundle Setup
|
||||
|
||||
1069
lite/build.js
1069
lite/build.js
File diff suppressed because it is too large
Load Diff
2130
lite/nostr-lite.js
2130
lite/nostr-lite.js
File diff suppressed because it is too large
Load Diff
276
lite/ui/modal.js
276
lite/ui/modal.js
@@ -4,11 +4,13 @@
|
||||
*/
|
||||
|
||||
class Modal {
|
||||
constructor(options) {
|
||||
constructor(options = {}) {
|
||||
this.options = options;
|
||||
this.container = null;
|
||||
this.isVisible = false;
|
||||
this.currentScreen = null;
|
||||
this.isEmbedded = !!options.embedded;
|
||||
this.embeddedContainer = options.embedded;
|
||||
|
||||
// Initialize modal container and styles
|
||||
this._initModal();
|
||||
@@ -17,32 +19,59 @@ class Modal {
|
||||
_initModal() {
|
||||
// Create modal container
|
||||
this.container = document.createElement('div');
|
||||
this.container.id = 'nl-modal';
|
||||
this.container.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
display: none;
|
||||
z-index: 10000;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
`;
|
||||
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 = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
display: none;
|
||||
z-index: 10000;
|
||||
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||
`;
|
||||
}
|
||||
|
||||
// Create modal content
|
||||
const modalContent = document.createElement('div');
|
||||
modalContent.style.cssText = `
|
||||
position: relative;
|
||||
background: white;
|
||||
width: 90%;
|
||||
max-width: 400px;
|
||||
margin: 50px auto;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
||||
max-height: 600px;
|
||||
overflow: hidden;
|
||||
`;
|
||||
if (this.isEmbedded) {
|
||||
// Embedded content: no centering margin, full width
|
||||
modalContent.style.cssText = `
|
||||
position: relative;
|
||||
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%;
|
||||
max-width: 400px;
|
||||
margin: 50px auto;
|
||||
border-radius: var(--nl-border-radius, 15px);
|
||||
border: var(--nl-border-width) solid var(--nl-primary-color);
|
||||
max-height: 600px;
|
||||
overflow: hidden;
|
||||
`;
|
||||
}
|
||||
|
||||
// Header
|
||||
const modalHeader = document.createElement('div');
|
||||
@@ -51,6 +80,8 @@ class Modal {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: transparent;
|
||||
border-bottom: none;
|
||||
`;
|
||||
|
||||
const modalTitle = document.createElement('h2');
|
||||
@@ -59,31 +90,44 @@ class Modal {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #1f2937;
|
||||
color: var(--nl-primary-color);
|
||||
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||
`;
|
||||
|
||||
const closeButton = document.createElement('button');
|
||||
closeButton.innerHTML = '×';
|
||||
closeButton.onclick = () => this.close();
|
||||
closeButton.style.cssText = `
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 28px;
|
||||
color: #6b7280;
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 6px;
|
||||
`;
|
||||
closeButton.onmouseover = () => closeButton.style.background = '#f3f4f6';
|
||||
closeButton.onmouseout = () => closeButton.style.background = 'none';
|
||||
|
||||
modalHeader.appendChild(modalTitle);
|
||||
modalHeader.appendChild(closeButton);
|
||||
|
||||
// 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');
|
||||
closeButton.innerHTML = '×';
|
||||
closeButton.onclick = () => this.close();
|
||||
closeButton.style.cssText = `
|
||||
background: var(--nl-secondary-color);
|
||||
border: var(--nl-border-width) solid var(--nl-primary-color);
|
||||
border-radius: var(--nl-border-radius);
|
||||
font-size: 28px;
|
||||
color: var(--nl-primary-color);
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||
`;
|
||||
closeButton.onmouseover = () => {
|
||||
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(closeButton);
|
||||
}
|
||||
|
||||
// Body
|
||||
this.modalBody = document.createElement('div');
|
||||
@@ -91,38 +135,52 @@ class Modal {
|
||||
padding: 24px;
|
||||
overflow-y: auto;
|
||||
max-height: 500px;
|
||||
background: transparent;
|
||||
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||
`;
|
||||
|
||||
modalContent.appendChild(modalHeader);
|
||||
modalContent.appendChild(this.modalBody);
|
||||
this.container.appendChild(modalContent);
|
||||
|
||||
// Add to body
|
||||
document.body.appendChild(this.container);
|
||||
|
||||
// Click outside to close
|
||||
this.container.onclick = (e) => {
|
||||
if (e.target === this.container) {
|
||||
this.close();
|
||||
// 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);
|
||||
}
|
||||
} 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 (only for modal mode)
|
||||
if (!this.isEmbedded) {
|
||||
this.container.onclick = (e) => {
|
||||
if (e.target === this.container) {
|
||||
this.close();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Update theme
|
||||
this.updateTheme();
|
||||
}
|
||||
|
||||
updateTheme() {
|
||||
const isDark = this.options?.darkMode;
|
||||
const modalContent = this.container.querySelector(':nth-child(1)');
|
||||
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';
|
||||
}
|
||||
// The theme will automatically update through CSS custom properties
|
||||
// No manual styling needed - the CSS variables handle everything
|
||||
}
|
||||
|
||||
open(opts = {}) {
|
||||
@@ -205,26 +263,41 @@ class Modal {
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
margin-bottom: 12px;
|
||||
background: ${this.options?.darkMode ? '#374151' : 'white'};
|
||||
border: 1px solid ${this.options?.darkMode ? '#4b5563' : '#d1d5db'};
|
||||
border-radius: 8px;
|
||||
background: var(--nl-secondary-color);
|
||||
color: var(--nl-primary-color);
|
||||
border: var(--nl-border-width) solid var(--nl-primary-color);
|
||||
border-radius: var(--nl-border-radius);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||
`;
|
||||
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.style.boxShadow = 'none';
|
||||
button.style.borderColor = 'var(--nl-primary-color)';
|
||||
button.style.background = 'var(--nl-secondary-color)';
|
||||
};
|
||||
|
||||
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 = `
|
||||
font-size: 24px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
margin-right: 16px;
|
||||
width: 24px;
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
color: var(--nl-primary-color);
|
||||
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||
`;
|
||||
|
||||
const contentDiv = document.createElement('div');
|
||||
@@ -235,14 +308,16 @@ class Modal {
|
||||
titleDiv.style.cssText = `
|
||||
font-weight: 600;
|
||||
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');
|
||||
descDiv.textContent = option.description;
|
||||
descDiv.style.cssText = `
|
||||
font-size: 14px;
|
||||
color: ${this.options?.darkMode ? '#9ca3af' : '#6b7280'};
|
||||
color: #666666;
|
||||
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||
`;
|
||||
|
||||
contentDiv.appendChild(titleDiv);
|
||||
@@ -446,11 +521,22 @@ class Modal {
|
||||
|
||||
const title = document.createElement('h3');
|
||||
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');
|
||||
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(description);
|
||||
@@ -465,21 +551,23 @@ class Modal {
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
margin-bottom: 12px;
|
||||
background: ${this.options?.darkMode ? '#374151' : 'white'};
|
||||
border: 1px solid ${this.options?.darkMode ? '#4b5563' : '#d1d5db'};
|
||||
border-radius: 8px;
|
||||
background: var(--nl-secondary-color);
|
||||
color: var(--nl-primary-color);
|
||||
border: var(--nl-border-width) solid var(--nl-primary-color);
|
||||
border-radius: var(--nl-border-radius);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
text-align: left;
|
||||
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||
`;
|
||||
|
||||
button.onmouseover = () => {
|
||||
button.style.boxShadow = '0 4px 6px -1px rgba(0, 0, 0, 0.1)';
|
||||
button.style.transform = 'translateY(-1px)';
|
||||
button.style.borderColor = 'var(--nl-accent-color)';
|
||||
button.style.background = 'var(--nl-secondary-color)';
|
||||
};
|
||||
button.onmouseout = () => {
|
||||
button.style.boxShadow = 'none';
|
||||
button.style.transform = 'none';
|
||||
button.style.borderColor = 'var(--nl-primary-color)';
|
||||
button.style.background = 'var(--nl-secondary-color)';
|
||||
};
|
||||
|
||||
const iconDiv = document.createElement('div');
|
||||
@@ -499,15 +587,16 @@ class Modal {
|
||||
nameDiv.style.cssText = `
|
||||
font-weight: 600;
|
||||
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');
|
||||
pathDiv.textContent = ext.name;
|
||||
pathDiv.style.cssText = `
|
||||
font-size: 12px;
|
||||
color: ${this.options?.darkMode ? '#9ca3af' : '#6b7280'};
|
||||
font-family: monospace;
|
||||
color: #666666;
|
||||
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||
`;
|
||||
|
||||
contentDiv.appendChild(nameDiv);
|
||||
@@ -1041,23 +1130,24 @@ class Modal {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
border: var(--nl-border-width) solid var(--nl-primary-color);
|
||||
border-radius: var(--nl-border-radius);
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-family: var(--nl-font-family, 'Courier New', monospace);
|
||||
`;
|
||||
|
||||
if (type === 'primary') {
|
||||
return baseStyle + `
|
||||
background: #3b82f6;
|
||||
color: white;
|
||||
background: var(--nl-secondary-color);
|
||||
color: var(--nl-primary-color);
|
||||
`;
|
||||
} else {
|
||||
return baseStyle + `
|
||||
background: #6b7280;
|
||||
color: white;
|
||||
background: #cccccc;
|
||||
color: var(--nl-primary-color);
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user