Add Operations/Finance mode switcher to sidebar nav
Two-tab strip between Dashboard and the Operations section lets users toggle between the shop-management view and the accounting view. FOUC-prevention: server-side controller detection stamps data-nav-mode on <html> before first paint; CSS hides the inactive side instantly. JS (nav-mode.js) auto-switches to Finance when navigating to an accounting controller, restores saved preference everywhere else. Vendors appears in both modes; all 39 nav items carry data-nav tags. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -32,6 +32,15 @@
|
||||
_ => "#374151" // gray-700 for anything else
|
||||
};
|
||||
|
||||
// Nav mode: used by FOUC-prevention inline script + nav-mode.js
|
||||
var _finCtrlSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase) {
|
||||
"bills", "accounts", "journalentries", "vendorcredits",
|
||||
"bankreconciliations", "fixedassets", "budgets", "recurringtemplates",
|
||||
"accountingexport", "taxrates"
|
||||
};
|
||||
var _navController = ViewContext.RouteData.Values["controller"]?.ToString() ?? "";
|
||||
var _serverNavMode = _finCtrlSet.Contains(_navController) ? "fin" : "ops";
|
||||
|
||||
if (User.Identity?.IsAuthenticated == true)
|
||||
{
|
||||
if (isImpersonating)
|
||||
@@ -319,6 +328,54 @@
|
||||
width: 1.5rem;
|
||||
}
|
||||
|
||||
/* ── Nav mode: FOUC prevention — CSS wins before JS runs ─────── */
|
||||
html[data-nav-mode="ops"] [data-nav="fin"] { display: none !important; }
|
||||
html[data-nav-mode="fin"] [data-nav="ops"] { display: none !important; }
|
||||
|
||||
/* ── Nav mode strip (Operations | Finance tab switcher) ──────── */
|
||||
.nav-mode-strip {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 3px;
|
||||
padding: 8px 12px 10px;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.08);
|
||||
}
|
||||
|
||||
.nav-mode-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 5px;
|
||||
padding: 7px 6px;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
font-family: var(--font-mono, 'IBM Plex Mono', ui-monospace, monospace);
|
||||
font-size: 0.64rem;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
background: transparent;
|
||||
color: rgba(255,255,255,0.38);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-mode-btn i {
|
||||
font-size: 0.85rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.nav-mode-btn:hover {
|
||||
background: rgba(255,255,255,0.08);
|
||||
color: rgba(255,255,255,0.8);
|
||||
}
|
||||
|
||||
.nav-mode-btn.active {
|
||||
background: var(--pcl-ember, #d97706);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Main Content */
|
||||
.main-content {
|
||||
margin-left: var(--sidebar-width);
|
||||
@@ -878,7 +935,10 @@
|
||||
@* Page-specific styles *@
|
||||
@await RenderSectionAsync("Styles", required: false)
|
||||
</head>
|
||||
<body style="padding-top: var(--env-banner-height);">
|
||||
<body style="padding-top: var(--env-banner-height);" data-controller="@_navController.ToLower()">
|
||||
<script>
|
||||
(function(){var s='@_serverNavMode',p=localStorage.getItem('pcl-nav-mode')||'ops';document.documentElement.dataset.navMode=s==='fin'?'fin':p;})();
|
||||
</script>
|
||||
@if (_isNonProd)
|
||||
{
|
||||
<div style="position:fixed;top:0;left:0;width:100%;height:var(--env-banner-height);z-index:2000;
|
||||
@@ -1010,56 +1070,66 @@
|
||||
var showInventorySection = hasInventory || hasVendors;
|
||||
var showEquipmentSection = hasEquipment || hasMaintenance;
|
||||
|
||||
<div class="nav-section-title">Main Menu</div>
|
||||
<a asp-controller="Dashboard" asp-action="Index" class="nav-link">
|
||||
<div class="nav-section-title" data-nav="both">Main Menu</div>
|
||||
<a asp-controller="Dashboard" asp-action="Index" class="nav-link" data-nav="both">
|
||||
<i class="bi bi-house-door"></i>
|
||||
<span>Dashboard</span>
|
||||
</a>
|
||||
@if (!isPlatformAdmin)
|
||||
{
|
||||
<div class="nav-mode-strip" role="tablist" aria-label="Navigation mode">
|
||||
<button class="nav-mode-btn" data-mode="ops" role="tab" aria-selected="true" title="Operations">
|
||||
<i class="bi bi-tools"></i>
|
||||
<span>Operations</span>
|
||||
</button>
|
||||
<button class="nav-mode-btn" data-mode="fin" role="tab" aria-selected="false" title="Finance">
|
||||
<i class="bi bi-journal-bookmark"></i>
|
||||
<span>Finance</span>
|
||||
</button>
|
||||
</div>
|
||||
@* ── Operations ───────────────────────────────────────────── *@
|
||||
@if (showOperations)
|
||||
{
|
||||
<div class="nav-section-title">Operations</div>
|
||||
<div class="nav-section-title" data-nav="ops">Operations</div>
|
||||
}
|
||||
@if (hasCustomers)
|
||||
{
|
||||
<a asp-controller="Customers" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="Customers" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-people"></i>
|
||||
<span>Customers</span>
|
||||
</a>
|
||||
}
|
||||
@if (hasQuotes)
|
||||
{
|
||||
<a asp-controller="Quotes" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="Quotes" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-file-text"></i>
|
||||
<span>Quotes</span>
|
||||
</a>
|
||||
}
|
||||
@if (hasJobs)
|
||||
{
|
||||
<a asp-controller="Jobs" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="Jobs" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-briefcase"></i>
|
||||
<span>Jobs</span>
|
||||
</a>
|
||||
}
|
||||
@if (hasInvoices)
|
||||
{
|
||||
<a asp-controller="Invoices" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="Invoices" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-receipt"></i>
|
||||
<span>Invoices</span>
|
||||
</a>
|
||||
}
|
||||
@if (hasCalendar)
|
||||
{
|
||||
<a asp-controller="Appointments" asp-action="Calendar" asp-route-view="month" class="nav-link">
|
||||
<a asp-controller="Appointments" asp-action="Calendar" asp-route-view="month" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-calendar-event"></i>
|
||||
<span>Appointments</span>
|
||||
</a>
|
||||
}
|
||||
@if (hasJobs)
|
||||
{
|
||||
<a asp-controller="JobsPriority" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="JobsPriority" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-clipboard2-check"></i>
|
||||
<span>Daily Board</span>
|
||||
</a>
|
||||
@@ -1069,19 +1139,19 @@
|
||||
@if (hasInvoices)
|
||||
{
|
||||
var _allowOnlinePayments = Context.Items["AllowOnlinePayments"] as bool? ?? false;
|
||||
<div class="nav-section-title">Billing & Payments</div>
|
||||
<div class="nav-section-title" data-nav="ops">Billing & Payments</div>
|
||||
@if (_allowOnlinePayments)
|
||||
{
|
||||
<a asp-controller="Invoices" asp-action="OnlinePayments" class="nav-link">
|
||||
<a asp-controller="Invoices" asp-action="OnlinePayments" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-credit-card"></i>
|
||||
<span>Online Payments</span>
|
||||
</a>
|
||||
}
|
||||
<a asp-controller="CreditMemos" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="CreditMemos" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-journal-minus"></i>
|
||||
<span>Credit Memos</span>
|
||||
</a>
|
||||
<a asp-controller="GiftCertificates" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="GiftCertificates" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-gift"></i>
|
||||
<span>Gift Certificates</span>
|
||||
</a>
|
||||
@@ -1090,18 +1160,18 @@
|
||||
@* ── Inventory & Purchasing ───────────────────────────────── *@
|
||||
@if (hasProducts || showInventorySection)
|
||||
{
|
||||
<div class="nav-section-title">Inventory & Purchasing</div>
|
||||
<div class="nav-section-title" data-nav="ops">Inventory & Purchasing</div>
|
||||
}
|
||||
@if (hasProducts)
|
||||
{
|
||||
<a asp-controller="CatalogItems" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="CatalogItems" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-book"></i>
|
||||
<span>Product Catalog</span>
|
||||
</a>
|
||||
}
|
||||
@if (hasInventory)
|
||||
{
|
||||
<a asp-controller="Inventory" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="Inventory" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-box-seam"></i>
|
||||
<span>Inventory</span>
|
||||
</a>
|
||||
@@ -1109,11 +1179,11 @@
|
||||
}
|
||||
@if (hasVendors)
|
||||
{
|
||||
<a asp-controller="Vendors" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="Vendors" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-truck"></i>
|
||||
<span>Vendors</span>
|
||||
</a>
|
||||
<a asp-controller="PurchaseOrders" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="PurchaseOrders" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-cart-check"></i>
|
||||
<span>Purchase Orders</span>
|
||||
</a>
|
||||
@@ -1125,46 +1195,50 @@
|
||||
var _allowAccounting = Context.Items["AllowAccounting"] as bool? ?? false;
|
||||
if (_allowAccounting)
|
||||
{
|
||||
<div class="nav-section-title">Finance</div>
|
||||
<a asp-controller="Bills" asp-action="Index" class="nav-link">
|
||||
<div class="nav-section-title" data-nav="fin">Finance</div>
|
||||
<a asp-controller="Bills" asp-action="Index" class="nav-link" data-nav="fin">
|
||||
<i class="bi bi-receipt-cutoff"></i>
|
||||
<span>Bills / Expenses</span>
|
||||
</a>
|
||||
<a asp-controller="Accounts" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="Vendors" asp-action="Index" class="nav-link" data-nav="fin">
|
||||
<i class="bi bi-truck"></i>
|
||||
<span>Vendors</span>
|
||||
</a>
|
||||
<a asp-controller="Accounts" asp-action="Index" class="nav-link" data-nav="fin">
|
||||
<i class="bi bi-journal-bookmark"></i>
|
||||
<span>Chart of Accounts</span>
|
||||
</a>
|
||||
<a asp-controller="JournalEntries" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="JournalEntries" asp-action="Index" class="nav-link" data-nav="fin">
|
||||
<i class="bi bi-journal-text"></i>
|
||||
<span>Journal Entries</span>
|
||||
</a>
|
||||
<a asp-controller="VendorCredits" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="VendorCredits" asp-action="Index" class="nav-link" data-nav="fin">
|
||||
<i class="bi bi-arrow-return-left"></i>
|
||||
<span>Vendor Credits</span>
|
||||
</a>
|
||||
<a asp-controller="BankReconciliations" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="BankReconciliations" asp-action="Index" class="nav-link" data-nav="fin">
|
||||
<i class="bi bi-bank2"></i>
|
||||
<span>Bank Reconciliation</span>
|
||||
</a>
|
||||
<a asp-controller="FixedAssets" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="FixedAssets" asp-action="Index" class="nav-link" data-nav="fin">
|
||||
<i class="bi bi-building-gear"></i>
|
||||
<span>Fixed Assets</span>
|
||||
</a>
|
||||
<a asp-controller="Budgets" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="Budgets" asp-action="Index" class="nav-link" data-nav="fin">
|
||||
<i class="bi bi-pie-chart"></i>
|
||||
<span>Budgets</span>
|
||||
</a>
|
||||
<a asp-controller="Accounts" asp-action="YearEndClose" class="nav-link">
|
||||
<a asp-controller="Accounts" asp-action="YearEndClose" class="nav-link" data-nav="fin">
|
||||
<i class="bi bi-calendar-check"></i>
|
||||
<span>Year-End Close</span>
|
||||
</a>
|
||||
<a asp-controller="RecurringTemplates" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="RecurringTemplates" asp-action="Index" class="nav-link" data-nav="fin">
|
||||
<i class="bi bi-arrow-repeat"></i>
|
||||
<span>Recurring Transactions</span>
|
||||
</a>
|
||||
if (hasReports)
|
||||
{
|
||||
<a asp-controller="AccountingExport" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="AccountingExport" asp-action="Index" class="nav-link" data-nav="fin">
|
||||
<i class="bi bi-box-arrow-up"></i>
|
||||
<span>Accounting Export</span>
|
||||
</a>
|
||||
@@ -1173,33 +1247,33 @@
|
||||
}
|
||||
|
||||
@* ── Shop Floor ───────────────────────────────────────────── *@
|
||||
<div class="nav-section-title">Shop Floor</div>
|
||||
<div class="nav-section-title" data-nav="ops">Shop Floor</div>
|
||||
@if (hasEquipment)
|
||||
{
|
||||
<a asp-controller="Equipment" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="Equipment" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-gear"></i>
|
||||
<span>Equipment</span>
|
||||
</a>
|
||||
}
|
||||
@if (hasMaintenance)
|
||||
{
|
||||
<a asp-controller="Maintenance" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="Maintenance" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-tools"></i>
|
||||
<span>Maintenance</span>
|
||||
</a>
|
||||
}
|
||||
@if (hasInventory || _isAdminOrManager)
|
||||
{
|
||||
<a asp-controller="PowderInsights" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="PowderInsights" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-graph-up"></i>
|
||||
<span>Powder Insights</span>
|
||||
</a>
|
||||
}
|
||||
<a asp-controller="Jobs" asp-action="ShopDisplay" class="nav-link" target="_blank">
|
||||
<a asp-controller="Jobs" asp-action="ShopDisplay" class="nav-link" data-nav="ops" target="_blank">
|
||||
<i class="bi bi-display"></i>
|
||||
<span>Shop Display</span>
|
||||
</a>
|
||||
<a asp-controller="Jobs" asp-action="ShopMobile" class="nav-link">
|
||||
<a asp-controller="Jobs" asp-action="ShopMobile" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-phone"></i>
|
||||
<span>Shop Mobile</span>
|
||||
</a>
|
||||
@@ -1207,17 +1281,17 @@
|
||||
@* ── Reports & Templates ──────────────────────────────────── *@
|
||||
@if (hasReports || hasJobs)
|
||||
{
|
||||
<div class="nav-section-title">Reports & Templates</div>
|
||||
<div class="nav-section-title" data-nav="both">Reports & Templates</div>
|
||||
@if (hasReports)
|
||||
{
|
||||
<a asp-controller="Reports" asp-action="Landing" class="nav-link">
|
||||
<a asp-controller="Reports" asp-action="Landing" class="nav-link" data-nav="both">
|
||||
<i class="bi bi-bar-chart-line"></i>
|
||||
<span>Reports</span>
|
||||
</a>
|
||||
}
|
||||
@if (hasJobs)
|
||||
{
|
||||
<a asp-controller="JobTemplates" asp-action="Index" class="nav-link">
|
||||
<a asp-controller="JobTemplates" asp-action="Index" class="nav-link" data-nav="ops">
|
||||
<i class="bi bi-layout-text-window-reverse"></i>
|
||||
<span>Job Templates</span>
|
||||
</a>
|
||||
@@ -1680,6 +1754,9 @@
|
||||
<!-- Bootstrap 5 JS Bundle -->
|
||||
<script src="~/lib/bootstrap/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<!-- Nav mode switcher (Operations / Finance) -->
|
||||
<script src="~/js/nav-mode.js" asp-append-version="true"></script>
|
||||
|
||||
<!-- Custom Scripts -->
|
||||
<script>
|
||||
// Add active class to current nav item
|
||||
|
||||
Reference in New Issue
Block a user