menu fix
This commit is contained in:
parent
cc7bbafb63
commit
3948dde2e7
6 changed files with 114 additions and 66 deletions
|
|
@ -131,25 +131,12 @@ textarea {
|
||||||
.primary-nav {
|
.primary-nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
justify-content: center;
|
|
||||||
gap: 10px;
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-group {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-group + .nav-group {
|
|
||||||
padding-left: 10px;
|
|
||||||
border-left: 1px solid var(--line);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-link {
|
.nav-link {
|
||||||
padding: 9px 10px;
|
padding: 9px 10px;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
|
|
@ -163,6 +150,60 @@ textarea {
|
||||||
background: var(--accent-soft);
|
background: var(--accent-soft);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.account-menu {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-menu summary {
|
||||||
|
list-style: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-menu summary::-webkit-details-marker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-menu summary::after {
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
margin-left: 7px;
|
||||||
|
border-left: 4px solid transparent;
|
||||||
|
border-right: 4px solid transparent;
|
||||||
|
border-top: 5px solid currentColor;
|
||||||
|
transform: translateY(1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-menu-panel {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: calc(100% + 10px);
|
||||||
|
min-width: 210px;
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: var(--radius);
|
||||||
|
background: rgba(8, 18, 33, 0.98);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
display: grid;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-menu-link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 40px;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-menu-link:hover,
|
||||||
|
.account-menu-link.is-active {
|
||||||
|
color: var(--text);
|
||||||
|
background: var(--accent-soft);
|
||||||
|
}
|
||||||
|
|
||||||
.header-actions {
|
.header-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
|
|
@ -723,6 +764,7 @@ textarea {
|
||||||
.primary-nav {
|
.primary-nav {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
row-gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-actions {
|
.header-actions {
|
||||||
|
|
@ -786,29 +828,36 @@ textarea {
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nav-group,
|
|
||||||
.nav-group + .nav-group {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
justify-items: stretch;
|
|
||||||
gap: 4px;
|
|
||||||
padding-left: 0;
|
|
||||||
padding-top: 8px;
|
|
||||||
border-left: 0;
|
|
||||||
border-top: 1px solid var(--line);
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-group:first-child {
|
|
||||||
border-top: 0;
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nav-link {
|
.nav-link {
|
||||||
min-height: 44px;
|
min-height: 44px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.account-menu {
|
||||||
|
border-top: 1px solid var(--line);
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-menu summary {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-menu-panel {
|
||||||
|
position: static;
|
||||||
|
min-width: 0;
|
||||||
|
margin-top: 6px;
|
||||||
|
padding: 4px 0 0 12px;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account-menu-link {
|
||||||
|
min-height: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
.header-actions {
|
.header-actions {
|
||||||
grid-column: 1 / -1;
|
grid-column: 1 / -1;
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
const toggle = document.querySelector('[data-nav-toggle]');
|
const toggle = document.querySelector('[data-nav-toggle]');
|
||||||
const menu = document.querySelector('[data-nav-menu]');
|
const menu = document.querySelector('[data-nav-menu]');
|
||||||
const actions = document.querySelector('[data-header-actions]');
|
const actions = document.querySelector('[data-header-actions]');
|
||||||
|
const accountMenu = document.querySelector('[data-account-menu]');
|
||||||
|
|
||||||
if (!toggle || !menu) {
|
if (!toggle || !menu) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -14,5 +15,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||||
if (actions) {
|
if (actions) {
|
||||||
actions.classList.toggle('is-open', !expanded);
|
actions.classList.toggle('is-open', !expanded);
|
||||||
}
|
}
|
||||||
|
if (accountMenu && window.matchMedia('(max-width: 820px)').matches) {
|
||||||
|
accountMenu.open = !expanded;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -436,15 +436,14 @@ function website_table_exists(string $tableName): bool
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $db->prepare('SHOW TABLES LIKE ?');
|
$escapedTableName = $db->real_escape_string($tableName);
|
||||||
if (!$stmt) {
|
$result = @$db->query("SHOW TABLES LIKE '{$escapedTableName}'");
|
||||||
|
if (!$result instanceof mysqli_result) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$stmt->bind_param('s', $tableName);
|
|
||||||
$stmt->execute();
|
$exists = $result->num_rows > 0;
|
||||||
$result = $stmt->get_result();
|
$result->free();
|
||||||
$exists = $result instanceof mysqli_result && $result->num_rows > 0;
|
|
||||||
$stmt->close();
|
|
||||||
return $exists;
|
return $exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ declare(strict_types=1);
|
||||||
$activePage = $activePage ?? '';
|
$activePage = $activePage ?? '';
|
||||||
$currentUser = website_current_user();
|
$currentUser = website_current_user();
|
||||||
$cartCount = website_cart_count();
|
$cartCount = website_cart_count();
|
||||||
$publicLinks = [
|
$primaryLinks = [
|
||||||
['key' => 'home', 'label' => 'Home', 'href' => website_url('index.php')],
|
['key' => 'home', 'label' => 'Home', 'href' => website_url('index.php')],
|
||||||
['key' => 'servers', 'label' => 'Game Servers', 'href' => website_url('serverlist.php')],
|
['key' => 'servers', 'label' => 'Game Servers', 'href' => website_url('serverlist.php')],
|
||||||
['key' => 'pricing', 'label' => 'Pricing', 'href' => website_url('pricing.php')],
|
['key' => 'pricing', 'label' => 'Pricing', 'href' => website_url('pricing.php')],
|
||||||
|
|
@ -19,18 +19,22 @@ if ($currentUser) {
|
||||||
['key' => 'orders', 'label' => 'My Orders', 'href' => website_url('my_orders.php')],
|
['key' => 'orders', 'label' => 'My Orders', 'href' => website_url('my_orders.php')],
|
||||||
['key' => 'servers', 'label' => 'My Servers', 'href' => website_url('my_servers.php')],
|
['key' => 'servers', 'label' => 'My Servers', 'href' => website_url('my_servers.php')],
|
||||||
['key' => 'cart', 'label' => 'Cart' . ($cartCount > 0 ? ' (' . $cartCount . ')' : ''), 'href' => website_cart_url()],
|
['key' => 'cart', 'label' => 'Cart' . ($cartCount > 0 ? ' (' . $cartCount . ')' : ''), 'href' => website_cart_url()],
|
||||||
['key' => 'logout', 'label' => 'Logout', 'href' => website_url('logout.php')],
|
|
||||||
];
|
];
|
||||||
|
if (website_current_user_is_staff()) {
|
||||||
|
$accountLinks[] = ['key' => 'staff', 'label' => 'Staff Dashboard', 'href' => website_url('staff.php')];
|
||||||
|
}
|
||||||
|
$accountLinks[] = ['key' => 'logout', 'label' => 'Logout', 'href' => website_url('logout.php')];
|
||||||
|
$accountLabel = 'Account';
|
||||||
} else {
|
} else {
|
||||||
$accountLinks = [
|
$accountLinks = [
|
||||||
['key' => 'account', 'label' => 'Login', 'href' => website_login_url()],
|
['key' => 'account', 'label' => 'Login', 'href' => website_login_url()],
|
||||||
['key' => 'register', 'label' => 'Create Account', 'href' => website_register_url()],
|
['key' => 'register', 'label' => 'Create Account', 'href' => website_register_url()],
|
||||||
['key' => 'cart', 'label' => 'Cart' . ($cartCount > 0 ? ' (' . $cartCount . ')' : ''), 'href' => website_cart_url()],
|
['key' => 'cart', 'label' => 'Cart' . ($cartCount > 0 ? ' (' . $cartCount . ')' : ''), 'href' => website_cart_url()],
|
||||||
];
|
];
|
||||||
|
$accountLabel = 'Account';
|
||||||
}
|
}
|
||||||
$staffLinks = ($currentUser && website_current_user_is_staff()) ? [
|
$accountActiveKeys = array_column($accountLinks, 'key');
|
||||||
['key' => 'staff', 'label' => 'Staff Dashboard', 'href' => website_url('staff.php')],
|
$accountIsActive = in_array($activePage, $accountActiveKeys, true);
|
||||||
] : [];
|
|
||||||
?>
|
?>
|
||||||
<header class="site-header">
|
<header class="site-header">
|
||||||
<div class="container header-shell">
|
<div class="container header-shell">
|
||||||
|
|
@ -50,29 +54,21 @@ $staffLinks = ($currentUser && website_current_user_is_staff()) ? [
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<nav class="primary-nav" id="primary-nav" data-nav-menu aria-label="Primary navigation">
|
<nav class="primary-nav" id="primary-nav" data-nav-menu aria-label="Primary navigation">
|
||||||
<div class="nav-group nav-group-public">
|
<?php foreach ($primaryLinks as $link): ?>
|
||||||
<?php foreach ($publicLinks as $link): ?>
|
|
||||||
<a class="nav-link<?= $activePage === $link['key'] ? ' is-active' : '' ?>" href="<?= website_escape($link['href']) ?>">
|
<a class="nav-link<?= $activePage === $link['key'] ? ' is-active' : '' ?>" href="<?= website_escape($link['href']) ?>">
|
||||||
<?= website_escape($link['label']) ?>
|
<?= website_escape($link['label']) ?>
|
||||||
</a>
|
</a>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
<details class="account-menu" data-account-menu>
|
||||||
<div class="nav-group nav-group-account" aria-label="Account navigation">
|
<summary class="nav-link<?= $accountIsActive ? ' is-active' : '' ?>"><?= website_escape($accountLabel) ?></summary>
|
||||||
<?php foreach ($accountLinks as $link): ?>
|
<div class="account-menu-panel">
|
||||||
<a class="nav-link<?= $activePage === $link['key'] ? ' is-active' : '' ?>" href="<?= website_escape($link['href']) ?>">
|
<?php foreach ($accountLinks as $link): ?>
|
||||||
<?= website_escape($link['label']) ?>
|
<a class="account-menu-link<?= $activePage === $link['key'] ? ' is-active' : '' ?>" href="<?= website_escape($link['href']) ?>">
|
||||||
</a>
|
<?= website_escape($link['label']) ?>
|
||||||
<?php endforeach; ?>
|
</a>
|
||||||
</div>
|
<?php endforeach; ?>
|
||||||
<?php if (!empty($staffLinks)): ?>
|
</div>
|
||||||
<div class="nav-group nav-group-staff" aria-label="Staff navigation">
|
</details>
|
||||||
<?php foreach ($staffLinks as $link): ?>
|
|
||||||
<a class="nav-link<?= $activePage === $link['key'] ? ' is-active' : '' ?>" href="<?= website_escape($link['href']) ?>">
|
|
||||||
<?= website_escape($link['label']) ?>
|
|
||||||
</a>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="header-actions" data-header-actions>
|
<div class="header-actions" data-header-actions>
|
||||||
|
|
|
||||||
|
|
@ -77,12 +77,11 @@ Website footer account links are state-aware:
|
||||||
- logged in: `My Account`, `Order a Server`, `Control Panel`, `My Servers`, `Log Out`
|
- logged in: `My Account`, `Order a Server`, `Control Panel`, `My Servers`, `Log Out`
|
||||||
- staff-only links appear only for Panel admin users and still enforce website staff authorization server-side
|
- staff-only links appear only for Panel admin users and still enforce website staff authorization server-side
|
||||||
|
|
||||||
The shared header groups navigation by purpose:
|
The shared header uses one responsive navigation bar:
|
||||||
|
|
||||||
- public: Home, Game Servers, Pricing, Locations, Documentation, Support
|
- primary links: Home, Game Servers, Pricing, Locations, Documentation, Support
|
||||||
- account: Login/Create Account/Cart or My Account/My Orders/My Servers/Cart/Logout
|
- account menu: Login/Create Account/Cart or My Account/My Orders/My Servers/Cart/Staff Dashboard/Logout
|
||||||
- staff: Staff Dashboard, only for authorized website staff
|
- action buttons: Custom Projects and Control Panel
|
||||||
- actions: Custom Projects and Control Panel
|
|
||||||
|
|
||||||
Control Panel links point directly to the configured Panel domain. `My Servers`
|
Control Panel links point directly to the configured Panel domain. `My Servers`
|
||||||
opens a website customer page that summarizes website orders and links to the
|
opens a website customer page that summarizes website orders and links to the
|
||||||
|
|
|
||||||
|
|
@ -254,6 +254,7 @@ Check:
|
||||||
- expected catalog columns exist or can be added by the idempotent migration runner
|
- expected catalog columns exist or can be added by the idempotent migration runner
|
||||||
- `remote_servers` schema is the current Panel schema
|
- `remote_servers` schema is the current Panel schema
|
||||||
- the page is not assuming `remote_servers.enabled` exists
|
- the page is not assuming `remote_servers.enabled` exists
|
||||||
|
- `website_table_exists()` is not using `SHOW TABLES LIKE ?`; MySQL does not support binding the table pattern in that statement through mysqli prepared placeholders
|
||||||
|
|
||||||
The current helper treats missing `remote_servers.enabled` as enabled for display and lets staff assign locations from current Panel remote-server rows.
|
The current helper treats missing `remote_servers.enabled` as enabled for display and lets staff assign locations from current Panel remote-server rows.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue