Center sector bar in sticky header, consolidate financial hub, and integrate department nav buttons

This commit is contained in:
Christian 2026-10-16 12:58:51 +02:00
parent 0a9a022fbc
commit f68ecbd20c
6 changed files with 263 additions and 63 deletions

View file

@ -98,48 +98,89 @@
background: var(--primary-blue-light); background: var(--primary-blue-light);
} }
/* Financial HUD Grid */ /* Financial HUD: Desktop 3-part layout (Left: Finances, Center: Sector Bar, Right: Dept Buttons & Multiplier) */
#financial-hud { #financial-hud {
display: grid; display: flex;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); justify-content: space-between;
gap: 12px;
padding: 10px 16px;
align-items: center; align-items: center;
gap: 16px;
padding: 8px 16px;
max-width: 1680px;
margin: 0 auto;
box-sizing: border-box;
} }
.hud-stat-box { /* Consolidated Executive Financial Hub */
background: var(--bg-surface); .executive-fin-hub {
border: 1px solid var(--border-color); display: flex;
flex-direction: row;
align-items: center;
gap: 14px;
padding: 6px 14px;
border-radius: var(--radius-md); border-radius: var(--radius-md);
padding: 8px 12px; background: #f8faff;
border: 1px solid #bfdbfe;
flex-shrink: 0;
min-width: 270px;
box-shadow: var(--shadow-sm);
}
.fin-hub-main {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.primary-hud-box { .fin-hub-divider {
border-color: #bfdbfe; width: 1px;
background: #f8faff; height: 38px;
background: #cbd5e1;
}
.fin-hub-details {
display: flex;
flex-direction: column;
gap: 2px;
}
.fin-detail-row {
display: flex;
align-items: center;
gap: 6px;
font-size: 0.75rem;
white-space: nowrap;
}
.fin-detail-label {
font-size: 0.68rem;
font-weight: 700;
color: var(--text-muted);
text-transform: uppercase;
}
.fin-detail-val {
font-weight: 700;
color: var(--text-primary);
} }
.hud-label { .hud-label {
font-size: 0.72rem; font-size: 0.68rem;
font-weight: 600; font-weight: 700;
color: var(--text-secondary); color: var(--text-secondary);
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.04em; letter-spacing: 0.04em;
} }
.hud-main-val { .hud-main-val {
font-size: 1.25rem; font-size: 1.20rem;
font-weight: 700; font-weight: 800;
color: var(--text-primary); color: var(--text-primary);
line-height: 1.2; line-height: 1.1;
margin: 2px 0; margin: 1px 0;
} }
.hud-sub-val { .hud-sub-val {
font-size: 0.75rem; font-size: 0.72rem;
font-weight: 600; font-weight: 700;
} }
.rate-positive { .rate-positive {
@ -150,17 +191,100 @@
color: var(--purple-rnd); color: var(--purple-rnd);
} }
/* Centered Sector Container in Sticky Header */
#header-sector-container {
flex: 1;
display: flex;
justify-content: center;
min-width: 0;
max-width: 820px;
}
#header-sector-container .production-toolbar {
width: 100%;
background: var(--bg-surface);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
padding: 4px 6px;
box-sizing: border-box;
box-shadow: 0 1px 2px rgba(0,0,0,0.03);
}
#header-sector-container .sector-pill {
padding: 6px 4px;
}
/* Right Header Actions: Department Nav & Buy Multiplier */
.header-right-actions {
display: flex;
align-items: center;
gap: 10px;
flex-shrink: 0;
}
.header-nav-group {
display: flex;
align-items: center;
gap: 4px;
background: var(--bg-surface-sub);
border: 1px solid var(--border-color);
border-radius: var(--radius-sm);
padding: 3px;
}
.header-nav-btn {
display: inline-flex;
align-items: center;
gap: 5px;
padding: 5px 10px;
background: transparent;
border: 1px solid transparent;
border-radius: 4px;
color: var(--text-secondary);
font-size: 0.78rem;
font-weight: 700;
cursor: pointer;
transition: all 0.15s;
white-space: nowrap;
text-decoration: none;
line-height: 1;
}
.header-nav-btn iconify-icon {
font-size: 1.05rem;
}
.header-nav-btn:hover {
background: var(--bg-surface);
color: var(--text-primary);
border-color: var(--border-color);
}
.header-nav-btn.active {
background: var(--primary-blue);
color: #ffffff;
border-color: var(--primary-blue);
box-shadow: var(--shadow-sm);
}
.header-nav-btn.active .nav-pill-badge {
background: #ffffff;
color: var(--primary-blue);
}
.header-nav-btn.active iconify-icon {
color: #ffffff;
}
.header-nav-btn .nav-pill-badge {
margin-left: 2px;
padding: 1px 5px;
font-size: 0.65rem;
}
.hud-multiplier-box { .hud-multiplier-box {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px;
justify-content: flex-end;
}
.multi-label {
font-size: 0.72rem;
font-weight: 700;
color: var(--text-secondary);
} }
.multi-button-group { .multi-button-group {
@ -175,7 +299,7 @@
.btn-multi-pill { .btn-multi-pill {
background: transparent; background: transparent;
border: none; border: none;
padding: 4px 10px; padding: 4px 8px;
border-radius: 4px; border-radius: 4px;
font-size: 0.75rem; font-size: 0.75rem;
font-weight: 700; font-weight: 700;
@ -186,7 +310,7 @@
} }
.btn-multi-pill.active { .btn-multi-pill.active {
background: var(--primary-blue); background: var(--text-primary);
color: #ffffff; color: #ffffff;
box-shadow: var(--shadow-sm); box-shadow: var(--shadow-sm);
} }

View file

@ -64,6 +64,26 @@
.production-grid, .contracts-grid, .perks-grid, .achievements-grid { .production-grid, .contracts-grid, .perks-grid, .achievements-grid {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
.header-nav-group {
display: none;
}
#financial-hud {
flex-wrap: wrap;
gap: 8px;
}
.executive-fin-hub {
min-width: auto;
flex: 1;
}
#header-sector-container {
order: 3;
width: 100%;
max-width: 100%;
}
} }
/* Cramped / Mobile viewport: Hide sector pill numbers so only icons are displayed */ /* Cramped / Mobile viewport: Hide sector pill numbers so only icons are displayed */

