@profidev/pleiades 1.8.1 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,60 +3,71 @@
3
3
  import * as Sidebar from '../../ui/sidebar';
4
4
  import type {
5
5
  NavGroup,
6
- NavItem,
7
6
  SidebarUserInfo
8
7
  } from './types';
9
8
 
10
9
  interface Props {
11
10
  items: NavGroup[];
12
- user: SidebarUserInfo;
11
+ user: SidebarUserInfo | Promise<SidebarUserInfo>;
13
12
  }
14
13
 
15
- const { items, user }: Props = $props();
14
+ const { items, user: userPromise }: Props = $props();
16
15
 
17
- let filteredItems = $derived(
16
+ const filteredItems = (items: NavGroup[], user: SidebarUserInfo) =>
18
17
  items
19
- .map((group) => {
20
- group.items = group.items.filter((item) => {
18
+ .map((group) => ({
19
+ ...group,
20
+ items: group.items.filter((item) => {
21
21
  if (item.requiredPermission) {
22
- return user.permissions.includes(item.requiredPermission);
22
+ return user?.permissions.includes(item.requiredPermission);
23
23
  }
24
24
  return true;
25
- });
26
- return group;
27
- })
28
- .filter((item) => item.items.length > 0)
29
- );
25
+ })
26
+ }))
27
+ .filter((item) => item.items.length > 0);
30
28
 
31
- let current = $derived<NavItem | undefined>(
29
+ const current = (filteredItems: NavGroup[]) =>
32
30
  filteredItems
33
31
  .flatMap((group) => group.items)
34
32
  .filter((item) => page.url.pathname.startsWith(item.href))
35
- .sort((a, b) => b.href.length - a.href.length)[0] ?? undefined
36
- );
33
+ .sort((a, b) => b.href.length - a.href.length)[0] ?? undefined;
37
34
  </script>
38
35
 
