Add menu enable toggle, user status, and mobile/UI polish

- Admin menu page: mobile item cards now put Actions in the top-right
  corner next to Status, matching the desktop row layout instead of
  stacking at the bottom; same treatment applied to announcements and
  users for consistency across all three admin lists
- Center button label text everywhere via .btn { justify-content: center }
  instead of one-off overrides
- Add a Disable/Enable Menu toggle to the admin menu toolbar; the public
  menu page shows its existing "menu being updated" message while disabled
- Add an Enabled/Disabled status to user accounts, with its own toggle
  badge, guardrails against disabling your own account or the last
  enabled account, and an immediate session kick for anyone disabled
  mid-session
- Fix the announcement banner / hero tagline "·" separators to hide only
  when their neighboring text actually wraps onto a different line,
  instead of a fixed breakpoint or always-on dot

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
David DyerandClaude Sonnet 5 committed 2026-09-01 14:10:08 -04:00
1 parent eab20899de
commit cd4c6c1969
13 files changed
+405 -50

No files matched your search

+53 -10
View File
@@ -93,6 +93,32 @@ function handle_change_password(array $post, array $currentUser): array {
return ['success' => true];
}
function handle_toggle_user_enabled(array $post, array $currentUser): array {
$targetId = (int) ($post['user_id'] ?? 0);
$target = $targetId > 0 ? get_user_by_id($targetId) : null;
if (!$target) {
return ['success' => false, 'error' => 'User not found.'];
}
if ($targetId === (int) $currentUser['id']) {
return ['success' => false, 'error' => "You can't disable your own account while logged in as it."];
}
$currentlyEnabled = (int) $target['is_enabled'] === 1;
if ($currentlyEnabled && count_enabled_users() <= 1) {
return ['success' => false, 'error' => 'At least one user account must remain enabled.'];
}
toggle_user_enabled($targetId);
$isEnabled = (int) get_user_by_id($targetId)['is_enabled'] === 1;
return [
'success' => true,
'is_enabled' => $isEnabled,
'status_badge' => $isEnabled ? '● Enabled' : '○ Disabled',
'status_class' => $isEnabled ? 'active' : 'inactive',
];
}
function handle_delete_user(array $post, array $currentUser): array {
$targetId = (int) ($post['user_id'] ?? 0);
if ($targetId <= 0 || !get_user_by_id($targetId)) {
@@ -113,6 +139,7 @@ function handle_users_action(string $action, array $post, array $currentUser): a
return match ($action) {
'create_user' => handle_create_user($post, $currentUser),
'change_password' => handle_change_password($post, $currentUser),
'toggle_user_enabled' => handle_toggle_user_enabled($post, $currentUser),
'delete_user' => handle_delete_user($post, $currentUser),
default => ['success' => false, 'error' => 'Unknown action'],
};
@@ -191,6 +218,7 @@ $users = get_all_users();
<div class="user-grid-wrap">
<div class="user-grid-head" aria-hidden="true">
<span class="col-status">Status</span>
<span class="col-username">Username</span>
<span class="col-role">Role</span>
<span class="col-created">Created</span>
@@ -198,10 +226,23 @@ $users = get_all_users();
</div>
<div class="user-rows" id="users-rows">
<?php foreach ($users as $row): ?>
<?php $isSelf = (int) $row['id'] === (int) $user['id']; ?>
<?php $isEnabled = (int) $row['is_enabled'] === 1; ?>
<div class="user-row" id="user-row-<?= (int) $row['id'] ?>" data-user-id="<?= (int) $row['id'] ?>">
<div data-label="Status">
<?php if ($isSelf): ?>
<span class="status-badge <?= $isEnabled ? 'active' : 'inactive' ?>" title="You can't disable your own account.">
<?= $isEnabled ? '● Enabled' : '○ Disabled' ?>
</span>
<?php else: ?>
<button type="button" class="status-badge btn-toggle-user <?= $isEnabled ? 'active' : 'inactive' ?>" data-id="<?= (int) $row['id'] ?>" title="Click to mark as <?= $isEnabled ? 'disabled' : 'enabled' ?>">
<?= $isEnabled ? '● Enabled' : '○ Disabled' ?>
</button>
<?php endif; ?>
</div>
<div data-label="Username">
<strong><?= htmlspecialchars($row['username']) ?></strong>
<?php if ((int) $row['id'] === (int) $user['id']): ?>
<?php if ($isSelf): ?>
<span class="muted"> (you)</span>
<?php endif; ?>
</div>
@@ -209,16 +250,18 @@ $users = get_all_users();
<div class="font-mono timestamp-cell" data-label="Created"><?= htmlspecialchars($row['created_at']) ?></div>
<div data-label="Actions">
<div class="row-actions">
<button type="button" class="btn btn-outline btn-sm btn-change-password"
data-id="<?= (int) $row['id'] ?>"
data-username="<?= htmlspecialchars($row['username']) ?>">
Change Password
</button>
<?php if ((int) $row['id'] !== (int) $user['id']): ?>
<button type="button" class="btn btn-danger btn-sm btn-delete-user" data-id="<?= (int) $row['id'] ?>">
Delete
<div class="action-stack">
<button type="button" class="btn btn-outline btn-sm btn-change-password"
data-id="<?= (int) $row['id'] ?>"
data-username="<?= htmlspecialchars($row['username']) ?>">
Change Password
</button>
<?php endif; ?>
<?php if (!$isSelf): ?>
<button type="button" class="btn btn-danger btn-sm btn-delete-user" data-id="<?= (int) $row['id'] ?>">
Delete
</button>
<?php endif; ?>
</div>
</div>
</div>
</div>