Fully functioning theme system. Bugs fixed

This commit is contained in:
Your Name
2025-09-14 13:23:52 -04:00
parent 3b1eb7f951
commit b59bf17372
4 changed files with 2124 additions and 1393 deletions

View File

@@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -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,32 +19,59 @@ 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';
this.container.style.cssText = `
position: fixed; if (this.isEmbedded) {
top: 0; // Embedded mode: inline positioning, no overlay
left: 0; this.container.style.cssText = `
right: 0; position: relative;
bottom: 0; display: none;
background: rgba(0, 0, 0, 0.75); font-family: var(--nl-font-family, 'Courier New', monospace);
display: none; width: 100%;
z-index: 10000; `;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } 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 // Create modal content
const modalContent = document.createElement('div'); const modalContent = document.createElement('div');
modalContent.style.cssText = ` if (this.isEmbedded) {
position: relative; // Embedded content: no centering margin, full width
background: white; modalContent.style.cssText = `
width: 90%; position: relative;
max-width: 400px; background: var(--nl-secondary-color);
margin: 50px auto; color: var(--nl-primary-color);
border-radius: 12px; width: 100%;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); border-radius: var(--nl-border-radius, 15px);
max-height: 600px; border: var(--nl-border-width) solid var(--nl-primary-color);
overflow: hidden; 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 // 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,31 +90,44 @@ 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);
`; `;
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(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 // 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
document.body.appendChild(this.container); if (this.isEmbedded && this.embeddedContainer) {
// Append to specified container for embedding
// Click outside to close if (typeof this.embeddedContainer === 'string') {
this.container.onclick = (e) => { const targetElement = document.querySelector(this.embeddedContainer);
if (e.target === this.container) { if (targetElement) {
this.close(); 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 // 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);
`; `;
} }
} }