Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(frontend) migrate menu to melt menu #5208

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
35 changes: 21 additions & 14 deletions frontend/src/lib/components/DropdownV2.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<script lang="ts">
import { MoreVertical } from 'lucide-svelte'
import Menu from './common/menu/MenuV2.svelte'
import { Menu, Menubar } from '$lib/components/meltComponents'
import { melt } from '@melt-ui/svelte'
import type { Placement } from '@floating-ui/core'

import DropdownV2Inner from './DropdownV2Inner.svelte'

Expand All @@ -17,6 +19,7 @@
export let items: Item[] | (() => Item[]) | (() => Promise<Item[]>) = []
export let justifyEnd: boolean = true
export let disabled = false
export let placement: Placement = 'bottom-end'

async function computeItems(): Promise<Item[]> {
if (typeof items === 'function') {
Expand All @@ -27,17 +30,21 @@
}
</script>

<Menu placement="bottom-end" {justifyEnd} on:close on:open {disabled}>
<div slot="trigger">
{#if $$slots.buttonReplacement}
<slot name="buttonReplacement" />
{:else}
<MoreVertical
size={16}
class="w-8 h-8 p-2 hover:bg-surface-hover cursor-pointer rounded-md"
/>
{/if}
</div>
<Menubar let:createMenu>
<Menu {createMenu} {placement} {justifyEnd} on:close on:open {disabled} let:item>
<svelte:fragment slot="trigger" let:trigger>
<div use:melt={trigger}>
{#if $$slots.buttonReplacement}
<slot name="buttonReplacement" />
{:else}
<MoreVertical
size={16}
class="w-8 h-8 p-2 hover:bg-surface-hover cursor-pointer rounded-md"
/>
{/if}
</div>
</svelte:fragment>

<DropdownV2Inner items={computeItems} />
</Menu>
<DropdownV2Inner items={computeItems} meltItem={item} />
</Menu>
</Menubar>
11 changes: 7 additions & 4 deletions frontend/src/lib/components/DropdownV2Inner.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import { MenuItem } from '@rgossiaux/svelte-headlessui'
import { MenuItem } from '$lib/components/meltComponents'
import { Loader2 } from 'lucide-svelte'
import { twMerge } from 'tailwind-merge'

Expand All @@ -14,6 +14,7 @@
}

export let items: Item[] | (() => Item[]) | (() => Promise<Item[]>) = []
export let meltItem: any

let computedItems: Item[] | undefined = undefined
async function computeItems() {
Expand All @@ -31,17 +32,19 @@
<div class="flex flex-col">
{#each computedItems ?? [] as item}
<MenuItem
on:click={(e) => item?.action?.(e)}
on:click={(e) => item?.action?.(e.detail)}
href={item?.href}
disabled={item?.disabled}
class={twMerge(
'px-4 py-2 text-primary hover:bg-surface-hover hover:text-primary cursor-pointer text-xs transition-all',
'px-4 py-2 text-primary font-normal hover:bg-surface-hover cursor-pointer text-xs transition-all',
'data-[highlighted]:bg-surface-hover',
'flex flex-row gap-2 items-center',
item?.disabled && 'text-gray-400 cursor-not-allowed',
item?.type === 'delete' &&
!item?.disabled &&
'text-red-500 hover:bg-red-100 hover:text-red-500'
'text-red-500 hover:bg-red-100 hover:text-red-500 data-[highlighted]:text-red-500 data-[highlighted]:bg-red-100'
)}
item={meltItem}
>
{#if item.icon}
<svelte:component this={item.icon} size={14} />
Expand Down
144 changes: 78 additions & 66 deletions frontend/src/lib/components/apps/components/display/AppMenu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
import { Button } from '$lib/components/common'
import { loadIcon } from '../icon'
import ResolveStyle from '../helpers/ResolveStyle.svelte'
import Menu from '$lib/components/common/menu/MenuV2.svelte'
import { AppButton } from '../buttons'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import { Menubar, Menu } from '$lib/components/meltComponents'
import { melt } from '@melt-ui/svelte'

export let id: string
export let configuration: RichConfigurations
Expand Down Expand Up @@ -96,71 +97,82 @@

{#if render}
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
<Menu placement="bottom-end" justifyEnd={false} on:close on:open>
<div slot="trigger">
<Button
on:pointerdown={(e) => e.stopPropagation()}
btnClasses={twMerge(
css?.button?.class,
'wm-button',
'wm-menu-button',
resolvedConfig.fillContainer ? 'w-full h-full' : ''
)}
wrapperClasses={twMerge(
'wm-button-container',
'wm-menu-button-container',
resolvedConfig.fillContainer ? 'w-full h-full' : ''
)}
style={css?.button?.style}
size={resolvedConfig.size}
color={resolvedConfig.color}
nonCaptureEvent
>
<span class="truncate inline-flex gap-2 items-center">
{#if resolvedConfig.beforeIcon}
{#key resolvedConfig.beforeIcon}
<div class="min-w-4" bind:this={beforeIconComponent} />
{/key}
{/if}
{#if resolvedConfig.label && resolvedConfig.label?.length > 0}
<div>{resolvedConfig.label}</div>
{/if}
{#if resolvedConfig.afterIcon}
{#key resolvedConfig.afterIcon}
<div class="min-w-4" bind:this={afterIconComponent} />
{/key}
{/if}
</span>
</Button>
</div>
<Menubar let:createMenu class={resolvedConfig.fillContainer ? 'w-full h-full' : ''}>
<Menu
{createMenu}
placement="bottom-end"
justifyEnd={false}
on:close
on:open
class={resolvedConfig.fillContainer ? 'w-full h-full' : ''}
>
<svelte:fragment slot="trigger" let:trigger>
<div use:melt={trigger} class="w-full h-full">
<Button
on:pointerdown={(e) => e.stopPropagation()}
btnClasses={twMerge(
css?.button?.class,
'wm-button',
'wm-menu-button',
resolvedConfig.fillContainer ? 'w-full h-full' : ''
)}
wrapperClasses={twMerge(
'wm-button-container',
'wm-menu-button-container',
resolvedConfig.fillContainer ? 'w-full h-full' : ''
)}
style={css?.button?.style}
size={resolvedConfig.size}
color={resolvedConfig.color}
nonCaptureEvent
>
<span class="truncate inline-flex gap-2 items-center">
{#if resolvedConfig.beforeIcon}
{#key resolvedConfig.beforeIcon}
<div class="min-w-4" bind:this={beforeIconComponent} />
{/key}
{/if}
{#if resolvedConfig.label && resolvedConfig.label?.length > 0}
<div>{resolvedConfig.label}</div>
{/if}
{#if resolvedConfig.afterIcon}
{#key resolvedConfig.afterIcon}
<div class="min-w-4" bind:this={afterIconComponent} />
{/key}
{/if}
</span>
</Button>
</div>
</svelte:fragment>

<div class="flex flex-col w-full p-1 gap-2">
{#if menuItems.length > 0}
{#each menuItems as actionButton, actionIndex (actionButton?.id)}
{#if actionButton.type == 'buttoncomponent'}
<div
on:pointerup={() => {
outputs?.result.set({
latestButtonClicked: actionButton.id
})
}}
>
<AppButton
extraKey={'idx' + actionIndex}
{render}
id={actionButton.id}
customCss={actionButton.customCss}
configuration={actionButton.configuration}
recomputeIds={actionButton.recomputeIds}
componentInput={actionButton.componentInput}
noWFull={false}
isMenuItem={true}
/>
</div>
{/if}
{/each}
{/if}
</div>
</Menu>
<div class="flex flex-col w-full p-1 gap-2">
{#if menuItems.length > 0}
{#each menuItems as actionButton, actionIndex (actionButton?.id)}
{#if actionButton.type == 'buttoncomponent'}
<div
on:pointerup={() => {
outputs?.result.set({
latestButtonClicked: actionButton.id
})
}}
>
<AppButton
extraKey={'idx' + actionIndex}
{render}
id={actionButton.id}
customCss={actionButton.customCss}
configuration={actionButton.configuration}
recomputeIds={actionButton.recomputeIds}
componentInput={actionButton.componentInput}
noWFull={false}
isMenuItem={true}
/>
</div>
{/if}
{/each}
{/if}
</div>
</Menu>
</Menubar>
</AlignWrapper>
{/if}
54 changes: 0 additions & 54 deletions frontend/src/lib/components/common/menu/MenuV2.svelte

This file was deleted.

39 changes: 12 additions & 27 deletions frontend/src/lib/components/details/DetailPageHeader.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
<script lang="ts">
import { Badge, Button } from '$lib/components/common'

import Menu from '$lib/components/details/Menu.svelte'
import MenuItem from '$lib/components/common/menu/MenuItem.svelte'
import { classNames } from '$lib/utils'
import DropdownV2 from '$lib/components/DropdownV2.svelte'
import ErrorHandlerToggleButton from './ErrorHandlerToggleButton.svelte'
import { twMerge } from 'tailwind-merge'
import { userStore } from '$lib/stores'
Expand Down Expand Up @@ -73,30 +71,17 @@
</div>
<div class="flex gap-1 md:gap-2 items-center">
{#if menuItems.length > 0}
<Menu>
<svelte:fragment slot="items">
{#each menuItems as { label, Icon, onclick, color } (label)}
<MenuItem
on:click={() => {
const div = document.querySelector('[id^="headlessui-menu-items"]')
div?.parentElement?.remove()

onclick()
}}
>
<div
class={classNames(
'text-xs flex items-center gap-2 flex-row-2 ',
color === 'red' ? 'text-red-500' : ''
)}
>
<Icon class="h-4" />
{label}
</div>
</MenuItem>
{/each}
</svelte:fragment>
</Menu>
{#key menuItems}
<DropdownV2
items={menuItems.map((item) => ({
displayName: item.label,
icon: item.Icon,
action: item.onclick,
type: item.color === 'red' ? 'delete' : 'action'
}))}
placement="bottom-end"
/>
{/key}
{/if}
<ErrorHandlerToggleButton
kind={errorHandlerKind}
Expand Down
Loading