View file

@ -46,37 +46,66 @@
</div> </div>
</div> </div>
<!-- Financial HUD (Liquid Capital, Net Flow, Valuation, Venture Equity) --> <!-- Executive Header Main Bar: Consolidated Finances (Left), Centered Sector Bar, Department Actions (Right) -->
<div id="financial-hud"> <div id="financial-hud">
<div class="hud-stat-box primary-hud-box"> <!-- Left: Consolidated Financial Hub (Liquid Capital, Rate, Valuation, Venture Capital) -->
<div class="hud-label">Liquid Capital</div> <div class="hud-stat-box primary-hud-box executive-fin-hub" title="Corporate Financial Summary">
<div class="hud-main-val font-mono">$<span id="hud-cash">0.00</span></div> <div class="fin-hub-main">
<div class="hud-sub-val font-mono rate-positive">+$<span id="hud-rate">0.00</span>/s</div> <div class="hud-label">Capital & Valuation</div>
</div> <div class="hud-main-val font-mono">$<span id="hud-cash">0.00</span></div>
<div class="hud-sub-val font-mono rate-positive">+$<span id="hud-rate">0.00</span>/s</div>
<div class="hud-stat-box"> </div>
<div class="hud-label">Enterprise Valuation</div> <div class="fin-hub-divider"></div>
<div class="hud-main-val font-mono" id="hud-valuation">$0.00</div> <div class="fin-hub-details">
<div class="hud-sub-val font-mono text-muted">Asset Value & Equity</div> <div class="fin-detail-row" title="Enterprise Valuation: Asset Value & Equity">
</div> <span class="fin-detail-label">Valuation:</span>
<span class="fin-detail-val font-mono" id="hud-valuation">$0.00</span>
<div class="hud-stat-box"> </div>
<div class="hud-label">Venture Capital ($V-Shares)</div> <div class="fin-detail-row" title="Venture Capital: Available $V-Shares for IPO Expansion">
<div class="hud-main-val font-mono text-equity"> <span class="fin-detail-label">V-Shares:</span>
<iconify-icon icon="lucide:gem"></iconify-icon> <span class="fin-detail-val font-mono text-equity">
<span id="hud-shares">0</span> <iconify-icon icon="lucide:gem"></iconify-icon>
<span id="hud-shares">0</span>
</span>
</div>
</div> </div>
<div class="hud-sub-val font-mono text-equity">IPO Expansion Equity</div>
</div> </div>
<!-- Buy Multiplier Selector --> <!-- Center: Centered Sector Toolbar (Same width as content) -->
<div class="hud-multiplier-box"> <div id="header-sector-container">
<span class="multi-label">Buy Batch:</span> <!-- Dynamically mounted with sector tabs -->
<div class="multi-button-group"> </div>
<button class="btn-multi-pill active" data-mode="1">1x</button>
<button class="btn-multi-pill" data-mode="10">10x</button> <!-- Right: Department Navigation Buttons & Buy Multiplier -->
<button class="btn-multi-pill" data-mode="100">100x</button> <div class="header-right-actions">
<button class="btn-multi-pill" data-mode="next">Next</button> <nav class="header-nav-group">
<button class="nav-btn active header-nav-btn" data-tab="production" title="Production Floor">
<iconify-icon icon="lucide:layout-grid"></iconify-icon>
<span class="header-btn-text">Floor</span>
</button>
<button class="nav-btn header-nav-btn" data-tab="contracts" title="B2B Contracts">
<iconify-icon icon="lucide:scroll-text"></iconify-icon>
<span class="header-btn-text">B2B</span>
<span id="contracts-badge" class="nav-pill-badge">0</span>
</button>
<button class="nav-btn header-nav-btn" data-tab="boardroom" title="Boardroom & IPO">
<iconify-icon icon="lucide:trending-up"></iconify-icon>
<span class="header-btn-text">Board</span>
</button>
<button class="nav-btn header-nav-btn" data-tab="milestones" title="Milestones">
<iconify-icon icon="lucide:trophy"></iconify-icon>
<span class="header-btn-text">Milestones</span>
</button>
</nav>
<!-- Buy Multiplier Selector -->
<div class="hud-multiplier-box">
<div class="multi-button-group">
<button class="btn-multi-pill active" data-mode="1">1x</button>
<button class="btn-multi-pill" data-mode="10">10x</button>
<button class="btn-multi-pill" data-mode="100">100x</button>
<button class="btn-multi-pill" data-mode="next">Next</button>
</div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -7,6 +7,7 @@ import { SyncManager } from './core/sync.js';
import { fmtCurrency, fmtNum, fmtRate, getNotation, setNotation } from './core/formatters.js'; import { fmtCurrency, fmtNum, fmtRate, getNotation, setNotation } from './core/formatters.js';
import { PRODUCTS, SECTORS, getProduct } from './data/products.js'; import { PRODUCTS, SECTORS, getProduct } from './data/products.js';
import { mountProductionFloor, updateProductionFloor, calculateMultiCost } from './ui/productionView.js'; import { mountProductionFloor, updateProductionFloor, calculateMultiCost } from './ui/productionView.js';
import { renderSectorTabsHtml } from './ui/production/sectorBar.js';
import { mountContractsBoard, updateContractsBoard } from './ui/contractsView.js'; import { mountContractsBoard, updateContractsBoard } from './ui/contractsView.js';
import { mountBoardroom, updateBoardroom } from './ui/boardroomView.js'; import { mountBoardroom, updateBoardroom } from './ui/boardroomView.js';
import { mountInspector, updateInspector } from './ui/inspectorView.js'; import { mountInspector, updateInspector } from './ui/inspectorView.js';
@ -141,6 +142,12 @@ class ProductionApp {
switch (action.type) { switch (action.type) {
case 'SELECT_SECTOR': case 'SELECT_SECTOR':
state.selectedSector = action.sector; state.selectedSector = action.sector;
if (state.activeTab !== 'production') {
state.activeTab = 'production';
document.querySelectorAll('.nav-btn, .nav-tab').forEach(b => {
b.classList.toggle('active', b.dataset.tab === 'production');
});
}
this.mountActiveView(); this.mountActiveView();
break; break;
@ -466,6 +473,16 @@ class ProductionApp {
} }
} }
mountHeaderSectorBar() {
const headerSectorContainer = document.getElementById('header-sector-container');
if (!headerSectorContainer) return;
const selectedSector = this.sm.state.selectedSector || 'all';
headerSectorContainer.innerHTML = renderSectorTabsHtml(selectedSector, this.engine);
headerSectorContainer.querySelectorAll('.sector-pill').forEach(btn => {
btn.onclick = () => this.handleAction({ type: 'SELECT_SECTOR', sector: btn.dataset.sector });
});
}
/** /**
* Mounts the main viewport view ONCE when the tab or sector changes * Mounts the main viewport view ONCE when the tab or sector changes
*/ */
@ -478,6 +495,9 @@ class ProductionApp {
this.currentMountedTab = tab; this.currentMountedTab = tab;
this.currentMountedSector = sector; this.currentMountedSector = sector;
// Keep header sector tabs in sync with selectedSector
this.mountHeaderSectorBar();
if (tab === 'production') { if (tab === 'production') {
mountProductionFloor(container, this.sm.state, (a) => this.handleAction(a), this.engine); mountProductionFloor(container, this.sm.state, (a) => this.handleAction(a), this.engine);
} else if (tab === 'contracts') { } else if (tab === 'contracts') {

View file

@ -2,10 +2,8 @@
import { SECTORS } from '../../data/products.js'; import { SECTORS } from '../../data/products.js';
import { fmtNum } from '../../core/formatters.js'; import { fmtNum } from '../../core/formatters.js';
export function renderSectorBarHtml(selectedSector, engine) { export function renderSectorTabsHtml(selectedSector, engine) {
const currentSectorObj = SECTORS.find(s => s.id === selectedSector); return `
let html = `
<div class="production-toolbar"> <div class="production-toolbar">
<div class="sector-tabs-scroll"> <div class="sector-tabs-scroll">
<button class="sector-pill ${selectedSector === 'all' ? 'active' : ''}" data-sector="all" title="All Sectors"> <button class="sector-pill ${selectedSector === 'all' ? 'active' : ''}" data-sector="all" title="All Sectors">
@ -24,6 +22,11 @@ export function renderSectorBarHtml(selectedSector, engine) {
</div> </div>
</div> </div>
`; `;
}
export function renderSectorSummariesHtml(selectedSector, engine) {
const currentSectorObj = SECTORS.find(s => s.id === selectedSector);
let html = '';
// 1. Single Sector Executive Summary Banner // 1. Single Sector Executive Summary Banner
if (selectedSector !== 'all' && currentSectorObj) { if (selectedSector !== 'all' && currentSectorObj) {
@ -99,6 +102,10 @@ export function renderSectorBarHtml(selectedSector, engine) {
return html; return html;
} }
export function renderSectorBarHtml(selectedSector, engine) {
return renderSectorTabsHtml(selectedSector, engine) + renderSectorSummariesHtml(selectedSector, engine);
}
export function updateSectorBarDom(selectedSector, engine) { export function updateSectorBarDom(selectedSector, engine) {
const elPillRateAll = document.getElementById('pill-rate-all'); const elPillRateAll = document.getElementById('pill-rate-all');
if (elPillRateAll) { if (elPillRateAll) {

View file

@ -2,7 +2,7 @@
// Clean modular orchestrator connecting sector toolbar, facility cards, and fine-grained DOM updating // Clean modular orchestrator connecting sector toolbar, facility cards, and fine-grained DOM updating
import { PRODUCTS } from '../data/products.js'; import { PRODUCTS } from '../data/products.js';
import { renderSectorBarHtml, updateSectorBarDom } from './production/sectorBar.js'; import { renderSectorBarHtml, renderSectorSummariesHtml, updateSectorBarDom } from './production/sectorBar.js';
import { renderFacilityCardHtml, updateFacilityCardDom } from './production/facilityCard.js'; import { renderFacilityCardHtml, updateFacilityCardDom } from './production/facilityCard.js';
export { calculateMultiCost, getProductOutputRates } from './production/ratesCalculator.js'; export { calculateMultiCost, getProductOutputRates } from './production/ratesCalculator.js';
@ -18,7 +18,7 @@ export function mountProductionFloor(container, state, onAction, engine) {
return p.sector === selectedSector; return p.sector === selectedSector;
}); });
let html = renderSectorBarHtml(selectedSector, engine); let html = renderSectorSummariesHtml(selectedSector, engine);
html += `<div class="production-grid">`; html += `<div class="production-grid">`;
for (const p of filteredProducts) { for (const p of filteredProducts) {