Replace alert/confirm with modals, hide sector numbers on cramped layout, enforce 2/3/6 grid for All Sectors
This commit is contained in:
parent
638947f04c
commit
21cb0aeb50
4 changed files with 151 additions and 14 deletions
|
|
@ -66,6 +66,23 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Cramped / Mobile viewport: Hide sector pill numbers so only icons are displayed */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.sector-pill .sector-pill-rate {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sector-pill {
|
||||||
|
padding: 8px 4px;
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sector-pill iconify-icon {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ==========================================================================
|
/* ==========================================================================
|
||||||
TOASTS & MODALS
|
TOASTS & MODALS
|
||||||
========================================================================== */
|
========================================================================== */
|
||||||
|
|
@ -232,3 +249,20 @@
|
||||||
.btn-text-close:hover {
|
.btn-text-close:hover {
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal-error-box {
|
||||||
|
background: #fef2f2;
|
||||||
|
border: 1px solid #fecaca;
|
||||||
|
color: #b91c1c;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
font-size: 0.78rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body-text {
|
||||||
|
font-size: 0.88rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -216,13 +216,33 @@
|
||||||
color: var(--emerald-dark);
|
color: var(--emerald-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* All Sectors Overview Grid */
|
/* All Sectors Overview Grid (Strict 6, 3, or 2 grid for 6 sectors) */
|
||||||
.all-sectors-summary-grid {
|
.all-sectors-summary-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
grid-template-columns: repeat(3, 1fr);
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 1400px) {
|
||||||
|
.all-sectors-summary-grid {
|
||||||
|
grid-template-columns: repeat(6, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.all-sectors-summary-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.all-sectors-summary-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.sector-mini-card {
|
.sector-mini-card {
|
||||||
background: var(--bg-surface);
|
background: var(--bg-surface);
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
|
|
|
||||||
|
|
@ -213,6 +213,9 @@
|
||||||
<input type="password" id="auth-password" class="modal-input" placeholder="••••••••" autocomplete="current-password">
|
<input type="password" id="auth-password" class="modal-input" placeholder="••••••••" autocomplete="current-password">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- In-modal Error Feedback (Replacing alert()) -->
|
||||||
|
<div id="auth-error-msg" class="modal-error-box" style="display: none;"></div>
|
||||||
|
|
||||||
<!-- Honeypot field for bot protection -->
|
<!-- Honeypot field for bot protection -->
|
||||||
<div style="display: none;" aria-hidden="true">
|
<div style="display: none;" aria-hidden="true">
|
||||||
<input type="text" id="auth-website-hp" name="website_hp" tabindex="-1" autocomplete="off">
|
<input type="text" id="auth-website-hp" name="website_hp" tabindex="-1" autocomplete="off">
|
||||||
|
|
@ -227,6 +230,24 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Universal Corporate Confirmation & Prompt Modal (No browser alert() / confirm()) -->
|
||||||
|
<div id="confirm-modal" class="modal-overlay">
|
||||||
|
<div class="modal-card">
|
||||||
|
<div class="modal-header">
|
||||||
|
<iconify-icon icon="lucide:alert-triangle" class="modal-icon text-warning" id="confirm-modal-icon"></iconify-icon>
|
||||||
|
<div>
|
||||||
|
<h3 class="modal-title" id="confirm-modal-title">Executive Action Required</h3>
|
||||||
|
<p class="modal-subtitle" id="confirm-modal-subtitle">Corporate Board Authorization</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body-text" id="confirm-modal-text"></div>
|
||||||
|
<div class="modal-actions-row">
|
||||||
|
<button id="btn-confirm-cancel" class="btn-corp-secondary">Cancel</button>
|
||||||
|
<button id="btn-confirm-ok" class="btn-primary-corp">Confirm Authorization</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Application Entry Point (Native ES Module) -->
|
<!-- Application Entry Point (Native ES Module) -->
|
||||||
|
|
|
||||||
|
|
@ -275,15 +275,23 @@ class ProductionApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'TRIGGER_IPO': {
|
case 'TRIGGER_IPO': {
|
||||||
const confirmed = confirm('Confirm Corporate Initial Public Offering (IPO)?\n\nYour factories and cash will reset in exchange for permanent Venture Shares ($V-Shares) and corporate equity!');
|
this.showConfirmModal({
|
||||||
if (confirmed) {
|
title: 'Authorize Initial Public Offering (IPO)',
|
||||||
const success = this.sm.performIPO();
|
subtitle: 'Corporate Equity Transition',
|
||||||
if (success) {
|
icon: 'lucide:trending-up',
|
||||||
this.showToast(`IPO Successful! Welcome to Wall Street, CEO!`, 'success');
|
text: 'Confirm Corporate Initial Public Offering (IPO)?<br><br>All factory floors and cash will be liquidated in exchange for permanent <strong>Venture Shares ($V-Shares)</strong> and corporate prestige bonuses!',
|
||||||
this.mountActiveView();
|
okText: 'Execute IPO',
|
||||||
this.mountInspectorPane();
|
cancelText: 'Abort'
|
||||||
|
}).then(confirmed => {
|
||||||
|
if (confirmed) {
|
||||||
|
const success = this.sm.performIPO();
|
||||||
|
if (success) {
|
||||||
|
this.showToast(`IPO Successful! Welcome to Wall Street, CEO!`, 'success');
|
||||||
|
this.mountActiveView();
|
||||||
|
this.mountInspectorPane();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -468,8 +476,52 @@ class ProductionApp {
|
||||||
}, 3200);
|
}, 3200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showConfirmModal({ title = 'Executive Authorization', subtitle = 'Board Confirmation', icon = 'lucide:alert-triangle', text = '', okText = 'Confirm', cancelText = 'Cancel' } = {}) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const modal = document.getElementById('confirm-modal');
|
||||||
|
const elTitle = document.getElementById('confirm-modal-title');
|
||||||
|
const elSub = document.getElementById('confirm-modal-subtitle');
|
||||||
|
const elIcon = document.getElementById('confirm-modal-icon');
|
||||||
|
const elText = document.getElementById('confirm-modal-text');
|
||||||
|
const btnOk = document.getElementById('btn-confirm-ok');
|
||||||
|
const btnCancel = document.getElementById('btn-confirm-cancel');
|
||||||
|
|
||||||
|
if (!modal) return resolve(false);
|
||||||
|
|
||||||
|
if (elTitle) elTitle.textContent = title;
|
||||||
|
if (elSub) elSub.textContent = subtitle;
|
||||||
|
if (elIcon) elIcon.setAttribute('icon', icon);
|
||||||
|
if (elText) elText.innerHTML = text;
|
||||||
|
if (btnOk) btnOk.textContent = okText;
|
||||||
|
if (btnCancel) btnCancel.textContent = cancelText;
|
||||||
|
|
||||||
|
const cleanup = () => {
|
||||||
|
modal.classList.remove('open');
|
||||||
|
btnOk.onclick = null;
|
||||||
|
btnCancel.onclick = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
btnOk.onclick = () => {
|
||||||
|
cleanup();
|
||||||
|
resolve(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
btnCancel.onclick = () => {
|
||||||
|
cleanup();
|
||||||
|
resolve(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
modal.classList.add('open');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
openAuthModal() {
|
openAuthModal() {
|
||||||
const modal = document.getElementById('auth-modal');
|
const modal = document.getElementById('auth-modal');
|
||||||
|
const errBox = document.getElementById('auth-error-msg');
|
||||||
|
if (errBox) {
|
||||||
|
errBox.style.display = 'none';
|
||||||
|
errBox.textContent = '';
|
||||||
|
}
|
||||||
if (modal) modal.classList.add('open');
|
if (modal) modal.classList.add('open');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -478,10 +530,20 @@ class ProductionApp {
|
||||||
if (modal) modal.classList.remove('open');
|
if (modal) modal.classList.remove('open');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showAuthError(msg) {
|
||||||
|
const errBox = document.getElementById('auth-error-msg');
|
||||||
|
if (errBox) {
|
||||||
|
errBox.textContent = msg;
|
||||||
|
errBox.style.display = 'block';
|
||||||
|
} else {
|
||||||
|
this.showToast(msg, 'warning');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async handleLogin() {
|
async handleLogin() {
|
||||||
const u = document.getElementById('auth-username')?.value.trim();
|
const u = document.getElementById('auth-username')?.value.trim();
|
||||||
const p = document.getElementById('auth-password')?.value;
|
const p = document.getElementById('auth-password')?.value;
|
||||||
if (!u || !p) return alert('Please enter username and password');
|
if (!u || !p) return this.showAuthError('Please enter username and password');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.sync.login(u, p);
|
await this.sync.login(u, p);
|
||||||
|
|
@ -489,7 +551,7 @@ class ProductionApp {
|
||||||
this.closeAuthModal();
|
this.closeAuthModal();
|
||||||
this.updateHud();
|
this.updateHud();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert(err.message || 'Login failed');
|
this.showAuthError(err.message || 'Login failed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -497,7 +559,7 @@ class ProductionApp {
|
||||||
const u = document.getElementById('auth-username')?.value.trim();
|
const u = document.getElementById('auth-username')?.value.trim();
|
||||||
const p = document.getElementById('auth-password')?.value;
|
const p = document.getElementById('auth-password')?.value;
|
||||||
const hp = document.getElementById('auth-website-hp')?.value;
|
const hp = document.getElementById('auth-website-hp')?.value;
|
||||||
if (!u || !p) return alert('Please enter username and password');
|
if (!u || !p) return this.showAuthError('Please enter username and password');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.sync.register(u, p, hp);
|
await this.sync.register(u, p, hp);
|
||||||
|
|
@ -505,7 +567,7 @@ class ProductionApp {
|
||||||
this.closeAuthModal();
|
this.closeAuthModal();
|
||||||
this.updateHud();
|
this.updateHud();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert(err.message || 'Registration failed');
|
this.showAuthError(err.message || 'Registration failed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue