mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-24 16:01:42 +00:00
partial app svelte 5 migration (#5945)
This commit is contained in:
@@ -66,6 +66,7 @@
|
||||
let args: Record<string, unknown> = $state(!iterContext ? (outputs?.values?.peak() ?? {}) : {})
|
||||
|
||||
function handleArgsChange() {
|
||||
// console.log('handleArgsChange', args)
|
||||
const newArgs: Record<string, unknown> = {}
|
||||
|
||||
for (const key in args) {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { createBubbler, stopPropagation } from 'svelte/legacy'
|
||||
|
||||
const bubble = createBubbler()
|
||||
import { getContext } from 'svelte'
|
||||
import { initOutput } from '../../editor/appUtils'
|
||||
import SubGridEditor from '../../editor/SubGridEditor.svelte'
|
||||
@@ -11,12 +14,23 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let customCss: ComponentCustomCSS<'accordionlistcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let initializing: boolean | undefined
|
||||
export let componentContainerHeight: number
|
||||
interface Props {
|
||||
id: string
|
||||
componentInput: AppInput | undefined
|
||||
customCss?: ComponentCustomCSS<'accordionlistcomponent'> | undefined
|
||||
render: boolean
|
||||
initializing: boolean | undefined
|
||||
componentContainerHeight: number
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
componentInput,
|
||||
customCss = undefined,
|
||||
render,
|
||||
initializing = $bindable(),
|
||||
componentContainerHeight
|
||||
}: Props = $props()
|
||||
|
||||
type AccordionListValue = { header: string; [key: string]: any }
|
||||
|
||||
@@ -24,16 +38,18 @@
|
||||
value: AccordionListValue[]
|
||||
}
|
||||
|
||||
$: accordionInput = componentInput as InternalAccordionListInput
|
||||
let accordionInput = $derived(componentInput as InternalAccordionListInput)
|
||||
|
||||
const { app, focusedGrid, selectedComponent, worldStore, connectingInput } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let everRender = render
|
||||
let everRender = $state(render)
|
||||
|
||||
$: render && !everRender && (everRender = true)
|
||||
$effect.pre(() => {
|
||||
render && !everRender && (everRender = true)
|
||||
})
|
||||
|
||||
let activeIndex: number = 0
|
||||
let activeIndex: number = $state(0)
|
||||
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
result: undefined,
|
||||
@@ -49,17 +65,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.accordionlistcomponent, customCss)
|
||||
let result: any[] | undefined = undefined
|
||||
let css = $state(initCss($app.css?.accordionlistcomponent, customCss))
|
||||
let result: any[] | undefined = $state(undefined)
|
||||
|
||||
let inputs = {}
|
||||
let inputs = $state({})
|
||||
|
||||
$: $selectedComponent?.includes(id) &&
|
||||
$focusedGrid === undefined &&
|
||||
($focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
})
|
||||
$effect.pre(() => {
|
||||
$selectedComponent?.includes(id) &&
|
||||
$focusedGrid === undefined &&
|
||||
($focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
})
|
||||
})
|
||||
|
||||
function toggleAccordion(index: number) {
|
||||
activeIndex = activeIndex === index ? -1 : index
|
||||
@@ -95,8 +113,8 @@
|
||||
{#each result ?? [] as value, index}
|
||||
<div class="border-b">
|
||||
<button
|
||||
on:pointerdown|stopPropagation
|
||||
on:click={() => toggleAccordion(index)}
|
||||
onpointerdown={stopPropagation(bubble('pointerdown'))}
|
||||
onclick={() => toggleAccordion(index)}
|
||||
class={twMerge(
|
||||
'w-full text-left bg-surface !truncate text-sm hover:text-primary px-1 py-2',
|
||||
'wm-tabs-alltabs',
|
||||
|
||||
@@ -16,19 +16,33 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let customCss: ComponentCustomCSS<'carousellistcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let initializing: boolean | undefined
|
||||
export let componentContainerHeight: number
|
||||
interface Props {
|
||||
id: string
|
||||
componentInput: AppInput | undefined
|
||||
configuration: RichConfigurations
|
||||
customCss?: ComponentCustomCSS<'carousellistcomponent'> | undefined
|
||||
render: boolean
|
||||
initializing: boolean | undefined
|
||||
componentContainerHeight: number
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
componentInput,
|
||||
configuration,
|
||||
customCss = undefined,
|
||||
render,
|
||||
initializing = $bindable(),
|
||||
componentContainerHeight
|
||||
}: Props = $props()
|
||||
|
||||
const { app, focusedGrid, selectedComponent, worldStore, connectingInput } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let everRender = render
|
||||
$: render && !everRender && (everRender = true)
|
||||
let everRender = $state(render)
|
||||
$effect.pre(() => {
|
||||
render && !everRender && (everRender = true)
|
||||
})
|
||||
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
result: undefined,
|
||||
@@ -36,9 +50,8 @@
|
||||
inputs: {}
|
||||
})
|
||||
|
||||
const resolvedConfig = initConfig(
|
||||
components['carousellistcomponent'].initialData.configuration,
|
||||
configuration
|
||||
const resolvedConfig = $state(
|
||||
initConfig(components['carousellistcomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
function onFocus() {
|
||||
@@ -48,19 +61,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.carousellistcomponent, customCss)
|
||||
let result: any[] | undefined = undefined
|
||||
let css = $state(initCss($app.css?.carousellistcomponent, customCss))
|
||||
let result: any[] | undefined = $state(undefined)
|
||||
|
||||
let inputs = {}
|
||||
let carousel: Carousel
|
||||
let inputs = $state({})
|
||||
let carousel: Carousel = $state()
|
||||
|
||||
$: $selectedComponent?.includes(id) &&
|
||||
$focusedGrid === undefined &&
|
||||
($focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
})
|
||||
let currentPageIndex = 0
|
||||
$effect.pre(() => {
|
||||
$selectedComponent?.includes(id) &&
|
||||
$focusedGrid === undefined &&
|
||||
($focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
})
|
||||
})
|
||||
let currentPageIndex = $state(0)
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['carousellistcomponent'].initialData.configuration) as key (key)}
|
||||
@@ -116,41 +131,45 @@
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div slot="prev" class="h-full flex justify-center flex-col p-2">
|
||||
<div>
|
||||
<Button
|
||||
color="light"
|
||||
on:click={() => {
|
||||
const pagesCount = result?.length ?? 0
|
||||
{#snippet prev()}
|
||||
<div class="h-full flex justify-center flex-col p-2">
|
||||
<div>
|
||||
<Button
|
||||
color="light"
|
||||
on:click={() => {
|
||||
const pagesCount = result?.length ?? 0
|
||||
|
||||
if (currentPageIndex > 0) {
|
||||
carousel.goTo(currentPageIndex - 1)
|
||||
} else {
|
||||
carousel.goTo(pagesCount - 1)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ArrowLeftCircle size={16} />
|
||||
</Button>
|
||||
if (currentPageIndex > 0) {
|
||||
carousel.goTo(currentPageIndex - 1)
|
||||
} else {
|
||||
carousel.goTo(pagesCount - 1)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ArrowLeftCircle size={16} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="next" class="h-full flex justify-center flex-col p-2">
|
||||
<div>
|
||||
<Button
|
||||
color="light"
|
||||
on:click={() => {
|
||||
const pagesCount = result?.length ?? 0
|
||||
if (currentPageIndex < pagesCount - 1) {
|
||||
carousel.goTo(currentPageIndex + 1)
|
||||
} else {
|
||||
carousel.goTo(0)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ArrowRightCircle size={16} />
|
||||
</Button>
|
||||
{/snippet}
|
||||
{#snippet next()}
|
||||
<div class="h-full flex justify-center flex-col p-2">
|
||||
<div>
|
||||
<Button
|
||||
color="light"
|
||||
on:click={() => {
|
||||
const pagesCount = result?.length ?? 0
|
||||
if (currentPageIndex < pagesCount - 1) {
|
||||
carousel.goTo(currentPageIndex + 1)
|
||||
} else {
|
||||
carousel.goTo(0)
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ArrowRightCircle size={16} />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
{#each result ?? [] as value, index}
|
||||
<div class="overflow-auto w-full">
|
||||
<ListWrapper
|
||||
|
||||
@@ -3,27 +3,42 @@
|
||||
import type { HorizontalAlignment, VerticalAlignment } from '../../types'
|
||||
import { tailwindHorizontalAlignment, tailwindVerticalAlignment } from '../../utils'
|
||||
|
||||
export let horizontalAlignment: HorizontalAlignment | undefined = undefined
|
||||
export let verticalAlignment: VerticalAlignment | undefined = undefined
|
||||
export let noWFull = false
|
||||
export let hFull = false
|
||||
let c = ''
|
||||
export { c as class }
|
||||
export let style = ''
|
||||
export let render: boolean = true
|
||||
interface Props {
|
||||
horizontalAlignment?: HorizontalAlignment | undefined
|
||||
verticalAlignment?: VerticalAlignment | undefined
|
||||
noWFull?: boolean
|
||||
hFull?: boolean
|
||||
class?: string
|
||||
style?: string
|
||||
render?: boolean
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
$: classes = twMerge(
|
||||
'flex z-auto',
|
||||
noWFull ? '' : 'w-full',
|
||||
tailwindHorizontalAlignment(horizontalAlignment),
|
||||
tailwindVerticalAlignment(verticalAlignment),
|
||||
verticalAlignment || hFull ? 'h-full' : '',
|
||||
c
|
||||
let {
|
||||
horizontalAlignment = undefined,
|
||||
verticalAlignment = undefined,
|
||||
noWFull = false,
|
||||
hFull = false,
|
||||
class: c = '',
|
||||
style = '',
|
||||
render = true,
|
||||
children
|
||||
}: Props = $props()
|
||||
|
||||
let classes = $derived(
|
||||
twMerge(
|
||||
'flex z-auto',
|
||||
noWFull ? '' : 'w-full',
|
||||
tailwindHorizontalAlignment(horizontalAlignment),
|
||||
tailwindVerticalAlignment(verticalAlignment),
|
||||
verticalAlignment || hFull ? 'h-full' : '',
|
||||
c
|
||||
)
|
||||
)
|
||||
</script>
|
||||
|
||||
{#if render}
|
||||
<div class={classes} {style}>
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -1,206 +1,23 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { initConfig, initOutput } from '../../editor/appUtils'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
import { initCss } from '../../utils'
|
||||
import type { ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InitializeComponent from '../helpers/InitializeComponent.svelte'
|
||||
import { components } from '../../editor/component'
|
||||
import ResolveConfig from '../helpers/ResolveConfig.svelte'
|
||||
|
||||
// @ts-ignore
|
||||
import MultiSelect from 'svelte-multiselect'
|
||||
import Portal from '$lib/components/Portal.svelte'
|
||||
|
||||
import { createFloatingActions } from 'svelte-floating-ui'
|
||||
import { extractCustomProperties } from '$lib/utils'
|
||||
import { tick } from 'svelte'
|
||||
import { offset, flip, shift } from 'svelte-floating-ui/dom'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let customCss: ComponentCustomCSS<'multiselectcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
|
||||
const [floatingRef, floatingContent] = createFloatingActions({
|
||||
strategy: 'absolute',
|
||||
middleware: [offset(5), flip(), shift()]
|
||||
})
|
||||
|
||||
const { app, worldStore, selectedComponent, componentControl } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
let items: string[]
|
||||
|
||||
const resolvedConfig = initConfig(
|
||||
components['multiselectcomponent'].initialData.configuration,
|
||||
configuration
|
||||
)
|
||||
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
result: [] as string[]
|
||||
})
|
||||
|
||||
let value: string[] | undefined = [...new Set(outputs?.result.peak())] as string[]
|
||||
|
||||
$componentControl[id] = {
|
||||
setValue(nvalue: string[]) {
|
||||
value = [...new Set(nvalue)]
|
||||
outputs?.result.set([...(value ?? [])])
|
||||
}
|
||||
}
|
||||
|
||||
$: resolvedConfig.items && handleItems()
|
||||
|
||||
function handleItems() {
|
||||
if (Array.isArray(resolvedConfig.items)) {
|
||||
items = resolvedConfig.items?.map((label) => {
|
||||
return typeof label === 'string' ? label : `NOT_STRING`
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
$: resolvedConfig.defaultItems && handleDefaultItems()
|
||||
|
||||
function handleDefaultItems() {
|
||||
if (Array.isArray(resolvedConfig.defaultItems)) {
|
||||
const nvalue = resolvedConfig.defaultItems?.map((label) => {
|
||||
return typeof label === 'string' ? label : `NOT_STRING`
|
||||
})
|
||||
value = [...new Set(nvalue)]
|
||||
outputs?.result.set([...(value ?? [])])
|
||||
}
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.multiselectcomponent, customCss)
|
||||
|
||||
function setOuterDivStyle(outerDiv: HTMLDivElement, portalRef: HTMLDivElement, style: string) {
|
||||
outerDiv.setAttribute('style', style)
|
||||
// find ul in portalRef and set style
|
||||
const ul = portalRef.querySelector('ul')
|
||||
ul?.setAttribute('style', extractCustomProperties(style))
|
||||
}
|
||||
|
||||
$: outerDiv &&
|
||||
portalRef &&
|
||||
css?.multiselect?.style &&
|
||||
setOuterDivStyle(outerDiv, portalRef, css?.multiselect?.style)
|
||||
|
||||
let outerDiv: HTMLDivElement | undefined = undefined
|
||||
let portalRef: HTMLDivElement | undefined = undefined
|
||||
|
||||
function moveOptionsToPortal() {
|
||||
// Find ul element with class 'options' within the outerDiv
|
||||
const ul = outerDiv?.querySelector('.options')
|
||||
|
||||
if (ul) {
|
||||
// Move the ul element to the portal
|
||||
portalRef?.appendChild(ul)
|
||||
}
|
||||
}
|
||||
|
||||
$: if (render && portalRef && outerDiv && items?.length > 0) {
|
||||
tick().then(() => {
|
||||
moveOptionsToPortal()
|
||||
})
|
||||
}
|
||||
|
||||
let w = 0
|
||||
let open = false
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['multiselectcomponent'].initialData.configuration) as key (key)}
|
||||
<ResolveConfig
|
||||
{id}
|
||||
{key}
|
||||
bind:resolvedConfig={resolvedConfig[key]}
|
||||
configuration={configuration[key]}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
{#each Object.keys(css ?? {}) as key (key)}
|
||||
<ResolveStyle
|
||||
{id}
|
||||
{customCss}
|
||||
{key}
|
||||
bind:css={css[key]}
|
||||
componentStyle={$app.css?.multiselectcomponent}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
<InitializeComponent {id} />
|
||||
|
||||
<AlignWrapper {render} hFull {verticalAlignment}>
|
||||
<div
|
||||
class="w-full app-editor-input"
|
||||
on:pointerdown={(e) => {
|
||||
$selectedComponent = [id]
|
||||
|
||||
if (!e.shiftKey) {
|
||||
e.stopPropagation()
|
||||
}
|
||||
selectedComponent.set([id])
|
||||
}}
|
||||
use:floatingRef
|
||||
bind:clientWidth={w}
|
||||
>This version of the multiselect component is not supported anymore. Recreate the multiselect
|
||||
component to use this new version.</div
|
||||
>
|
||||
{#if !value || Array.isArray(value)}
|
||||
<MultiSelect
|
||||
bind:outerDiv
|
||||
outerDivClass={`${resolvedConfig.allowOverflow ? '' : 'h-full'}`}
|
||||
ulSelectedClass={`${resolvedConfig.allowOverflow ? '' : 'overflow-auto max-h-full'} `}
|
||||
ulOptionsClass={'p-2 !bg-surface-secondary'}
|
||||
--sms-border={'none'}
|
||||
--sms-min-height={'32px'}
|
||||
--sms-focus-border={'none'}
|
||||
bind:selected={value}
|
||||
options={Array.isArray(items) ? items : []}
|
||||
placeholder={resolvedConfig.placeholder}
|
||||
allowUserOptions={resolvedConfig.create}
|
||||
onchange={(event) => {
|
||||
if (event?.type === 'removeAll') {
|
||||
outputs?.result.set([])
|
||||
} else {
|
||||
outputs?.result.set([...(value ?? [])])
|
||||
}
|
||||
}}
|
||||
onopen={() => {
|
||||
$selectedComponent = [id]
|
||||
open = true
|
||||
}}
|
||||
onclose={() => {
|
||||
open = false
|
||||
}}
|
||||
>
|
||||
{#snippet children({ option })}
|
||||
<!-- needed because portal doesn't work for mouseup event en mobile -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="w-full"
|
||||
on:mouseup|stopPropagation
|
||||
on:pointerdown|stopPropagation={(e) => {
|
||||
let newe = new MouseEvent('mouseup')
|
||||
e.target?.['parentElement']?.dispatchEvent(newe)
|
||||
}}
|
||||
>
|
||||
{option}
|
||||
</div>
|
||||
{/snippet}
|
||||
</MultiSelect>
|
||||
<Portal name="app-multiselect">
|
||||
<div use:floatingContent class="z5000" hidden={!open}>
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
bind:this={portalRef}
|
||||
class="multiselect"
|
||||
style={`min-width: ${w}px;`}
|
||||
on:click|stopPropagation
|
||||
></div>
|
||||
</div>
|
||||
</Portal>
|
||||
{:else}
|
||||
Value {value} is not an array
|
||||
{/if}
|
||||
</div>
|
||||
</AlignWrapper>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { getContext, untrack } from 'svelte'
|
||||
import { initOutput } from '../../editor/appUtils'
|
||||
import SubGridEditor from '../../editor/SubGridEditor.svelte'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfiguration } from '../../types'
|
||||
@@ -9,12 +9,23 @@
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentContainerHeight: number
|
||||
export let customCss: ComponentCustomCSS<'conditionalwrapper'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let conditions: RichConfiguration[]
|
||||
export let onTabChange: string[] | undefined = undefined
|
||||
interface Props {
|
||||
id: string
|
||||
componentContainerHeight: number
|
||||
customCss?: ComponentCustomCSS<'conditionalwrapper'> | undefined
|
||||
render: boolean
|
||||
conditions: RichConfiguration[]
|
||||
onTabChange?: string[] | undefined
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
componentContainerHeight,
|
||||
customCss = undefined,
|
||||
render,
|
||||
conditions,
|
||||
onTabChange = undefined
|
||||
}: Props = $props()
|
||||
|
||||
const {
|
||||
app,
|
||||
@@ -31,8 +42,10 @@
|
||||
selectedTabIndex: 0
|
||||
})
|
||||
|
||||
let everRender = render
|
||||
$: render && !everRender && (everRender = true)
|
||||
let everRender = $state(render)
|
||||
$effect.pre(() => {
|
||||
render && !everRender && (everRender = true)
|
||||
})
|
||||
|
||||
function onFocus() {
|
||||
$focusedGrid = {
|
||||
@@ -41,10 +54,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.conditionalwrapper, customCss)
|
||||
let css = $state(initCss($app.css?.conditionalwrapper, customCss))
|
||||
|
||||
let resolvedConditions: boolean[] = conditions.map((_x) => false)
|
||||
let selectedConditionIndex = 0
|
||||
let resolvedConditions: boolean[] = $state(conditions.map((_x) => false))
|
||||
let selectedConditionIndex = $state(0)
|
||||
|
||||
function handleResolvedConditions() {
|
||||
const slicedArray = resolvedConditions.slice(0, conditions.length)
|
||||
@@ -66,7 +79,9 @@
|
||||
onTabChange?.forEach((id) => $runnableComponents?.[id]?.cb?.forEach((cb) => cb?.()))
|
||||
}
|
||||
|
||||
$: resolvedConditions && handleResolvedConditions()
|
||||
$effect.pre(() => {
|
||||
resolvedConditions && untrack(() => handleResolvedConditions())
|
||||
})
|
||||
|
||||
$componentControl[id] = {
|
||||
setTab: (conditionIndex: number) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { getContext, onMount } from 'svelte'
|
||||
import { getContext, onMount, untrack } from 'svelte'
|
||||
import { initOutput } from '../../editor/appUtils'
|
||||
import SubGridEditor from '../../editor/SubGridEditor.svelte'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
@@ -12,23 +12,40 @@
|
||||
import GroupWrapper from '../GroupWrapper.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentContainerHeight: number
|
||||
export let customCss: ComponentCustomCSS<'containercomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let groupFields: RichConfigurations | undefined = undefined
|
||||
interface Props {
|
||||
id: string
|
||||
componentContainerHeight: number
|
||||
customCss?: ComponentCustomCSS<'containercomponent'> | undefined
|
||||
render: boolean
|
||||
groupFields?: RichConfigurations | undefined
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
componentContainerHeight,
|
||||
customCss = undefined,
|
||||
render,
|
||||
groupFields = undefined
|
||||
}: Props = $props()
|
||||
|
||||
const { app, focusedGrid, selectedComponent, worldStore, connectingInput, componentControl } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let everRender = render
|
||||
$: render && !everRender && (everRender = true)
|
||||
let everRender = $state(render)
|
||||
$effect.pre(() => {
|
||||
render && !everRender && (everRender = true)
|
||||
})
|
||||
|
||||
let groupContext = writable({})
|
||||
|
||||
let outputs = initOutput($worldStore, id, { group: $groupContext })
|
||||
|
||||
$: outputs.group.set($groupContext, true)
|
||||
$effect.pre(() => {
|
||||
$groupContext
|
||||
untrack(() => {
|
||||
outputs.group.set($groupContext, true)
|
||||
})
|
||||
})
|
||||
|
||||
function onFocus() {
|
||||
$focusedGrid = {
|
||||
@@ -48,7 +65,7 @@
|
||||
}
|
||||
})
|
||||
|
||||
let css = initCss($app.css?.containercomponent, customCss)
|
||||
let css = $state(initCss($app.css?.containercomponent, customCss))
|
||||
</script>
|
||||
|
||||
<InitializeComponent {id} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { getContext, untrack } from 'svelte'
|
||||
import SubGridEditor from '../../editor/SubGridEditor.svelte'
|
||||
import type { AppViewerContext, ComponentCustomCSS } from '../../types'
|
||||
import { initCss } from '../../utils'
|
||||
@@ -14,14 +14,34 @@
|
||||
import { getFirstNode, isDebugging } from '../../editor/settingsPanel/decisionTree/utils'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentContainerHeight: number
|
||||
export let customCss: ComponentCustomCSS<'decisiontreecomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let nodes: DecisionTreeNode[]
|
||||
interface Props {
|
||||
id: string
|
||||
componentContainerHeight: number
|
||||
customCss?: ComponentCustomCSS<'decisiontreecomponent'> | undefined
|
||||
render: boolean
|
||||
nodes: DecisionTreeNode[]
|
||||
}
|
||||
|
||||
let everRender = render
|
||||
$: render && !everRender && (everRender = true)
|
||||
let { id, componentContainerHeight, customCss = undefined, render, nodes }: Props = $props()
|
||||
|
||||
let resolvedConditions = $derived(
|
||||
nodes.reduce((acc, node) => {
|
||||
acc[node.id] = acc[node.id] || []
|
||||
return acc
|
||||
}, {})
|
||||
)
|
||||
|
||||
let resolvedNext = $derived(
|
||||
nodes.reduce((acc, node) => {
|
||||
acc[node.id] = acc[node.id] || false
|
||||
return acc
|
||||
}, {})
|
||||
)
|
||||
|
||||
let everRender = $state(render)
|
||||
$effect.pre(() => {
|
||||
render && !everRender && (everRender = true)
|
||||
})
|
||||
|
||||
const {
|
||||
app,
|
||||
@@ -33,35 +53,27 @@
|
||||
debuggingComponents
|
||||
} = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let css = initCss($app.css?.conditionalwrapper, customCss)
|
||||
let css = $state(initCss($app.css?.conditionalwrapper, customCss))
|
||||
let selectedConditionIndex = 0
|
||||
let currentNodeId = getFirstNode(nodes)?.id ?? ''
|
||||
let currentNodeId = $state(getFirstNode(nodes)?.id ?? '')
|
||||
|
||||
let outputs = initOutput($worldStore, id, {
|
||||
currentNodeId,
|
||||
currentNodeIndex: selectedConditionIndex
|
||||
})
|
||||
|
||||
$: resolvedConditions = nodes.reduce((acc, node) => {
|
||||
acc[node.id] = acc[node.id] || []
|
||||
return acc
|
||||
}, resolvedConditions || {})
|
||||
$effect.pre(() => {
|
||||
if (!nodes.map((n) => n.id).includes(currentNodeId)) {
|
||||
const firstNode = untrack(() => getFirstNode(nodes)?.id)
|
||||
|
||||
$: resolvedNext = nodes.reduce((acc, node) => {
|
||||
acc[node.id] = acc[node.id] || false
|
||||
return acc
|
||||
}, resolvedNext || {})
|
||||
|
||||
$: if (!nodes.map((n) => n.id).includes(currentNodeId)) {
|
||||
const firstNode = getFirstNode(nodes)?.id
|
||||
|
||||
if (firstNode) {
|
||||
currentNodeId = firstNode
|
||||
if (firstNode) {
|
||||
currentNodeId = firstNode
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
$: lastNodeId = nodes?.find((node) => node.next.length === 0)?.id
|
||||
$: isNextDisabled = resolvedNext?.[currentNodeId] === false
|
||||
let lastNodeId = $derived(nodes?.find((node) => node.next.length === 0)?.id)
|
||||
let isNextDisabled = $derived(resolvedNext?.[currentNodeId] === false)
|
||||
|
||||
const history: string[] = []
|
||||
|
||||
@@ -136,17 +148,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: if (currentNodeId) {
|
||||
outputs.currentNodeId.set(currentNodeId)
|
||||
outputs.currentNodeIndex.set(nodes.findIndex((next) => next.id == currentNodeId))
|
||||
}
|
||||
|
||||
$: if ($selectedComponent?.[0] === id && !$focusedGrid) {
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: nodes.findIndex((node) => node.id === currentNodeId)
|
||||
$effect.pre(() => {
|
||||
if (currentNodeId) {
|
||||
outputs.currentNodeId.set(currentNodeId)
|
||||
outputs.currentNodeIndex.set(nodes.findIndex((next) => next.id == currentNodeId))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
$effect.pre(() => {
|
||||
if ($selectedComponent?.[0] === id && !$focusedGrid) {
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: nodes.findIndex((node) => node.id === currentNodeId)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#if Object.keys(resolvedConditions).length === nodes.length}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy'
|
||||
|
||||
import { getContext } from 'svelte'
|
||||
import SubGridEditor from '../../editor/SubGridEditor.svelte'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
@@ -14,18 +16,34 @@
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
|
||||
export let customCss: ComponentCustomCSS<'drawercomponent'> | undefined = undefined
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let noWFull = false
|
||||
export let render: boolean
|
||||
export let onOpenRecomputeIds: string[] | undefined = undefined
|
||||
export let onCloseRecomputeIds: string[] | undefined = undefined
|
||||
interface Props {
|
||||
customCss?: ComponentCustomCSS<'drawercomponent'> | undefined
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
horizontalAlignment?: 'left' | 'center' | 'right' | undefined
|
||||
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined
|
||||
noWFull?: boolean
|
||||
render: boolean
|
||||
onOpenRecomputeIds?: string[] | undefined
|
||||
onCloseRecomputeIds?: string[] | undefined
|
||||
}
|
||||
|
||||
let everRender = render
|
||||
$: render && !everRender && (everRender = true)
|
||||
let {
|
||||
customCss = undefined,
|
||||
id,
|
||||
configuration,
|
||||
horizontalAlignment = undefined,
|
||||
verticalAlignment = undefined,
|
||||
noWFull = false,
|
||||
render,
|
||||
onOpenRecomputeIds = undefined,
|
||||
onCloseRecomputeIds = undefined
|
||||
}: Props = $props()
|
||||
|
||||
let everRender = $state(render)
|
||||
run(() => {
|
||||
render && !everRender && (everRender = true)
|
||||
})
|
||||
|
||||
const {
|
||||
app,
|
||||
@@ -38,17 +56,16 @@
|
||||
runnableComponents
|
||||
} = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
const resolvedConfig = initConfig(
|
||||
components['drawercomponent'].initialData.configuration,
|
||||
configuration
|
||||
const resolvedConfig = $state(
|
||||
initConfig(components['drawercomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
open: false
|
||||
})
|
||||
|
||||
let containerHeight: number = 0
|
||||
let containerHeight: number = $state(0)
|
||||
|
||||
let appDrawer: Drawer
|
||||
let appDrawer: Drawer | undefined = $state()
|
||||
|
||||
$componentControl[id] = {
|
||||
open: () => {
|
||||
@@ -59,7 +76,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.drawercomponent, customCss)
|
||||
let css = $state(initCss($app.css?.drawercomponent, customCss))
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['drawercomponent'].initialData.configuration) as key (key)}
|
||||
@@ -105,7 +122,7 @@
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
}
|
||||
appDrawer.toggleDrawer()
|
||||
appDrawer?.toggleDrawer()
|
||||
}}
|
||||
size={resolvedConfig.size}
|
||||
color={resolvedConfig.color}
|
||||
@@ -122,7 +139,6 @@
|
||||
{#if everRender}
|
||||
<Portal target="#app-editor-top-level-drawer" name="app-drawer">
|
||||
<Drawer
|
||||
let:open
|
||||
bind:this={appDrawer}
|
||||
size="800px"
|
||||
alwaysOpen
|
||||
@@ -138,48 +154,50 @@
|
||||
}}
|
||||
disableChatOffset={true}
|
||||
>
|
||||
<DrawerContent
|
||||
title={resolvedConfig.drawerTitle}
|
||||
on:close={() => {
|
||||
appDrawer?.toggleDrawer()
|
||||
$focusedGrid = undefined
|
||||
}}
|
||||
fullScreen={$mode !== 'dnd'}
|
||||
>
|
||||
<div
|
||||
class={twMerge('h-full', css?.drawer?.class, 'wm-drawer')}
|
||||
style={css?.drawer?.style}
|
||||
bind:clientHeight={containerHeight}
|
||||
on:pointerdown={(e) => {
|
||||
e?.stopPropagation()
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [id]
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
}
|
||||
}
|
||||
{#snippet children({ open })}
|
||||
<DrawerContent
|
||||
title={resolvedConfig.drawerTitle}
|
||||
on:close={() => {
|
||||
appDrawer?.toggleDrawer()
|
||||
$focusedGrid = undefined
|
||||
}}
|
||||
fullScreen={$mode !== 'dnd'}
|
||||
>
|
||||
{#if $app.subgrids?.[`${id}-0`]}
|
||||
<SubGridEditor
|
||||
visible={open && render}
|
||||
{id}
|
||||
{containerHeight}
|
||||
subGridId={`${id}-0`}
|
||||
on:focus={() => {
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [id]
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
}
|
||||
<div
|
||||
class={twMerge('h-full', css?.drawer?.class, 'wm-drawer')}
|
||||
style={css?.drawer?.style}
|
||||
bind:clientHeight={containerHeight}
|
||||
onpointerdown={(e) => {
|
||||
e?.stopPropagation()
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [id]
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</DrawerContent>
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if $app.subgrids?.[`${id}-0`]}
|
||||
<SubGridEditor
|
||||
visible={open && render}
|
||||
{id}
|
||||
{containerHeight}
|
||||
subGridId={`${id}-0`}
|
||||
on:focus={() => {
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [id]
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</DrawerContent>
|
||||
{/snippet}
|
||||
</Drawer>
|
||||
</Portal>
|
||||
{:else if $app.subgrids?.[`${id}-0`]}
|
||||
|
||||
@@ -15,19 +15,32 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let customCss: ComponentCustomCSS<'listcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let initializing: boolean | undefined
|
||||
interface Props {
|
||||
id: string
|
||||
componentInput: AppInput | undefined
|
||||
configuration: RichConfigurations
|
||||
customCss?: ComponentCustomCSS<'listcomponent'> | undefined
|
||||
render: boolean
|
||||
initializing: boolean | undefined
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
componentInput,
|
||||
configuration,
|
||||
customCss = undefined,
|
||||
render,
|
||||
initializing = $bindable()
|
||||
}: Props = $props()
|
||||
|
||||
const { app, focusedGrid, selectedComponent, worldStore, connectingInput, allIdsInPath, mode } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
let page = 0
|
||||
let page = $state(0)
|
||||
|
||||
let everRender = render
|
||||
$: render && !everRender && (everRender = true)
|
||||
let everRender = $state(render)
|
||||
$effect.pre(() => {
|
||||
render && !everRender && (everRender = true)
|
||||
})
|
||||
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
result: undefined,
|
||||
@@ -36,9 +49,8 @@
|
||||
page: 0
|
||||
})
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['listcomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['listcomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
function onFocus() {
|
||||
@@ -48,20 +60,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.listcomponent, customCss)
|
||||
let result: any[] | undefined = undefined
|
||||
let css = $state(initCss($app.css?.listcomponent, customCss))
|
||||
let result: any[] | undefined = $state(undefined)
|
||||
|
||||
$: isCard = resolvedConfig.width?.selected == 'card'
|
||||
let isCard = $derived(resolvedConfig.width?.selected == 'card')
|
||||
|
||||
let inputs = {}
|
||||
let loading: boolean = false
|
||||
let isPreviousLoading = false
|
||||
let isNextLoading = false
|
||||
let inputs = $state({})
|
||||
let loading: boolean = $state(false)
|
||||
let isPreviousLoading = $state(false)
|
||||
let isNextLoading = $state(false)
|
||||
|
||||
$: if (!loading) {
|
||||
isPreviousLoading = false
|
||||
isNextLoading = false
|
||||
}
|
||||
$effect.pre(() => {
|
||||
if (!loading) {
|
||||
isPreviousLoading = false
|
||||
isNextLoading = false
|
||||
}
|
||||
})
|
||||
|
||||
function getPagination(
|
||||
configuration: {
|
||||
@@ -99,11 +113,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: pagination = getPagination(
|
||||
resolvedConfig.pagination?.configuration,
|
||||
resolvedConfig.pagination?.selected,
|
||||
result,
|
||||
page
|
||||
let pagination = $derived(
|
||||
getPagination(
|
||||
resolvedConfig.pagination?.configuration,
|
||||
resolvedConfig.pagination?.selected,
|
||||
result,
|
||||
page
|
||||
)
|
||||
)
|
||||
</script>
|
||||
|
||||
@@ -150,8 +166,8 @@
|
||||
: 'overflow-auto'} {isCard
|
||||
? 'gap-2 flex-wrap'
|
||||
: resolvedConfig?.displayBorders
|
||||
? 'divide-y flex-col'
|
||||
: 'flex-col'}"
|
||||
? 'divide-y flex-col'
|
||||
: 'flex-col'}"
|
||||
>
|
||||
{#if $app.subgrids?.[`${id}-0`] && Array.isArray(result) && result.length > 0}
|
||||
{#each result ?? [] as value, index (index)}
|
||||
@@ -162,16 +178,16 @@
|
||||
isCard
|
||||
? `min-width: ${resolvedConfig.width?.configuration?.card?.minWidthPx}px; `
|
||||
: ''
|
||||
} max-height: ${resolvedConfig.heightPx}px;`
|
||||
} max-height: ${resolvedConfig.heightPx}px;`
|
||||
: ''}
|
||||
class={inRange
|
||||
? `${
|
||||
$allIdsInPath.includes(id)
|
||||
? 'overflow-visible'
|
||||
: resolvedConfig.heightPx
|
||||
? 'overflow-auto'
|
||||
: ''
|
||||
} ${!isCard ? 'w-full' : resolvedConfig?.displayBorders ? 'border' : ''}`
|
||||
? 'overflow-auto'
|
||||
: ''
|
||||
} ${!isCard ? 'w-full' : resolvedConfig?.displayBorders ? 'border' : ''}`
|
||||
: 'h-0 float overflow-hidden invisible absolute'}
|
||||
>
|
||||
<ListWrapper
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { stopPropagation } from 'svelte/legacy'
|
||||
|
||||
import { getContext } from 'svelte'
|
||||
import SubGridEditor from '../../editor/SubGridEditor.svelte'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
@@ -17,16 +19,29 @@
|
||||
import Disposable from '$lib/components/common/drawer/Disposable.svelte'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
|
||||
export let customCss: ComponentCustomCSS<'modalcomponent'> | undefined = undefined
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let noWFull = false
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
customCss?: ComponentCustomCSS<'modalcomponent'> | undefined
|
||||
id: string
|
||||
configuration: RichConfigurations
|
||||
horizontalAlignment?: 'left' | 'center' | 'right' | undefined
|
||||
verticalAlignment?: 'top' | 'center' | 'bottom' | undefined
|
||||
noWFull?: boolean
|
||||
render: boolean
|
||||
onOpenRecomputeIds?: string[] | undefined
|
||||
onCloseRecomputeIds?: string[] | undefined
|
||||
}
|
||||
|
||||
export let onOpenRecomputeIds: string[] | undefined = undefined
|
||||
export let onCloseRecomputeIds: string[] | undefined = undefined
|
||||
let {
|
||||
customCss = undefined,
|
||||
id,
|
||||
configuration,
|
||||
horizontalAlignment = undefined,
|
||||
verticalAlignment = undefined,
|
||||
noWFull = false,
|
||||
render,
|
||||
onOpenRecomputeIds = undefined,
|
||||
onCloseRecomputeIds = undefined
|
||||
}: Props = $props()
|
||||
|
||||
const {
|
||||
app,
|
||||
@@ -40,23 +55,24 @@
|
||||
breakpoint
|
||||
} = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
let everRender = render
|
||||
$: render && !everRender && (everRender = true)
|
||||
let everRender = $state(render)
|
||||
$effect.pre(() => {
|
||||
render && !everRender && (everRender = true)
|
||||
})
|
||||
|
||||
//used so that we can count number of outputs setup for first refresh
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
open: false
|
||||
})
|
||||
|
||||
let css = initCss($app.css?.modalcomponent, customCss)
|
||||
let disposable: Disposable | undefined = undefined
|
||||
let css = $state(initCss($app.css?.modalcomponent, customCss))
|
||||
let disposable: Disposable | undefined = $state(undefined)
|
||||
|
||||
let resolvedConfig = initConfig(
|
||||
components['modalcomponent'].initialData.configuration,
|
||||
configuration
|
||||
let resolvedConfig = $state(
|
||||
initConfig(components['modalcomponent'].initialData.configuration, configuration)
|
||||
)
|
||||
|
||||
let unclickableOutside = false
|
||||
let unclickableOutside = $state(false)
|
||||
function unclosableModal() {
|
||||
unclickableOutside = true
|
||||
setTimeout(() => {
|
||||
@@ -81,14 +97,16 @@
|
||||
disposable?.closeDrawer()
|
||||
}
|
||||
}
|
||||
let wrapperHeight: number = 0
|
||||
let headerHeight: number = 0
|
||||
let wrapperHeight: number = $state(0)
|
||||
let headerHeight: number = $state(0)
|
||||
|
||||
$: containerHeight = Math.min(
|
||||
// 8px * 2 of padding
|
||||
maxHeight($app.subgrids?.[`${id}-0`] ?? [], 0, $breakpoint) * (ROW_HEIGHT + ROW_GAP_Y) + 16,
|
||||
// 32px (2rem) of top and bottom margin
|
||||
wrapperHeight - headerHeight - 64
|
||||
let containerHeight = $derived(
|
||||
Math.min(
|
||||
// 8px * 2 of padding
|
||||
maxHeight($app.subgrids?.[`${id}-0`] ?? [], 0, $breakpoint) * (ROW_HEIGHT + ROW_GAP_Y) + 16,
|
||||
// 32px (2rem) of top and bottom margin
|
||||
wrapperHeight - headerHeight - 64
|
||||
)
|
||||
)
|
||||
|
||||
async function getMenuElements(): Promise<HTMLElement[]> {
|
||||
@@ -154,9 +172,6 @@
|
||||
<Portal target="#app-editor-top-level-drawer" name="app-modal">
|
||||
<Disposable
|
||||
{id}
|
||||
let:handleClickAway
|
||||
let:zIndex
|
||||
let:open
|
||||
bind:this={disposable}
|
||||
on:open={() => {
|
||||
outputs?.open.set(true)
|
||||
@@ -167,80 +182,82 @@
|
||||
onCloseRecomputeIds?.forEach((id) => $runnableComponents?.[id]?.cb?.map((cb) => cb?.()))
|
||||
}}
|
||||
>
|
||||
<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'
|
||||
)}
|
||||
style="z-index: {zIndex}"
|
||||
bind:clientHeight={wrapperHeight}
|
||||
>
|
||||
{#snippet children({ handleClickAway, zIndex, open })}
|
||||
<div
|
||||
style={css?.popup?.style}
|
||||
class={twMerge('mx-24 mt-8 bg-surface wm-modal rounded-lg relative', css?.popup?.class)}
|
||||
use:clickOutside={{
|
||||
capture: false,
|
||||
stopPropagation: false,
|
||||
exclude: getMenuElements
|
||||
}}
|
||||
on:click_outside={(e) => {
|
||||
if ($mode !== 'dnd' && !unclickableOutside) {
|
||||
handleClickAway(e)
|
||||
}
|
||||
}}
|
||||
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}"
|
||||
bind:clientHeight={wrapperHeight}
|
||||
>
|
||||
<div
|
||||
class="px-4 py-2 border-b flex justify-between items-center"
|
||||
bind:clientHeight={headerHeight}
|
||||
>
|
||||
<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={twMerge('wm-modal-container h-full', 'overflow-y-auto', css?.container?.class)}
|
||||
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 wm-modal rounded-lg relative', css?.popup?.class)}
|
||||
use:clickOutside={{
|
||||
capture: false,
|
||||
stopPropagation: false,
|
||||
exclude: getMenuElements,
|
||||
onClickOutside: (e: MouseEvent) => {
|
||||
if ($mode !== 'dnd' && !unclickableOutside) {
|
||||
handleClickAway(e)
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if $app.subgrids?.[`${id}-0`]}
|
||||
<SubGridEditor
|
||||
visible={open && render}
|
||||
{id}
|
||||
{containerHeight}
|
||||
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"
|
||||
bind:clientHeight={headerHeight}
|
||||
>
|
||||
<div>{resolvedConfig.modalTitle}</div>
|
||||
<div class="w-8">
|
||||
<button
|
||||
onclick={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={twMerge('wm-modal-container h-full', 'overflow-y-auto', css?.container?.class)}
|
||||
onpointerdown={(e) => {
|
||||
e?.stopPropagation()
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [id]
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if $app.subgrids?.[`${id}-0`]}
|
||||
<SubGridEditor
|
||||
visible={open && render}
|
||||
{id}
|
||||
{containerHeight}
|
||||
subGridId={`${id}-0`}
|
||||
on:focus={() => {
|
||||
if (!$connectingInput.opened) {
|
||||
$selectedComponent = [id]
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: 0
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Disposable>
|
||||
</Portal>
|
||||
{:else if $app.subgrids?.[`${id}-0`]}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { stopPropagation } from 'svelte/legacy'
|
||||
|
||||
import { getContext } from 'svelte'
|
||||
import SubGridEditor from '../../editor/SubGridEditor.svelte'
|
||||
import type { AppViewerContext, ComponentCustomCSS } from '../../types'
|
||||
@@ -10,14 +12,25 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import ResolveStyle from '../helpers/ResolveStyle.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentContainerHeight: number
|
||||
export let customCss:
|
||||
| ComponentCustomCSS<'horizontalsplitpanescomponent' | 'verticalsplitpanescomponent'>
|
||||
| undefined = undefined
|
||||
export let horizontal: boolean = false
|
||||
export let panes: number[]
|
||||
export let render: boolean
|
||||
interface Props {
|
||||
id: string
|
||||
componentContainerHeight: number
|
||||
customCss?:
|
||||
| ComponentCustomCSS<'horizontalsplitpanescomponent' | 'verticalsplitpanescomponent'>
|
||||
| undefined
|
||||
horizontal?: boolean
|
||||
panes: number[]
|
||||
render: boolean
|
||||
}
|
||||
|
||||
let {
|
||||
id,
|
||||
componentContainerHeight,
|
||||
customCss = undefined,
|
||||
horizontal = false,
|
||||
panes,
|
||||
render
|
||||
}: Props = $props()
|
||||
|
||||
const { app, focusedGrid, selectedComponent, componentControl, worldStore, connectingInput } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
@@ -25,9 +38,11 @@
|
||||
//used so that we can count number of outputs setup for first refresh
|
||||
initOutput($worldStore, id, {})
|
||||
|
||||
let everRender = render
|
||||
let everRender = $state(render)
|
||||
|
||||
$: render && !everRender && (everRender = true)
|
||||
$effect.pre(() => {
|
||||
render && !everRender && (everRender = true)
|
||||
})
|
||||
|
||||
function onFocus() {
|
||||
$focusedGrid = {
|
||||
@@ -36,7 +51,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
let css = initCss($app.css?.containercomponent, customCss)
|
||||
let css = $state(initCss($app.css?.containercomponent, customCss))
|
||||
|
||||
$componentControl[id] = {
|
||||
left: () => {
|
||||
@@ -63,13 +78,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
let sumedup = panes.map((x) => (x / panes.reduce((a, b) => a + b, 0)) * 100)
|
||||
$: {
|
||||
let sumedup = $state(panes.map((x) => (x / panes.reduce((a, b) => a + b, 0)) * 100))
|
||||
$effect.pre(() => {
|
||||
let ns = panes.map((x) => (x / panes.reduce((a, b) => a + b, 0)) * 100)
|
||||
if (!deepEqual(ns, sumedup)) {
|
||||
sumedup = ns
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{#each Object.keys(css ?? {}) as key (key)}
|
||||
@@ -87,20 +102,20 @@
|
||||
<InitializeComponent {id} />
|
||||
|
||||
{#if everRender}
|
||||
<div class="h-full w-full border" on:pointerdown={onFocus}>
|
||||
<div class="h-full w-full border" onpointerdown={onFocus}>
|
||||
{#key sumedup}
|
||||
<Splitpanes {horizontal}>
|
||||
{#each sumedup as paneSize, index (index)}
|
||||
<Pane size={paneSize} minSize={20}>
|
||||
<div
|
||||
class="w-full h-full"
|
||||
on:pointerdown|stopPropagation={() => {
|
||||
onpointerdown={stopPropagation(() => {
|
||||
$selectedComponent = [id]
|
||||
$focusedGrid = {
|
||||
parentComponentId: id,
|
||||
subGridIndex: index
|
||||
}
|
||||
}}
|
||||
})}
|
||||
>
|
||||
{#if $app.subgrids?.[`${id}-${index}`]}
|
||||
<SubGridEditor
|
||||
|
||||
@@ -443,6 +443,7 @@
|
||||
let box: HTMLElement | undefined = $state(undefined)
|
||||
function parseScroll() {
|
||||
$yTop = box?.scrollTop ?? 0
|
||||
// console.log('parse scroll', $yTop)
|
||||
}
|
||||
|
||||
let mounted = false
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { stopPropagation } from 'svelte/legacy'
|
||||
|
||||
import { push } from '$lib/history'
|
||||
import { classNames } from '$lib/utils'
|
||||
import { createEventDispatcher, getContext, onDestroy } from 'svelte'
|
||||
@@ -21,18 +23,31 @@
|
||||
import GridViewer from './GridViewer.svelte'
|
||||
import GridEditorMenu from './GridEditorMenu.svelte'
|
||||
|
||||
export let containerHeight: number | undefined = undefined
|
||||
export let containerWidth: number | undefined = undefined
|
||||
let classes = ''
|
||||
interface Props {
|
||||
containerHeight?: number | undefined
|
||||
containerWidth?: number | undefined
|
||||
class?: string
|
||||
style?: string
|
||||
noPadding?: boolean
|
||||
noYPadding?: boolean
|
||||
subGridId: string
|
||||
visible?: boolean
|
||||
id: string
|
||||
shouldHighlight?: boolean
|
||||
}
|
||||
|
||||
export { classes as class }
|
||||
export let style = ''
|
||||
export let noPadding = false
|
||||
export let noYPadding = false
|
||||
export let subGridId: string
|
||||
export let visible: boolean = true
|
||||
export let id: string
|
||||
export let shouldHighlight: boolean = true
|
||||
let {
|
||||
containerHeight = undefined,
|
||||
containerWidth = undefined,
|
||||
class: classes = '',
|
||||
style = '',
|
||||
noPadding = false,
|
||||
noYPadding = false,
|
||||
subGridId,
|
||||
visible = true,
|
||||
id,
|
||||
shouldHighlight = true
|
||||
}: Props = $props()
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
@@ -50,17 +65,19 @@
|
||||
|
||||
const editorContext = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
let isActive = false
|
||||
let isActive = $state(false)
|
||||
let sber = editorContext?.componentActive?.subscribe((x) => (isActive = x))
|
||||
|
||||
let everVisible = visible
|
||||
let everVisible = $state(visible)
|
||||
|
||||
$: visible && !everVisible && (everVisible = true)
|
||||
$effect.pre(() => {
|
||||
visible && !everVisible && (everVisible = true)
|
||||
})
|
||||
|
||||
onDestroy(() => {
|
||||
sber?.()
|
||||
})
|
||||
$: highlight = id === $focusedGrid?.parentComponentId && shouldHighlight
|
||||
let highlight = $derived(id === $focusedGrid?.parentComponentId && shouldHighlight)
|
||||
|
||||
const onpointerdown = (e) => {
|
||||
dispatch('focus')
|
||||
@@ -80,9 +97,11 @@
|
||||
$app = $app
|
||||
}
|
||||
|
||||
let container: HTMLElement | undefined = undefined
|
||||
let container: HTMLElement | undefined = $state(undefined)
|
||||
|
||||
$: maxRow = maxHeight($app.subgrids?.[subGridId] ?? [], containerHeight ?? 0, $breakpoint)
|
||||
let maxRow = $derived(
|
||||
maxHeight($app.subgrids?.[subGridId] ?? [], containerHeight ?? 0, $breakpoint)
|
||||
)
|
||||
|
||||
export function moveComponentBetweenSubgrids(
|
||||
componentId: string,
|
||||
@@ -177,13 +196,15 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- {visible}
|
||||
{everVisible} -->
|
||||
{#if everVisible || $app.eagerRendering}
|
||||
<div
|
||||
class="translate-x-0 translate-y-0 w-full subgrid {visible
|
||||
? 'visible'
|
||||
: 'invisible h-0 overflow-hidden'}"
|
||||
bind:this={container}
|
||||
on:pointerdown={onpointerdown}
|
||||
{onpointerdown}
|
||||
>
|
||||
<div
|
||||
class={twMerge(
|
||||
@@ -204,6 +225,7 @@
|
||||
}`
|
||||
: ''}
|
||||
>
|
||||
<!-- A{JSON.stringify($app.subgrids?.[subGridId]) ?? []}B -->
|
||||
<Grid
|
||||
allIdsInPath={$allIdsInPath}
|
||||
items={$app.subgrids?.[subGridId] ?? []}
|
||||
@@ -214,10 +236,6 @@
|
||||
}
|
||||
}}
|
||||
selectedIds={$selectedComponent}
|
||||
let:dataItem
|
||||
let:overlapped
|
||||
let:moveMode
|
||||
let:componentDraggedId
|
||||
scroller={container}
|
||||
parentWidth={$parentWidth - 17}
|
||||
{containerWidth}
|
||||
@@ -250,81 +268,86 @@
|
||||
}}
|
||||
disableMove={!!$connectingInput.opened}
|
||||
>
|
||||
<ComponentWrapper
|
||||
id={dataItem.id}
|
||||
type={dataItem.data.type}
|
||||
class={classNames(
|
||||
'h-full w-full center-center',
|
||||
$selectedComponent?.includes(dataItem.id) ? 'active-grid-item' : '',
|
||||
'top-0'
|
||||
)}
|
||||
>
|
||||
<GridEditorMenu id={dataItem.id}>
|
||||
<Component
|
||||
{overlapped}
|
||||
fullHeight={dataItem?.[$breakpoint === 'sm' ? 3 : 12]?.fullHeight}
|
||||
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)
|
||||
{#snippet children({ dataItem, overlapped, moveMode, componentDraggedId })}
|
||||
<ComponentWrapper
|
||||
id={dataItem.id}
|
||||
type={dataItem.data.type}
|
||||
class={classNames(
|
||||
'h-full w-full center-center',
|
||||
$selectedComponent?.includes(dataItem.id) ? 'active-grid-item' : '',
|
||||
'top-0'
|
||||
)}
|
||||
>
|
||||
<GridEditorMenu id={dataItem.id}>
|
||||
<Component
|
||||
{overlapped}
|
||||
fullHeight={dataItem?.[$breakpoint === 'sm' ? 3 : 12]?.fullHeight}
|
||||
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
|
||||
}}
|
||||
on:fillHeight={() => {
|
||||
const gridItem = findGridItem($app, dataItem.id)
|
||||
const b = $breakpoint === 'sm' ? 3 : 12
|
||||
expandGriditem(
|
||||
$app.subgrids?.[subGridId] ?? [],
|
||||
dataItem.id,
|
||||
$breakpoint,
|
||||
parentGridItem
|
||||
)
|
||||
$app = $app
|
||||
}}
|
||||
on:fillHeight={() => {
|
||||
const gridItem = findGridItem($app, dataItem.id)
|
||||
const b = $breakpoint === 'sm' ? 3 : 12
|
||||
|
||||
if (gridItem?.[b]) {
|
||||
gridItem[b].fullHeight = !gridItem[b].fullHeight
|
||||
}
|
||||
$app = $app
|
||||
}}
|
||||
{moveMode}
|
||||
{componentDraggedId}
|
||||
/>
|
||||
</GridEditorMenu>
|
||||
</ComponentWrapper>
|
||||
if (gridItem?.[b]) {
|
||||
gridItem[b].fullHeight = !gridItem[b].fullHeight
|
||||
}
|
||||
$app = $app
|
||||
}}
|
||||
{moveMode}
|
||||
{componentDraggedId}
|
||||
/>
|
||||
</GridEditorMenu>
|
||||
</ComponentWrapper>
|
||||
{/snippet}
|
||||
</Grid>
|
||||
</div>
|
||||
{:else}
|
||||
<GridViewer
|
||||
allIdsInPath={$allIdsInPath}
|
||||
items={$app.subgrids?.[subGridId] ?? []}
|
||||
let:dataItem
|
||||
breakpoint={$breakpoint}
|
||||
parentWidth={$parentWidth - 17}
|
||||
{containerWidth}
|
||||
{maxRow}
|
||||
>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
on:pointerdown|stopPropagation={(e) => selectComponent(e, dataItem.id)}
|
||||
class={classNames('h-full w-full center-center', 'top-0')}
|
||||
>
|
||||
<Component
|
||||
fullHeight={dataItem?.[$breakpoint === 'sm' ? 3 : 12]?.fullHeight}
|
||||
render={visible}
|
||||
component={dataItem.data}
|
||||
selected={Boolean($selectedComponent?.includes(dataItem.id))}
|
||||
locked={isFixed(dataItem)}
|
||||
/>
|
||||
</div>
|
||||
{#snippet children({ dataItem })}
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<div
|
||||
onpointerdown={stopPropagation((e) =>
|
||||
selectComponent(e as PointerEvent, dataItem.id)
|
||||
)}
|
||||
class={classNames('h-full w-full center-center', 'top-0')}
|
||||
>
|
||||
<Component
|
||||
fullHeight={dataItem?.[$breakpoint === 'sm' ? 3 : 12]?.fullHeight}
|
||||
render={visible}
|
||||
component={dataItem.data}
|
||||
selected={Boolean($selectedComponent?.includes(dataItem.id))}
|
||||
locked={isFixed(dataItem)}
|
||||
/>
|
||||
</div>
|
||||
{/snippet}
|
||||
</GridViewer>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -476,7 +476,7 @@ export function appComponentFromType<T extends keyof typeof components>(
|
||||
),
|
||||
recomputeIds: init.recomputeIds ? [] : undefined,
|
||||
actionButtons: init.actionButtons ? [] : undefined,
|
||||
actions: [],
|
||||
actions: undefined,
|
||||
menuItems: init.menuItems ? [] : undefined,
|
||||
numberOfSubgrids: init.numberOfSubgrids,
|
||||
horizontalAlignment: override?.horizontalAlignment ?? init.horizontalAlignment,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<script lang="ts" context="module">
|
||||
<script lang="ts" module>
|
||||
import { writable } from 'svelte/store'
|
||||
|
||||
const componentDraggedIdStore = writable<string | undefined>(undefined)
|
||||
@@ -42,35 +42,51 @@
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
export let items: FilledItem<T>[]
|
||||
export let rowHeight: number = ROW_HEIGHT
|
||||
interface Props {
|
||||
items: FilledItem<T>[]
|
||||
rowHeight?: number
|
||||
gap?: any
|
||||
throttleUpdate?: number
|
||||
throttleResize?: number
|
||||
selectedIds: string[] | undefined
|
||||
allIdsInPath: string[] | undefined
|
||||
containerWidth?: number | undefined
|
||||
scroller?: HTMLElement | undefined
|
||||
sensor?: number
|
||||
root?: boolean
|
||||
parentWidth?: number | undefined
|
||||
disableMove?: boolean
|
||||
children?: import('svelte').Snippet<[any]>
|
||||
}
|
||||
|
||||
export let gap = [ROW_GAP_X, ROW_GAP_Y]
|
||||
export let throttleUpdate = 100
|
||||
export let throttleResize = 100
|
||||
export let selectedIds: string[] | undefined
|
||||
export let allIdsInPath: string[] | undefined
|
||||
export let containerWidth: number | undefined = undefined
|
||||
export let scroller: HTMLElement | undefined = undefined
|
||||
export let sensor = 20
|
||||
export let root: boolean = false
|
||||
export let parentWidth: number | undefined = undefined
|
||||
export let disableMove: boolean = false
|
||||
let {
|
||||
items,
|
||||
rowHeight = ROW_HEIGHT,
|
||||
gap = [ROW_GAP_X, ROW_GAP_Y],
|
||||
throttleUpdate = 100,
|
||||
throttleResize = 100,
|
||||
selectedIds,
|
||||
allIdsInPath,
|
||||
containerWidth = $bindable(undefined),
|
||||
scroller = undefined,
|
||||
sensor = 20,
|
||||
root = false,
|
||||
parentWidth = undefined,
|
||||
disableMove = false,
|
||||
children
|
||||
}: Props = $props()
|
||||
const cols = columnConfiguration
|
||||
|
||||
let getComputedCols: 3 | 12 | undefined =
|
||||
let getComputedCols: 3 | 12 | undefined = $state(
|
||||
$app.mobileViewOnSmallerScreens == false ? WIDE_GRID_COLUMNS : undefined
|
||||
let container
|
||||
)
|
||||
let container = $state()
|
||||
|
||||
$: [gapX, gapY] = gap
|
||||
|
||||
let xPerPx = 0
|
||||
let xPerPx = $state(0)
|
||||
let yPerPx = rowHeight
|
||||
|
||||
$: containerHeight = getContainerHeight(items, yPerPx, getComputedCols)
|
||||
|
||||
const onResize = throttle(() => {
|
||||
items = specifyUndefinedColumns(items, getComputedCols, cols)
|
||||
sortedItems = specifyUndefinedColumns(sortedItems, getComputedCols, cols)
|
||||
dispatch('resize', {
|
||||
cols: getComputedCols,
|
||||
xPerPx,
|
||||
@@ -79,7 +95,7 @@
|
||||
})
|
||||
}, throttleUpdate)
|
||||
|
||||
let mounted = false
|
||||
let mounted = $state(false)
|
||||
|
||||
onMount(() => {
|
||||
const sizeObserver = new ResizeObserver((entries) => {
|
||||
@@ -99,7 +115,7 @@
|
||||
xPerPx = width / getComputedCols!
|
||||
|
||||
if (!containerWidth) {
|
||||
items = specifyUndefinedColumns(items, getComputedCols, cols)
|
||||
sortedItems = specifyUndefinedColumns(sortedItems, getComputedCols, cols)
|
||||
|
||||
dispatch('mount', {
|
||||
cols: getComputedCols,
|
||||
@@ -115,15 +131,14 @@
|
||||
})
|
||||
})
|
||||
|
||||
sizeObserver.observe(container)
|
||||
sizeObserver.observe(container as Element)
|
||||
|
||||
return () => sizeObserver.disconnect()
|
||||
})
|
||||
|
||||
let sortedItems: FilledItem<T>[] = []
|
||||
$: sortedItems = smartCopy(items).sort((a, b) => a.id.localeCompare(b.id))
|
||||
let sortedItems: FilledItem<T>[] = $state([])
|
||||
|
||||
let resizing: boolean = false
|
||||
let resizing: boolean = $state(false)
|
||||
|
||||
function handleKeyUp(event) {
|
||||
if ((event.key === 'Control' || event.key === 'Meta') && $isCtrlOrMetaPressedStore) {
|
||||
@@ -199,9 +214,9 @@
|
||||
return item
|
||||
})
|
||||
|
||||
let { items } = moveItem(activeItem, fixedContainer, getComputedCols)
|
||||
let { items: nitems } = moveItem(activeItem, fixedContainer, getComputedCols)
|
||||
|
||||
items = items.map((item) => {
|
||||
nitems = nitems.map((item) => {
|
||||
if (initialFixedStates.has(item.id)) {
|
||||
const initialState = initialFixedStates.get(item.id)
|
||||
|
||||
@@ -213,12 +228,12 @@
|
||||
return item
|
||||
})
|
||||
|
||||
sortedItems = items
|
||||
sortedItems = nitems
|
||||
}
|
||||
} else {
|
||||
let { items } = moveItem(activeItem, sortedItems, getComputedCols)
|
||||
let { items: nitems } = moveItem(activeItem, sortedItems, getComputedCols)
|
||||
|
||||
sortedItems = items
|
||||
sortedItems = nitems
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,8 +253,16 @@
|
||||
|
||||
//let hiddenComponents = writable({})
|
||||
|
||||
let lastDetail: { isPointerUp: false; activate: false; id: string | undefined } | undefined =
|
||||
undefined
|
||||
let lastDetail:
|
||||
| {
|
||||
cordDiff: { x: number; y: number }
|
||||
clientY: number
|
||||
intersectingElement?: string | undefined
|
||||
shadow?: GridShadow | undefined
|
||||
overlapped?: string | undefined
|
||||
}
|
||||
| undefined = $state(undefined)
|
||||
|
||||
const handleRepaint = ({ detail }) => {
|
||||
if (!detail.isPointerUp) {
|
||||
throttleMatrix({ detail })
|
||||
@@ -273,12 +296,20 @@
|
||||
}
|
||||
|
||||
let moveResizes: Record<string, MoveResize> = {}
|
||||
let shadows: Record<string, { x: number; y: number; w: number; h: number } | undefined> = {}
|
||||
let shadows: Record<string, { x: number; y: number; w: number; h: number } | undefined> = $state(
|
||||
{}
|
||||
)
|
||||
|
||||
export function handleMove({ detail }) {
|
||||
export function handleMove(detail: {
|
||||
cordDiff: { x: number; y: number }
|
||||
clientY: number
|
||||
intersectingElement?: string | undefined
|
||||
shadow?: GridShadow | undefined
|
||||
overlapped?: string | undefined
|
||||
}) {
|
||||
Object.entries(moveResizes).forEach(([id, moveResize]) => {
|
||||
if (selectedIds?.includes(id)) {
|
||||
moveResize?.updateMove(structuredClone(stateSnapshot(detail.cordDiff)), detail.eventY)
|
||||
moveResize?.updateMove(detail.cordDiff, detail.clientY)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -304,7 +335,7 @@
|
||||
draggedItem[getComputedCols].y = detail.shadow.y
|
||||
}
|
||||
|
||||
let items: GridItem[] = []
|
||||
let nitems: GridItem[] = []
|
||||
|
||||
if ($overlappedStore) {
|
||||
const div = document.getElementById(`component-${$overlappedStore}`)
|
||||
@@ -316,16 +347,16 @@
|
||||
|
||||
const index = type ? subGridIndexKey(type, $overlappedStore, $worldStore) : 0
|
||||
|
||||
items = $app.subgrids[`${$overlappedStore}-${index}`] ?? []
|
||||
nitems = $app.subgrids[`${$overlappedStore}-${index}`] ?? []
|
||||
} else {
|
||||
items = $app.grid ?? []
|
||||
nitems = $app.grid ?? []
|
||||
}
|
||||
|
||||
if (!draggedItem) {
|
||||
return
|
||||
}
|
||||
|
||||
const freeSpace = gridHelp.findSpace(draggedItem, items, getComputedCols)
|
||||
const freeSpace = gridHelp.findSpace(draggedItem, nitems, getComputedCols)
|
||||
|
||||
$fakeShadowStore = {
|
||||
x: freeSpace.x,
|
||||
@@ -357,16 +388,21 @@
|
||||
}
|
||||
})
|
||||
}
|
||||
let [gapX, gapY] = $derived(gap)
|
||||
let containerHeight = $derived(getContainerHeight(items, yPerPx, getComputedCols))
|
||||
$effect.pre(() => {
|
||||
sortedItems = smartCopy(items).sort((a, b) => a.id.localeCompare(b.id))
|
||||
})
|
||||
</script>
|
||||
|
||||
<svelte:window
|
||||
on:focus={() => {
|
||||
onfocus={() => {
|
||||
if ($isCtrlOrMetaPressedStore) {
|
||||
$isCtrlOrMetaPressedStore = false
|
||||
}
|
||||
}}
|
||||
on:keydown={handleKeyDown}
|
||||
on:keyup={handleKeyUp}
|
||||
onkeydown={handleKeyDown}
|
||||
onkeyup={handleKeyUp}
|
||||
/>
|
||||
|
||||
<div
|
||||
@@ -458,7 +494,7 @@
|
||||
<MoveResize
|
||||
{mounted}
|
||||
on:initmove={() => handleInitMove(item.id)}
|
||||
on:move={handleMove}
|
||||
onMove={handleMove}
|
||||
bind:shadow={shadows[item.id]}
|
||||
bind:this={moveResizes[item.id]}
|
||||
on:repaint={handleRepaint}
|
||||
@@ -502,13 +538,13 @@
|
||||
{disableMove}
|
||||
>
|
||||
{#if item[getComputedCols]}
|
||||
<slot
|
||||
dataItem={item}
|
||||
hidden={false}
|
||||
overlapped={$overlappedStore}
|
||||
moveMode={$isCtrlOrMetaPressedStore ? 'insert' : 'move'}
|
||||
componentDraggedId={$componentDraggedIdStore}
|
||||
/>
|
||||
{@render children?.({
|
||||
dataItem: item,
|
||||
hidden: false,
|
||||
overlapped: $overlappedStore,
|
||||
moveMode: $isCtrlOrMetaPressedStore ? 'insert' : 'move',
|
||||
componentDraggedId: $componentDraggedIdStore
|
||||
})}
|
||||
{/if}
|
||||
</MoveResize>
|
||||
{/if}
|
||||
|
||||
@@ -13,33 +13,65 @@
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
export let sensor
|
||||
export let width
|
||||
export let height
|
||||
export let left
|
||||
export let top
|
||||
interface Props {
|
||||
sensor: any
|
||||
width: any
|
||||
height: any
|
||||
left: any
|
||||
top: any
|
||||
id: any
|
||||
container: any
|
||||
xPerPx: any
|
||||
yPerPx: any
|
||||
gapX: any
|
||||
gapY: any
|
||||
item: any
|
||||
cols: any
|
||||
nativeContainer: any
|
||||
onTop: any
|
||||
shadow?: { x: number; y: number; w: number; h: number } | undefined
|
||||
overlapped?: string | undefined
|
||||
moveMode?: 'move' | 'insert'
|
||||
type?: string | undefined
|
||||
fakeShadow?: GridShadow | undefined
|
||||
disableMove?: boolean
|
||||
mounted?: boolean
|
||||
onMove: (detail: {
|
||||
cordDiff: { x: number; y: number }
|
||||
clientY: number
|
||||
intersectingElement?: string | undefined
|
||||
shadow?: GridShadow | undefined
|
||||
overlapped?: string | undefined
|
||||
}) => void
|
||||
children?: import('svelte').Snippet
|
||||
}
|
||||
|
||||
export let id
|
||||
export let container
|
||||
|
||||
export let xPerPx
|
||||
export let yPerPx
|
||||
|
||||
export let gapX
|
||||
export let gapY
|
||||
export let item
|
||||
|
||||
export let cols
|
||||
|
||||
export let nativeContainer
|
||||
export let onTop
|
||||
export let shadow: { x: number; y: number; w: number; h: number } | undefined = undefined
|
||||
export let overlapped: string | undefined = undefined
|
||||
export let moveMode: 'move' | 'insert' = 'move'
|
||||
export let type: string | undefined = undefined
|
||||
export let fakeShadow: GridShadow | undefined = undefined
|
||||
export let disableMove: boolean = true
|
||||
export let mounted: boolean = false
|
||||
let {
|
||||
sensor,
|
||||
width,
|
||||
height,
|
||||
left,
|
||||
top,
|
||||
id,
|
||||
container,
|
||||
xPerPx,
|
||||
yPerPx,
|
||||
gapX,
|
||||
gapY,
|
||||
item,
|
||||
cols,
|
||||
nativeContainer,
|
||||
onTop,
|
||||
shadow = $bindable(undefined),
|
||||
overlapped = undefined,
|
||||
moveMode = 'move',
|
||||
type = undefined,
|
||||
fakeShadow = undefined,
|
||||
disableMove = true,
|
||||
mounted = false,
|
||||
onMove,
|
||||
children
|
||||
}: Props = $props()
|
||||
|
||||
const ctx = getContext<AppEditorContext>('AppEditorContext')
|
||||
const { mode, app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
@@ -47,9 +79,9 @@
|
||||
const scale = ctx ? ctx.scale : writable(100)
|
||||
|
||||
const divId = `component-${id}`
|
||||
let shadowElement
|
||||
let shadowElement: HTMLElement | undefined = $state()
|
||||
|
||||
let active = false
|
||||
let active = $state(false)
|
||||
|
||||
let initX, initY
|
||||
|
||||
@@ -58,10 +90,10 @@
|
||||
y: 0
|
||||
}
|
||||
|
||||
let cordDiff = { x: 0, y: 0 }
|
||||
let cordDiff = $state({ x: 0, y: 0 })
|
||||
|
||||
let newSize = { width, height }
|
||||
let trans = false
|
||||
let newSize = $state({ width, height })
|
||||
let trans = $state(false)
|
||||
|
||||
let anima
|
||||
|
||||
@@ -88,7 +120,7 @@
|
||||
y: (moveY / $scale) * 100 - initY
|
||||
}
|
||||
|
||||
dispatch('move', { cordDiff, clientY: clientY })
|
||||
onMove({ cordDiff, clientY: clientY })
|
||||
}
|
||||
return x
|
||||
})
|
||||
@@ -114,6 +146,8 @@
|
||||
shadowBound = irect
|
||||
}
|
||||
|
||||
if (!rect) return
|
||||
|
||||
const xdragBound = rect.left + cordDiff.x
|
||||
const ydragBound = rect.top + cordDiff.y
|
||||
|
||||
@@ -142,7 +176,7 @@
|
||||
// Autoscroll
|
||||
let _scrollTop = 0
|
||||
let containerFrame
|
||||
let rect
|
||||
let rect = $state() as { top: number; left: number } | undefined
|
||||
let scrollElement
|
||||
|
||||
const getContainerFrame = (element) => {
|
||||
@@ -205,7 +239,6 @@
|
||||
|
||||
containerFrame = getContainerFrame(container)
|
||||
scrollElement = getScroller(container)
|
||||
|
||||
_scrollTop = scrollElement.scrollTop
|
||||
}
|
||||
|
||||
@@ -256,7 +289,7 @@
|
||||
const cordDiff = { x: (clientX / $scale) * 100 - initX, y: (clientY / $scale) * 100 - initY }
|
||||
|
||||
if (moveMode === 'move') {
|
||||
dispatch('move', {
|
||||
onMove({
|
||||
cordDiff,
|
||||
clientY,
|
||||
intersectingElement: undefined,
|
||||
@@ -268,7 +301,7 @@
|
||||
|
||||
throttledComputeShadow(clientX, clientY)
|
||||
|
||||
dispatch('move', {
|
||||
onMove({
|
||||
cordDiff,
|
||||
clientY,
|
||||
intersectingElement: currentIntersectingElementId,
|
||||
@@ -285,7 +318,6 @@
|
||||
trans = false
|
||||
}
|
||||
cordDiff = newCoordDiff
|
||||
// console.log(cordDiff, id, 'B')
|
||||
const Y_SENSOR = sensor
|
||||
|
||||
if (containerFrame) {
|
||||
@@ -317,7 +349,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
let element: HTMLElement | undefined = undefined
|
||||
let element: HTMLElement | undefined = $state(undefined)
|
||||
|
||||
function computeShadow(clientX: number, clientY: number) {
|
||||
const elementsAtPoint = document.elementsFromPoint(clientX, clientY)
|
||||
@@ -481,12 +513,16 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
||||
<div
|
||||
bind:this={element}
|
||||
draggable="false"
|
||||
on:pointerdown|stopPropagation|preventDefault={pointerdown}
|
||||
onpointerdown={(e) => {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
pointerdown(e)
|
||||
}}
|
||||
id={divId}
|
||||
class="svlt-grid-item"
|
||||
data-iscontainer={type ? isContainer(type) : false}
|
||||
@@ -495,30 +531,26 @@
|
||||
style="width: {xPerPx == 0 ? 0 : active ? newSize.width : width}px; height:{xPerPx == 0
|
||||
? 0
|
||||
: active
|
||||
? newSize.height
|
||||
: height}px;
|
||||
? newSize.height
|
||||
: height}px;
|
||||
{xPerPx == 0 ? 'overflow: hidden;' : ''}
|
||||
{onTop ? 'z-index: 1000;' : ''}
|
||||
|
||||
{active && rect
|
||||
? `transform: translate(${cordDiff.x}px, ${cordDiff.y}px);top:${rect.top}px;left:${rect.left}px;z-index:10000;`
|
||||
: trans
|
||||
? `transform: translate(${cordDiff.x}px, ${cordDiff.y}px); position:absolute; transition: width 0.2s, height 0.2s;`
|
||||
: `${
|
||||
xPerPx > 0 && mounted ? 'transition: transform 0.1s, opacity 0.1s;' : ''
|
||||
} transform: translate(${left}px, ${top}px); `} "
|
||||
? `transform: translate(${cordDiff.x}px, ${cordDiff.y}px); position:absolute; transition: width 0.2s, height 0.2s;`
|
||||
: `${
|
||||
xPerPx > 0 && mounted ? 'transition: transform 0.1s, opacity 0.1s;' : ''
|
||||
} transform: translate(${left}px, ${top}px); `} "
|
||||
>
|
||||
<slot />
|
||||
{@render children?.()}
|
||||
{#if moveMode === 'move' && !disableMove}
|
||||
<div
|
||||
class="svlt-grid-resizer-bottom"
|
||||
on:pointerdown={(e) => resizePointerDown(e, 'vertical')}
|
||||
<div class="svlt-grid-resizer-bottom" onpointerdown={(e) => resizePointerDown(e, 'vertical')}
|
||||
></div>
|
||||
<div
|
||||
class="svlt-grid-resizer-side"
|
||||
on:pointerdown={(e) => resizePointerDown(e, 'horizontal')}
|
||||
<div class="svlt-grid-resizer-side" onpointerdown={(e) => resizePointerDown(e, 'horizontal')}
|
||||
></div>
|
||||
<div class="svlt-grid-resizer" on:pointerdown={(e) => resizePointerDown(e, 'both')}></div>
|
||||
<div class="svlt-grid-resizer" onpointerdown={(e) => resizePointerDown(e, 'both')}></div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -141,13 +141,13 @@ export function moveItem(active, items, cols) {
|
||||
}
|
||||
|
||||
// Update items
|
||||
items = updateItem(items, active, item, cols)
|
||||
const nitems = updateItem(items, active, item, cols)
|
||||
|
||||
// Create matrix of items expect close elements
|
||||
matrix = makeMatrixFromItemsIgnore(items, closeBlocks, getRowsCount(items, cols), cols)
|
||||
matrix = makeMatrixFromItemsIgnore(nitems, closeBlocks, getRowsCount(nitems, cols), cols)
|
||||
|
||||
// Create temp vars
|
||||
let tempItems = items
|
||||
let tempItems = nitems
|
||||
let tempCloseBlocks = closeBlocks
|
||||
|
||||
// Exclude resolved elements ids in array
|
||||
|
||||
@@ -54,7 +54,7 @@ export function createAppFromScript(path: string, schema: Record<string, any> |
|
||||
style: ''
|
||||
}
|
||||
},
|
||||
actions: [],
|
||||
actions: undefined,
|
||||
numberOfSubgrids: 1,
|
||||
id: 'topbar'
|
||||
},
|
||||
@@ -478,7 +478,7 @@ export function createAppFromScript(path: string, schema: Record<string, any> |
|
||||
style: ''
|
||||
}
|
||||
},
|
||||
actions: [],
|
||||
actions: undefined,
|
||||
horizontalAlignment: 'left',
|
||||
verticalAlignment: 'center',
|
||||
id: 'title'
|
||||
@@ -511,7 +511,6 @@ export function createAppFromScript(path: string, schema: Record<string, any> |
|
||||
class: ''
|
||||
}
|
||||
},
|
||||
actions: [],
|
||||
menuItems: [],
|
||||
horizontalAlignment: 'right',
|
||||
verticalAlignment: 'center',
|
||||
@@ -616,7 +615,6 @@ export function createAppFromFlow(path: string, schema: Record<string, any> | un
|
||||
style: ''
|
||||
}
|
||||
},
|
||||
actions: [],
|
||||
numberOfSubgrids: 1,
|
||||
id: 'topbar'
|
||||
},
|
||||
@@ -1041,7 +1039,6 @@ export function createAppFromFlow(path: string, schema: Record<string, any> | un
|
||||
style: ''
|
||||
}
|
||||
},
|
||||
actions: [],
|
||||
horizontalAlignment: 'left',
|
||||
verticalAlignment: 'center',
|
||||
id: 'title'
|
||||
@@ -1074,7 +1071,6 @@ export function createAppFromFlow(path: string, schema: Record<string, any> | un
|
||||
class: ''
|
||||
}
|
||||
},
|
||||
actions: [],
|
||||
menuItems: [],
|
||||
horizontalAlignment: 'right',
|
||||
verticalAlignment: 'center',
|
||||
|
||||
@@ -80,7 +80,6 @@ const emptyApp = {
|
||||
style: ''
|
||||
}
|
||||
},
|
||||
actions: [],
|
||||
numberOfSubgrids: 1,
|
||||
id: 'a'
|
||||
},
|
||||
@@ -163,7 +162,6 @@ const emptyApp = {
|
||||
style: ''
|
||||
}
|
||||
},
|
||||
actions: [],
|
||||
horizontalAlignment: 'left',
|
||||
verticalAlignment: 'center',
|
||||
id: 'b'
|
||||
@@ -190,7 +188,6 @@ const emptyApp = {
|
||||
data: {
|
||||
type: 'recomputeallcomponent',
|
||||
configuration: {},
|
||||
actions: [],
|
||||
menuItems: [],
|
||||
horizontalAlignment: 'right',
|
||||
verticalAlignment: 'center',
|
||||
|
||||
@@ -34,10 +34,10 @@
|
||||
$importStore = undefined
|
||||
}
|
||||
|
||||
const state = nodraft ? undefined : localStorage.getItem('app')
|
||||
const appState = nodraft ? undefined : localStorage.getItem('app')
|
||||
|
||||
let summary = ''
|
||||
let value: App = {
|
||||
let summary = $state('')
|
||||
let value: App = $state({
|
||||
grid: [],
|
||||
fullscreen: false,
|
||||
unusedInlineScripts: [],
|
||||
@@ -46,7 +46,7 @@
|
||||
type: 'path',
|
||||
path: DEFAULT_THEME
|
||||
}
|
||||
}
|
||||
})
|
||||
afterNavigate(() => {
|
||||
if (nodraft) {
|
||||
let url = new URL($page.url.href)
|
||||
@@ -54,13 +54,13 @@
|
||||
replaceState(url.toString(), $page.state)
|
||||
}
|
||||
})
|
||||
let policy: Policy = {
|
||||
let policy: Policy = $state({
|
||||
on_behalf_of: $userStore?.username.includes('@')
|
||||
? $userStore?.username
|
||||
: `u/${$userStore?.username}`,
|
||||
on_behalf_of_email: $userStore?.email,
|
||||
execution_mode: 'publisher'
|
||||
}
|
||||
})
|
||||
|
||||
loadApp()
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
summary = hub.app.summary
|
||||
sendUserToast('App loaded from Hub')
|
||||
goto('?', { replaceState: true })
|
||||
} else if (!templatePath && !hubId && state) {
|
||||
} else if (!templatePath && !hubId && appState) {
|
||||
sendUserToast('App restored from browser stored autosave', false, [
|
||||
{
|
||||
label: 'Start from blank',
|
||||
@@ -116,7 +116,7 @@
|
||||
}
|
||||
}
|
||||
])
|
||||
value = decodeState(state)
|
||||
value = decodeState(appState)
|
||||
} else {
|
||||
const preset = presets['topbarcomponent']
|
||||
|
||||
@@ -168,18 +168,17 @@
|
||||
replaceStateFn={(path) => replaceState(path, $page.state)}
|
||||
gotoFn={(path, opt) => goto(path, opt)}
|
||||
>
|
||||
<svelte:fragment
|
||||
slot="unsavedConfirmationModal"
|
||||
let:diffDrawer
|
||||
let:additionalExitAction
|
||||
let:getInitialAndModifiedValues
|
||||
>
|
||||
{#snippet unsavedConfirmationModal({
|
||||
diffDrawer,
|
||||
additionalExitAction,
|
||||
getInitialAndModifiedValues
|
||||
})}
|
||||
<UnsavedConfirmationModal
|
||||
{diffDrawer}
|
||||
{additionalExitAction}
|
||||
{getInitialAndModifiedValues}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</AppEditor>
|
||||
{/key}
|
||||
</div>
|
||||
|
||||
@@ -16,8 +16,11 @@
|
||||
import type { App } from '$lib/components/apps/types'
|
||||
import UnsavedConfirmationModal from '$lib/components/common/confirmationModal/UnsavedConfirmationModal.svelte'
|
||||
import { stateSnapshot } from '$lib/svelte5Utils.svelte'
|
||||
import { untrack } from 'svelte'
|
||||
|
||||
let app = undefined as (AppWithLastVersion & { draft_only?: boolean; value: any }) | undefined
|
||||
let app = $state(
|
||||
undefined as (AppWithLastVersion & { draft_only?: boolean; value: any }) | undefined
|
||||
)
|
||||
let savedApp:
|
||||
| {
|
||||
value: App
|
||||
@@ -28,8 +31,8 @@
|
||||
draft_only?: boolean
|
||||
custom_path?: string
|
||||
}
|
||||
| undefined = undefined
|
||||
let redraw = 0
|
||||
| undefined = $state(undefined)
|
||||
let redraw = $state(0)
|
||||
let path = $page.params.path
|
||||
|
||||
let nodraft = $page.url.searchParams.get('nodraft')
|
||||
@@ -93,8 +96,8 @@
|
||||
actions.push({
|
||||
label: 'Show diff',
|
||||
callback: async () => {
|
||||
diffDrawer.openDrawer()
|
||||
diffDrawer.setDiff({
|
||||
diffDrawer?.openDrawer()
|
||||
diffDrawer?.setDiff({
|
||||
mode: 'simple',
|
||||
original: draftOrDeployed,
|
||||
current: urlScript,
|
||||
@@ -139,8 +142,8 @@
|
||||
{
|
||||
label: 'Show diff',
|
||||
callback: async () => {
|
||||
diffDrawer.openDrawer()
|
||||
diffDrawer.setDiff({
|
||||
diffDrawer?.openDrawer()
|
||||
diffDrawer?.setDiff({
|
||||
mode: 'simple',
|
||||
original: deployed,
|
||||
current: draft,
|
||||
@@ -156,18 +159,20 @@
|
||||
}
|
||||
}
|
||||
|
||||
$: {
|
||||
$effect(() => {
|
||||
if ($workspaceStore) {
|
||||
loadApp()
|
||||
untrack(() => {
|
||||
loadApp()
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
async function restoreDraft() {
|
||||
if (!savedApp || !savedApp.draft) {
|
||||
sendUserToast('Could not restore to draft', true)
|
||||
return
|
||||
}
|
||||
diffDrawer.closeDrawer()
|
||||
diffDrawer?.closeDrawer()
|
||||
goto(`/apps/edit/${savedApp.draft.path}`)
|
||||
await loadApp()
|
||||
redraw++
|
||||
@@ -178,7 +183,7 @@
|
||||
sendUserToast('Could not restore to deployed', true)
|
||||
return
|
||||
}
|
||||
diffDrawer.closeDrawer()
|
||||
diffDrawer?.closeDrawer()
|
||||
if (savedApp.draft) {
|
||||
await DraftService.deleteDraft({
|
||||
workspace: $workspaceStore!,
|
||||
@@ -191,7 +196,7 @@
|
||||
redraw++
|
||||
}
|
||||
|
||||
let diffDrawer: DiffDrawer
|
||||
let diffDrawer: DiffDrawer | undefined = $state()
|
||||
|
||||
function onRestore(ev: any) {
|
||||
sendUserToast('App restored from previous deployment')
|
||||
@@ -233,18 +238,17 @@
|
||||
replaceStateFn={(path) => replaceState(path, $page.state)}
|
||||
gotoFn={(path, opt) => goto(path, opt)}
|
||||
>
|
||||
<svelte:fragment
|
||||
slot="unsavedConfirmationModal"
|
||||
let:diffDrawer
|
||||
let:additionalExitAction
|
||||
let:getInitialAndModifiedValues
|
||||
>
|
||||
{#snippet unsavedConfirmationModal({
|
||||
diffDrawer,
|
||||
additionalExitAction,
|
||||
getInitialAndModifiedValues
|
||||
})}
|
||||
<UnsavedConfirmationModal
|
||||
{diffDrawer}
|
||||
{additionalExitAction}
|
||||
{getInitialAndModifiedValues}
|
||||
/>
|
||||
</svelte:fragment>
|
||||
{/snippet}
|
||||
</AppEditor>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user