Adds navigation menu persistence
This commit is contained in:
+37
-55
@@ -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
|
|
||||||
if (menuItem.title === targetTitle) {
|
|
||||||
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(menuItems, $page.data.title);
|
|
||||||
menuItems = menuItems;
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
menuItems = menuItems
|
||||||
|
dispatch('menuClicked');
|
||||||
|
}
|
||||||
|
|
||||||
|
$: setActiveMenuItem($page.data.title);
|
||||||
</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={() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user