Sidebar is closed when links are clicked on mobile
All checks were successful
Production Build and Deploy / Build (push) Successful in 1m6s
Production Build and Deploy / Deploy (push) Successful in 22s

This commit is contained in:
Liviu Burcusel 2026-01-20 12:42:09 +01:00
parent 84252b76bb
commit 3d1627a384
Signed by: liviu
GPG key ID: 6CDB37A4AD2C610C
5 changed files with 71 additions and 14 deletions

View file

@ -1,5 +1,6 @@
<script setup lang="ts">
import { computed } from "vue";
import { useSidebar } from "~/components/ui/sidebar";
import { useRuntimeConfig } from "#app";
import { BookOpen, BookOpenText, ChevronRight, HandCoins, Settings2, SquareTerminal } from "lucide-vue-next";
@ -99,6 +100,14 @@ const props = withDefaults(defineProps<SidebarLayoutProps>(), {
const navMain = computed(() => props.navItems || data.navMain);
const config = useRuntimeConfig();
const { isMobile, setOpenMobile } = useSidebar();
const closeSidebarOnMobile = () => {
if (isMobile.value) {
setOpenMobile(false);
}
};
</script>
<template>
@ -107,7 +116,7 @@ const config = useRuntimeConfig();
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton size="lg" as-child>
<NuxtLink to="/">
<NuxtLink to="/" @click="closeSidebarOnMobile">
<div
class="flex aspect-square size-8 items-center justify-center rounded-lg bg-sidebar-primary text-sidebar-primary-foreground"
>
@ -147,7 +156,7 @@ const config = useRuntimeConfig();
<SidebarMenuSub>
<SidebarMenuSubItem v-for="subItem in item.items" :key="subItem.title">
<SidebarMenuSubButton as-child>
<NuxtLink :to="subItem.url">
<NuxtLink :to="subItem.url" @click="closeSidebarOnMobile">
<span>{{ subItem.title }}</span>
</NuxtLink>
</SidebarMenuSubButton>

View file

@ -16,7 +16,7 @@ import { BadgeCheck, Bell, ChevronsUpDown, CreditCard, LogIn, LogOut } from "luc
import type { User } from "better-auth";
const { isMobile } = useSidebar();
const { isMobile, setOpenMobile } = useSidebar();
const props = defineProps<{ user?: User | null | undefined }>();
@ -28,12 +28,9 @@ const userInititials = computed(() => {
.join("");
});
const handleLogout = () => {
navigateTo("/auth/logout");
};
const handleLogin = () => {
navigateTo("/auth/login");
const handleAuthNavigation = (action: string) => {
setOpenMobile(false);
navigateTo(`/auth/${action}`);
};
</script>
@ -93,7 +90,7 @@ const handleLogin = () => {
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuItem @click="handleLogout">
<DropdownMenuItem @click="handleAuthNavigation('logout')">
<LogOut />
Log out
</DropdownMenuItem>
@ -136,7 +133,7 @@ const handleLogin = () => {
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem @click="handleLogin">
<DropdownMenuItem @click="handleAuthNavigation('login')">
<LogIn />
Log in
</DropdownMenuItem>

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{
"name": "glowing-fiesta",
"version": "0.0.5",
"version": "0.0.6",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "glowing-fiesta",
"version": "0.0.5",
"version": "0.0.6",
"hasInstallScript": true,
"dependencies": {
"@pinia/nuxt": "^0.11.3",

View file

@ -1,6 +1,6 @@
{
"name": "glowing-fiesta",
"version": "0.0.5",
"version": "0.0.6",
"type": "module",
"private": true,
"scripts": {

View file

@ -267,4 +267,55 @@ describe("SidebarLayout", () => {
// and renders the menu items.
expect(text).toContain("Playground");
});
it("calls setOpenMobile(false) when clicking a sub-menu item on mobile", async () => {
const setOpenMobile = vi.fn();
useSidebarMock.mockReturnValue({
isMobile: ref(true),
state: ref("expanded"),
openMobile: ref(true),
setOpenMobile,
});
const wrapper = mount({
components: { SidebarLayout },
template: "<Suspense><SidebarLayout /></Suspense>",
});
await flushPromises();
// Find the link containing 'History' (from default data)
const link = wrapper.findAll("a").find((el) => el.text().includes("History"));
expect(link).toBeDefined();
await link.trigger("click");
expect(setOpenMobile).toHaveBeenCalledTimes(1);
expect(setOpenMobile).toHaveBeenCalledWith(false);
});
it("does not call setOpenMobile(false) when clicking a sub-menu item on desktop", async () => {
const setOpenMobile = vi.fn();
useSidebarMock.mockReturnValue({
isMobile: ref(false),
state: ref("expanded"),
openMobile: ref(true),
setOpenMobile,
});
const wrapper = mount({
components: { SidebarLayout },
template: "<Suspense><SidebarLayout /></Suspense>",
});
await flushPromises();
// Find the link containing 'History' (from default data)
const link = wrapper.findAll("a").find((el) => el.text().includes("History"));
expect(link).toBeDefined();
await link.trigger("click");
expect(setOpenMobile).not.toHaveBeenCalled();
});
});