mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-05 00:03:08 +00:00
use melt menu in sidebar
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
<script lang="ts">
|
||||
import Portal from '$lib/components/Portal.svelte'
|
||||
import { melt, createSync } from '@melt-ui/svelte'
|
||||
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ResolveOpen from '$lib/components/common/menu/ResolveOpen.svelte'
|
||||
|
||||
export let placement: any = 'right-start'
|
||||
export let justifyEnd: boolean = false
|
||||
export let lightMode: boolean = false
|
||||
export let maxHeight: number = 900
|
||||
export let disabled = false
|
||||
export let createMenu: (any) => any
|
||||
export let invisible: boolean = false
|
||||
|
||||
// Use the passed createMenu function
|
||||
const menu = createMenu({
|
||||
positioning: {
|
||||
placement
|
||||
}
|
||||
})
|
||||
|
||||
//Melt
|
||||
const {
|
||||
elements: { trigger, menu: menuElement, item },
|
||||
states
|
||||
} = menu
|
||||
|
||||
let open = false
|
||||
|
||||
const sync = createSync(states)
|
||||
$: sync.open(open, (v) => (open = Boolean(v)))
|
||||
</script>
|
||||
|
||||
<div class="w-full h-8">
|
||||
<ResolveOpen {open} on:open on:close />
|
||||
|
||||
<button class={twMerge('w-full', justifyEnd ? 'flex justify-end' : '')} {disabled}>
|
||||
<slot name="trigger" trigger={$trigger} />
|
||||
</button>
|
||||
|
||||
<Portal name="menu-v3">
|
||||
<div class="z-[6000]" use:melt={$menuElement}>
|
||||
<div
|
||||
class={twMerge(
|
||||
'border w-56 origin-top-right rounded-md shadow-md focus:outline-none overflow-y-auto',
|
||||
lightMode ? 'bg-surface-inverse' : 'bg-surface',
|
||||
invisible ? 'opacity-0' : ''
|
||||
)}
|
||||
style="max-height: {maxHeight}px;"
|
||||
>
|
||||
<div class="my-1">
|
||||
<slot item={$item} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Portal>
|
||||
</div>
|
||||
@@ -0,0 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { melt } from '@melt-ui/svelte'
|
||||
|
||||
export let createMenu: () => any
|
||||
|
||||
const menu = createMenu()
|
||||
|
||||
const {
|
||||
elements: { trigger, item, menu: menuElement }
|
||||
} = menu
|
||||
</script>
|
||||
|
||||
<div class="hover:z-50 flex w-full h-8">
|
||||
<slot name="trigger" trigger={$trigger} />
|
||||
<div use:melt={$menuElement}>
|
||||
<slot item={$item} />
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { createMenubar, melt } from '@melt-ui/svelte'
|
||||
|
||||
const {
|
||||
elements: { menubar },
|
||||
builders: { createMenu }
|
||||
} = createMenubar()
|
||||
</script>
|
||||
|
||||
<div use:melt={$menubar}>
|
||||
<slot {createMenu} />
|
||||
</div>
|
||||
@@ -0,0 +1,94 @@
|
||||
<script lang="ts">
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import Popover from '../Popover.svelte'
|
||||
import { melt } from '@melt-ui/svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import SideBarNotification from './SideBarNotification.svelte'
|
||||
import { goto } from '$app/navigation'
|
||||
|
||||
export let label: string | undefined = undefined
|
||||
export let icon: any | undefined = undefined
|
||||
export let isCollapsed: boolean
|
||||
export let disabled: boolean = false
|
||||
export let lightMode: boolean = false
|
||||
export let stopPropagationOnClick: boolean = false
|
||||
export let shortcut: string = ''
|
||||
export let notificationsCount: number = 0
|
||||
export let color: string | null = null
|
||||
export let trigger: any | undefined = undefined
|
||||
export let href: string | undefined = undefined
|
||||
export let openHref: boolean = false
|
||||
|
||||
let dispatch = createEventDispatcher()
|
||||
</script>
|
||||
|
||||
{#if !disabled}
|
||||
<Popover appearTimeout={0} disappearTimeout={0} class="w-full" disablePopup={!isCollapsed}>
|
||||
<button
|
||||
on:click={(e) => {
|
||||
if (stopPropagationOnClick) e.preventDefault()
|
||||
if (openHref && href) {
|
||||
goto(href)
|
||||
}
|
||||
dispatch('click')
|
||||
}}
|
||||
class={twMerge(
|
||||
'group flex items-center px-2 py-2 font-light rounded-md h-8 gap-3 w-full',
|
||||
lightMode
|
||||
? 'text-primary data-[highlighted]:bg-surface-hover hover:bg-surface-hover'
|
||||
: 'data-[highlighted]:bg-[#2A3648] hover:bg-[#2A3648] text-primary-inverse dark:text-primary',
|
||||
color ? 'border-4' : '',
|
||||
'transition-all',
|
||||
$$props.class
|
||||
)}
|
||||
style={color ? `border-color: ${color}; padding: 0 calc(0.5rem - 4px);` : ''}
|
||||
title={label}
|
||||
use:melt={trigger}
|
||||
>
|
||||
{#if icon}
|
||||
<svelte:component
|
||||
this={icon}
|
||||
size={16}
|
||||
class={twMerge(
|
||||
'flex-shrink-0',
|
||||
lightMode
|
||||
? 'text-primary group-hover:text-secondary'
|
||||
: 'text-primary-inverse group-hover:text-secondary-inverse dark:group-hover:text-secondary dark:text-primary',
|
||||
'transition-all'
|
||||
)}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if !isCollapsed && label}
|
||||
<span
|
||||
class={twMerge(
|
||||
'whitespace-pre truncate',
|
||||
lightMode ? 'text-primary' : 'text-primary-inverse dark:text-primary',
|
||||
'transition-all',
|
||||
$$props.class
|
||||
)}
|
||||
>
|
||||
{label}
|
||||
<span class="pl-2 text-xs dark:text-secondary light:text-secondary-inverse font-semibold">
|
||||
{shortcut}
|
||||
</span>
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
{#if isCollapsed && notificationsCount > 0}
|
||||
<div class="absolute translate-x-1/2 translate-y-1/2 -top-2 right-1 flex h-fit w-fit">
|
||||
<SideBarNotification notificationCount={notificationsCount} small={true} />
|
||||
</div>
|
||||
{:else if notificationsCount > 0}
|
||||
<div class="ml-auto">
|
||||
<SideBarNotification notificationCount={notificationsCount} small={false} />
|
||||
</div>
|
||||
{/if}
|
||||
</button>
|
||||
<svelte:fragment slot="text">
|
||||
{#if label}
|
||||
{label}
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
{/if}
|
||||
@@ -0,0 +1,86 @@
|
||||
<script lang="ts">
|
||||
import { classNames } from '$lib/utils'
|
||||
import { navigating, page } from '$app/stores'
|
||||
import Popover from '../Popover.svelte'
|
||||
import { base } from '$app/paths'
|
||||
import { melt } from '@melt-ui/svelte'
|
||||
export let label: string
|
||||
export let href: string
|
||||
export let icon: any | undefined = undefined
|
||||
export let isCollapsed: boolean
|
||||
export let disabled: boolean = false
|
||||
export let lightMode: boolean = false
|
||||
export let item: any
|
||||
let isSelected = false
|
||||
|
||||
navigating.subscribe(() => {
|
||||
if (href === `${base}/`) {
|
||||
isSelected = $page.url.pathname === href
|
||||
} else {
|
||||
isSelected = $page.url.pathname.startsWith(href)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if !disabled}
|
||||
<Popover appearTimeout={0} disappearTimeout={0} class="w-full" disablePopup={!isCollapsed}>
|
||||
<a
|
||||
{href}
|
||||
class={classNames(
|
||||
'group flex items-center px-2 py-2 text-sm font-light rounded-md h-8 gap-3',
|
||||
isSelected
|
||||
? lightMode
|
||||
? 'bg-surface-selected hover:bg-surface-hover rounded-none data-[highlighted]:bg-surface-hover'
|
||||
: 'bg-frost-700 hover:bg-[#30404e] data-[highlighted]:bg-[#30404e]'
|
||||
: lightMode
|
||||
? 'hover:bg-surface-hover rounded-none data-[highlighted]:bg-surface-hover'
|
||||
: 'hover:bg-[#2A3648] data-[highlighted]:bg-[#2A3648]',
|
||||
|
||||
'hover:transition-all',
|
||||
$$props.class
|
||||
)}
|
||||
target={href.includes('http') ? '_blank' : null}
|
||||
title={isCollapsed ? undefined : label}
|
||||
use:melt={item}
|
||||
>
|
||||
{#if icon}
|
||||
<svelte:component
|
||||
this={icon}
|
||||
size={16}
|
||||
class={classNames(
|
||||
'flex-shrink-0',
|
||||
isSelected
|
||||
? lightMode
|
||||
? 'text-primary group-hover:text-secondary'
|
||||
: 'text-frost-200 group-hover:text-white'
|
||||
: lightMode
|
||||
? 'text-primary group-hover:text-secondary'
|
||||
: 'text-gray-100 group-hover:text-white',
|
||||
'transition-all'
|
||||
)}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if !isCollapsed}
|
||||
<span
|
||||
class={classNames(
|
||||
'whitespace-pre truncate',
|
||||
isSelected
|
||||
? lightMode
|
||||
? 'text-primary group-hover:text-secondary'
|
||||
: 'text-frost-200 group-hover:text-white'
|
||||
: lightMode
|
||||
? 'text-primary group-hover:text-secondary'
|
||||
: 'text-gray-100 group-hover:text-white',
|
||||
'transition-all duration-75'
|
||||
)}
|
||||
>
|
||||
{label}
|
||||
</span>
|
||||
{/if}
|
||||
</a>
|
||||
<svelte:fragment slot="text">
|
||||
{label}
|
||||
</svelte:fragment>
|
||||
</Popover>
|
||||
{/if}
|
||||
@@ -35,9 +35,6 @@
|
||||
AlertCircle,
|
||||
Database
|
||||
} from 'lucide-svelte'
|
||||
import Menu from '../common/menu/MenuV2.svelte'
|
||||
import MenuButton from './MenuButton.svelte'
|
||||
import { MenuItem } from '@rgossiaux/svelte-headlessui'
|
||||
import UserMenu from './UserMenu.svelte'
|
||||
import DiscordIcon from '../icons/brands/Discord.svelte'
|
||||
import { WorkspaceService } from '$lib/gen'
|
||||
@@ -53,7 +50,12 @@
|
||||
import SideBarNotification from './SideBarNotification.svelte'
|
||||
import KafkaIcon from '../icons/KafkaIcon.svelte'
|
||||
import NatsIcon from '../icons/NatsIcon.svelte'
|
||||
|
||||
import Menubar from '../meltComponents/Menubar.svelte'
|
||||
import Menu from '../meltComponents/Menu.svelte'
|
||||
import { melt } from '@melt-ui/svelte'
|
||||
import MenuButtonMelt from './MenuButtonMelt.svelte'
|
||||
import MenuSingleItem from '../meltComponents/MenuSingleItem.svelte'
|
||||
import MenuLinkMelt from './MenuLinkMelt.svelte'
|
||||
export let numUnacknowledgedCriticalAlerts = 0
|
||||
|
||||
$: mainMenuLinks = [
|
||||
@@ -321,141 +323,182 @@
|
||||
class:opacity-0={isCollapsed}>Triggers</div
|
||||
>
|
||||
<div class="space-y-1">
|
||||
{#each triggerMenuLinks as menuLink (menuLink.href ?? menuLink.label)}
|
||||
<MenuLink class="!text-xs" {...menuLink} {isCollapsed} />
|
||||
{/each}
|
||||
{#if extraTriggerLinks.length > 0 && !$userStore?.operator}
|
||||
<Menu>
|
||||
<div
|
||||
slot="trigger"
|
||||
class="w-full text-gray-400 text-2xs flex flex-row gap-1 py-1 items-center px-2 hover:bg-[#2A3648] dark:hover:bg-[#30404e] rounded"
|
||||
>
|
||||
<Plus size={14} />
|
||||
</div>
|
||||
{#each extraTriggerLinks as subItem (subItem.href ?? subItem.label)}
|
||||
<MenuItem>
|
||||
<div class="py-1" role="none">
|
||||
<a
|
||||
href={subItem.disabled ? '' : subItem.href}
|
||||
class={twMerge(
|
||||
'text-secondary block px-4 py-2 text-2xs hover:bg-surface-hover hover:text-primary',
|
||||
subItem.disabled ? 'pointer-events-none opacity-50' : ''
|
||||
)}
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
{#if subItem.icon}
|
||||
<svelte:component this={subItem.icon} size={16} />
|
||||
{/if}
|
||||
{subItem.label}
|
||||
</div>
|
||||
</a>
|
||||
<Menubar let:createMenu>
|
||||
{#each triggerMenuLinks as menuLink (menuLink.href ?? menuLink.label)}
|
||||
<MenuLink class="!text-xs" {...menuLink} {isCollapsed} />
|
||||
{/each}
|
||||
{#if extraTriggerLinks.length > 0 && !$userStore?.operator}
|
||||
<Menu {createMenu} let:item>
|
||||
<svelte:fragment slot="trigger" let:trigger>
|
||||
<div
|
||||
slot="trigger"
|
||||
class={twMerge(
|
||||
'w-full text-gray-400 text-2xs flex flex-row gap-1 py-1 items-center px-2 hover:bg-[#2A3648] dark:hover:bg-[#30404e] rounded',
|
||||
'data-[highlighted]:bg-[#2A3648] dark:data-[highlighted]:bg-[#30404e]'
|
||||
)}
|
||||
use:melt={trigger}
|
||||
>
|
||||
<Plus size={14} />
|
||||
</div>
|
||||
</MenuItem>
|
||||
{/each}
|
||||
</Menu>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
{#each extraTriggerLinks as subItem (subItem.href ?? subItem.label)}
|
||||
<div>
|
||||
<div class="py-1" role="none">
|
||||
<a
|
||||
href={subItem.disabled ? '' : subItem.href}
|
||||
class={twMerge(
|
||||
'text-secondary block px-4 py-2 text-2xs hover:bg-surface-hover hover:text-primary',
|
||||
'data-[highlighted]:bg-surface-hover data-[highlighted]:text-primary',
|
||||
subItem.disabled ? 'pointer-events-none opacity-50' : ''
|
||||
)}
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
use:melt={item}
|
||||
>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
{#if subItem.icon}
|
||||
<svelte:component this={subItem.icon} size={16} />
|
||||
{/if}
|
||||
{subItem.label}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</Menu>
|
||||
{/if}
|
||||
</Menubar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col h-full justify-end">
|
||||
<div class={twMerge('space-y-0.5 mb-6 md:mb-10', noGap ? 'md:mb-0 mb-0' : 'mb-6 md:mb-10')}>
|
||||
<UserMenu {isCollapsed} />
|
||||
{#each secondaryMenuLinks as menuLink (menuLink.href ?? menuLink.label)}
|
||||
{#if menuLink.subItems}
|
||||
{@const notificationsCount = computeAllNotificationsCount(menuLink.subItems)}
|
||||
<Menu>
|
||||
<div slot="trigger">
|
||||
<MenuButton class="!text-2xs" {...menuLink} {isCollapsed} {notificationsCount} />
|
||||
<Menubar let:createMenu>
|
||||
<UserMenu {isCollapsed} {createMenu} />
|
||||
{#each secondaryMenuLinks as menuLink (menuLink.href ?? menuLink.label)}
|
||||
{#if menuLink.subItems}
|
||||
{@const notificationsCount = computeAllNotificationsCount(menuLink.subItems)}
|
||||
<Menu {createMenu} let:item>
|
||||
<svelte:fragment slot="trigger" let:trigger>
|
||||
<MenuButtonMelt
|
||||
class="!text-2xs"
|
||||
{...menuLink}
|
||||
{isCollapsed}
|
||||
{notificationsCount}
|
||||
{trigger}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
<div>
|
||||
{#each menuLink.subItems as subItem (subItem.href ?? subItem.label)}
|
||||
<div class="py-1" role="none">
|
||||
{#if subItem?.['action']}
|
||||
<button
|
||||
class="text-secondary font-normal w-full block px-4 py-2 text-2xs data-[highlighted]:bg-surface-hover data-[highlighted]:text-primary"
|
||||
on:click={subItem?.['action']}
|
||||
use:melt={item}
|
||||
>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
{#if subItem.icon}
|
||||
<svelte:component this={subItem.icon} size={16} />
|
||||
{/if}
|
||||
|
||||
{subItem.label}
|
||||
{#if subItem?.['notificationCount']}
|
||||
<div class="ml-auto">
|
||||
<SideBarNotification
|
||||
notificationCount={subItem['notificationCount']}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</button>
|
||||
{:else}
|
||||
<a
|
||||
href={subItem.href}
|
||||
class="text-secondary font-normal block px-4 py-2 text-2xs data-[highlighted]:bg-surface-hover data-[highlighted]:text-primary"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
use:melt={item}
|
||||
>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
{#if subItem.icon}
|
||||
<svelte:component this={subItem.icon} size={16} />
|
||||
{/if}
|
||||
|
||||
{subItem.label}
|
||||
|
||||
{#if subItem?.['notificationCount']}
|
||||
<div class="ml-auto">
|
||||
<SideBarNotification
|
||||
notificationCount={subItem['notificationCount']}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</Menu>
|
||||
{:else}
|
||||
<div>
|
||||
<MenuSingleItem {createMenu} let:item>
|
||||
<svelte:fragment slot="trigger" let:trigger>
|
||||
<div class="w-full">
|
||||
<MenuButtonMelt
|
||||
class="!text-2xs"
|
||||
{...menuLink}
|
||||
{isCollapsed}
|
||||
{trigger}
|
||||
openHref={true}
|
||||
/>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<MenuLinkMelt class="!text-2xs" {...menuLink} {isCollapsed} {item} />
|
||||
</MenuSingleItem>
|
||||
</div>
|
||||
{#each menuLink.subItems as subItem (subItem.href ?? subItem.label)}
|
||||
<MenuItem>
|
||||
<div class="py-1" role="none">
|
||||
{#if subItem?.['action']}
|
||||
<button
|
||||
class="text-secondary font-normal w-full block px-4 py-2 text-2xs hover:bg-surface-hover hover:text-primary"
|
||||
on:click={subItem?.['action']}
|
||||
>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
{#if subItem.icon}
|
||||
<svelte:component this={subItem.icon} size={16} />
|
||||
{/if}
|
||||
|
||||
{subItem.label}
|
||||
{#if subItem?.['notificationCount']}
|
||||
<div class="ml-auto">
|
||||
<SideBarNotification notificationCount={subItem['notificationCount']} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</button>
|
||||
{:else}
|
||||
<a
|
||||
href={subItem.href}
|
||||
class="text-secondary font-normal block px-4 py-2 text-2xs hover:bg-surface-hover hover:text-primary"
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
{#if subItem.icon}
|
||||
<svelte:component this={subItem.icon} size={16} />
|
||||
{/if}
|
||||
|
||||
{subItem.label}
|
||||
|
||||
{#if subItem?.['notificationCount']}
|
||||
<div class="ml-auto">
|
||||
<SideBarNotification notificationCount={subItem['notificationCount']} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
</MenuItem>
|
||||
{/each}
|
||||
</Menu>
|
||||
{:else}
|
||||
<MenuLink class="!text-2xs" {...menuLink} {isCollapsed} />
|
||||
{/if}
|
||||
{/each}
|
||||
{/if}
|
||||
{/each}
|
||||
</Menubar>
|
||||
</div>
|
||||
<div class="space-y-0.5">
|
||||
{#each thirdMenuLinks as menuLink (menuLink)}
|
||||
{#if menuLink.subItems}
|
||||
<Menu>
|
||||
<div slot="trigger">
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="relative"
|
||||
on:click={() => {
|
||||
if (menuLink.label === 'Help') {
|
||||
openChangelogs()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<MenuButton class="!text-2xs" {...menuLink} {isCollapsed} />
|
||||
{#if menuLink.label === 'Help' && hasNewChangelogs}
|
||||
<span class="absolute top-1 right-1 flex h-2 w-2">
|
||||
<span
|
||||
class="animate-ping absolute inline-flex h-full w-full rounded-full bg-frost-400 opacity-75"
|
||||
/>
|
||||
<span class="relative inline-flex rounded-full h-2 w-2 bg-frost-500" />
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{#each menuLink.subItems as subItem (subItem.href ?? subItem.label)}
|
||||
<MenuItem>
|
||||
<Menubar let:createMenu>
|
||||
{#each thirdMenuLinks as menuLink (menuLink)}
|
||||
{#if menuLink.subItems}
|
||||
<Menu {createMenu} let:item>
|
||||
<svelte:fragment slot="trigger" let:trigger>
|
||||
<button
|
||||
class="relative w-full"
|
||||
on:click={() => {
|
||||
if (menuLink.label === 'Help') {
|
||||
openChangelogs()
|
||||
}
|
||||
}}
|
||||
>
|
||||
<MenuButtonMelt class="!text-2xs" {...menuLink} {isCollapsed} {trigger} />
|
||||
{#if menuLink.label === 'Help' && hasNewChangelogs}
|
||||
<span class="absolute top-1 right-1 flex h-2 w-2">
|
||||
<span
|
||||
class="animate-ping absolute inline-flex h-full w-full rounded-full bg-frost-400 opacity-75"
|
||||
/>
|
||||
<span class="relative inline-flex rounded-full h-2 w-2 bg-frost-500" />
|
||||
</span>
|
||||
{/if}
|
||||
</button>
|
||||
</svelte:fragment>
|
||||
{#each menuLink.subItems as subItem (subItem.href ?? subItem.label)}
|
||||
<div class="py-1" role="none">
|
||||
<a
|
||||
href={subItem.href}
|
||||
class="text-secondary block px-4 py-2 text-xs hover:bg-surface-hover hover:text-primary relative"
|
||||
class={twMerge(
|
||||
'text-secondary block px-4 py-2 text-xs hover:bg-surface-hover hover:text-primary relative',
|
||||
'data-[highlighted]:bg-surface-hover data-[highlighted]:text-primary'
|
||||
)}
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
target="_blank"
|
||||
use:melt={item}
|
||||
>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
{#if subItem.icon}
|
||||
@@ -466,13 +509,11 @@
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</MenuItem>
|
||||
{/each}
|
||||
{#if recentChangelogs.length > 0}
|
||||
<div class="w-full h-1 border-t" />
|
||||
<span class="text-xs px-4 font-bold"> Latest changelogs </span>
|
||||
{#each recentChangelogs as changelog}
|
||||
<MenuItem>
|
||||
{/each}
|
||||
{#if recentChangelogs.length > 0}
|
||||
<div class="w-full h-1 border-t" />
|
||||
<span class="text-xs px-4 font-bold"> Latest changelogs </span>
|
||||
{#each recentChangelogs as changelog}
|
||||
<div class="py-1" role="none">
|
||||
<a
|
||||
href={changelog.href}
|
||||
@@ -480,18 +521,19 @@
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
target="_blank"
|
||||
use:melt={item}
|
||||
>
|
||||
<div class="flex flex-row items-center gap-2">
|
||||
{changelog.label}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</MenuItem>
|
||||
{/each}
|
||||
{/if}
|
||||
</Menu>
|
||||
{/if}
|
||||
{/each}
|
||||
{/each}
|
||||
{/if}
|
||||
</Menu>
|
||||
{/if}
|
||||
{/each}
|
||||
</Menubar>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -8,30 +8,32 @@
|
||||
isPremiumStore,
|
||||
workspaceStore
|
||||
} from '$lib/stores'
|
||||
import Menu from '../common/menu/MenuV2.svelte'
|
||||
import { USER_SETTINGS_HASH } from './settings'
|
||||
import { isCloudHosted } from '$lib/cloud'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { Crown, HardHat, LogOut, Moon, Settings, Sun, User } from 'lucide-svelte'
|
||||
import DarkModeObserver from '../DarkModeObserver.svelte'
|
||||
import MenuButton from './MenuButton.svelte'
|
||||
import { MenuItem } from '@rgossiaux/svelte-headlessui'
|
||||
import MenuButtonMelt from './MenuButtonMelt.svelte'
|
||||
|
||||
import { melt } from '@melt-ui/svelte'
|
||||
import Menu from '$lib/components/meltComponents/Menu.svelte'
|
||||
let darkMode: boolean = false
|
||||
export let isCollapsed: boolean = false
|
||||
export let lightMode: boolean = false
|
||||
export let createMenu: (any) => any
|
||||
</script>
|
||||
|
||||
<Menu>
|
||||
<div slot="trigger" class="w-full">
|
||||
<MenuButton
|
||||
<Menu {createMenu} let:item>
|
||||
<svelte:fragment slot="trigger" let:trigger>
|
||||
<MenuButtonMelt
|
||||
class="!text-xs"
|
||||
icon={User}
|
||||
label={`User (${$userStore?.username ?? $userStore?.email})`}
|
||||
{isCollapsed}
|
||||
{lightMode}
|
||||
{trigger}
|
||||
/>
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<div class="divide-y z-20">
|
||||
<div class="px-4 py-3" role="none">
|
||||
<p class="text-sm font-medium text-primary truncate" role="none">
|
||||
@@ -47,17 +49,18 @@
|
||||
</div>
|
||||
|
||||
<div class="py-1" role="none">
|
||||
<MenuItem
|
||||
<a
|
||||
href={USER_SETTINGS_HASH}
|
||||
class={twMerge(
|
||||
'flex flex-row gap-2 items-center px-4 py-2 ',
|
||||
'text-secondary text-sm',
|
||||
'hover:bg-surface-hover hover:text-primary cursor-pointer'
|
||||
'data-[highlighted]:bg-surface-hover data-[highlighted]:text-primary'
|
||||
)}
|
||||
use:melt={item}
|
||||
>
|
||||
<Settings size={14} />
|
||||
Account settings
|
||||
</MenuItem>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="py-1" role="none">
|
||||
@@ -72,11 +75,13 @@
|
||||
}
|
||||
}}
|
||||
class={twMerge(
|
||||
'text-secondary block text-left px-4 py-2 font-normal text-sm hover:bg-surface-hover hover:text-primary w-full',
|
||||
'flex flex-row items-center gap-2'
|
||||
'text-secondary block text-left px-4 py-2 font-normal text-sm w-full',
|
||||
'flex flex-row items-center gap-2',
|
||||
'data-[highlighted]:bg-surface-hover data-[highlighted]:text-primary'
|
||||
)}
|
||||
role="menuitem"
|
||||
tabindex="-1"
|
||||
use:melt={item}
|
||||
>
|
||||
{#if darkMode}
|
||||
<Sun size={14} />
|
||||
@@ -88,18 +93,18 @@
|
||||
</div>
|
||||
|
||||
<div class="py-1" role="none">
|
||||
<MenuItem
|
||||
href="#"
|
||||
<button
|
||||
on:click={() => logout()}
|
||||
class={twMerge(
|
||||
'flex flex-row gap-2 items-center px-4 py-2 ',
|
||||
'flex flex-row gap-2 items-center px-4 py-2 w-full',
|
||||
'text-secondary text-sm',
|
||||
'hover:bg-surface-hover hover:text-primary cursor-pointer'
|
||||
'data-[highlighted]:bg-surface-hover data-[highlighted]:text-primary'
|
||||
)}
|
||||
use:melt={item}
|
||||
>
|
||||
<LogOut size={14} />
|
||||
Sign out
|
||||
</MenuItem>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{#if isCloudHosted()}
|
||||
|
||||
Reference in New Issue
Block a user