fix: Use solid RGB colors for modal and menu backgrounds
Problem: CSS variables --rpg-bg and --rpg-accent have 0.9 opacity, making all modals and menus transparent even with gradient backgrounds. Solution: Use solid RGB colors directly in gradients: - rgba(22, 33, 62, 1) instead of var(--rpg-accent) - rgba(26, 26, 46, 1) instead of var(--rpg-bg) Changes: - style.css: .rpg-modal-content uses solid gradient - tabContextMenu.js: Context menu uses solid gradient - Both maintain inset shadow for depth - Mobile long-press support included Now modals and context menus have opaque backgrounds matching widget styling instead of see-through transparency.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Prompt Dialog System
|
||||
*
|
||||
* Provides styled prompt dialogs for text input, similar to confirmDialog.
|
||||
* Provides styled prompt dialogs for text input, matching extension theming.
|
||||
* Used for tab renaming, creation, etc.
|
||||
*/
|
||||
|
||||
@@ -29,98 +29,55 @@ export function showPromptDialog(options) {
|
||||
validator = null
|
||||
} = options;
|
||||
|
||||
// Create modal container
|
||||
// Create modal container (uses .rpg-modal class for theming)
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'rpg-modal rpg-prompt-modal';
|
||||
modal.style.display = 'flex';
|
||||
modal.style.position = 'fixed';
|
||||
modal.style.inset = '0';
|
||||
modal.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
|
||||
modal.style.zIndex = '10001';
|
||||
modal.style.alignItems = 'center';
|
||||
modal.style.justifyContent = 'center';
|
||||
|
||||
// Create modal content
|
||||
// Create modal content (uses .rpg-modal-content class for theming)
|
||||
const modalContent = document.createElement('div');
|
||||
modalContent.className = 'rpg-modal-content rpg-prompt-content';
|
||||
modalContent.style.cssText = `
|
||||
background: #16213e;
|
||||
border-radius: 8px;
|
||||
padding: 0;
|
||||
min-width: 400px;
|
||||
max-width: 90vw;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
|
||||
`;
|
||||
|
||||
// Header
|
||||
// Header (uses .rpg-modal-header class)
|
||||
const header = document.createElement('div');
|
||||
header.className = 'rpg-modal-header';
|
||||
header.style.cssText = `
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #0f3460;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
`;
|
||||
|
||||
const headerContent = document.createElement('div');
|
||||
headerContent.style.display = 'flex';
|
||||
headerContent.style.alignItems = 'center';
|
||||
headerContent.style.gap = '10px';
|
||||
headerContent.style.gap = '0.5rem';
|
||||
|
||||
const icon = document.createElement('i');
|
||||
icon.className = 'fa-solid fa-pencil';
|
||||
icon.style.color = '#4ecca3';
|
||||
icon.style.fontSize = '20px';
|
||||
icon.style.color = 'var(--rpg-highlight)';
|
||||
|
||||
const titleEl = document.createElement('h3');
|
||||
titleEl.textContent = title;
|
||||
titleEl.style.cssText = `
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
color: #eeeeee;
|
||||
`;
|
||||
titleEl.style.margin = '0';
|
||||
|
||||
const closeBtn = document.createElement('button');
|
||||
closeBtn.className = 'rpg-modal-close';
|
||||
closeBtn.innerHTML = '<i class="fa-solid fa-times"></i>';
|
||||
closeBtn.style.cssText = `
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #eeeeee;
|
||||
font-size: 20px;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: background 0.2s;
|
||||
`;
|
||||
closeBtn.onmouseenter = () => closeBtn.style.background = '#e94560';
|
||||
closeBtn.onmouseleave = () => closeBtn.style.background = 'transparent';
|
||||
|
||||
headerContent.appendChild(icon);
|
||||
headerContent.appendChild(titleEl);
|
||||
header.appendChild(headerContent);
|
||||
header.appendChild(closeBtn);
|
||||
|
||||
// Body
|
||||
// Body (uses .rpg-modal-body class)
|
||||
const body = document.createElement('div');
|
||||
body.className = 'rpg-modal-body';
|
||||
body.style.cssText = `
|
||||
padding: 20px;
|
||||
`;
|
||||
|
||||
if (message) {
|
||||
const messageEl = document.createElement('p');
|
||||
messageEl.textContent = message;
|
||||
messageEl.style.cssText = `
|
||||
margin: 0 0 15px 0;
|
||||
color: #eeeeee;
|
||||
font-size: 14px;
|
||||
margin: 0 0 1rem 0;
|
||||
color: var(--rpg-text);
|
||||
`;
|
||||
body.appendChild(messageEl);
|
||||
}
|
||||
@@ -131,12 +88,12 @@ export function showPromptDialog(options) {
|
||||
input.placeholder = placeholder;
|
||||
input.style.cssText = `
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
background: #0f3460;
|
||||
border: 1px solid #1a4d7a;
|
||||
padding: 0.5rem;
|
||||
background: var(--rpg-accent);
|
||||
border: 1px solid var(--rpg-border);
|
||||
border-radius: 4px;
|
||||
color: #eeeeee;
|
||||
font-size: 14px;
|
||||
color: var(--rpg-text);
|
||||
font-size: 1rem;
|
||||
font-family: inherit;
|
||||
box-sizing: border-box;
|
||||
`;
|
||||
@@ -144,58 +101,26 @@ export function showPromptDialog(options) {
|
||||
const errorEl = document.createElement('div');
|
||||
errorEl.className = 'rpg-prompt-error';
|
||||
errorEl.style.cssText = `
|
||||
margin-top: 8px;
|
||||
color: #e94560;
|
||||
font-size: 12px;
|
||||
min-height: 18px;
|
||||
margin-top: 0.5rem;
|
||||
color: var(--rpg-highlight);
|
||||
font-size: 0.875rem;
|
||||
min-height: 1.25rem;
|
||||
`;
|
||||
|
||||
body.appendChild(input);
|
||||
body.appendChild(errorEl);
|
||||
|
||||
// Footer
|
||||
// Footer (uses .rpg-modal-footer class)
|
||||
const footer = document.createElement('div');
|
||||
footer.className = 'rpg-modal-footer';
|
||||
footer.style.cssText = `
|
||||
padding: 20px;
|
||||
border-top: 1px solid #0f3460;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: flex-end;
|
||||
`;
|
||||
|
||||
const cancelBtn = document.createElement('button');
|
||||
cancelBtn.className = 'rpg-btn-secondary';
|
||||
cancelBtn.textContent = cancelText;
|
||||
cancelBtn.style.cssText = `
|
||||
padding: 10px 20px;
|
||||
background: #0f3460;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
color: #eeeeee;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
`;
|
||||
cancelBtn.onmouseenter = () => cancelBtn.style.background = '#1a4d7a';
|
||||
cancelBtn.onmouseleave = () => cancelBtn.style.background = '#0f3460';
|
||||
cancelBtn.innerHTML = `<i class="fa-solid fa-times"></i> ${cancelText}`;
|
||||
|
||||
const confirmBtn = document.createElement('button');
|
||||
confirmBtn.className = 'rpg-btn-primary';
|
||||
confirmBtn.textContent = confirmText;
|
||||
confirmBtn.style.cssText = `
|
||||
padding: 10px 20px;
|
||||
background: #4ecca3;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
color: #16213e;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: background 0.2s;
|
||||
`;
|
||||
confirmBtn.onmouseenter = () => confirmBtn.style.background = '#45b993';
|
||||
confirmBtn.onmouseleave = () => confirmBtn.style.background = '#4ecca3';
|
||||
confirmBtn.innerHTML = `<i class="fa-solid fa-check"></i> ${confirmText}`;
|
||||
|
||||
footer.appendChild(cancelBtn);
|
||||
footer.appendChild(confirmBtn);
|
||||
|
||||
@@ -45,7 +45,12 @@ export class TabContextMenu {
|
||||
attachHandlers() {
|
||||
if (!this.tabsContainer) return;
|
||||
|
||||
// Use event delegation for dynamically added tabs
|
||||
// Long press support for mobile
|
||||
let longPressTimer = null;
|
||||
let longPressTarget = null;
|
||||
let touchStartPos = { x: 0, y: 0 };
|
||||
|
||||
// Desktop: Right-click context menu
|
||||
this.tabsContainer.addEventListener('contextmenu', (e) => {
|
||||
// Find closest tab element
|
||||
const tabElement = e.target.closest('.rpg-dashboard-tab');
|
||||
@@ -60,8 +65,77 @@ export class TabContextMenu {
|
||||
this.showMenu(e.pageX, e.pageY, tabId);
|
||||
});
|
||||
|
||||
// Close menu on any click outside
|
||||
// Mobile: Long press support (touch and hold)
|
||||
this.tabsContainer.addEventListener('touchstart', (e) => {
|
||||
const tabElement = e.target.closest('.rpg-dashboard-tab');
|
||||
if (!tabElement) return;
|
||||
|
||||
const tabId = tabElement.dataset.tabId;
|
||||
if (!tabId) return;
|
||||
|
||||
// Store touch position
|
||||
const touch = e.touches[0];
|
||||
touchStartPos = { x: touch.pageX, y: touch.pageY };
|
||||
longPressTarget = { tabId, x: touch.pageX, y: touch.pageY };
|
||||
|
||||
// Start long press timer (500ms)
|
||||
longPressTimer = setTimeout(() => {
|
||||
if (longPressTarget) {
|
||||
// Prevent default touch behavior
|
||||
e.preventDefault();
|
||||
// Show context menu at touch position
|
||||
this.showMenu(longPressTarget.x, longPressTarget.y, longPressTarget.tabId);
|
||||
// Provide haptic feedback if available
|
||||
if (navigator.vibrate) {
|
||||
navigator.vibrate(50);
|
||||
}
|
||||
longPressTarget = null;
|
||||
}
|
||||
}, 500);
|
||||
}, { passive: false });
|
||||
|
||||
// Cancel long press on touch move (if moved too far)
|
||||
this.tabsContainer.addEventListener('touchmove', (e) => {
|
||||
if (!longPressTimer) return;
|
||||
|
||||
const touch = e.touches[0];
|
||||
const deltaX = Math.abs(touch.pageX - touchStartPos.x);
|
||||
const deltaY = Math.abs(touch.pageY - touchStartPos.y);
|
||||
|
||||
// Cancel if moved more than 10px
|
||||
if (deltaX > 10 || deltaY > 10) {
|
||||
clearTimeout(longPressTimer);
|
||||
longPressTimer = null;
|
||||
longPressTarget = null;
|
||||
}
|
||||
});
|
||||
|
||||
// Cancel long press on touch end (if timer still running)
|
||||
this.tabsContainer.addEventListener('touchend', () => {
|
||||
if (longPressTimer) {
|
||||
clearTimeout(longPressTimer);
|
||||
longPressTimer = null;
|
||||
longPressTarget = null;
|
||||
}
|
||||
});
|
||||
|
||||
// Cancel long press on touch cancel
|
||||
this.tabsContainer.addEventListener('touchcancel', () => {
|
||||
if (longPressTimer) {
|
||||
clearTimeout(longPressTimer);
|
||||
longPressTimer = null;
|
||||
longPressTarget = null;
|
||||
}
|
||||
});
|
||||
|
||||
// Close menu on any click/touch outside
|
||||
document.addEventListener('click', () => this.hideMenu());
|
||||
document.addEventListener('touchstart', (e) => {
|
||||
// Close menu if touching outside context menu
|
||||
if (this.menu && !this.menu.contains(e.target)) {
|
||||
this.hideMenu();
|
||||
}
|
||||
});
|
||||
document.addEventListener('contextmenu', (e) => {
|
||||
// Only hide if right-clicking outside tabs
|
||||
if (!e.target.closest('.rpg-dashboard-tab')) {
|
||||
@@ -83,17 +157,17 @@ export class TabContextMenu {
|
||||
const tab = this.tabManager.getTab(tabId);
|
||||
if (!tab) return;
|
||||
|
||||
// Create menu container
|
||||
// Create menu container (matches widget styling with solid background)
|
||||
this.menu = document.createElement('div');
|
||||
this.menu.className = 'rpg-tab-context-menu';
|
||||
this.menu.style.cssText = `
|
||||
position: fixed;
|
||||
left: ${x}px;
|
||||
top: ${y}px;
|
||||
background: #16213e;
|
||||
border: 1px solid #0f3460;
|
||||
background: linear-gradient(135deg, rgba(22, 33, 62, 1) 0%, rgba(26, 26, 46, 1) 100%);
|
||||
border: 2px solid var(--rpg-border);
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
|
||||
box-shadow: 0 4px 18px var(--rpg-shadow), inset 0 0 12px rgba(0, 0, 0, 0.3);
|
||||
z-index: 10002;
|
||||
min-width: 180px;
|
||||
padding: 6px 0;
|
||||
@@ -115,7 +189,7 @@ export class TabContextMenu {
|
||||
const separator = document.createElement('div');
|
||||
separator.style.cssText = `
|
||||
height: 1px;
|
||||
background: #0f3460;
|
||||
background: var(--rpg-border);
|
||||
margin: 6px 0;
|
||||
`;
|
||||
this.menu.appendChild(separator);
|
||||
@@ -142,8 +216,8 @@ export class TabContextMenu {
|
||||
const menuItem = document.createElement('div');
|
||||
menuItem.className = 'rpg-tab-context-menu-item';
|
||||
|
||||
const baseColor = item.danger ? '#e94560' : '#eeeeee';
|
||||
const hoverBg = item.danger ? '#8b2a3a' : '#0f3460';
|
||||
const baseColor = item.danger ? 'var(--rpg-highlight)' : 'var(--rpg-text)';
|
||||
const hoverBg = item.danger ? 'rgba(233, 69, 96, 0.2)' : 'var(--rpg-accent)';
|
||||
|
||||
menuItem.style.cssText = `
|
||||
padding: 10px 16px;
|
||||
@@ -172,7 +246,7 @@ export class TabContextMenu {
|
||||
icon.style.cssText = `
|
||||
width: 16px;
|
||||
text-align: center;
|
||||
color: ${item.danger ? '#e94560' : '#4ecca3'};
|
||||
color: ${item.danger ? 'var(--rpg-highlight)' : 'var(--rpg-border)'};
|
||||
`;
|
||||
|
||||
const label = document.createElement('span');
|
||||
@@ -338,44 +412,31 @@ export class TabContextMenu {
|
||||
*/
|
||||
showIconPicker(iconOptions, currentIcon) {
|
||||
return new Promise((resolve) => {
|
||||
// Create modal
|
||||
// Create modal (uses .rpg-modal class for theming)
|
||||
const modal = document.createElement('div');
|
||||
modal.className = 'rpg-modal';
|
||||
modal.style.cssText = `
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(0,0,0,0.7);
|
||||
z-index: 10001;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
`;
|
||||
modal.style.display = 'flex';
|
||||
|
||||
// Modal content (uses .rpg-modal-content class for theming)
|
||||
const content = document.createElement('div');
|
||||
content.className = 'rpg-modal-content';
|
||||
content.style.cssText = `
|
||||
background: #16213e;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
max-width: 500px;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
`;
|
||||
content.style.padding = '1.5rem';
|
||||
content.style.maxWidth = '500px';
|
||||
|
||||
const title = document.createElement('h3');
|
||||
title.textContent = 'Choose Icon';
|
||||
title.style.cssText = `
|
||||
margin: 0 0 20px 0;
|
||||
color: #eeeeee;
|
||||
font-size: 18px;
|
||||
margin: 0 0 1.25rem 0;
|
||||
color: var(--rpg-text);
|
||||
font-size: 1.25rem;
|
||||
`;
|
||||
|
||||
const grid = document.createElement('div');
|
||||
grid.style.cssText = `
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 12px;
|
||||
margin-bottom: 20px;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 1.25rem;
|
||||
`;
|
||||
|
||||
// Extract icon name without fa-solid prefix for comparison
|
||||
@@ -386,12 +447,12 @@ export class TabContextMenu {
|
||||
const isSelected = option.icon === currentIconName;
|
||||
|
||||
iconBtn.style.cssText = `
|
||||
padding: 16px;
|
||||
background: ${isSelected ? '#4ecca3' : '#0f3460'};
|
||||
border: 2px solid ${isSelected ? '#4ecca3' : '#1a4d7a'};
|
||||
padding: 1rem;
|
||||
background: ${isSelected ? 'var(--rpg-highlight)' : 'var(--rpg-accent)'};
|
||||
border: 2px solid ${isSelected ? 'var(--rpg-highlight)' : 'var(--rpg-border)'};
|
||||
border-radius: 6px;
|
||||
color: ${isSelected ? '#16213e' : '#eeeeee'};
|
||||
font-size: 24px;
|
||||
color: ${isSelected ? 'white' : 'var(--rpg-text)'};
|
||||
font-size: 1.5rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
@@ -404,14 +465,14 @@ export class TabContextMenu {
|
||||
|
||||
iconBtn.onmouseenter = () => {
|
||||
if (!isSelected) {
|
||||
iconBtn.style.background = '#1a4d7a';
|
||||
iconBtn.style.borderColor = '#4ecca3';
|
||||
iconBtn.style.borderColor = 'var(--rpg-highlight)';
|
||||
iconBtn.style.transform = 'scale(1.05)';
|
||||
}
|
||||
};
|
||||
iconBtn.onmouseleave = () => {
|
||||
if (!isSelected) {
|
||||
iconBtn.style.background = '#0f3460';
|
||||
iconBtn.style.borderColor = '#1a4d7a';
|
||||
iconBtn.style.borderColor = 'var(--rpg-border)';
|
||||
iconBtn.style.transform = 'scale(1)';
|
||||
}
|
||||
};
|
||||
|
||||
@@ -424,17 +485,9 @@ export class TabContextMenu {
|
||||
});
|
||||
|
||||
const cancelBtn = document.createElement('button');
|
||||
cancelBtn.textContent = 'Cancel';
|
||||
cancelBtn.style.cssText = `
|
||||
padding: 10px 20px;
|
||||
background: #0f3460;
|
||||
border: none;
|
||||
border-radius: 6px;
|
||||
color: #eeeeee;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
`;
|
||||
cancelBtn.className = 'rpg-btn-secondary';
|
||||
cancelBtn.innerHTML = '<i class="fa-solid fa-times"></i> Cancel';
|
||||
cancelBtn.style.width = '100%';
|
||||
cancelBtn.onclick = () => {
|
||||
modal.remove();
|
||||
resolve(null);
|
||||
|
||||
@@ -1479,13 +1479,13 @@ body:has(.rpg-panel.rpg-position-left) #sheld {
|
||||
|
||||
/* Modal Content Container */
|
||||
.rpg-modal-content {
|
||||
background: var(--rpg-bg);
|
||||
background: linear-gradient(135deg, rgba(22, 33, 62, 1) 0%, rgba(26, 26, 46, 1) 100%);
|
||||
border: 2px solid var(--rpg-border);
|
||||
border-radius: 8px;
|
||||
max-width: 600px;
|
||||
max-height: 80vh;
|
||||
overflow: auto;
|
||||
box-shadow: 0 4px 20px var(--rpg-shadow);
|
||||
box-shadow: 0 4px 18px var(--rpg-shadow), inset 0 0 12px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/* Modal Header */
|
||||
|
||||
Reference in New Issue
Block a user