Center sector bar in sticky header, consolidate financial hub, and integrate department nav buttons
This commit is contained in:
parent
0a9a022fbc
commit
f68ecbd20c
6 changed files with 263 additions and 63 deletions
|
|
@ -98,48 +98,89 @@
|
|||
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 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 12px;
|
||||
padding: 10px 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
padding: 8px 16px;
|
||||
max-width: 1680px;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.hud-stat-box {
|
||||
background: var(--bg-surface);
|
||||
border: 1px solid var(--border-color);
|
||||
/* Consolidated Executive Financial Hub */
|
||||
.executive-fin-hub {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
padding: 6px 14px;
|
||||
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;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.primary-hud-box {
|
||||
border-color: #bfdbfe;
|
||||
background: #f8faff;
|
||||
.fin-hub-divider {
|
||||
width: 1px;
|
||||
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 {
|
||||
font-size: 0.72rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.68rem;
|
||||
font-weight: 700;
|
||||
color: var(--text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.hud-main-val {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
font-size: 1.20rem;
|
||||
font-weight: 800;
|
||||
color: var(--text-primary);
|
||||
line-height: 1.2;
|
||||
margin: 2px 0;
|
||||
line-height: 1.1;
|
||||
margin: 1px 0;
|
||||
}
|
||||
|
||||
.hud-sub-val {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.rate-positive {
|
||||
|
|
@ -150,17 +191,100 @@
|
|||
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 {
|
||||
display: flex;
|
||||
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 {
|
||||
|
|
@ -175,7 +299,7 @@
|
|||
.btn-multi-pill {
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 4px 10px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
|
|
@ -186,7 +310,7 @@
|
|||
}
|
||||
|
||||
.btn-multi-pill.active {
|
||||
background: var(--primary-blue);
|
||||
background: var(--text-primary);
|
||||
color: #ffffff;
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,6 +64,26 @@
|
|||
.production-grid, .contracts-grid, .perks-grid, .achievements-grid {
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -46,32 +46,60 @@
|
|||
</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 class="hud-stat-box primary-hud-box">
|
||||
<div class="hud-label">Liquid Capital</div>
|
||||
<!-- Left: Consolidated Financial Hub (Liquid Capital, Rate, Valuation, Venture Capital) -->
|
||||
<div class="hud-stat-box primary-hud-box executive-fin-hub" title="Corporate Financial Summary">
|
||||
<div class="fin-hub-main">
|
||||
<div class="hud-label">Capital & Valuation</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>
|
||||
|
||||
<div class="hud-stat-box">
|
||||
<div class="hud-label">Enterprise Valuation</div>
|
||||
<div class="hud-main-val font-mono" id="hud-valuation">$0.00</div>
|
||||
<div class="hud-sub-val font-mono text-muted">Asset Value & Equity</div>
|
||||
<div class="fin-hub-divider"></div>
|
||||
<div class="fin-hub-details">
|
||||
<div class="fin-detail-row" title="Enterprise Valuation: Asset Value & Equity">
|
||||
<span class="fin-detail-label">Valuation:</span>
|
||||
<span class="fin-detail-val font-mono" id="hud-valuation">$0.00</span>
|
||||
</div>
|
||||
|
||||
<div class="hud-stat-box">
|
||||
<div class="hud-label">Venture Capital ($V-Shares)</div>
|
||||
<div class="hud-main-val font-mono text-equity">
|
||||
<div class="fin-detail-row" title="Venture Capital: Available $V-Shares for IPO Expansion">
|
||||
<span class="fin-detail-label">V-Shares:</span>
|
||||
<span class="fin-detail-val font-mono text-equity">
|
||||
<iconify-icon icon="lucide:gem"></iconify-icon>
|
||||
<span id="hud-shares">0</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="hud-sub-val font-mono text-equity">IPO Expansion Equity</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Center: Centered Sector Toolbar (Same width as content) -->
|
||||
<div id="header-sector-container">
|
||||
<!-- Dynamically mounted with sector tabs -->
|
||||
</div>
|
||||
|
||||
<!-- Right: Department Navigation Buttons & Buy Multiplier -->
|
||||
<div class="header-right-actions">
|
||||
<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">
|
||||
<span class="multi-label">Buy Batch:</span>
|
||||
<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>
|
||||
|
|
@ -80,6 +108,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Main Workspace Layout (3-Column Desktop Grid / 1-Column Mobile) -->
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { SyncManager } from './core/sync.js';
|
|||
import { fmtCurrency, fmtNum, fmtRate, getNotation, setNotation } from './core/formatters.js';
|
||||
import { PRODUCTS, SECTORS, getProduct } from './data/products.js';
|
||||
import { mountProductionFloor, updateProductionFloor, calculateMultiCost } from './ui/productionView.js';
|
||||
import { renderSectorTabsHtml } from './ui/production/sectorBar.js';
|
||||
import { mountContractsBoard, updateContractsBoard } from './ui/contractsView.js';
|
||||
import { mountBoardroom, updateBoardroom } from './ui/boardroomView.js';
|
||||
import { mountInspector, updateInspector } from './ui/inspectorView.js';
|
||||
|
|
@ -141,6 +142,12 @@ class ProductionApp {
|
|||
switch (action.type) {
|
||||
case 'SELECT_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();
|
||||
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
|
||||
*/
|
||||
|
|
@ -478,6 +495,9 @@ class ProductionApp {
|
|||
this.currentMountedTab = tab;
|
||||
this.currentMountedSector = sector;
|
||||
|
||||
// Keep header sector tabs in sync with selectedSector
|
||||
this.mountHeaderSectorBar();
|
||||
|
||||
if (tab === 'production') {
|
||||
mountProductionFloor(container, this.sm.state, (a) => this.handleAction(a), this.engine);
|
||||
} else if (tab === 'contracts') {
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@
|
|||
import { SECTORS } from '../../data/products.js';
|
||||
import { fmtNum } from '../../core/formatters.js';
|
||||
|
||||
export function renderSectorBarHtml(selectedSector, engine) {
|
||||
const currentSectorObj = SECTORS.find(s => s.id === selectedSector);
|
||||
|
||||
let html = `
|
||||
export function renderSectorTabsHtml(selectedSector, engine) {
|
||||
return `
|
||||
<div class="production-toolbar">
|
||||
<div class="sector-tabs-scroll">
|
||||
<button class="sector-pill ${selectedSector === 'all' ? 'active' : ''}" data-sector="all" title="All Sectors">
|
||||
|
|
@ -24,6 +22,11 @@ export function renderSectorBarHtml(selectedSector, engine) {
|
|||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
export function renderSectorSummariesHtml(selectedSector, engine) {
|
||||
const currentSectorObj = SECTORS.find(s => s.id === selectedSector);
|
||||
let html = '';
|
||||
|
||||
// 1. Single Sector Executive Summary Banner
|
||||
if (selectedSector !== 'all' && currentSectorObj) {
|
||||
|
|
@ -99,6 +102,10 @@ export function renderSectorBarHtml(selectedSector, engine) {
|
|||
return html;
|
||||
}
|
||||
|
||||
export function renderSectorBarHtml(selectedSector, engine) {
|
||||
return renderSectorTabsHtml(selectedSector, engine) + renderSectorSummariesHtml(selectedSector, engine);
|
||||
}
|
||||
|
||||
export function updateSectorBarDom(selectedSector, engine) {
|
||||
const elPillRateAll = document.getElementById('pill-rate-all');
|
||||
if (elPillRateAll) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// Clean modular orchestrator connecting sector toolbar, facility cards, and fine-grained DOM updating
|
||||
|
||||
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';
|
||||
export { calculateMultiCost, getProductOutputRates } from './production/ratesCalculator.js';
|
||||
|
||||
|
|
@ -18,7 +18,7 @@ export function mountProductionFloor(container, state, onAction, engine) {
|
|||
return p.sector === selectedSector;
|
||||
});
|
||||
|
||||
let html = renderSectorBarHtml(selectedSector, engine);
|
||||
let html = renderSectorSummariesHtml(selectedSector, engine);
|
||||
html += `<div class="production-grid">`;
|
||||
|
||||
for (const p of filteredProducts) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue