feat(frontend): Copy, Cut and Paste (#1279)

* feat(frontend): add copy, paste and cut

* feat(frontend): simplify code

* feat(frontend): add apple modifiers

---------

Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
This commit is contained in:
Faton Ramadani
2023-03-12 20:58:06 +01:00
committed by GitHub
parent 11421a55e1
commit d604a273ee
16 changed files with 254 additions and 263 deletions

View File

@@ -1,6 +1,7 @@
<script lang="ts">
import { Tab, Tabs } from '$lib/components/common'
import { getContext, onMount } from 'svelte'
import { initOutput } from '../../editor/appUtils'
import SubGridEditor from '../../editor/SubGridEditor.svelte'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
@@ -27,6 +28,12 @@
let noPadding: boolean | undefined = undefined
let tabHeight: number = 0
$: outputs = $worldStore
? initOutput($worldStore, id, {
selectedTabIndex: 0
})
: undefined
function handleTabSelection() {
const selectedIndex = tabs?.indexOf(selected)
outputs?.selectedTabIndex.set(selectedIndex, true)
@@ -76,10 +83,6 @@
$: selected && handleTabSelection()
$: outputs = $worldStore?.outputsById[id] as {
selectedTabIndex: Output<number>
}
$: selectedIndex = tabs?.indexOf(selected) ?? -1
$: css = concatCustomCss($app.css?.tabscomponent, customCss)
@@ -88,7 +91,7 @@
<InputValue {id} input={configuration.noPadding} bind:value={noPadding} />
<div>
<div bind:clientHeight={tabHeight} on:pointerdown|stopPropagation>
<div bind:clientHeight={tabHeight}>
<Tabs bind:selected class={css?.tabRow?.class} style={css?.tabRow?.style}>
{#each tabs ?? [] as res}
<Tab

View File

@@ -250,7 +250,7 @@
</div>
</Tab>
<div slot="content" class="h-full overflow-y-auto pb-4">
<TabContent class="overflow-auto" value="settings">
<TabContent class="overflow-auto h-full" value="settings">
{#if $selectedComponent !== undefined}
<SettingsPanel />
{:else}

View File

@@ -491,12 +491,12 @@
<ToggleButton position="left" value="dnd" size="xs">
<div class="inline-flex gap-1 items-center">
<Pencil size={14} />
<span class="hidden md:inline">Editor</span>
<span class="hidden lg:inline">Editor</span>
</div>
</ToggleButton>
<ToggleButton position="right" value="preview" size="xs">
<div class="inline-flex gap-1 items-center">
<Eye size={14} /> <span class="hidden md:inline">Preview</span>
<Eye size={14} /> <span class="hidden lg:inline">Preview</span>
</div>
</ToggleButton>
</ToggleButtonGroup>
@@ -530,19 +530,21 @@
</div>
</div>
{#if $focusedGrid !== undefined}
<Badge color="indigo">
<div class="flex flex-row gap-2 justify-center items-center">
<div>{`Sub grid: ${$focusedGrid.parentComponentId} (${$focusedGrid.subGridIndex})`}</div>
<button
on:click={() => {
$selectedComponent = undefined
$focusedGrid = undefined
}}
>
<X size={14} />
</button>
</div>
</Badge>
<div class="hidden lg:block">
<Badge color="indigo">
<div class="flex flex-row gap-2 justify-center items-center">
<div>{`Sub grid: ${$focusedGrid.parentComponentId} (${$focusedGrid.subGridIndex})`}</div>
<button
on:click={() => {
$selectedComponent = undefined
$focusedGrid = undefined
}}
>
<X size={14} />
</button>
</div>
</Badge>
</div>
{/if}
<div class="flex flex-row gap-2 justify-end items-center overflow-visible">
@@ -592,7 +594,7 @@
variant="border"
startIcon={{ icon: faBug }}
>
<span class="hidden md:inline">Debug Runs</span>
<span class="hidden xl:inline">Debug Runs</span>
</Button>
</span>
<AppExportButton bind:this={appExport} />
@@ -603,7 +605,7 @@
variant="border"
startIcon={{ icon: faExternalLink }}
>
<span class="hidden md:inline">Publish</span>
<span class="hidden xl:inline">Publish</span>
</Button>
{#if appPath == ''}
<Button

View File

@@ -41,13 +41,14 @@
{#if pointerdown || selected || hover}
<button
title="Position locking"
title="Lock Position"
class={classNames(
'text-gray-800 px-1 text-2xs py-0.5 font-bold w-fit shadow border border-gray-300 absolute -top-1 right-[2.5rem] z-50 cursor-pointer',
' hover:bg-gray-300',
selected ? 'bg-gray-200/80' : 'bg-gray-200/80'
)}
on:click={() => dispatch('lock')}
on:pointerdown|stopPropagation
>
{#if locked}
<Anchor aria-label="Unlock position" size={14} class="text-orange-500" />
@@ -63,6 +64,7 @@
selected ? 'bg-gray-200/80' : 'bg-gray-200/80'
)}
on:click={() => dispatch('expand')}
on:pointerdown|stopPropagation
>
<Expand aria-label="Expand position" size={14} />
</button>

View File

@@ -218,8 +218,9 @@
}}
on:expand={() => {
push(history, $app)
$selectedComponent = gridComponent.data.id
expandGriditem($app.grid, gridComponent, $breakpoint)
$app = { ...$app }
$app = $app
}}
/>
</div>

View File

@@ -136,11 +136,11 @@
if (!parentGridItem) {
return
}
$selectedComponent = gridComponent.data.id
push(history, $app)
expandGriditem(subGrid, gridComponent, $breakpoint, parentGridItem)
$app = { ...$app }
$app = $app
}}
/>
</div>

View File

@@ -4,6 +4,7 @@ import { getRecommendedDimensionsByComponent, type AppComponent } from './compon
import gridHelp from '@windmill-labs/svelte-grid/src/utils/helper'
import { gridColumns } from '../gridUtils'
import { allItems } from '../utils'
import type { Output, World } from '../rx'
function findGridItemById(
root: GridItem[],
@@ -18,7 +19,7 @@ function findGridItemById(
return undefined
}
export function findGridItemParentId(app: App, id: string): string | undefined {
export function findGridItemParentGrid(app: App, id: string): string | undefined {
const gridItem = app.grid.find((x) => x.id === id)
if (gridItem) {
return undefined
@@ -27,7 +28,7 @@ export function findGridItemParentId(app: App, id: string): string | undefined {
const subGrid = app.subgrids[key]
const gridItem = subGrid.find((x) => x.id === id)
if (gridItem) {
return key.split('-')[0]
return key
}
}
}
@@ -46,9 +47,6 @@ export function getNextGridItemId(app: App): string {
}
export function createNewGridItem(grid: GridItem[], id: string, data: AppComponent): GridItem {
const appComponent = data
appComponent.id = id
const newComponent = {
resizable: true,
@@ -57,7 +55,8 @@ export function createNewGridItem(grid: GridItem[], id: string, data: AppCompone
y: 0
}
let newData: AppComponent = JSON.parse(JSON.stringify(appComponent))
let newData: AppComponent = JSON.parse(JSON.stringify(data))
newData.id = id
const newItem: GridItem = {
data: newData,
@@ -65,7 +64,7 @@ export function createNewGridItem(grid: GridItem[], id: string, data: AppCompone
}
gridColumns.forEach((column) => {
const rec = getRecommendedDimensionsByComponent(appComponent.type, column)
const rec = getRecommendedDimensionsByComponent(newData.type, column)
newItem[column] = {
...newComponent,
@@ -84,6 +83,16 @@ export function createNewGridItem(grid: GridItem[], id: string, data: AppCompone
return newItem
}
export function getGridItems(app: App, focusedGrid: FocusedGrid | undefined): GridItem[] {
if (!focusedGrid) {
return app.grid
} else {
const { parentComponentId, subGridIndex } = focusedGrid
const key = `${parentComponentId}-${subGridIndex ?? 0}`
return app?.subgrids?.[key] ?? []
}
}
export function insertNewGridItem(
app: App,
data: AppComponent,
@@ -96,18 +105,7 @@ export function insertNewGridItem(
app.subgrids = {}
}
if (!focusedGrid) {
const newItem = createNewGridItem(app.grid, id, data)
app.grid.push(newItem)
} else {
const { parentComponentId, subGridIndex } = focusedGrid
const key = `${parentComponentId}-${subGridIndex ?? 0}`
const subGrid = app.subgrids[key] ?? []
subGrid.push(createNewGridItem(subGrid, id, data))
app.subgrids[key] = subGrid
}
// We only want to set subgrids when we are not moving
if (!keepId) {
for (let i = 0; i < (data.numberOfSubgrids ?? 0); i++) {
@@ -115,6 +113,16 @@ export function insertNewGridItem(
}
}
const key = focusedGrid ? `${focusedGrid?.parentComponentId}-${focusedGrid?.subGridIndex ?? 0}` : undefined
let grid = focusedGrid ? app.subgrids[key!] : app.grid
const newItem = createNewGridItem(grid, id, data)
grid.push(newItem)
if (focusedGrid) {
app.subgrids[key!] = grid
}
return id
}
@@ -169,27 +177,7 @@ export function deleteGridItem(
return components
}
export function duplicateGridItem(
app: App,
parent: string | undefined,
id: string
): string | undefined {
const gridItem = findGridItem(app, id)
if (gridItem) {
const newId = getNextGridItemId(app)
const newItem = JSON.parse(JSON.stringify(gridItem))
newItem.id = newId
newItem.data.id = newId
let focusedGrid = parent
? { parentComponentId: parent.split('-')[0], subGridIndex: Number(parent.split('-')[1]) }
: undefined
return insertNewGridItem(app, newItem.data, focusedGrid)
}
return undefined
}
type AvailableSpace = {
left: number
@@ -206,7 +194,7 @@ export function findAvailableSpace(
): AvailableSpace | undefined {
if (gridItem) {
const breakpoint = editorBreakpoint === 'sm' ? 3 : 12
const maxHeight = parentGridItem ? parentGridItem[breakpoint].h - 1 : 12
const maxHeight = parentGridItem ? parentGridItem[breakpoint].h - 1 : 16
const maxWidth = 12
const availableSpace = {
@@ -297,6 +285,22 @@ function isOverlapping(item1: any, item2: any) {
)
}
type Outputtable<Type> = {
-readonly [Property in keyof Type]: Output<Type[Property]>;
};
export function initOutput<I extends Record<string, any>>(world: World, id: string, init: I): Outputtable<I> {
const output = world.outputsById[id] as Outputtable<I>
if (init) {
for (const key in init) {
if (output && output[key] && output[key].peak() == undefined) {
output[key].set(init[key] as any)
}
}
}
return output
}
export function expandGriditem(
grid: GridItem[],
gridComponent: GridItem,
@@ -305,16 +309,17 @@ export function expandGriditem(
) {
const availableSpace = findAvailableSpace(grid, gridComponent, $breakpoint, parentGridItem)
console.log(availableSpace)
if (!availableSpace) {
return
}
const { left, right, top, bottom } = availableSpace
const width = $breakpoint === 'sm' ? 3 : 12
const previousGridItem = JSON.parse(JSON.stringify(gridComponent[width]))
const item = gridComponent[width]
gridComponent[width].x = previousGridItem.x - left
gridComponent[width].y = previousGridItem.y - top
gridComponent[width].w = previousGridItem.w + left + right
gridComponent[width].h = previousGridItem.h + top + bottom
item.x = item.x - left
item.y = item.y - top
item.w = item.w + left + right
item.h = item.h + top + bottom
}

View File

@@ -1,23 +1,35 @@
<script lang="ts">
import { getContext } from 'svelte'
import {
deleteGridItem,
findGridItem,
findGridItemParentGrid,
getAllSubgridsAndComponentIds,
getGridItems,
insertNewGridItem
} from '../appUtils'
import type { AppEditorContext, AppViewerContext, EditorBreakpoint, GridItem } from '../../types'
import { findGridItemParentId } from '../appUtils'
import { push } from '$lib/history'
import { sendUserToast } from '$lib/utils'
const { app, selectedComponent, breakpoint, focusedGrid } =
getContext<AppViewerContext>('AppViewerContext')
const { componentControl } = getContext<AppEditorContext>('AppEditorContext')
const { componentControl, history } = getContext<AppEditorContext>('AppEditorContext')
let tempGridItem: GridItem | undefined = undefined
let copiedGridItem: GridItem | undefined = undefined
function getSortedGridItemsOfChildren(): GridItem[] {
if (!$focusedGrid) {
return sortGridItems($app.grid, $breakpoint)
return sortGridItemsPosition($app.grid, $breakpoint)
}
if (!$app.subgrids) {
return []
}
return sortGridItems(
return sortGridItemsPosition(
$app.subgrids[`${$focusedGrid.parentComponentId}-${$focusedGrid.subGridIndex}`],
$breakpoint
)
@@ -25,14 +37,14 @@
function getSortedGridItemsOfGrid(): GridItem[] {
if ($app.grid.find((item) => item.id === $selectedComponent)) {
return sortGridItems($app.grid, $breakpoint)
return sortGridItemsPosition($app.grid, $breakpoint)
}
if (!$app.subgrids) {
return []
}
return sortGridItems(
return sortGridItemsPosition(
Object.values($app.subgrids ?? {}).find((grid) =>
grid.find((item) => item.id === $selectedComponent)
) ?? [],
@@ -79,7 +91,7 @@
return
}
const sortedGridItems = sortGridItems(subgrid, $breakpoint)
const sortedGridItems = sortGridItemsPosition(subgrid, $breakpoint)
if (sortedGridItems) {
$selectedComponent = sortedGridItems[0].id
@@ -88,23 +100,88 @@
}
}
function handleEscape(event: KeyboardEvent) {
$selectedComponent = undefined
$focusedGrid = undefined
event.preventDefault()
}
function handleArrowUp(event: KeyboardEvent) {
if (!$selectedComponent) return
let parentId = findGridItemParentGrid($app, $selectedComponent)?.split('-')[0]
if (parentId) {
$selectedComponent = parentId
} else {
$selectedComponent = undefined
$focusedGrid = undefined
}
}
function handleCopy(event: KeyboardEvent) {
if (!$selectedComponent) {
return
}
tempGridItem = undefined
copiedGridItem = findGridItem($app, $selectedComponent)
}
function handleCut(event: KeyboardEvent) {
if (!$selectedComponent) {
return
}
push(history, $app)
const gridItem = findGridItem($app, $selectedComponent)
copiedGridItem = gridItem
if (!gridItem) {
return
}
// Store the grid item in a temp variable so we can paste it later
tempGridItem = gridItem
}
function handlePaste(event: KeyboardEvent) {
push(history, $app)
if (tempGridItem) {
if (
$focusedGrid &&
getAllSubgridsAndComponentIds($app, tempGridItem.data)[0].includes(
`${$focusedGrid.parentComponentId}-${$focusedGrid.subGridIndex}`
)
) {
sendUserToast('Cannot paste a component into itself', true)
return
}
let parentGrid = findGridItemParentGrid($app, tempGridItem.data.id)
const grid = parentGrid ? $app.subgrids![parentGrid] : $app.grid
let idx = grid.findIndex((item) => {
return item.id == tempGridItem!.data.id
})
if (idx > -1) {
grid.splice(idx, 1)
}
insertNewGridItem($app, tempGridItem.data, $focusedGrid, true)
copiedGridItem = tempGridItem
tempGridItem = undefined
} else if (copiedGridItem) {
insertNewGridItem($app, copiedGridItem.data, $focusedGrid, false)
}
$app = $app
}
function keydown(event: KeyboardEvent) {
switch (event.key) {
case 'Escape':
$selectedComponent = undefined
event.preventDefault()
handleEscape(event)
break
case 'ArrowUp': {
if (!$selectedComponent) return
let parentId = findGridItemParentId($app, $selectedComponent)
if (parentId) {
$selectedComponent = parentId
} else {
$selectedComponent = undefined
$focusedGrid = undefined
}
break
handleArrowUp(event)
}
case 'ArrowDown': {
@@ -122,12 +199,30 @@
break
}
case 'c':
if (event.ctrlKey || event.metaKey) {
handleCopy(event)
}
break
case 'v':
if (event.ctrlKey || event.metaKey) {
handlePaste(event)
}
break
case 'x':
if (event.ctrlKey || event.metaKey) {
handleCut(event)
}
break
default:
break
}
}
function sortGridItems(gridItems: GridItem[], breakpoint: EditorBreakpoint): GridItem[] {
function sortGridItemsPosition(gridItems: GridItem[], breakpoint: EditorBreakpoint): GridItem[] {
return gridItems.sort((a: GridItem, b: GridItem) => {
const width = breakpoint === 'lg' ? 12 : 3

View File

@@ -8,7 +8,6 @@
import { inferArgs } from '$lib/infer'
import type { Schema } from '$lib/common'
import Badge from '$lib/components/common/badge/Badge.svelte'
import { fly } from 'svelte/transition'
import Editor from '$lib/components/Editor.svelte'
import { emptySchema, scriptLangToEditorLang } from '$lib/utils'
import Popover from '../../../Popover.svelte'

View File

@@ -19,14 +19,12 @@
import TemplateEditor from '$lib/components/TemplateEditor.svelte'
import type { AppComponent } from '../component'
import CssProperty from '../componentsPanel/CssProperty.svelte'
import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore'
import GridTab from './GridTab.svelte'
import { duplicateGridItem } from '../appUtils'
import { deleteGridItem } from '../appUtils'
import MoveToOtherGrid from './MoveToOtherGrid.svelte'
import GridPane from './GridPane.svelte'
import { slide } from 'svelte/transition'
import { push } from '$lib/history'
import Kbd from '$lib/components/common/kbd/Kbd.svelte'
export let component: AppComponent
export let rowColumns = false
@@ -47,13 +45,6 @@
const { history } = getContext<AppEditorContext>('AppEditorContext')
function duplicateElement(id: string) {
push(history, $app)
$dirtyStore = true
const newId = duplicateGridItem($app, parent, id)
$selectedComponent = newId
}
function removeGridElement() {
push(history, $app)
$selectedComponent = undefined
@@ -96,7 +87,7 @@
<svelte:window on:keydown={keydown} />
{#if component}
<div class="flex flex-col min-w-[150px] w-full divide-y">
<div class="flex min-h-full flex-col min-w-[150px] w-full divide-y">
{#if component.componentInput}
<PanelSection
smallPadding
@@ -195,6 +186,8 @@
<Recompute bind:recomputeIds={component.recomputeIds} ownId={component.id} />
{/if}
<div class="grow shrink" />
{#if Object.keys(component.customCss ?? {}).length > 0}
<PanelSection title="Custom CSS">
<div slot="action">
@@ -222,8 +215,20 @@
{/if}
{#if duplicateMoveAllowed}
<PanelSection title="Duplicate">
<Button
<PanelSection title="Copy/Move">
<div slot="action">
<Button size="xs" color="red" variant="border" on:click={removeGridElement}>
Delete&nbsp;&nbsp;
<Kbd>Del</Kbd>
</Button>
</div>
<div class="flex flex-col">
<div
><span class="text-gray-600 text-xs mr-2">Copy:</span><Kbd>CTRL+C</Kbd> + <Kbd
>CTRL+V</Kbd
></div
>
<!-- <Button
size="xs"
color="dark"
startIcon={{ icon: faCopy }}
@@ -234,24 +239,19 @@
}}
>
Duplicate component: {component.id}
</Button>
</PanelSection>
<PanelSection title="Move to other grid">
<MoveToOtherGrid bind:component {parent} />
</Button> -->
<div
><span class="text-gray-600 text-xs mr-2">Move:</span><Kbd>CTRL+X</Kbd> + <Kbd
>CTRL+V</Kbd
></div
>
<div
><span class="text-gray-600 text-xs mr-2">Navigate:</span><Kbd>&leftarrow;</Kbd><Kbd
>&uparrow;</Kbd
><Kbd>&rightarrow;</Kbd><Kbd>ESC</Kbd></div
>
</div>
</PanelSection>
{/if}
<PanelSection title="Danger zone">
<Button
size="xs"
color="red"
variant="border"
startIcon={{ icon: faTrashAlt }}
on:click={removeGridElement}
>
Delete component: {component.id}
</Button>
</PanelSection>
</div>
{/if}

View File

@@ -1,6 +1,8 @@
<script lang="ts">
import Button from '$lib/components/common/button/Button.svelte'
import CloseButton from '$lib/components/common/CloseButton.svelte'
import { faPlus, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
import { CrossIcon } from 'lucide-svelte'
import { getContext } from 'svelte'
import type { AppViewerContext } from '../../types'
import { deleteGridItem } from '../appUtils'
@@ -56,18 +58,8 @@
<div class="w-full flex flex-row gap-2 items-center relative">
<input on:keydown|stopPropagation type="text" bind:value />
<div class="absolute top-1 right-1">
<Button
size="xs"
color="light"
variant="border"
on:click={() => {
deleteSubgrid(index)
}}
iconOnly
btnClasses="!text-red-500"
startIcon={{ icon: faTrashAlt }}
/>
<div class="absolute right-1">
<CloseButton noBg on:close={() => deleteSubgrid(index)} />
</div>
</div>
{/each}

View File

@@ -1,123 +0,0 @@
<script lang="ts">
import { Button } from '$lib/components/common'
import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore'
import { push } from '$lib/history'
import { faCopy } from '@fortawesome/free-solid-svg-icons'
import { getContext } from 'svelte'
import type { App, AppEditorContext, AppViewerContext } from '../../types'
import {
createNewGridItem,
deleteGridItem,
findGridItem,
getAllSubgridsAndComponentIds,
insertNewGridItem
} from '../appUtils'
import type { AppComponent } from '../component'
export let component: AppComponent | undefined
export let parent: string | undefined
let selectedOption: string
const { app } = getContext<AppViewerContext>('AppViewerContext')
const { history } = getContext<AppEditorContext>('AppEditorContext')
function listAllSubGrids(app: App) {
return app.subgrids ? Object.keys(app.subgrids) : []
}
function findAndDelete(id: string) {
const node = findGridItem($app, id)
if (!node) {
return
}
const data: AppComponent = JSON.parse(JSON.stringify(node.data))
const shouldKeepSubGrid = data.numberOfSubgrids ? data.numberOfSubgrids >= 1 : false
$dirtyStore = true
deleteGridItem($app, data, parent, shouldKeepSubGrid)
return data
}
function insertComponentInSubGrid(
data: AppComponent,
targetId: string,
targetSubGridIndex: number
) {
push(history, $app)
const focusedGrid = {
parentComponentId: targetId,
subGridIndex: targetSubGridIndex
}
insertNewGridItem($app, data, focusedGrid, true)
$app.grid = [...$app.grid]
}
function insertComponentInMainGrid(data: AppComponent) {
const newComponent = createNewGridItem($app.grid, data.id, data)
$app.grid = [...$app.grid, newComponent]
}
function onMove(component: AppComponent) {
push(history, $app)
const data = findAndDelete(component.id)
if (!data) {
return
}
if (selectedOption !== 'main-grid') {
const [targetId, targetSubGridIndex] = selectedOption.split('-')
insertComponentInSubGrid(data, targetId, parseInt(targetSubGridIndex))
} else {
insertComponentInMainGrid(data)
}
}
const defaultOption = {
label: 'Main grid',
value: 'main-grid',
disabled: parent === undefined
}
$: [subgrids] = component ? getAllSubgridsAndComponentIds($app, component) : [[], []]
$: availableGrids = listAllSubGrids($app)
$: options = availableGrids
? [
defaultOption,
...availableGrids?.map((grid) => ({
label: grid,
value: grid,
disabled: grid === parent || subgrids.includes(grid)
}))
]
: [defaultOption]
</script>
{#if component && !options.every((option) => option.disabled)}
<select bind:value={selectedOption} class="w-full">
{#each options as option}
<option value={option.value} disabled={option.disabled}>{option.label}</option>
{/each}
</select>
<Button
size="xs"
color="dark"
startIcon={{ icon: faCopy }}
on:click={() => {
if (component) {
onMove(component)
}
}}
>
Move component: {component.id}
</Button>
{:else}
<p class="text-gray-500 text-sm">No grids available</p>
{/if}

View File

@@ -0,0 +1,18 @@
<script>
import { faClose } from '@fortawesome/free-solid-svg-icons'
import { createEventDispatcher } from 'svelte'
import { Icon } from 'svelte-awesome'
export let noBg = false
const dispatch = createEventDispatcher()
</script>
<button
on:click={() => dispatch('close')}
class="hover:bg-gray-200 {noBg
? ''
: 'bg-gray-100'} rounded-full w-8 h-8 flex items-center justify-center transition-all"
>
<Icon data={faClose} class="text-gray-500" />
</button>

View File

@@ -3,6 +3,7 @@
import { faClose } from '@fortawesome/free-solid-svg-icons'
import { createEventDispatcher } from 'svelte'
import { Icon } from 'svelte-awesome'
import CloseButton from '../CloseButton.svelte'
export let title: string | undefined = undefined
export let overflow_y = true
@@ -15,12 +16,7 @@
<div class="flex flex-col divide-y h-screen max-h-screen">
<div class="flex justify-between w-wull items-center px-2 py-2 ">
<div class="flex items-center gap-2">
<button
on:click={() => dispatch('close')}
class="hover:bg-gray-200 bg-gray-100 rounded-full w-8 h-8 flex items-center justify-center transition-all"
>
<Icon data={faClose} class="text-gray-500" />
</button>
<CloseButton on:close />
<span class="font-semibold truncate text-gray-800">{title}</span>
</div>

View File

@@ -35,6 +35,7 @@
)}
style={`${style} ${$selected?.startsWith(value) ? selectedStyle : ''}`}
on:click={() => update(value)}
on:pointerdown|stopPropagation
>
<slot />
</div>

View File

@@ -341,7 +341,7 @@
undefined,
1000,
loopDepth,
0,
modules.findIndex((m) => m.id == module.id) + 1,
true,
undefined,
module.id