feat: redesign phone directory UI and add new department-specific JSON data files

This commit is contained in:
Justin committed 2026-04-14 21:22:01 -05:00
1 parent 611553efbc
commit 7ab089839e
18 files changed
+1664 -565

No files matched your search

+568 -247
View File
@@ -1,266 +1,587 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Bossier City Phone Directory</title>
<meta name="viewport" content="width=divice-width,initial-scale=1" />
<meta name="description" content="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="Bossier City Casino Phone Directory" />
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<link rel="icon" href="favicon.png">
<style>
body {
background-color: #A99ABD; /* Background color of page */
}
table.banner {
padding-top: 50px;
text-align: center;
font-size: xxx-large;
width:100%;
color:#CCCCCC; /* Color of title font */
}
table.mainTable {
margin-left:auto;
margin-right:auto;
padding-left:10px;
padding-top: 50px;
}
td[colspan]:not([colspan="1"]) {
text-align: center;
}
.titleBar td {
border: none;
background-color: #C0D8C0; /* Background color of title bar */
text-align: center;
font-size: large;
}
.header td {
border: none;
background-color: #E1EFCA; /* Background color of column header bar */
text-align: center;
font-size: x-large;
}
table.mainTable td {
height: 25px;
text-align: center;
vertical-align: middle;
padding-left:10px;
padding-right:10px;
white-space: nowrap;
}
table.mainTable td.first {
text-align: center;
}
table.mainTable td.second {
text-align: center;
}
table.mainTable td.third {
text-align: center;
}
table.mainTable td.forth {
text-align: center;
}
</style>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--gold: #d4af37;
--gold-dim: #b8962e;
--navy-deep: #0f1b2d;
--navy-mid: #16263e;
--navy-lite: #1e3353;
--surface: rgba(255,255,255,0.05);
--border: rgba(255,255,255,0.10);
--text: #e2e8f0;
--muted: #94a3b8;
--sidebar-w: 240px;
}
html, body { height: 100%; }
body {
font-family: 'Segoe UI', Arial, sans-serif;
background: var(--navy-deep);
color: var(--text);
display: flex;
flex-direction: column;
min-height: 100vh;
}
/* ══ TOP HEADER ══ */
.top-header {
background: linear-gradient(90deg, var(--navy-deep) 0%, var(--navy-mid) 100%);
border-bottom: 2px solid rgba(212,175,55,0.4);
padding: 14px 24px;
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: 12px;
position: sticky;
top: 0;
z-index: 100;
}
.top-header h1 {
font-size: clamp(1rem, 2.5vw, 1.45rem);
font-weight: 700;
letter-spacing: 0.06em;
color: var(--gold);
text-shadow: 0 2px 10px rgba(212,175,55,0.3);
white-space: nowrap;
}
/* search */
.search-wrap {
position: relative;
flex: 0 1 280px;
}
.search-wrap input {
width: 100%;
padding: 8px 12px 8px 36px;
border-radius: 8px;
border: 1px solid var(--border);
background: rgba(255,255,255,0.07);
color: var(--text);
font-size: 0.875rem;
outline: none;
transition: border-color 0.2s;
}
.search-wrap input::placeholder { color: var(--muted); }
.search-wrap input:focus { border-color: rgba(212,175,55,0.55); }
.search-wrap svg {
position: absolute;
left: 10px;
top: 50%;
transform: translateY(-50%);
color: var(--muted);
pointer-events: none;
}
/* ══ PROPERTY TABS ══ */
.prop-tabs {
display: flex;
background: var(--navy-mid);
border-bottom: 1px solid var(--border);
padding: 0 24px;
}
.prop-tab {
padding: 10px 28px;
font-size: 0.85rem;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--muted);
cursor: pointer;
border-bottom: 3px solid transparent;
transition: color 0.15s, border-color 0.15s;
user-select: none;
}
.prop-tab:hover { color: var(--text); }
.prop-tab.active {
color: var(--gold);
border-bottom-color: var(--gold);
}
/* ══ BODY LAYOUT ══ */
.layout {
display: flex;
flex: 1;
overflow: hidden;
}
/* ══ SIDEBAR ══ */
.sidebar {
width: var(--sidebar-w);
min-width: var(--sidebar-w);
background: var(--navy-mid);
border-right: 1px solid var(--border);
overflow-y: auto;
padding: 12px 0 24px;
}
.sidebar-group { margin-bottom: 4px; }
.sidebar-group-btn {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 9px 16px 9px 20px;
background: none;
border: none;
color: var(--gold);
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
cursor: pointer;
text-align: left;
transition: background 0.15s;
}
.sidebar-group-btn:hover { background: rgba(255,255,255,0.04); }
.sidebar-group-btn .chevron {
transition: transform 0.2s;
flex-shrink: 0;
}
.sidebar-group-btn.open .chevron { transform: rotate(90deg); }
.sidebar-items {
display: none;
flex-direction: column;
}
.sidebar-items.open { display: flex; }
.dept-btn {
padding: 8px 16px 8px 32px;
background: none;
border: none;
color: var(--muted);
font-size: 0.83rem;
text-align: left;
cursor: pointer;
border-left: 3px solid transparent;
transition: color 0.12s, background 0.12s, border-color 0.12s;
}
.dept-btn:hover {
color: var(--text);
background: rgba(255,255,255,0.05);
}
.dept-btn.active {
color: var(--gold);
border-left-color: var(--gold);
background: rgba(212,175,55,0.08);
}
/* ══ MAIN CONTENT ══ */
.main {
flex: 1;
overflow-y: auto;
padding: 28px 32px 48px;
}
.dept-heading {
font-size: 1.3rem;
font-weight: 700;
color: var(--gold);
margin-bottom: 20px;
padding-bottom: 12px;
border-bottom: 1px solid rgba(212,175,55,0.25);
display: flex;
align-items: center;
gap: 10px;
}
.dept-heading span.prop-badge {
font-size: 0.65rem;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
padding: 3px 8px;
border-radius: 4px;
background: rgba(212,175,55,0.18);
color: var(--gold);
border: 1px solid rgba(212,175,55,0.3);
}
/* table */
.table-wrap {
overflow-x: auto;
border-radius: 10px;
border: 1px solid var(--border);
}
table.dir-table {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
}
table.dir-table thead tr {
background: rgba(212,175,55,0.12);
border-bottom: 1px solid rgba(212,175,55,0.3);
}
table.dir-table thead th {
padding: 11px 16px;
text-align: left;
font-size: 0.7rem;
font-weight: 700;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--gold);
white-space: nowrap;
}
table.dir-table tbody tr {
border-bottom: 1px solid var(--border);
transition: background 0.1s;
}
table.dir-table tbody tr:last-child { border-bottom: none; }
table.dir-table tbody tr:hover { background: rgba(255,255,255,0.04); }
table.dir-table tbody tr.hidden { display: none; }
table.dir-table td {
padding: 10px 16px;
color: var(--text);
white-space: nowrap;
}
table.dir-table td:first-child { font-weight: 600; }
table.dir-table td.ext { font-family: 'Courier New', monospace; color: var(--gold); }
table.dir-table td.ext-empty { color: var(--muted); font-style: italic; }
.no-results {
text-align: center;
padding: 48px 16px;
color: var(--muted);
font-size: 0.9rem;
}
.loading {
text-align: center;
padding: 48px 16px;
color: var(--muted);
font-size: 0.9rem;
}
/* ══ QUICK LINKS FOOTER ══ */
.quick-links {
display: flex;
flex-wrap: wrap;
gap: 12px;
justify-content: center;
padding: 18px 24px;
background: rgba(0,0,0,0.3);
border-top: 1px solid rgba(212,175,55,0.2);
}
.quick-links a {
display: inline-flex;
align-items: center;
gap: 7px;
padding: 10px 22px;
border-radius: 7px;
font-size: 0.82rem;
font-weight: 700;
letter-spacing: 0.05em;
color: var(--navy-deep);
background: linear-gradient(135deg, var(--gold), var(--gold-dim));
text-decoration: none;
transition: opacity 0.15s, transform 0.15s;
box-shadow: 0 3px 12px rgba(212,175,55,0.3);
}
.quick-links a:hover { opacity: 0.85; transform: translateY(-1px); }
/* ══ RESPONSIVE ══ */
@media (max-width: 700px) {
.sidebar { width: 200px; min-width: 200px; }
.main { padding: 20px 16px 40px; }
}
@media (max-width: 520px) {
.layout { flex-direction: column; }
.sidebar { width: 100%; min-width: 0; border-right: none; border-bottom: 1px solid var(--border); max-height: 220px; }
}
</style>
</head>
<body>
<table class=banner>
<tr>
<td>Bossier City Phone Directory</td>
<tr>
</table>
<!-- ══ TOP HEADER ══ -->
<header class="top-header">
<h1>Bossier City Phone Directory</h1>
<div class="search-wrap">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2">
<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>
</svg>
<input type="search" id="searchInput" placeholder="Search name, title, extension…" autocomplete="off" />
</div>
</header>
<table class=mainTable>
<tr class=titleBar>
<td>Casino Operations</td>
<td>Executive</td>
<td>Finance and Admin</td>
<td>Food and Beverage</td>
<td>Hotel</td>
<td>Human Resources</td>
<td>Sales and Marketing</td>
<td>Support Operations</td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/btbc-casino_operations.html';">BTBC Casino Operations</button></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-executive.html';">BTBC Executive</button></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-accounting.html';">BTBC Accounting</button></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-food_and_beverage.html';">BTBC Food and Beverage</button></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-hotel.html';">BTBC Hotel</button></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-human_resources.html';">BTBC Human Resources</button></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-sales_and_marketing.html';">BTBC Sales and Marketing</button></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-facilities.html';">BTBC Facilities</button></td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/btbc-security.html';">BTBC Security</button></td>
<td></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-cage.html';">BTBC Cage</button></td>
<td></td>
<td></td>
<td></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-entertainment.html';">BTBC Entertainment</button></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-information_technology.html';">BTBC Information Technology</button></td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/btbc-slot_performance.html';">BTBC Slot Performance</button></td>
<td></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-compliance.html';">BTBC Compliance</button></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/btbc-slots.html';">BTBC Slots</button></td>
<td></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-count.html';">BTBC Count</button></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/btbc-sports_betting.html';">BTBC Sports Betting</button></td>
<td></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-purchasing.html';">BTBC Purchasing</button></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/btbc-surveillance.html';">BTBC Surveillance</button></td>
<td></td>
<td><button onclick="window.location.href='http://mvbc-files/btbc-receiving.html';">BTBC Receiving</button></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/btbc-table_games.html';">BTBC Table Games</button></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
<!-- ══ PROPERTY TABS ══ -->
<div class="prop-tabs">
<div class="prop-tab active" data-prop="btbc">Boomtown &mdash; BTBC</div>
<div class="prop-tab" data-prop="mvbc">Margaritaville &mdash; MVBC</div>
</div>
<table class=mainTable>
<tr class=titleBar>
<td>Casino Operations</td>
<td>Executive</td>
<td>Finance and Admin</td>
<td>Food and Beverage</td>
<td>Hotel</td>
<td>Human Resources</td>
<td>Sales and Marketing</td>
<td>Support Operations</td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-casino_operations.html';">MVBC Casino Operations</button></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-executive.html';">MVBC Executive</button></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-accounting.html';">MVBC Accounting</button></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-food_and_beverage.html';">MVBC Food and Beverage</button></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-hotel.html';">MVBC Hotel</button></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-human_resources.html';">MVBC Human Resources</button></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-sales_and_marketing.html';">MVBC Sales and Marketing</button></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-facilities.html';">MVBC Facilities</button></td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-security.html';">MVBC Security</button></td>
<td></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-cage.html';">MVBC Cage</button></td>
<td></td>
<td></td>
<td></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-entertainment.html';">MVBC Entertainment</button></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-information_technology.html';">MVBC Information Technology</button></td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-slot_performance.html';">MVBC Slot Performance</button></td>
<td></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-compliance.html';">MVBC Compliance</button></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-slots.html';">MVBC Slots</button></td>
<td></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-count.html';">MVBC Count</button></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-sports_betting.html';">MVBC Sports Betting</button></td>
<td></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-purchasing.html';">MVBC Purchasing</button></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-surveillance.html';">MVBC Surveillance</button></td>
<td></td>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-receiving.html';">MVBC Receiving</button></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/mvbc-table_games.html';">MVBC Table Games</button></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
<!-- ══ LAYOUT ══ -->
<div class="layout">
<!-- Sidebar -->
<nav class="sidebar" id="sidebar">
<!-- rendered by JS -->
</nav>
<table class=mainTable>
<tr>
<td><button onclick="window.location.href='http://mvbc-files/Phone User Guide.pdf';">MVBC Quick Phone Reference</button></td>
<td><button onclick="window.location.href='http://10.3.32.10/ucmuser/main#phonesettings';">MVBC Self Care Portal</button></td>
</tr>
</table>
<!-- Main panel -->
<main class="main" id="mainPanel">
<div class="loading">Select a department from the sidebar.</div>
</main>
</div>
<!-- ══ QUICK LINKS ══ -->
<footer class="quick-links">
<a href="http://mvbc-files/Phone User Guide.pdf">&#128222; MVBC Quick Phone Reference</a>
<a href="http://10.3.32.10/ucmuser/main#phonesettings">&#9881; MVBC Self Care Portal</a>
</footer>
<script>
// ─────────────────────────────────────────────
// DATA MAP – dept label → JSON file path
// ─────────────────────────────────────────────
const DEPTS = [
{
group: 'Casino Operations',
items: [
{ label: 'Casino Operations', btbc: 'json/btbc-casino-ops.json', mvbc: 'json/mvbc-casino-ops.json' },
{ label: 'Security', btbc: 'json/btbc-security.json', mvbc: 'json/mvbc-security.json' },
{ label: 'Slots', btbc: 'json/btbc-slots.json', mvbc: 'json/mvbc-slots.json' },
{ label: 'Slots Performance', btbc: 'json/btbc-slots-performance.json', mvbc: 'json/mvbc-slots-performance.json' },
{ label: 'Sports Betting', btbc: 'json/btbc-sport-betting.json', mvbc: 'json/mvbc-sport-betting.json' },
{ label: 'Surveillance', btbc: 'json/btbc-sureillance.json', mvbc: 'json/mvbc-surveillance.json' },
{ label: 'Table Games', btbc: 'json/btbc-table-games.json', mvbc: 'json/mvbc-table-games.json' },
]
},
{
group: 'Executive',
items: [
{ label: 'Executive', btbc: 'json/btbc-executive.json', mvbc: 'json/mvbc-executive.json' },
]
},
{
group: 'Finance & Admin',
items: [
{ label: 'Accounting', btbc: 'json/btbc-accounting.json', mvbc: 'json/mvbc-accounting.json' },
{ label: 'Cage', btbc: 'json/btbc-cage.json', mvbc: 'json/mvbc-cage.json' },
{ label: 'Compliance', btbc: 'json/btbc-compliance.json', mvbc: 'json/mvbc-compliance.json' },
{ label: 'Count', btbc: 'json/btbc-count.json', mvbc: 'json/mvbc-count.json' },
{ label: 'Purchasing', btbc: 'json/btbc-purchasing.json', mvbc: 'json/mvbc-purchasing.json' },
{ label: 'Receiving', btbc: 'json/btbc-receiving.json', mvbc: 'json/mvbc-receiving.json' },
]
},
{
group: 'Food & Beverage',
items: [
{ label: 'Food & Beverage', btbc: 'json/btbc-food-and-beverage.json', mvbc: 'json/mvbc-food-and-beverage.json' },
]
},
{
group: 'Hotel',
items: [
{ label: 'Hotel', btbc: 'json/btbc-hotel.json', mvbc: 'json/mvbc-hotel.json' },
]
},
{
group: 'Human Resources',
items: [
{ label: 'Human Resources', btbc: 'json/btbc-human-resources.json', mvbc: 'json/mvbc-human-resources.json' },
]
},
{
group: 'Sales & Marketing',
items: [
{ label: 'Sales & Marketing', btbc: 'json/btbc-sales-and-marketing.json', mvbc: 'json/mvbc-sales-and-marketing.json' },
{ label: 'Entertainment', btbc: 'json/btbc-entertainment.json', mvbc: 'json/mvbc-entertainment.json' },
]
},
{
group: 'Support Services',
items: [
{ label: 'Facilities', btbc: 'json/btbc-facilties.json', mvbc: 'json/mvbc-facilties.json' },
{ label: 'Information Technology', btbc: 'json/btbc-information-technology.json', mvbc: 'json/mvbc-information-technology.json' },
]
},
];
// ─────────────────────────────────────────────
// STATE
// ─────────────────────────────────────────────
let currentProp = 'btbc';
let currentDept = null; // { label, btbc, mvbc }
let currentData = [];
const sidebar = document.getElementById('sidebar');
const mainPanel = document.getElementById('mainPanel');
const searchInput = document.getElementById('searchInput');
// ─────────────────────────────────────────────
// RENDER SIDEBAR
// ─────────────────────────────────────────────
function renderSidebar() {
sidebar.innerHTML = '';
DEPTS.forEach((grp, gi) => {
const groupEl = document.createElement('div');
groupEl.className = 'sidebar-group';
const btn = document.createElement('button');
btn.className = 'sidebar-group-btn';
const hasActive = grp.items.some(it => it === currentDept);
if (hasActive) btn.classList.add('open');
btn.innerHTML = `${grp.group} <svg class="chevron" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="9 18 15 12 9 6"/></svg>`;
const itemsEl = document.createElement('div');
itemsEl.className = 'sidebar-items' + (hasActive ? ' open' : '');
grp.items.forEach(dept => {
const db = document.createElement('button');
db.className = 'dept-btn' + (dept === currentDept ? ' active' : '');
db.textContent = dept.label;
db.addEventListener('click', () => selectDept(dept));
itemsEl.appendChild(db);
});
btn.addEventListener('click', () => {
btn.classList.toggle('open');
itemsEl.classList.toggle('open');
});
groupEl.appendChild(btn);
groupEl.appendChild(itemsEl);
sidebar.appendChild(groupEl);
});
}
// ─────────────────────────────────────────────
// SELECT DEPARTMENT
// ─────────────────────────────────────────────
function selectDept(dept) {
currentDept = dept;
searchInput.value = '';
renderSidebar();
loadDept();
}
// ─────────────────────────────────────────────
// LOAD + DISPLAY
// ─────────────────────────────────────────────
function loadDept() {
if (!currentDept) return;
const jsonPath = currentDept[currentProp];
mainPanel.innerHTML = '<div class="loading">Loading&hellip;</div>';
fetch(jsonPath)
.then(r => {
if (!r.ok) throw new Error('HTTP ' + r.status);
return r.json();
})
.then(data => {
currentData = data;
renderTable(data);
})
.catch(() => {
mainPanel.innerHTML = '<div class="no-results">Could not load data for this department.</div>';
});
}
function propLabel(prop) {
return prop === 'btbc' ? 'BTBC' : 'MVBC';
}
function renderTable(data) {
const q = searchInput.value.trim().toLowerCase();
const filtered = q
? data.filter(r =>
(r.name || '').toLowerCase().includes(q) ||
(r.title || '').toLowerCase().includes(q) ||
(r.extension || '').toLowerCase().includes(q) ||
(r.exterior || '').toLowerCase().includes(q)
)
: data;
let html = `
<div class="dept-heading">
${escHtml(currentDept.label)}
<span class="prop-badge">${propLabel(currentProp)}</span>
</div>`;
if (filtered.length === 0) {
html += `<div class="no-results">No results${q ? ' matching "<strong>' + escHtml(q) + '</strong>"' : ''}.</div>`;
} else {
html += `
<div class="table-wrap">
<table class="dir-table">
<thead>
<tr>
<th>Name</th>
<th>Title</th>
<th>Extension</th>
<th>Exterior</th>
</tr>
</thead>
<tbody>`;
filtered.forEach(r => {
const ext = (r.extension || '').trim();
const exr = (r.exterior || '').trim();
html += `<tr>
<td>${escHtml(r.name || '')}</td>
<td>${escHtml(r.title || '')}</td>
<td class="${ext ? 'ext' : 'ext-empty'}">${ext ? escHtml(ext) : '—'}</td>
<td class="${exr ? 'ext' : 'ext-empty'}">${exr ? escHtml(exr) : '—'}</td>
</tr>`;
});
html += `</tbody></table></div>`;
}
mainPanel.innerHTML = html;
}
function escHtml(s) {
return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}
// ─────────────────────────────────────────────
// PROPERTY TABS
// ─────────────────────────────────────────────
document.querySelectorAll('.prop-tab').forEach(tab => {
tab.addEventListener('click', () => {
document.querySelectorAll('.prop-tab').forEach(t => t.classList.remove('active'));
tab.classList.add('active');
currentProp = tab.dataset.prop;
if (currentDept) loadDept();
});
});
// ─────────────────────────────────────────────
// SEARCH
// ─────────────────────────────────────────────
searchInput.addEventListener('input', () => {
if (currentDept && currentData.length) {
renderTable(currentData);
}
});
// ─────────────────────────────────────────────
// INIT – open Casino Operations, load first dept
// ─────────────────────────────────────────────
currentDept = DEPTS[0].items[0];
renderSidebar();
loadDept();
</script>
</body>
</html>
</html>