Adds navigation menu persistence

This commit is contained in:
Rune Harlyk
2024-04-29 21:37:01 +02:00
committed by Rune Harlyk
parent 028beabb5d
commit 0a144a7473
+39 -57
View File
@@ -17,7 +17,6 @@
import NTP from '~icons/mdi/clock-check'; import NTP from '~icons/mdi/clock-check';
import Metrics from '~icons/mdi/report-bar'; import Metrics from '~icons/mdi/report-bar';
import { page } from '$app/stores'; import { page } from '$app/stores';
import { onMount } from 'svelte';
import { user } from '$lib/stores/user'; import { user } from '$lib/stores/user';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
@@ -29,7 +28,7 @@
type menuItem = { type menuItem = {
title: string; title: string;
icon: object; icon: ConstructorOfATypedSvelteComponent;
href?: string; href?: string;
feature: boolean; feature: boolean;
active?: boolean; active?: boolean;
@@ -38,7 +37,7 @@
type subMenuItem = { type subMenuItem = {
title: string; title: string;
icon: object; icon: ConstructorOfATypedSvelteComponent;
href: string; href: string;
feature: boolean; feature: boolean;
active: boolean; active: boolean;
@@ -50,7 +49,6 @@
icon: MdiController, icon: MdiController,
href: '/controller', href: '/controller',
feature: true, feature: true,
active: false
}, },
{ {
title: 'Connections', title: 'Connections',
@@ -62,14 +60,14 @@
icon: MQTT, icon: MQTT,
href: '/connections/mqtt', href: '/connections/mqtt',
feature: $page.data.features.mqtt, feature: $page.data.features.mqtt,
active: false
}, },
{ {
title: 'NTP', title: 'NTP',
icon: NTP, icon: NTP,
href: '/connections/ntp', href: '/connections/ntp',
feature: $page.data.features.ntp, feature: $page.data.features.ntp,
active: false
} }
] ]
}, },
@@ -83,14 +81,14 @@
icon: Router, icon: Router,
href: '/wifi/sta', href: '/wifi/sta',
feature: true, feature: true,
active: false
}, },
{ {
title: 'Access Point', title: 'Access Point',
icon: AP, icon: AP,
href: '/wifi/ap', href: '/wifi/ap',
feature: true, feature: true,
active: false
} }
] ]
}, },
@@ -99,7 +97,7 @@
icon: Users, icon: Users,
href: '/user', href: '/user',
feature: $page.data.features.security && $user.admin, feature: $page.data.features.security && $user.admin,
active: false
}, },
{ {
title: 'System', title: 'System',
@@ -111,14 +109,14 @@
icon: Health, icon: Health,
href: '/system/status', href: '/system/status',
feature: true, feature: true,
active: false
}, },
{ {
title: 'System Metrics', title: 'System Metrics',
icon: Metrics, icon: Metrics,
href: '/system/metrics', href: '/system/metrics',
feature: $page.data.features.analytics, feature: $page.data.features.analytics,
active: false
}, },
{ {
title: 'Firmware Update', title: 'Firmware Update',
@@ -129,43 +127,25 @@
$page.data.features.upload_firmware || $page.data.features.upload_firmware ||
$page.data.features.download_firmware) && $page.data.features.download_firmware) &&
(!$page.data.features.security || $user.admin), (!$page.data.features.security || $user.admin),
active: false
} }
] ]
} }
]; ] as menuItem[];
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
function setActiveMenuItem(menuItems: menuItem[], targetTitle: string) { function setActiveMenuItem(targetTitle: string) {
for (let i = 0; i < menuItems.length; i++) { menuItems.forEach(item => {
const menuItem = menuItems[i]; item.active = item.title === targetTitle;
item.submenu?.forEach(subItem => {
// Clear any previous set active flags subItem.active = subItem.title === targetTitle;
menuItem.active = false; });
});
// Check if the current menu item's title matches the target title menuItems = menuItems
if (menuItem.title === targetTitle) { dispatch('menuClicked');
menuItem.active = true; // Set the active property to true
dispatch('menuClicked');
}
// Check if the current menu item has a submenu
if (menuItem.submenu && menuItem.submenu.length > 0) {
// Recursively call the function for each submenu item
setActiveMenuItem(menuItem.submenu, targetTitle);
}
}
if (targetTitle == '') {
dispatch('menuClicked');
}
menuItems = menuItems;
} }
onMount(() => { $: setActiveMenuItem($page.data.title);
setActiveMenuItem(menuItems, $page.data.title);
menuItems = menuItems;
});
</script> </script>
<div class="bg-base-200 text-base-content flex h-full w-80 flex-col p-4"> <div class="bg-base-200 text-base-content flex h-full w-80 flex-col p-4">
@@ -173,29 +153,31 @@
<a <a
href="/" href="/"
class="rounded-box mb-4 flex items-center hover:scale-[1.02] active:scale-[0.98]" class="rounded-box mb-4 flex items-center hover:scale-[1.02] active:scale-[0.98]"
on:click={() => setActiveMenuItem(menuItems, '')} on:click={() => setActiveMenuItem('')}
> >
<img src={logo} alt="Logo" class="h-12 w-12" /> <img src={logo} alt="Logo" class="h-12 w-12" />
<h1 class="px-4 text-2xl font-bold">{appName}</h1> <h1 class="px-4 text-2xl font-bold">{$page.data.appName}</h1>
</a> </a>
<ul class="menu rounded-box menu-vertical flex-nowrap overflow-y-auto"> <ul class="menu rounded-box menu-vertical flex-nowrap overflow-y-auto">
{#each menuItems as menuItem (menuItem.title)} {#each menuItems as menuItem, i (menuItem.title)}
{#if menuItem.feature} {#if menuItem.feature}
{#if menuItem.submenu} <li>
<li> {#if menuItem.submenu}
<details> <details>
<summary class="text-lg font-bold" <summary class="text-lg font-bold">
><svelte:component this={menuItem.icon} class="h-6 w-6" />{menuItem.title}</summary <svelte:component this={menuItem.icon} class="h-6 w-6" />
> {menuItem.title}
</summary>
<ul> <ul>
{#each menuItem.submenu as subMenuItem} {#each menuItem.submenu as subMenuItem}
{#if subMenuItem.feature} {#if subMenuItem.feature}
<li class="hover-bordered"> <li class="hover-bordered">
<a <a
href={subMenuItem.href} href={subMenuItem.href}
class="text-ml font-bold {subMenuItem.active ? 'bg-base-100' : ''}" class:bg-base-100={subMenuItem.active}
class="text-ml font-bold"
on:click={() => { on:click={() => {
setActiveMenuItem(menuItems, subMenuItem.title); setActiveMenuItem(subMenuItem.title);
menuItems = menuItems; menuItems = menuItems;
}} }}
><svelte:component ><svelte:component
@@ -208,19 +190,18 @@
{/each} {/each}
</ul> </ul>
</details> </details>
</li> {:else}
{:else}
<li class="hover-bordered">
<a <a
href={menuItem.href} href={menuItem.href}
class="text-lg font-bold {menuItem.active ? 'bg-base-100' : ''}" class:bg-base-100={menuItem.active}
class="text-lg font-bold"
on:click={() => { on:click={() => {
setActiveMenuItem(menuItems, menuItem.title); setActiveMenuItem(menuItem.title);
menuItems = menuItems; menuItems = menuItems;
}}><svelte:component this={menuItem.icon} class="h-6 w-6" />{menuItem.title}</a }}><svelte:component this={menuItem.icon} class="h-6 w-6" />{menuItem.title}</a
> >
</li> {/if}
{/if} </li>
{/if} {/if}
{/each} {/each}
</ul> </ul>
@@ -233,6 +214,7 @@
<Avatar class="h-8 w-8" /> <Avatar class="h-8 w-8" />
<span class="flex-grow px-4 text-xl font-bold">{$user.username}</span> <span class="flex-grow px-4 text-xl font-bold">{$user.username}</span>
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div <div
class="btn btn-ghost" class="btn btn-ghost"
on:click={() => { on:click={() => {