feat: replace gear dropdown with direct settings link

Remove the gear dropdown menu from AppHeader; cog icon is now a plain
router-link to /settings. Admin-only /admin/users and /admin/logs routes
are replaced with redirects to /settings. Mobile menu admin links removed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 21:13:43 -04:00
parent 89f3d94895
commit befee1110b
2 changed files with 10 additions and 77 deletions
+8 -67
View File
@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from "vue";
import { ref, computed } from "vue";
import { useRouter, useRoute } from "vue-router";
import { useTheme } from "@/composables/useTheme";
import { useShortcuts } from "@/composables/useShortcuts";
@@ -17,8 +17,6 @@ const route = useRoute();
const isChatActive = computed(() => route.path.startsWith("/chat"));
const mobileMenuOpen = ref(false);
const gearOpen = ref(false);
const gearMenuRef = ref<HTMLElement | null>(null);
const statusShortLabel = computed(() => {
if (chatStore.ollamaStatus === "unavailable") return "Offline";
@@ -51,16 +49,6 @@ function toggleMobileMenu() {
mobileMenuOpen.value = !mobileMenuOpen.value;
}
function toggleGear() {
gearOpen.value = !gearOpen.value;
}
function handleClickOutside(e: MouseEvent) {
if (gearMenuRef.value && !gearMenuRef.value.contains(e.target as Node)) {
gearOpen.value = false;
}
}
async function handleLogout() {
await authStore.logout();
mobileMenuOpen.value = false;
@@ -69,11 +57,7 @@ async function handleLogout() {
router.afterEach(() => {
mobileMenuOpen.value = false;
gearOpen.value = false;
});
onMounted(() => document.addEventListener("click", handleClickOutside));
onUnmounted(() => document.removeEventListener("click", handleClickOutside));
</script>
<template>
@@ -107,20 +91,13 @@ onUnmounted(() => document.removeEventListener("click", handleClickOutside));
{{ theme === "dark" ? "\u2600" : "\u263E" }}
</button>
<!-- Gear dropdown -->
<div class="gear-menu" ref="gearMenuRef">
<button class="btn-icon btn-gear" @click.stop="toggleGear" :class="{ active: gearOpen }" title="Settings">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"/>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
</svg>
</button>
<div v-if="gearOpen" class="gear-dropdown">
<router-link to="/settings" class="gear-item">Settings</router-link>
<router-link v-if="authStore.isAdmin" to="/admin/users" class="gear-item">Users</router-link>
<router-link v-if="authStore.isAdmin" to="/admin/logs" class="gear-item">Logs</router-link>
</div>
</div>
<!-- Settings link -->
<router-link to="/settings" class="btn-icon" aria-label="Settings" title="Settings">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3"/>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
</svg>
</router-link>
<div class="user-info">
<span class="username">{{ authStore.user?.username }}</span>
@@ -146,8 +123,6 @@ onUnmounted(() => document.removeEventListener("click", handleClickOutside));
<router-link to="/graph" class="nav-link">Graph</router-link>
<div class="mobile-divider"></div>
<router-link to="/settings" class="nav-link">Settings</router-link>
<router-link v-if="authStore.isAdmin" to="/admin/users" class="nav-link">Users</router-link>
<router-link v-if="authStore.isAdmin" to="/admin/logs" class="nav-link">Logs</router-link>
<div class="mobile-divider"></div>
<div class="mobile-actions">
<span class="status-indicator" :class="statusClass" :title="statusLabel">
@@ -281,40 +256,6 @@ onUnmounted(() => document.removeEventListener("click", handleClickOutside));
border-color: var(--color-primary);
}
/* Gear dropdown */
.gear-menu {
position: relative;
}
.gear-dropdown {
position: absolute;
top: calc(100% + 6px);
right: 0;
background: var(--color-bg-card);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
box-shadow: 0 4px 16px var(--color-shadow, rgba(0,0,0,0.15));
min-width: 140px;
z-index: 200;
overflow: hidden;
display: flex;
flex-direction: column;
}
.gear-item {
padding: 0.55rem 0.9rem;
font-size: 0.875rem;
color: var(--color-text-secondary);
text-decoration: none;
transition: background 0.12s, color 0.12s;
}
.gear-item:hover {
background: var(--color-bg-secondary);
color: var(--color-primary);
}
.gear-item.router-link-active {
color: var(--color-primary);
font-weight: 600;
}
/* User info */
.user-info {
display: flex;
+2 -10
View File
@@ -110,16 +110,8 @@ const router = createRouter({
name: "settings",
component: () => import("@/views/SettingsView.vue"),
},
{
path: "/admin/users",
name: "admin-users",
component: () => import("@/views/UserManagementView.vue"),
},
{
path: "/admin/logs",
name: "admin-logs",
component: () => import("@/views/LogsView.vue"),
},
{ path: "/admin/users", redirect: "/settings" },
{ path: "/admin/logs", redirect: "/settings" },
],
});