39
- {#each filteredItems as group}
36
+ {#await userPromise}
40
37
  <Sidebar.Group>
41
- <Sidebar.GroupLabel>{group.label}</Sidebar.GroupLabel>
42
- <Sidebar.Menu class="gap-1">
43
- {#each group.items as item}
38
+ <Sidebar.GroupLabel>Loading...</Sidebar.GroupLabel>
39
+ <Sidebar.Menu>
40
+ {#each Array.from({ length: 3 }) as _}
44
41
  <Sidebar.MenuItem>
45
- <Sidebar.MenuButton
46
- tooltipContent={item.label}
47
- class={item.href === current?.href ? 'bg-muted' : ''}
48
- >
49
- {#snippet child({ props })}
50
- <a href={item.href} {...props}>
51
- {#if item.icon}
52
- <item.icon />
53
- {/if}
54
- <span>{item.label}</span>
55
- </a>
56
- {/snippet}
57
- </Sidebar.MenuButton>
42
+ <Sidebar.MenuSkeleton />
58
43
  </Sidebar.MenuItem>
59
44
  {/each}
60
45
  </Sidebar.Menu>
61
46
  </Sidebar.Group>
62
- {/each}
47
+ {:then user}
48
+ {@const filtered = filteredItems(items, user)}
49
+ {#each filtered as group}
50
+ <Sidebar.Group>
51
+ <Sidebar.GroupLabel>{group.label}</Sidebar.GroupLabel>
52
+ <Sidebar.Menu class="gap-1">
53
+ {#each group.items as item}
54
+ <Sidebar.MenuItem>
55
+ <Sidebar.MenuButton
56
+ tooltipContent={item.label}
57
+ class={item.href === current(filtered)?.href ? 'bg-muted' : ''}
58
+ >
59
+ {#snippet child({ props })}
60
+ <a href={item.href} {...props}>
61
+ {#if item.icon}
62
+ <item.icon />
63
+ {/if}
64
+ <span>{item.label}</span>
65
+ </a>
66
+ {/snippet}
67
+ </Sidebar.MenuButton>
68
+ </Sidebar.MenuItem>
69
+ {/each}
70
+ </Sidebar.Menu>
71
+ </Sidebar.Group>
72
+ {/each}
73
+ {/await}
@@ -1,7 +1,7 @@
1
1
  import type { NavGroup, SidebarUserInfo } from './types';
2
2
  interface Props {
3
3
  items: NavGroup[];
4
- user: SidebarUserInfo;
4
+ user: SidebarUserInfo | Promise<SidebarUserInfo>;
5
5
  }
6
6
  declare const SidebarContent: import("svelte").Component<Props, {}, "">;
7
7
  type SidebarContent = ReturnType<typeof SidebarContent>;
@@ -4,14 +4,16 @@
4
4
  import PanelLeftOpen from '@lucide/svelte/icons/panel-left-open';
5
5
  import PanelLeftClose from '@lucide/svelte/icons/panel-left-close';
6
6
  import type { Component } from 'svelte';
7
+ import { cn } from '../../../utils';
7
8
 
8
9
  interface Props {
9
10
  version: string;
10
11
  app_name: string;
12
+ iconClass?: string;
11
13
  app_icon?: Component;
12
14
  }
13
15
 
14
- let { version, app_name, app_icon }: Props = $props();
16
+ let { version, app_name, app_icon, iconClass }: Props = $props();
15
17
 
16
18
  let sidebar = Sidebar.useSidebar();
17
19
  let isOpen = $derived(sidebar.props.open());
@@ -30,7 +32,7 @@
30
32
  <div
31
33
  class="bg-sidebar-primary text-sidebar-primary-foreground flex aspect-square size-8 items-center justify-center rounded-lg"
32
34
  >
33
- <AppIcon class="size-4 text-[#9db6ed]" />
35
+ <AppIcon class={cn('size-4 text-[#9db6ed]', iconClass)} />
34
36
  </div>
35
37
  <div class="flex flex-col gap-0.5 leading-none">
36
38
  <span class="font-medium text-nowrap">{app_name}</span>
@@ -2,6 +2,7 @@ import type { Component } from 'svelte';
2
2
  interface Props {
3
3
  version: string;
4
4
  app_name: string;
5
+ iconClass?: string;
5
6
  app_icon?: Component;
6
7
  }
7
8
  declare const SidebarHeader: Component<Props, {}, "">;
@@ -7,15 +7,16 @@
7
7
  import SettingsIcon from '@lucide/svelte/icons/settings';
8
8
  import { goto } from '$app/navigation';
9
9
  import { disconnectWebsocket } from '../../../backend/updater.svelte';
10
+ import type { SidebarUserInfo } from './types';
11
+ import { Skeleton } from '../../ui/skeleton';
10
12
 
11
13
  interface Props {
12
- name: string;
13
- email: string;
14
- avatar: string;
14
+ user: SidebarUserInfo | Promise<SidebarUserInfo>;
15
+ avatar?: string;
15
16
  logout: () => Promise<{ error?: any }>;
16
17
  }
17
18
 
18
- let { name, email, avatar, logout }: Props = $props();
19
+ let { logout, user: userPromise, avatar }: Props = $props();
19
20
 
20
21
  const sidebar = Sidebar.useSidebar();
21
22
  </script>
@@ -31,12 +32,19 @@
31
32
  {...props}
32
33
  >
33
34
  <Avatar.Root class="size-8 rounded-lg">
34
- <Avatar.Image src={avatar} alt={name} />
35
- <Avatar.Fallback class="rounded-lg">?</Avatar.Fallback>
35
+ {#await userPromise then user}
36
+ <Avatar.Image src={avatar} alt={user.name} />
37
+ {/await}
38
+ <Avatar.Fallback class="rounded-full">?</Avatar.Fallback>
36
39
  </Avatar.Root>
37
40
  <div class="grid flex-1 text-start text-sm leading-tight">
38
- <span class="truncate font-medium">{name}</span>
39
- <span class="truncate text-xs">{email}</span>
41
+ {#await userPromise}
42
+ <Skeleton class="mb-1 h-4" />
43
+ <Skeleton class="h-3" />
44
+ {:then user}
45
+ <span class="truncate font-medium">{user.name}</span>
46
+ <span class="truncate text-xs">{user.email}</span>
47
+ {/await}
40
48
  </div>
41
49
  <ChevronsUpDownIcon class="ms-auto size-4" />
42
50
  </Sidebar.MenuButton>
@@ -51,12 +59,19 @@
51
59
  <DropdownMenu.Label class="p-0 font-normal">
52
60
  <div class="flex items-center gap-2 px-1 py-1.5 text-start text-sm">
53
61
  <Avatar.Root class="size-8 rounded-lg">
54
- <Avatar.Image src={avatar} alt={name} />
55
- <Avatar.Fallback class="rounded-lg">?</Avatar.Fallback>
62
+ {#await userPromise then user}
63
+ <Avatar.Image src={avatar} alt={user.name} />
64
+ {/await}
65
+ <Avatar.Fallback class="rounded-full">?</Avatar.Fallback>
56
66
  </Avatar.Root>
57
67
  <div class="grid flex-1 text-start text-sm leading-tight">
58
- <span class="truncate font-medium">{name}</span>
59
- <span class="truncate text-xs">{email}</span>
68
+ {#await userPromise}
69
+ <Skeleton class="mb-1 h-4" />
70
+ <Skeleton class="h-3" />
71
+ {:then user}
72
+ <span class="truncate font-medium">{user.name}</span>
73
+ <span class="truncate text-xs">{user.email}</span>
74
+ {/await}
60
75
  </div>
61
76
  </div>
62
77
  </DropdownMenu.Label>
@@ -1,7 +1,7 @@
1
+ import type { SidebarUserInfo } from './types';
1
2
  interface Props {
2
- name: string;
3
- email: string;
4
- avatar: string;
3
+ user: SidebarUserInfo | Promise<SidebarUserInfo>;
4
+ avatar?: string;
5
5
  logout: () => Promise<{
6
6
  error?: any;
7
7
  }>;
@@ -7,34 +7,40 @@
7
7
  import type { NavGroup, SidebarUserInfo } from './types';
8
8
 
9
9
  interface Props {
10
- user: SidebarUserInfo;
10
+ user: SidebarUserInfo | Promise<SidebarUserInfo>;
11
+ avatar?: string;
11
12
  children: Snippet;
12
13
  version: string;
13
14
  app_name: string;
14
15
  app_icon?: Component;
16
+ iconClass?: string;
15
17
  items: NavGroup[];
16
18
  logout: () => Promise<{ error?: any }>;
17
19
  }
18
20
 
19
- const { children, user, version, app_name, app_icon, items, logout }: Props =
20
- $props();
21
+ const {
22
+ children,
23
+ user,
24
+ avatar,
25
+ version,
26
+ app_name,
27
+ app_icon,
28
+ items,
29
+ logout,
30
+ iconClass
31
+ }: Props = $props();
21
32
  </script>
22
33
 
23
34
  <Sidebar.Provider>
24
35
  <Sidebar.Root collapsible="icon" variant="floating">
25
36
  <Sidebar.Header>
26
- <SidebarHeader {app_name} {app_icon} {version} />
37
+ <SidebarHeader {app_name} {app_icon} {version} {iconClass} />
27
38
  </Sidebar.Header>
28
39
  <Sidebar.Content>
29
40
  <SidebarContent {items} {user} />
30
41
  </Sidebar.Content>
31
42
  <Sidebar.Footer>
32
- <SidebarUser
33
- name={user.name}
34
- email={user.email}
35
- avatar={`data:image/webp;base64,${user.avatar || ''}`}
36
- {logout}
37
- />
43
+ <SidebarUser {avatar} {user} {logout} />
38
44
  </Sidebar.Footer>
39
45
  </Sidebar.Root>
40
46
  <Sidebar.Inset>
@@ -2,11 +2,13 @@ import * as Sidebar from '../../ui/sidebar';
2
2
  import type { Component, Snippet } from 'svelte';
3
3
  import type { NavGroup, SidebarUserInfo } from './types';
4
4
  interface Props {
5
- user: SidebarUserInfo;
5
+ user: SidebarUserInfo | Promise<SidebarUserInfo>;
6
+ avatar?: string;
6
7
  children: Snippet;
7
8
  version: string;
8
9
  app_name: string;
9
10
  app_icon?: Component;
11
+ iconClass?: string;
10
12
  items: NavGroup[];
11
13
  logout: () => Promise<{
12
14
  error?: any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@profidev/pleiades",
3
- "version": "1.8.1",
3
+ "version": "1.9.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/Profiidev/pleiades"
@@ -796,6 +796,7 @@
796
796
  "zod": "^4.0.0"
797
797
  },
798
798
  "devDependencies": {
799
+ "@fontsource-variable/inter": "5.2.8",
799
800
  "@jsrepo/transform-oxfmt": "^7.0.0",
800
801
  "@sveltejs/adapter-auto": "7.0.1",
801
802
  "@sveltejs/package": "2.5.7",
@@ -808,6 +809,7 @@
808
809
  "oxlint-tsgolint": "0.23.0",
809
810
  "prettier-plugin-svelte": "4.0.1",
810
811
  "publint": "0.3.21",
812
+ "shadcn-svelte": "1.2.7",
811
813
  "svelte-check": "4.4.8",
812
814
  "tailwindcss": "4.3.0",
813
815
  "tw-animate-css": "1.4.0",