mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-18 16:02:10 +00:00
feat(frontend): Deeply nested Modals and Drawers (#3565)
* fix(frontend): Support deeply nested drawers and modals * fix(frontend): Support deeply nested drawers and modals * fix(frontend): Support deeply nested drawers and modals * feat(frontend): fix name * chore(main): release 1.308.2 (#3569) * chore(main): release 1.308.2 * Apply automatic changes --------- Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com> * feat(frontend): wip * feat(frontend): wip * fix(frontend): fix event propagation * fix(frontend): fix drawers globally * feat(frontend): Fix all drawers * feat(frontend): split zIndexes in a new file --------- Co-authored-by: Ruben Fiszel <ruben@windmill.dev> Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
This commit is contained in:
+278
-410
File diff suppressed because it is too large
Load Diff
@@ -5554,7 +5554,6 @@ paths:
|
||||
text/plain:
|
||||
type: string
|
||||
|
||||
|
||||
/w/{workspace}/jobs_u/get_flow_debug_info/{id}:
|
||||
get:
|
||||
summary: get flow debug info
|
||||
@@ -8764,14 +8763,14 @@ components:
|
||||
|
||||
Job:
|
||||
oneOf:
|
||||
- allOf:
|
||||
- allOf:
|
||||
- $ref: "#/components/schemas/CompletedJob"
|
||||
- type: object
|
||||
properties:
|
||||
type:
|
||||
type: string
|
||||
enum: [CompletedJob]
|
||||
- allOf:
|
||||
- allOf:
|
||||
- $ref: "#/components/schemas/QueuedJob"
|
||||
- type: object
|
||||
properties:
|
||||
@@ -9941,7 +9940,7 @@ components:
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
value:
|
||||
value:
|
||||
type: object
|
||||
policy:
|
||||
$ref: "#/components/schemas/Policy"
|
||||
|
||||
@@ -5,19 +5,16 @@
|
||||
import Drawer from './common/drawer/Drawer.svelte'
|
||||
import DrawerContent from './common/drawer/DrawerContent.svelte'
|
||||
import DefaultScriptsInner from './DefaultScriptsInner.svelte'
|
||||
import Portal from 'svelte-portal'
|
||||
|
||||
let drawer: Drawer
|
||||
</script>
|
||||
|
||||
{#if $userStore?.is_admin || $userStore?.is_super_admin}
|
||||
<Portal>
|
||||
<Drawer bind:this={drawer} placement="left">
|
||||
<DrawerContent title="Edit Default Scripts" on:close={drawer.closeDrawer}>
|
||||
<DefaultScriptsInner />
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</Portal>
|
||||
<Drawer bind:this={drawer} placement="left">
|
||||
<DrawerContent title="Edit Default Scripts" on:close={drawer.closeDrawer}>
|
||||
<DefaultScriptsInner />
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
<Button
|
||||
on:click={drawer?.openDrawer}
|
||||
startIcon={{ icon: SettingsIcon }}
|
||||
|
||||
@@ -588,46 +588,44 @@
|
||||
</div>
|
||||
|
||||
{#if !disableExpand && !noControls}
|
||||
<Portal>
|
||||
<Drawer bind:this={jsonViewer} size="900px">
|
||||
<DrawerContent title="Expanded Result" on:close={jsonViewer.closeDrawer}>
|
||||
<svelte:fragment slot="actions">
|
||||
<Button
|
||||
download="{filename ?? 'result'}.json"
|
||||
href={workspaceId && jobId
|
||||
? `/api/w/${workspaceId}/jobs_u/completed/get_result/${jobId}`
|
||||
: `data:text/json;charset=utf-8,${encodeURIComponent(toJsonStr(result))}`}
|
||||
startIcon={{ icon: Download }}
|
||||
color="light"
|
||||
size="xs"
|
||||
>
|
||||
Download
|
||||
</Button>
|
||||
<Button
|
||||
on:click={() => copyToClipboard(toJsonStr(result))}
|
||||
color="light"
|
||||
size="xs"
|
||||
startIcon={{
|
||||
icon: ClipboardCopy
|
||||
}}
|
||||
>
|
||||
Copy to clipboard
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
<svelte:self
|
||||
{noControls}
|
||||
{result}
|
||||
{requireHtmlApproval}
|
||||
{filename}
|
||||
{jobId}
|
||||
{workspaceId}
|
||||
{hideAsJson}
|
||||
{forceJson}
|
||||
disableExpand={true}
|
||||
/>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</Portal>
|
||||
<Drawer bind:this={jsonViewer} size="900px">
|
||||
<DrawerContent title="Expanded Result" on:close={jsonViewer.closeDrawer}>
|
||||
<svelte:fragment slot="actions">
|
||||
<Button
|
||||
download="{filename ?? 'result'}.json"
|
||||
href={workspaceId && jobId
|
||||
? `/api/w/${workspaceId}/jobs_u/completed/get_result/${jobId}`
|
||||
: `data:text/json;charset=utf-8,${encodeURIComponent(toJsonStr(result))}`}
|
||||
startIcon={{ icon: Download }}
|
||||
color="light"
|
||||
size="xs"
|
||||
>
|
||||
Download
|
||||
</Button>
|
||||
<Button
|
||||
on:click={() => copyToClipboard(toJsonStr(result))}
|
||||
color="light"
|
||||
size="xs"
|
||||
startIcon={{
|
||||
icon: ClipboardCopy
|
||||
}}
|
||||
>
|
||||
Copy to clipboard
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
<svelte:self
|
||||
{noControls}
|
||||
{result}
|
||||
{requireHtmlApproval}
|
||||
{filename}
|
||||
{jobId}
|
||||
{workspaceId}
|
||||
{hideAsJson}
|
||||
{forceJson}
|
||||
disableExpand={true}
|
||||
/>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
<Portal>
|
||||
<S3FilePicker bind:this={s3FileViewer} readOnlyMode={true} />
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
size="800px"
|
||||
alwaysOpen
|
||||
positionClass={$mode == 'dnd' ? '!absolute' : '!fixed'}
|
||||
shouldUsePortal={false}
|
||||
>
|
||||
<DrawerContent
|
||||
title={resolvedConfig.drawerTitle}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import { components } from '../../editor/component'
|
||||
import ResolveConfig from '../helpers/ResolveConfig.svelte'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
import Disposable from '$lib/components/common/drawer/Disposable.svelte'
|
||||
|
||||
export let customCss: ComponentCustomCSS<'modalcomponent'> | undefined = undefined
|
||||
export let id: string
|
||||
@@ -37,22 +38,7 @@
|
||||
initOutput($worldStore, id, {})
|
||||
|
||||
let css = initCss($app.css?.modalcomponent, customCss)
|
||||
let open = false
|
||||
|
||||
function handleKeyUp(event: KeyboardEvent): void {
|
||||
const key = event.key
|
||||
if (key === 'Escape' || key === 'Esc') {
|
||||
if (open) {
|
||||
event.preventDefault()
|
||||
closeDrawer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function closeDrawer(): void {
|
||||
console.log('Close drawer')
|
||||
open = false
|
||||
}
|
||||
let disposable: Disposable | undefined = undefined
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['modalcomponent'].initialData.configuration,
|
||||
@@ -69,23 +55,22 @@
|
||||
$componentControl[id] = {
|
||||
openModal: () => {
|
||||
unclosableModal()
|
||||
open = true
|
||||
|
||||
disposable?.openDrawer()
|
||||
},
|
||||
closeModal: () => {
|
||||
open = false
|
||||
disposable?.closeDrawer()
|
||||
},
|
||||
open: () => {
|
||||
unclosableModal()
|
||||
open = true
|
||||
disposable?.openDrawer()
|
||||
},
|
||||
close: () => {
|
||||
open = false
|
||||
disposable?.closeDrawer()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keyup={handleKeyUp} />
|
||||
|
||||
<InitializeComponent {id} />
|
||||
|
||||
{#each Object.keys(components['modalcomponent'].initialData.configuration) as key (key)}
|
||||
@@ -132,7 +117,7 @@
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
}
|
||||
open = true
|
||||
disposable?.toggleDrawer()
|
||||
}}
|
||||
size={resolvedConfig.buttonSize}
|
||||
color={resolvedConfig.buttonColor}
|
||||
@@ -144,69 +129,71 @@
|
||||
{/if}
|
||||
|
||||
<Portal target="#app-editor-top-level-drawer">
|
||||
<div
|
||||
class={twMerge(
|
||||
`${
|
||||
$mode == 'dnd' ? 'absolute' : 'fixed'
|
||||
} top-0 bottom-0 left-0 right-0 transition-all duration-50`,
|
||||
open ? ' bg-black bg-opacity-60' : 'h-0 overflow-hidden invisible',
|
||||
$mode === 'dnd' ? 'z-[1000]' : 'z-[1100]'
|
||||
)}
|
||||
>
|
||||
<Disposable {id} let:handleClickAway let:zIndex let:open bind:this={disposable}>
|
||||
<div
|
||||
style={css?.popup?.style}
|
||||
class={twMerge('mx-24 mt-8 bg-surface rounded-lg relative', css?.popup?.class)}
|
||||
use:clickOutside={false}
|
||||
on:click_outside={(e) => {
|
||||
if ($mode !== 'dnd' && !unclickableOutside) {
|
||||
closeDrawer()
|
||||
}
|
||||
}}
|
||||
class={twMerge(
|
||||
`${
|
||||
$mode == 'dnd' ? 'absolute' : 'fixed'
|
||||
} top-0 bottom-0 left-0 right-0 transition-all duration-50`,
|
||||
open ? ' bg-black bg-opacity-60' : 'h-0 overflow-hidden invisible'
|
||||
)}
|
||||
style="z-index: {zIndex}"
|
||||
>
|
||||
<div class="px-4 py-2 border-b flex justify-between items-center">
|
||||
<div>{resolvedConfig.modalTitle}</div>
|
||||
<div class="w-8">
|
||||
<button
|
||||
on:click|stopPropagation={() => {
|
||||
open = false
|
||||
}}
|
||||
class="hover:bg-surface-hover bg-surface-secondary rounded-full w-8 h-8 flex items-center justify-center transition-all"
|
||||
>
|
||||
<X class="text-tertiary" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="wm-modal"
|
||||
on:pointerdown={(e) => {
|
||||
e?.stopPropagation()
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [id]
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
}
|
||||
style={css?.popup?.style}
|
||||
class={twMerge('mx-24 mt-8 bg-surface rounded-lg relative', css?.popup?.class)}
|
||||
use:clickOutside={false}
|
||||
on:click_outside={(e) => {
|
||||
if ($mode !== 'dnd' && !unclickableOutside) {
|
||||
handleClickAway(e)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if $app.subgrids?.[`${id}-0`]}
|
||||
<SubGridEditor
|
||||
visible={open && render}
|
||||
{id}
|
||||
noPadding
|
||||
subGridId={`${id}-0`}
|
||||
on:focus={() => {
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [id]
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
}
|
||||
<div class="px-4 py-2 border-b flex justify-between items-center">
|
||||
<div>{resolvedConfig.modalTitle}</div>
|
||||
<div class="w-8">
|
||||
<button
|
||||
on:click|stopPropagation={() => {
|
||||
disposable?.closeDrawer()
|
||||
}}
|
||||
class="hover:bg-surface-hover bg-surface-secondary rounded-full w-8 h-8 flex items-center justify-center transition-all"
|
||||
>
|
||||
<X class="text-tertiary" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="wm-modal"
|
||||
on:pointerdown={(e) => {
|
||||
e?.stopPropagation()
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [id]
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if $app.subgrids?.[`${id}-0`]}
|
||||
<SubGridEditor
|
||||
visible={open && render}
|
||||
{id}
|
||||
noPadding
|
||||
subGridId={`${id}-0`}
|
||||
on:focus={() => {
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [id]
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Disposable>
|
||||
</Portal>
|
||||
|
||||
@@ -963,7 +963,7 @@
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
<Drawer bind:open={$jobsDrawerOpen} size="900px" --zIndex={1003}>
|
||||
<Drawer bind:open={$jobsDrawerOpen} size="900px">
|
||||
<DrawerContent
|
||||
noPadding
|
||||
title="Debug Runs"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
import Component from './component/Component.svelte'
|
||||
import ComponentWrapper from './component/ComponentWrapper.svelte'
|
||||
import GridViewer from './GridViewer.svelte'
|
||||
import GridEditorMenu from './GridEditorMenu.svelte'
|
||||
|
||||
export let containerHeight: number | undefined = undefined
|
||||
export let containerWidth: number | undefined = undefined
|
||||
@@ -120,31 +121,33 @@
|
||||
'top-0'
|
||||
)}
|
||||
>
|
||||
<Component
|
||||
render={visible}
|
||||
component={dataItem.data}
|
||||
selected={Boolean($selectedComponent?.includes(dataItem.id))}
|
||||
locked={isFixed(dataItem)}
|
||||
on:lock={() => lock(dataItem)}
|
||||
on:expand={() => {
|
||||
const parentGridItem = findGridItem($app, id)
|
||||
<GridEditorMenu id={dataItem.id}>
|
||||
<Component
|
||||
render={visible}
|
||||
component={dataItem.data}
|
||||
selected={Boolean($selectedComponent?.includes(dataItem.id))}
|
||||
locked={isFixed(dataItem)}
|
||||
on:lock={() => lock(dataItem)}
|
||||
on:expand={() => {
|
||||
const parentGridItem = findGridItem($app, id)
|
||||
|
||||
if (!parentGridItem) {
|
||||
return
|
||||
}
|
||||
if (!parentGridItem) {
|
||||
return
|
||||
}
|
||||
|
||||
$selectedComponent = [dataItem.id]
|
||||
push(editorContext?.history, $app)
|
||||
$selectedComponent = [dataItem.id]
|
||||
push(editorContext?.history, $app)
|
||||
|
||||
expandGriditem(
|
||||
$app.subgrids?.[subGridId] ?? [],
|
||||
dataItem.id,
|
||||
$breakpoint,
|
||||
parentGridItem
|
||||
)
|
||||
$app = $app
|
||||
}}
|
||||
/>
|
||||
expandGriditem(
|
||||
$app.subgrids?.[subGridId] ?? [],
|
||||
dataItem.id,
|
||||
$breakpoint,
|
||||
parentGridItem
|
||||
)
|
||||
$app = $app
|
||||
}}
|
||||
/>
|
||||
</GridEditorMenu>
|
||||
</ComponentWrapper>
|
||||
</Grid>
|
||||
</div>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import { ClearableInput } from '../../../../common'
|
||||
import { createPopperActions } from 'svelte-popperjs'
|
||||
import { fade } from 'svelte/transition'
|
||||
import { zIndexes } from '$lib/zIndexes'
|
||||
|
||||
export let value: string = '#fff'
|
||||
const dispatch = createEventDispatcher()
|
||||
@@ -25,7 +26,7 @@
|
||||
<div
|
||||
transition:fade={{ duration: 150 }}
|
||||
use:popperContent={{ placement: 'bottom', strategy: 'fixed' }}
|
||||
class="color-picker-input z-[1002] !text-primary"
|
||||
class={`color-picker-input z-[${zIndexes.colorInput}] !text-primary`}
|
||||
style="width: {width > 280 ? width : 280}px;"
|
||||
>
|
||||
<ColorPicker
|
||||
|
||||
+2
-2
@@ -4,6 +4,7 @@
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppViewerContext } from '../../../types'
|
||||
import CloseButton from '$lib/components/common/CloseButton.svelte'
|
||||
import { zIndexes } from '$lib/zIndexes'
|
||||
|
||||
const { selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
|
||||
export let right: boolean
|
||||
@@ -18,10 +19,9 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- z-index must be above the split pane handles' z-index (which is 1001 atm.) -->
|
||||
<div
|
||||
bind:clientWidth={width}
|
||||
class="absolute z-[1002] inset-0 overflow-hidden w-full"
|
||||
class={`absolute z-[${zIndexes.secondaryMenu}] inset-0 overflow-hidden w-full`}
|
||||
class:pointer-events-none={!$secondaryMenu.isOpen}
|
||||
>
|
||||
{#if $secondaryMenu.isOpen && $secondaryMenu.component}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<script lang="ts">
|
||||
import Portal from 'svelte-portal'
|
||||
|
||||
export let condition = false
|
||||
</script>
|
||||
|
||||
{#if condition}
|
||||
<Portal><slot /></Portal>
|
||||
{:else}
|
||||
<slot />
|
||||
{/if}
|
||||
@@ -0,0 +1,83 @@
|
||||
<script lang="ts" context="module">
|
||||
export let openedDrawers: string[] = []
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { zIndexes } from '$lib/zIndexes'
|
||||
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
export let open = false
|
||||
export let id = (Math.random() + 1).toString(36).substring(10)
|
||||
|
||||
if (open) {
|
||||
openedDrawers.push(id)
|
||||
}
|
||||
|
||||
let offset = 0
|
||||
|
||||
export function toggleDrawer() {
|
||||
if (!open) {
|
||||
openDrawer()
|
||||
} else {
|
||||
closeDrawer()
|
||||
}
|
||||
}
|
||||
|
||||
export function openDrawer() {
|
||||
open = true
|
||||
offset = openedDrawers.length - 1
|
||||
|
||||
if (openedDrawers.includes(id)) {
|
||||
return
|
||||
}
|
||||
|
||||
openedDrawers.push(id)
|
||||
}
|
||||
|
||||
export function closeDrawer() {
|
||||
open = false
|
||||
offset = 0
|
||||
// remove the last opened drawer
|
||||
openedDrawers = openedDrawers.filter((drawer) => drawer !== id)
|
||||
}
|
||||
|
||||
export function isOpen() {
|
||||
return open
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function handleClickAway(e) {
|
||||
const last = openedDrawers[openedDrawers.length - 1]
|
||||
|
||||
if (last === id) {
|
||||
e.stopPropagation()
|
||||
closeDrawer()
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyDown(event: KeyboardEvent) {
|
||||
if (open) {
|
||||
switch (event.key) {
|
||||
case 'Escape':
|
||||
if (id == openedDrawers[openedDrawers.length - 1] || openedDrawers.length == 0) {
|
||||
openedDrawers.pop()
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
event.stopImmediatePropagation()
|
||||
closeDrawer()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$: zIndex = zIndexes.disposables + offset
|
||||
|
||||
$: open ? dispatch('open') : dispatch('close')
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={onKeyDown} />
|
||||
|
||||
<slot {handleClickAway} {zIndex} {closeDrawer} {open} />
|
||||
@@ -1,38 +1,30 @@
|
||||
<script lang="ts" context="module">
|
||||
let openedDrawers: string[] = []
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { onMount, createEventDispatcher } from 'svelte'
|
||||
import { BROWSER } from 'esm-env'
|
||||
import Disposable from './Disposable.svelte'
|
||||
import ConditionalPortal from './ConditionalPortal.svelte'
|
||||
|
||||
export let open = false
|
||||
export let duration = 0.3
|
||||
export let placement = 'right'
|
||||
export let size = '600px'
|
||||
export let alwaysOpen = false
|
||||
export let shouldUsePortal: boolean = true
|
||||
|
||||
let id = (Math.random() + 1).toString(36).substring(10)
|
||||
let disposable: Disposable | undefined = undefined
|
||||
|
||||
$: durationMs = duration * 1000
|
||||
|
||||
export function toggleDrawer() {
|
||||
open = !open
|
||||
if (open) {
|
||||
openedDrawers.push(id)
|
||||
} else {
|
||||
openedDrawers = openedDrawers.filter((x) => x != id)
|
||||
}
|
||||
disposable?.toggleDrawer()
|
||||
}
|
||||
|
||||
export function openDrawer() {
|
||||
openedDrawers.push(id)
|
||||
open = true
|
||||
disposable?.openDrawer()
|
||||
}
|
||||
|
||||
export function closeDrawer() {
|
||||
open = false
|
||||
openedDrawers = openedDrawers.filter((x) => x != id)
|
||||
disposable?.closeDrawer()
|
||||
|
||||
setTimeout(() => {
|
||||
dispatch('afterClose')
|
||||
@@ -60,28 +52,7 @@
|
||||
|
||||
$: scrollLock(open)
|
||||
|
||||
function handleClickAway() {
|
||||
dispatch('clickAway')
|
||||
open = false
|
||||
}
|
||||
|
||||
function onKeyDown(event: KeyboardEvent) {
|
||||
if (open) {
|
||||
switch (event.key) {
|
||||
case 'Escape':
|
||||
if (id == openedDrawers[openedDrawers.length - 1] || openedDrawers.length == 0) {
|
||||
openedDrawers.pop()
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
event.stopImmediatePropagation()
|
||||
open = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$: open ? dispatch('open') : dispatch('close')
|
||||
$: open ? openDrawer() : closeDrawer()
|
||||
|
||||
let timeout = true
|
||||
$: !open ? setTimeout(() => (timeout = true), durationMs) : (timeout = false)
|
||||
@@ -90,22 +61,25 @@
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={onKeyDown} />
|
||||
|
||||
<aside
|
||||
class="drawer {$$props.class ?? ''} {$$props.positionClass ?? ''}"
|
||||
class:open
|
||||
class:close={!open && timeout}
|
||||
{style}
|
||||
>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div class="overlay {$$props.positionClass ?? ''}" on:click={handleClickAway} />
|
||||
<div class="panel {placement} {$$props.positionClass}" class:size>
|
||||
{#if open || !timeout || alwaysOpen}
|
||||
<slot {open} />
|
||||
{/if}
|
||||
</div>
|
||||
</aside>
|
||||
<ConditionalPortal condition={shouldUsePortal}>
|
||||
<Disposable let:handleClickAway let:zIndex bind:open bind:this={disposable} on:open on:close>
|
||||
<aside
|
||||
class="drawer {$$props.class ?? ''} {$$props.positionClass ?? ''}"
|
||||
class:open
|
||||
class:close={!open && timeout}
|
||||
style={`${style}; --zIndex: ${zIndex};`}
|
||||
>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="overlay {$$props.positionClass ?? ''}" on:click={handleClickAway} />
|
||||
<div class="panel {placement} {$$props.positionClass}" class:size>
|
||||
{#if open || !timeout || alwaysOpen}
|
||||
<slot {open} />
|
||||
{/if}
|
||||
</div>
|
||||
</aside>
|
||||
</Disposable>
|
||||
</ConditionalPortal>
|
||||
|
||||
<style>
|
||||
.drawer {
|
||||
@@ -123,7 +97,7 @@
|
||||
.drawer.open {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: var(--zIndex, 1002);
|
||||
z-index: var(--zIndex);
|
||||
transition: z-index var(--duration) step-start;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
export const zIndexes = {
|
||||
appEditorComponents: 1000,
|
||||
secondaryMenu: 1001,
|
||||
splitPanelHandle: 1001,
|
||||
colorInput: 1002,
|
||||
disposables: 1100, // Modals and Drawers
|
||||
svelteSelectOptions: 5000,
|
||||
contextMenu: 6000,
|
||||
draggingComponent: 10000,
|
||||
monacoEditor: 10000,
|
||||
monacoEditorSuggestions: 10001
|
||||
}
|
||||
@@ -50,7 +50,6 @@
|
||||
} from 'lucide-svelte'
|
||||
import { onMount } from 'svelte'
|
||||
import autosize from '$lib/autosize'
|
||||
import Portal from 'svelte-portal'
|
||||
|
||||
type ResourceW = ListableResource & { canWrite: boolean; marked?: string }
|
||||
type ResourceTypeW = ResourceType & { canWrite: boolean }
|
||||
@@ -360,21 +359,19 @@
|
||||
|
||||
<DeployWorkspaceDrawer bind:this={deploymentDrawer} />
|
||||
|
||||
<Portal>
|
||||
<Drawer bind:this={inferrer} size="800px">
|
||||
<DrawerContent title="Infer type from JSON" on:close={() => inferrer?.toggleDrawer?.()}>
|
||||
<SimpleEditor
|
||||
bind:code={inferrerJson}
|
||||
lang="json"
|
||||
class="h-full"
|
||||
fixedOverflowWidgets={false}
|
||||
/>
|
||||
<svelte:fragment slot="actions">
|
||||
<Button size="sm" on:click={inferJson}>Infer</Button>
|
||||
</svelte:fragment>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
</Portal>
|
||||
<Drawer bind:this={inferrer} size="800px">
|
||||
<DrawerContent title="Infer type from JSON" on:close={() => inferrer?.toggleDrawer?.()}>
|
||||
<SimpleEditor
|
||||
bind:code={inferrerJson}
|
||||
lang="json"
|
||||
class="h-full"
|
||||
fixedOverflowWidgets={false}
|
||||
/>
|
||||
<svelte:fragment slot="actions">
|
||||
<Button size="sm" on:click={inferJson}>Infer</Button>
|
||||
</svelte:fragment>
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
|
||||
<Drawer bind:this={resourceTypeViewer} size="800px">
|
||||
<DrawerContent title={resourceTypeViewerObj.rt} on:close={resourceTypeViewer.closeDrawer}>
|
||||
|
||||
Reference in New Issue
Block a user