🧼 Simplifies the menu structure
This commit is contained in:
@@ -1,271 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import logo from '$lib/assets/logo512.png';
|
|
||||||
import MdiGithub from '~icons/mdi/github';
|
|
||||||
import MdiConnection from '~icons/mdi/connection';
|
|
||||||
import Users from '~icons/mdi/users';
|
|
||||||
import Settings from '~icons/mdi/settings';
|
|
||||||
import MdiController from '~icons/mdi/controller';
|
|
||||||
import Devices from '~icons/mdi/devices'
|
|
||||||
import Camera from '~icons/mdi/camera-outline';
|
|
||||||
import Rotate3d from '~icons/mdi/rotate-3d';
|
|
||||||
import MotorOutline from '~icons/mdi/motor-outline';
|
|
||||||
import Health from '~icons/mdi/stethoscope';
|
|
||||||
import Folder from '~icons/mdi/folder-outline';
|
|
||||||
import Update from '~icons/mdi/reload';
|
|
||||||
import WiFi from '~icons/mdi/wifi';
|
|
||||||
import Router from '~icons/mdi/router';
|
|
||||||
import AP from '~icons/mdi/access-point';
|
|
||||||
import Remote from '~icons/mdi/network';
|
|
||||||
import Avatar from '~icons/mdi/user-circle';
|
|
||||||
import Logout from '~icons/mdi/logout';
|
|
||||||
import Copyright from '~icons/mdi/copyright';
|
|
||||||
import NTP from '~icons/mdi/clock-check';
|
|
||||||
import Metrics from '~icons/mdi/report-bar';
|
|
||||||
import { page } from '$app/stores';
|
|
||||||
import { user } from '$lib/stores/user';
|
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
import { useFeatureFlags } from '$lib/stores/featureFlags';
|
|
||||||
|
|
||||||
const features = useFeatureFlags();
|
|
||||||
|
|
||||||
const appName = $page.data.app_name;
|
|
||||||
|
|
||||||
const copyright = $page.data.copyright;
|
|
||||||
|
|
||||||
const github = { href: 'https://github.com/' + $page.data.github, active: true };
|
|
||||||
|
|
||||||
type menuItem = {
|
|
||||||
title: string;
|
|
||||||
icon: ConstructorOfATypedSvelteComponent;
|
|
||||||
href?: string;
|
|
||||||
feature: boolean;
|
|
||||||
active?: boolean;
|
|
||||||
submenu?: menuItem[];
|
|
||||||
};
|
|
||||||
|
|
||||||
$: menuItems = [
|
|
||||||
{
|
|
||||||
title: 'Controller',
|
|
||||||
icon: MdiController,
|
|
||||||
href: '/controller',
|
|
||||||
feature: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Peripherals',
|
|
||||||
icon: Devices,
|
|
||||||
feature: true,
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
title: 'I2C',
|
|
||||||
icon: MdiConnection,
|
|
||||||
href: '/peripherals/i2c',
|
|
||||||
feature: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Camera',
|
|
||||||
icon: Camera,
|
|
||||||
href: '/peripherals/camera',
|
|
||||||
feature: $features.camera,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Servo',
|
|
||||||
icon: MotorOutline,
|
|
||||||
href: '/peripherals/servo',
|
|
||||||
feature: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'IMU',
|
|
||||||
icon: Rotate3d,
|
|
||||||
href: '/peripherals/imu',
|
|
||||||
feature: $features.imu || $features.mag || $features.bmp,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Connections',
|
|
||||||
icon: Remote,
|
|
||||||
feature: $features.ntp,
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
title: 'NTP',
|
|
||||||
icon: NTP,
|
|
||||||
href: '/connections/ntp',
|
|
||||||
feature: $features.ntp,
|
|
||||||
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'WiFi',
|
|
||||||
icon: WiFi,
|
|
||||||
feature: true,
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
title: 'WiFi Station',
|
|
||||||
icon: Router,
|
|
||||||
href: '/wifi/sta',
|
|
||||||
feature: true,
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Access Point',
|
|
||||||
icon: AP,
|
|
||||||
href: '/wifi/ap',
|
|
||||||
feature: true,
|
|
||||||
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Users',
|
|
||||||
icon: Users,
|
|
||||||
href: '/user',
|
|
||||||
feature: $features.security && $user.admin,
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'System',
|
|
||||||
icon: Settings,
|
|
||||||
feature: true,
|
|
||||||
submenu: [
|
|
||||||
{
|
|
||||||
title: 'System Status',
|
|
||||||
icon: Health,
|
|
||||||
href: '/system/status',
|
|
||||||
feature: true,
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'File System',
|
|
||||||
icon: Folder,
|
|
||||||
href: '/system/filesystem',
|
|
||||||
feature: true,
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'System Metrics',
|
|
||||||
icon: Metrics,
|
|
||||||
href: '/system/metrics',
|
|
||||||
feature: $features.analytics,
|
|
||||||
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Firmware Update',
|
|
||||||
icon: Update,
|
|
||||||
href: '/system/update',
|
|
||||||
feature:
|
|
||||||
($features.ota ||
|
|
||||||
$features.upload_firmware ||
|
|
||||||
$features.download_firmware) &&
|
|
||||||
(!$features.security || $user.admin),
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
] as menuItem[];
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
|
|
||||||
function setActiveMenuItem(targetTitle: string) {
|
|
||||||
menuItems.forEach(item => {
|
|
||||||
item.active = item.title === targetTitle;
|
|
||||||
item.submenu?.forEach(subItem => {
|
|
||||||
subItem.active = subItem.title === targetTitle;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
menuItems = menuItems
|
|
||||||
dispatch('menuClicked');
|
|
||||||
}
|
|
||||||
|
|
||||||
$: setActiveMenuItem($page.data.title);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<div class="bg-base-200 text-base-content flex h-full w-80 flex-col p-4">
|
|
||||||
<!-- Sidebar content here -->
|
|
||||||
<a
|
|
||||||
href="/"
|
|
||||||
class="rounded-box mb-4 flex items-center hover:scale-[1.02] active:scale-[0.98]"
|
|
||||||
on:click={() => setActiveMenuItem('')}
|
|
||||||
>
|
|
||||||
<img src={logo} alt="Logo" class="h-12 w-12" />
|
|
||||||
<h1 class="px-4 text-2xl font-bold">{appName}</h1>
|
|
||||||
</a>
|
|
||||||
<ul class="menu rounded-box menu-vertical flex-nowrap overflow-y-auto">
|
|
||||||
{#each menuItems as menuItem, i (menuItem.title)}
|
|
||||||
{#if menuItem.feature}
|
|
||||||
<li>
|
|
||||||
{#if menuItem.submenu}
|
|
||||||
<details>
|
|
||||||
<summary class="text-lg font-bold">
|
|
||||||
<svelte:component this={menuItem.icon} class="h-6 w-6" />
|
|
||||||
{menuItem.title}
|
|
||||||
</summary>
|
|
||||||
<ul>
|
|
||||||
{#each menuItem.submenu as subMenuItem}
|
|
||||||
{#if subMenuItem.feature}
|
|
||||||
<li class="hover-bordered">
|
|
||||||
<a
|
|
||||||
href={subMenuItem.href}
|
|
||||||
class:bg-base-100={subMenuItem.active}
|
|
||||||
class="text-ml font-bold"
|
|
||||||
on:click={() => {
|
|
||||||
setActiveMenuItem(subMenuItem.title);
|
|
||||||
menuItems = menuItems;
|
|
||||||
}}
|
|
||||||
><svelte:component
|
|
||||||
this={subMenuItem.icon}
|
|
||||||
class="h-5 w-5"
|
|
||||||
/>{subMenuItem.title}</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
</details>
|
|
||||||
{:else}
|
|
||||||
<a
|
|
||||||
href={menuItem.href}
|
|
||||||
class:bg-base-100={menuItem.active}
|
|
||||||
class="text-lg font-bold"
|
|
||||||
on:click={() => {
|
|
||||||
setActiveMenuItem(menuItem.title);
|
|
||||||
menuItems = menuItems;
|
|
||||||
}}><svelte:component this={menuItem.icon} class="h-6 w-6" />{menuItem.title}</a
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
</li>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<div class="flex-col" />
|
|
||||||
<div class="flex-grow" />
|
|
||||||
|
|
||||||
{#if $features.security}
|
|
||||||
<div class="flex items-center">
|
|
||||||
<Avatar class="h-8 w-8" />
|
|
||||||
<span class="flex-grow px-4 text-xl font-bold">{$user.username}</span>
|
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
||||||
<div
|
|
||||||
class="btn btn-ghost"
|
|
||||||
on:click={() => {
|
|
||||||
user.invalidate();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Logout class="h-8 w-8 rotate-180" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<div class="divider my-0" />
|
|
||||||
<div class="flex items-center">
|
|
||||||
{#if github.active}
|
|
||||||
<a href={github.href} class="btn btn-ghost" target="_blank" rel="noopener noreferrer"
|
|
||||||
><MdiGithub class="h-5 w-5" /></a
|
|
||||||
>
|
|
||||||
{/if}
|
|
||||||
<div class="inline-flex flex-grow items-center justify-end text-sm">
|
|
||||||
<Copyright class="h-4 w-4" /><span class="px-2">{copyright}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import MdiGithub from '~icons/mdi/github';
|
||||||
|
export let github;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if github.active}
|
||||||
|
<a href={github.href} class="btn btn-ghost" target="_blank" rel="noopener noreferrer"
|
||||||
|
><MdiGithub class="h-5 w-5" />
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<script>
|
||||||
|
import logo from '$lib/assets/logo512.png';
|
||||||
|
|
||||||
|
export let appName;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href="/"
|
||||||
|
class="rounded-box mb-4 flex items-center hover:scale-[1.02] active:scale-[0.98]"
|
||||||
|
>
|
||||||
|
<img src={logo} alt="Logo" class="h-12 w-12" />
|
||||||
|
<h1 class="px-4 text-2xl font-bold">{appName}</h1>
|
||||||
|
</a>
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import MdiConnection from '~icons/mdi/connection';
|
||||||
|
import Users from '~icons/mdi/users';
|
||||||
|
import Settings from '~icons/mdi/settings';
|
||||||
|
import MdiController from '~icons/mdi/controller';
|
||||||
|
import Devices from '~icons/mdi/devices';
|
||||||
|
import Camera from '~icons/mdi/camera-outline';
|
||||||
|
import Rotate3d from '~icons/mdi/rotate-3d';
|
||||||
|
import MotorOutline from '~icons/mdi/motor-outline';
|
||||||
|
import Health from '~icons/mdi/stethoscope';
|
||||||
|
import Folder from '~icons/mdi/folder-outline';
|
||||||
|
import Update from '~icons/mdi/reload';
|
||||||
|
import WiFi from '~icons/mdi/wifi';
|
||||||
|
import Router from '~icons/mdi/router';
|
||||||
|
import AP from '~icons/mdi/access-point';
|
||||||
|
import Remote from '~icons/mdi/network';
|
||||||
|
import Copyright from '~icons/mdi/copyright';
|
||||||
|
import NTP from '~icons/mdi/clock-check';
|
||||||
|
import Metrics from '~icons/mdi/report-bar';
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
import { user } from '$lib/stores/user';
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import { useFeatureFlags } from '$lib/stores/featureFlags';
|
||||||
|
import UserButton from '../menu/UserButton.svelte';
|
||||||
|
import GithubButton from '../menu/GithubButton.svelte';
|
||||||
|
import LogoButton from '../menu/LogoButton.svelte';
|
||||||
|
import MenuList from '../menu/MenuList.svelte';
|
||||||
|
|
||||||
|
const features = useFeatureFlags();
|
||||||
|
|
||||||
|
const appName = $page.data.app_name;
|
||||||
|
|
||||||
|
const copyright = $page.data.copyright;
|
||||||
|
|
||||||
|
const github = { href: 'https://github.com/' + $page.data.github, active: true };
|
||||||
|
|
||||||
|
type menuItem = {
|
||||||
|
title: string;
|
||||||
|
icon: ConstructorOfATypedSvelteComponent;
|
||||||
|
href?: string;
|
||||||
|
feature: boolean;
|
||||||
|
active?: boolean;
|
||||||
|
submenu?: menuItem[];
|
||||||
|
};
|
||||||
|
|
||||||
|
$: menuItems = [
|
||||||
|
{
|
||||||
|
title: 'Controller',
|
||||||
|
icon: MdiController,
|
||||||
|
href: '/controller',
|
||||||
|
feature: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Peripherals',
|
||||||
|
icon: Devices,
|
||||||
|
feature: true,
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
title: 'I2C',
|
||||||
|
icon: MdiConnection,
|
||||||
|
href: '/peripherals/i2c',
|
||||||
|
feature: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Camera',
|
||||||
|
icon: Camera,
|
||||||
|
href: '/peripherals/camera',
|
||||||
|
feature: $features.camera
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Servo',
|
||||||
|
icon: MotorOutline,
|
||||||
|
href: '/peripherals/servo',
|
||||||
|
feature: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'IMU',
|
||||||
|
icon: Rotate3d,
|
||||||
|
href: '/peripherals/imu',
|
||||||
|
feature: $features.imu || $features.mag || $features.bmp
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Connections',
|
||||||
|
icon: Remote,
|
||||||
|
feature: $features.ntp,
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
title: 'NTP',
|
||||||
|
icon: NTP,
|
||||||
|
href: '/connections/ntp',
|
||||||
|
feature: $features.ntp
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'WiFi',
|
||||||
|
icon: WiFi,
|
||||||
|
feature: true,
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
title: 'WiFi Station',
|
||||||
|
icon: Router,
|
||||||
|
href: '/wifi/sta',
|
||||||
|
feature: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Access Point',
|
||||||
|
icon: AP,
|
||||||
|
href: '/wifi/ap',
|
||||||
|
feature: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Users',
|
||||||
|
icon: Users,
|
||||||
|
href: '/user',
|
||||||
|
feature: $features.security && $user.admin
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'System',
|
||||||
|
icon: Settings,
|
||||||
|
feature: true,
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
title: 'System Status',
|
||||||
|
icon: Health,
|
||||||
|
href: '/system/status',
|
||||||
|
feature: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'File System',
|
||||||
|
icon: Folder,
|
||||||
|
href: '/system/filesystem',
|
||||||
|
feature: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'System Metrics',
|
||||||
|
icon: Metrics,
|
||||||
|
href: '/system/metrics',
|
||||||
|
feature: $features.analytics
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Firmware Update',
|
||||||
|
icon: Update,
|
||||||
|
href: '/system/update',
|
||||||
|
feature:
|
||||||
|
($features.ota || $features.upload_firmware || $features.download_firmware) &&
|
||||||
|
(!$features.security || $user.admin)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
] as menuItem[];
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
function setActiveMenuItem(targetTitle: string) {
|
||||||
|
menuItems.forEach((item) => {
|
||||||
|
item.active = item.title === targetTitle;
|
||||||
|
item.submenu?.forEach((subItem) => {
|
||||||
|
subItem.active = subItem.title === targetTitle;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
menuItems = menuItems;
|
||||||
|
dispatch('menuClicked');
|
||||||
|
}
|
||||||
|
|
||||||
|
$: setActiveMenuItem($page.data.title);
|
||||||
|
|
||||||
|
const updateMenu = (event:any) => {
|
||||||
|
setActiveMenuItem(event.details)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="bg-base-200 text-base-content flex h-full w-80 flex-col p-4">
|
||||||
|
<LogoButton {appName} />
|
||||||
|
|
||||||
|
<MenuList {menuItems} on:select{updateMenu} class="flex-grow flex-nowrap overflow-y-auto"/>
|
||||||
|
|
||||||
|
<UserButton />
|
||||||
|
|
||||||
|
<div class="divider my-0" />
|
||||||
|
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<GithubButton {github} />
|
||||||
|
<div class="flex items-center justify-end text-sm gap-2">
|
||||||
|
<Copyright class="h-4 w-4" />{copyright}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
type menuItem = {
|
||||||
|
title: string;
|
||||||
|
icon: ConstructorOfATypedSvelteComponent;
|
||||||
|
href?: string;
|
||||||
|
feature: boolean;
|
||||||
|
active?: boolean;
|
||||||
|
submenu?: menuItem[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export let menuItems: menuItem[];
|
||||||
|
|
||||||
|
export let level = 0;
|
||||||
|
|
||||||
|
const selectMenuItem = (title: string) => {
|
||||||
|
dispatch('select', title);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ul class={$$props.class + ' menu'}>
|
||||||
|
{#each menuItems as menuItem, i (menuItem.title)}
|
||||||
|
{#if menuItem.feature}
|
||||||
|
<li>
|
||||||
|
{#if menuItem.submenu}
|
||||||
|
<details>
|
||||||
|
<summary class="text-lg font-bold">
|
||||||
|
<svelte:component this={menuItem.icon} class="h-6 w-6" />
|
||||||
|
{menuItem.title}
|
||||||
|
</summary>
|
||||||
|
<div class="pl-4">
|
||||||
|
<svelte:self menuItems={menuItem.submenu} level={level + 1} />
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
{:else}
|
||||||
|
<a
|
||||||
|
href={menuItem.href}
|
||||||
|
class="font-bold"
|
||||||
|
class:bg-base-100={menuItem.active}
|
||||||
|
class:text-lg={level === 0}
|
||||||
|
class:text-md={level === 1}
|
||||||
|
on:click={() => selectMenuItem(menuItem.title)}
|
||||||
|
>
|
||||||
|
<svelte:component this={menuItem.icon} class="h-6 w-6" />
|
||||||
|
{menuItem.title}
|
||||||
|
</a>
|
||||||
|
{/if}
|
||||||
|
</li>
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import Avatar from '~icons/mdi/user-circle';
|
||||||
|
import Logout from '~icons/mdi/logout';
|
||||||
|
import { user } from '$lib/stores';
|
||||||
|
import { useFeatureFlags } from "$lib/stores";
|
||||||
|
|
||||||
|
const features = useFeatureFlags();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if $features.security}
|
||||||
|
<div class="flex items-center">
|
||||||
|
<Avatar class="h-8 w-8" />
|
||||||
|
<span class="flex-grow px-4 text-xl font-bold">{$user.username}</span>
|
||||||
|
<button class="btn btn-ghost" on:click={user.invalidate}>
|
||||||
|
<Logout class="h-8 w-8 rotate-180" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
import { notifications } from '$lib/components/toasts/notifications';
|
import { notifications } from '$lib/components/toasts/notifications';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import '../app.css';
|
import '../app.css';
|
||||||
import Menu from '../lib/components/menu.svelte';
|
import Menu from '../lib/components/menu/Menu.svelte';
|
||||||
import Statusbar from '../lib/components/statusbar/statusbar.svelte';
|
import Statusbar from '../lib/components/statusbar/statusbar.svelte';
|
||||||
import Login from '../lib/components/login.svelte';
|
import Login from '../lib/components/login.svelte';
|
||||||
import {
|
import {
|
||||||
|
|||||||
Reference in New Issue
Block a user