mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-24 08:01:38 +00:00
improve type definition of apps and sync them with static components + purge app content of unecessary data
This commit is contained in:
@@ -23,7 +23,7 @@
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let noWFull = false
|
||||
export let preclickAction: (() => Promise<void>) | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'button'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'buttoncomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let initializing: boolean | undefined = true
|
||||
|
||||
@@ -158,10 +158,10 @@
|
||||
<Button
|
||||
btnClasses={twMerge(
|
||||
$app.css?.['buttoncomponent']?.['button']?.class,
|
||||
customCss?.button.class,
|
||||
customCss?.button?.class,
|
||||
resolvedConfig.fillContainer ? 'w-full h-full' : ''
|
||||
)}
|
||||
style={[$app.css?.['buttoncomponent']?.['button']?.style, customCss?.button.style].join(';')}
|
||||
style={[$app.css?.['buttoncomponent']?.['button']?.style, customCss?.button?.style].join(';')}
|
||||
disabled={resolvedConfig.disabled}
|
||||
on:pointerdown={(e) => {
|
||||
e?.stopPropagation()
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
export let recomputeIds: string[] | undefined = undefined
|
||||
export let extraQueryParams: Record<string, any> = {}
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'container' | 'button'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'formcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
export const staticOutputs: string[] = ['loading', 'result']
|
||||
@@ -72,7 +72,7 @@
|
||||
autoRefresh={false}
|
||||
forceSchemaDisplay={true}
|
||||
runnableClass="!block"
|
||||
runnableStyle={css?.container.style}
|
||||
runnableStyle={css?.container?.style}
|
||||
>
|
||||
<AlignWrapper {horizontalAlignment}>
|
||||
<div
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
export let extraQueryParams: Record<string, any> = {}
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'button' | 'popup'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'formbuttoncomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
export const staticOutputs: string[] = ['loading', 'result']
|
||||
@@ -85,8 +85,8 @@
|
||||
<Modal
|
||||
{open}
|
||||
title={labelValue}
|
||||
class={css?.popup.class}
|
||||
style={css?.popup.style}
|
||||
class={css?.popup?.class}
|
||||
style={css?.popup?.style}
|
||||
on:canceled={() => {
|
||||
open = false
|
||||
}}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'barchartcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'header' | 'container'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'displaycomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const requireHtmlApproval = getContext<boolean | undefined>(IS_APP_PUBLIC_CONTEXT_KEY)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'htmlcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = 'left'
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let customCss: ComponentCustomCSS<'container' | 'icon'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'iconcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let customCss: ComponentCustomCSS<'image'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'imagecomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let customCss: ComponentCustomCSS<'map'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'mapcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore, selectedComponent, connectingInput, focusedGrid, mode } =
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { getDocument, type PDFDocumentProxy, type PDFPageProxy } from 'pdfjs-dist'
|
||||
import 'pdfjs-dist/build/pdf.worker.entry'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfiguration, RichConfigurations } from '../../types'
|
||||
import type {
|
||||
AppViewerContext,
|
||||
ComponentCustomCSS,
|
||||
RichConfiguration,
|
||||
RichConfigurations
|
||||
} from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import { throttle } from '../../../../utils'
|
||||
@@ -14,14 +19,13 @@
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'pdfcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, mode, worldStore, selectedComponent } =
|
||||
getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
initOutput($worldStore, id, {
|
||||
result: undefined,
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
loading: false
|
||||
})
|
||||
|
||||
@@ -63,6 +67,7 @@
|
||||
return
|
||||
}
|
||||
try {
|
||||
outputs.loading.set(true)
|
||||
await resetDoc()
|
||||
doc = await getDocument(src).promise
|
||||
pageNumber = 1
|
||||
@@ -73,6 +78,7 @@
|
||||
error = err?.message ?? (typeof err === 'string' ? err : 'Error loading PDF')
|
||||
console.log(err)
|
||||
}
|
||||
outputs.loading.set(false)
|
||||
}
|
||||
|
||||
async function renderPdf(scaleToViewport = true, resizing = false) {
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'piechartcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -19,19 +19,14 @@
|
||||
import type { ChartOptions, ChartData } from 'chart.js'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import { getContext } from 'svelte'
|
||||
import type {
|
||||
AppViewerContext,
|
||||
ComponentCustomCSS,
|
||||
RichConfiguration,
|
||||
RichConfigurations
|
||||
} from '../../types'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
import { initOutput } from '../../editor/appUtils'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'scatterchartcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
let zoomable = false
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
AppEditorContext,
|
||||
AppViewerContext,
|
||||
ComponentCustomCSS,
|
||||
RichConfiguration,
|
||||
RichConfigurations
|
||||
} from '../../types'
|
||||
import { getContext } from 'svelte'
|
||||
@@ -25,7 +24,7 @@
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'text'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'textcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore, mode } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -20,12 +20,7 @@
|
||||
import { Scatter } from 'svelte-chartjs'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import type { ChartOptions, ChartData } from 'chart.js'
|
||||
import type {
|
||||
AppViewerContext,
|
||||
ComponentCustomCSS,
|
||||
RichConfiguration,
|
||||
RichConfigurations
|
||||
} from '../../types'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
import { getContext } from 'svelte'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import { initOutput } from '../../editor/appUtils'
|
||||
@@ -34,7 +29,7 @@
|
||||
export let componentInput: AppInput | undefined
|
||||
export let configuration: RichConfigurations
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'timeseriescomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -28,9 +28,7 @@
|
||||
export let configuration: RichConfigurations
|
||||
export let actionButtons: (BaseAppComponent & ButtonComponent)[]
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss:
|
||||
| ComponentCustomCSS<'container' | 'tableHeader' | 'tableBody' | 'tableFooter'>
|
||||
| undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'tablecomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
type T = Record<string, any>
|
||||
@@ -339,8 +337,8 @@
|
||||
paginationEnabled={pagination}
|
||||
{result}
|
||||
{table}
|
||||
class={css?.tableFooter.class}
|
||||
style={css?.tableFooter.style}
|
||||
class={css?.tableFooter?.class}
|
||||
style={css?.tableFooter?.style}
|
||||
/>
|
||||
</div>
|
||||
{:else if result != undefined}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
export let extraContext: Record<string, any> = {}
|
||||
export let key: string = ''
|
||||
|
||||
$: console.log(value)
|
||||
const { componentControl } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
@@ -27,7 +26,6 @@
|
||||
|
||||
let lastInput = input ? JSON.parse(JSON.stringify(input)) : undefined
|
||||
|
||||
$: console.log(input)
|
||||
$: if (input && !deepEqual(input, lastInput)) {
|
||||
lastInput = JSON.parse(JSON.stringify(input))
|
||||
// Needed because of file uploads
|
||||
@@ -65,7 +63,6 @@
|
||||
debounce(async () => (value = await evalExpr(lastInput)))
|
||||
|
||||
async function handleConnection() {
|
||||
console.log('handleConnection', lastInput)
|
||||
if (lastInput.type === 'connected') {
|
||||
$worldStore?.connect<any>(lastInput, onValueChange, `${id}-${key}`)
|
||||
} else if (lastInput.type === 'static' || lastInput.type == 'template') {
|
||||
|
||||
@@ -20,10 +20,6 @@
|
||||
result: Output<any>
|
||||
}
|
||||
|
||||
$: if (outputs?.loading != undefined) {
|
||||
outputs.loading.set(false, true)
|
||||
}
|
||||
|
||||
function setOutput(v: any) {
|
||||
outputs?.result?.set(v, true)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import Alert from '$lib/components/common/alert/Alert.svelte'
|
||||
import LightweightSchemaForm from '$lib/components/LightweightSchemaForm.svelte'
|
||||
import Popover from '$lib/components/Popover.svelte'
|
||||
import SchemaForm from '$lib/components/SchemaForm.svelte'
|
||||
import TestJobLoader from '$lib/components/TestJobLoader.svelte'
|
||||
import { AppService, type CompletedJob } from '$lib/gen'
|
||||
import { classNames, defaultIfEmptyString, emptySchema, sendUserToast } from '$lib/utils'
|
||||
@@ -51,7 +50,7 @@
|
||||
|
||||
$: autoRefresh && handleAutorefresh()
|
||||
|
||||
if (recomputable) {
|
||||
if (recomputable || autoRefresh) {
|
||||
$runnableComponents[id] = async () => {
|
||||
await executeComponent(true)
|
||||
}
|
||||
@@ -60,9 +59,6 @@
|
||||
|
||||
function handleAutorefresh() {
|
||||
if (autoRefresh && $worldStore) {
|
||||
$runnableComponents[id] = async () => {
|
||||
await executeComponent(true)
|
||||
}
|
||||
executeComponent(true)
|
||||
}
|
||||
}
|
||||
@@ -193,7 +189,7 @@
|
||||
|
||||
if (runnable?.type === 'runnableByName') {
|
||||
const { inlineScript } = runnable
|
||||
|
||||
// console.log(inlineScript?.content)
|
||||
if (inlineScript) {
|
||||
requestBody['raw_code'] = {
|
||||
content: inlineScript.content,
|
||||
@@ -260,6 +256,10 @@
|
||||
$: result?.error && recordError(result.error)
|
||||
</script>
|
||||
|
||||
<!-- {#if runnable?.type == 'runnableByName'}
|
||||
{runnable?.inlineScript?.content}
|
||||
{/if} -->
|
||||
|
||||
{#each Object.entries(fields ?? {}) as [key, v] (key)}
|
||||
{#if v.type != 'static' && v.type != 'user'}
|
||||
<InputValue {key} {id} input={fields[key]} bind:value={runnableInputValues[key]} />
|
||||
|
||||
@@ -35,14 +35,14 @@
|
||||
$staticExporter[id] = () => result
|
||||
})
|
||||
|
||||
function isRunnableDefined() {
|
||||
function isRunnableDefined(componentInput) {
|
||||
return isScriptByNameDefined(componentInput) || isScriptByPathDefined(componentInput)
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if componentInput === undefined}
|
||||
<slot />
|
||||
{:else if componentInput.type === 'runnable' && isRunnableDefined()}
|
||||
{:else if componentInput.type === 'runnable' && isRunnableDefined(componentInput)}
|
||||
<RunnableComponent
|
||||
{recomputeIds}
|
||||
gotoUrl={goto}
|
||||
|
||||
@@ -4,12 +4,7 @@
|
||||
import { initOutput } from '../../editor/appUtils'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type {
|
||||
AppViewerContext,
|
||||
ComponentCustomCSS,
|
||||
RichConfiguration,
|
||||
RichConfigurations
|
||||
} from '../../types'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import AlignWrapper from '../helpers/AlignWrapper.svelte'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
@@ -18,7 +13,7 @@
|
||||
export let configuration: RichConfigurations
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'text'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'checkboxcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
export let configuration: RichConfigurations
|
||||
export let inputType: 'date'
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'dateinputcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore, selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -3,15 +3,13 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { FileInput } from '../../../common'
|
||||
import { initOutput } from '../../editor/appUtils'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { Output } from '../../rx'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'containercomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
export let configuration: RichConfigurations
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'multiselectcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore, connectingInput, selectedComponent } =
|
||||
@@ -66,7 +66,6 @@
|
||||
multiple
|
||||
on:change={(e) => e.stopPropagation()}
|
||||
{items}
|
||||
class={css?.input?.class ?? ''}
|
||||
inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles}
|
||||
containerStyles={'border-color: #999;' +
|
||||
SELECT_INPUT_DEFAULT_STYLE.containerStyles +
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'numberinputcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore, selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'handles' | 'bar' | 'limits' | 'values'> | undefined =
|
||||
undefined
|
||||
export let customCss: ComponentCustomCSS<'rangecomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
export let configuration: RichConfigurations
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'selectcomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore, connectingInput, selectedComponent } =
|
||||
|
||||
@@ -13,8 +13,7 @@
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'handle' | 'limits' | 'value' | 'bar'> | undefined =
|
||||
undefined
|
||||
export let customCss: ComponentCustomCSS<'slidercomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore, selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
export let configuration: RichConfigurations
|
||||
export let inputType = 'text'
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'textinputcomponent'> | undefined = undefined
|
||||
export let appCssKey: 'textinputcomponent' | 'passwordinputcomponent' | 'emailinputcomponent' =
|
||||
'textinputcomponent'
|
||||
export let render: boolean
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'currencycomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import SubGridEditor from '../../editor/SubGridEditor.svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { AppViewerContext, ComponentCustomCSS, GridItem } from '../../types'
|
||||
import type { AppViewerContext, ComponentCustomCSS } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
|
||||
export let id: string
|
||||
export let componentContainerHeight: number
|
||||
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'containercomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
|
||||
const { app, focusedGrid, selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
|
||||
@@ -29,8 +28,8 @@
|
||||
<SubGridEditor
|
||||
visible={render}
|
||||
{id}
|
||||
class={css?.container.class}
|
||||
style={css?.container.style}
|
||||
class={css?.container?.class}
|
||||
style={css?.container?.style}
|
||||
bind:subGrid={$app.subgrids[`${id}-0`]}
|
||||
containerHeight={componentContainerHeight}
|
||||
on:focus={() => {
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
export let configuration: RichConfigurations
|
||||
export let horizontalAlignment: HorizontalAlignment | undefined = undefined
|
||||
export let verticalAlignment: VerticalAlignment | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'container' | 'divider'> | undefined = undefined
|
||||
export let customCss:
|
||||
| ComponentCustomCSS<'verticaldividercomponent' | 'horizontaldividercomponent'>
|
||||
| undefined = undefined
|
||||
export let position: 'horizontal' | 'vertical'
|
||||
export let render: boolean
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import SubGridEditor from '../../editor/SubGridEditor.svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import Portal from 'svelte-portal'
|
||||
@@ -10,7 +9,7 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import { AlignWrapper } from '../helpers'
|
||||
|
||||
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'drawercomponent'> | undefined = undefined
|
||||
export let id: string
|
||||
export let configuration: RichConfigurations
|
||||
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
|
||||
@@ -80,8 +79,8 @@
|
||||
<SubGridEditor
|
||||
visible={open && render}
|
||||
{id}
|
||||
class={css?.container.class}
|
||||
style={css?.container.style}
|
||||
class={css?.container?.class}
|
||||
style={css?.container?.style}
|
||||
bind:subGrid={$app.subgrids[`${id}-0`]}
|
||||
containerHeight={1200}
|
||||
on:focus={() => {
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import SubGridEditor from '../../editor/SubGridEditor.svelte'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type {
|
||||
AppEditorContext,
|
||||
AppViewerContext,
|
||||
ComponentCustomCSS,
|
||||
RichConfigurations
|
||||
} from '../../types'
|
||||
import type { AppViewerContext, ComponentCustomCSS } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import InputValue from '../helpers/InputValue.svelte'
|
||||
import { Pane, Splitpanes } from 'svelte-splitpanes'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
|
||||
export let id: string
|
||||
export let componentContainerHeight: number
|
||||
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
|
||||
export let customCss:
|
||||
| ComponentCustomCSS<'horizontalsplitpanescomponent' | 'verticalsplitpanescomponent'>
|
||||
| undefined = undefined
|
||||
export let horizontal: boolean = false
|
||||
export let panes: number[]
|
||||
export let render: boolean
|
||||
@@ -76,8 +71,8 @@
|
||||
visible={render}
|
||||
{id}
|
||||
shouldHighlight={$focusedGrid?.subGridIndex === index}
|
||||
class={css?.container.class}
|
||||
style={css?.container.style}
|
||||
class={css?.container?.class}
|
||||
style={css?.container?.style}
|
||||
bind:subGrid={$app.subgrids[`${id}-${index}`]}
|
||||
containerHeight={horizontal ? undefined : componentContainerHeight - 8}
|
||||
on:focus={() => {
|
||||
|
||||
@@ -12,9 +12,7 @@
|
||||
export let configuration: RichConfigurations
|
||||
export let componentContainerHeight: number
|
||||
export let tabs: string[]
|
||||
export let customCss:
|
||||
| ComponentCustomCSS<'tabRow' | 'tabs' | 'selectedTab' | 'container'>
|
||||
| undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'tabscomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let initializing: boolean | undefined = configuration.tabsKind != undefined
|
||||
|
||||
@@ -100,8 +98,8 @@
|
||||
{#each tabs ?? [] as res}
|
||||
<Tab
|
||||
value={res}
|
||||
class={css?.tabs?.class}
|
||||
style={css?.tabs?.style}
|
||||
class={css?.allTabs?.class}
|
||||
style={css?.allTabs?.style}
|
||||
selectedClass={css?.selectedTab?.class}
|
||||
selectedStyle={css?.selectedTab?.style}
|
||||
>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
import Component from './component/Component.svelte'
|
||||
import { deepEqual } from 'fast-equals'
|
||||
import { push } from '$lib/history'
|
||||
import { expandGriditem, findGridItem } from './appUtils'
|
||||
import { expandGriditem} from './appUtils'
|
||||
import Grid from '../svelte-grid/Grid.svelte'
|
||||
|
||||
export let policy: Policy
|
||||
@@ -180,9 +180,8 @@
|
||||
locked={isFixed(dataItem)}
|
||||
on:delete={() => removeGridElement(dataItem.data)}
|
||||
on:lock={() => {
|
||||
const gridItem = findGridItem($app, dataItem.data.id)
|
||||
if (gridItem) {
|
||||
toggleFixed(gridItem)
|
||||
if (dataItem.data) {
|
||||
toggleFixed(dataItem)
|
||||
}
|
||||
$app = $app
|
||||
}}
|
||||
@@ -190,7 +189,6 @@
|
||||
push(history, $app)
|
||||
$selectedComponent = dataItem.data.id
|
||||
expandGriditem($app.grid, dataItem, $breakpoint)
|
||||
$app = $app
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -57,9 +57,8 @@
|
||||
}
|
||||
|
||||
function lock(dataItem: GridItem) {
|
||||
let fComponent = findGridItem($app, dataItem.data.id)
|
||||
if (fComponent) {
|
||||
fComponent = toggleFixed(fComponent)
|
||||
if (dataItem) {
|
||||
toggleFixed(dataItem)
|
||||
}
|
||||
$app = $app
|
||||
}
|
||||
|
||||
@@ -1,6 +1,21 @@
|
||||
import { getNextId } from '$lib/components/flows/flowStateUtils'
|
||||
import type { App, ConnectingInput, EditorBreakpoint, FocusedGrid, GridItem } from '../types'
|
||||
import { getRecommendedDimensionsByComponent, type AppComponent } from './component'
|
||||
import type {
|
||||
App,
|
||||
BaseAppComponent,
|
||||
ConnectingInput,
|
||||
EditorBreakpoint,
|
||||
FocusedGrid,
|
||||
GridItem,
|
||||
StaticRichConfigurations
|
||||
} from '../types'
|
||||
import {
|
||||
ccomponents,
|
||||
components,
|
||||
getRecommendedDimensionsByComponent,
|
||||
type AppComponent,
|
||||
type BaseComponent,
|
||||
type TypedComponent
|
||||
} from './component'
|
||||
import { gridColumns } from '../gridUtils'
|
||||
import { allItems } from '../utils'
|
||||
import type { Output, World } from '../rx'
|
||||
@@ -73,8 +88,7 @@ export function getAllRecomputeIdsForComponent(app: App, id: string) {
|
||||
|
||||
export function createNewGridItem(grid: GridItem[], id: string, data: AppComponent): GridItem {
|
||||
const newComponent = {
|
||||
resizable: true,
|
||||
draggable: true,
|
||||
fixed: false,
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
@@ -92,13 +106,8 @@ export function createNewGridItem(grid: GridItem[], id: string, data: AppCompone
|
||||
|
||||
newItem[column] = {
|
||||
...newComponent,
|
||||
min: { w: 1, h: 1 },
|
||||
max: { w: column, h: 100 },
|
||||
w: rec.w,
|
||||
h: rec.h,
|
||||
customDragger: false,
|
||||
customResizer: false,
|
||||
fixed: false
|
||||
h: rec.h
|
||||
}
|
||||
const position = gridHelp.findSpace(newItem, grid, column) as { x: number; y: number }
|
||||
newItem[column] = { ...newItem[column], ...position }
|
||||
@@ -117,14 +126,48 @@ export function getGridItems(app: App, focusedGrid: FocusedGrid | undefined): Gr
|
||||
}
|
||||
}
|
||||
|
||||
export function appComponentFromType<T extends keyof typeof components>(
|
||||
type: T
|
||||
): (id: string) => BaseAppComponent & BaseComponent<T> {
|
||||
return (id: string) => {
|
||||
const init = ccomponents[type].initialData
|
||||
return {
|
||||
type,
|
||||
//TODO remove tooltip and onlyStatic from there
|
||||
configuration: Object.fromEntries(
|
||||
Object.entries(init.configuration).map(([key, value]) => {
|
||||
if (value.ctype === undefined) {
|
||||
if (value.type === 'static') {
|
||||
return [key, { type: value.type, value: value.value }]
|
||||
} else if (value.type === 'eval') {
|
||||
return [key, { type: value.type, expr: value.expr }]
|
||||
}
|
||||
}
|
||||
return [key, value]
|
||||
})
|
||||
),
|
||||
componentInput: init.componentInput,
|
||||
panes: init.panes,
|
||||
tabs: init.tabs,
|
||||
customCss: {},
|
||||
recomputeIds: init.recomputeIds ? [] : undefined,
|
||||
actionButtons: init.actionButtons ? [] : undefined,
|
||||
numberOfSubgrids: init.numberOfSubgrids,
|
||||
horizontalAlignment: init.horizontalAlignment,
|
||||
verticalAlignment: init.verticalAlignment,
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
export function insertNewGridItem(
|
||||
app: App,
|
||||
data: AppComponent,
|
||||
builddata: (id: string) => AppComponent,
|
||||
focusedGrid: FocusedGrid | undefined,
|
||||
keepId?: boolean
|
||||
keepId?: string
|
||||
) {
|
||||
const id = keepId ? data.id : getNextGridItemId(app)
|
||||
const id = keepId ?? getNextGridItemId(app)
|
||||
|
||||
const data = builddata(id)
|
||||
if (!app.subgrids) {
|
||||
app.subgrids = {}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import type { AppViewerContext } from '../../types'
|
||||
import ComponentHeader from '../ComponentHeader.svelte'
|
||||
import type { AppComponent } from './components'
|
||||
import { ccomponents, components, type AppComponent } from './components'
|
||||
import {
|
||||
AppBarChart,
|
||||
AppDisplayComponent,
|
||||
@@ -54,6 +54,8 @@
|
||||
|
||||
$: componentWithErrors = Object.values($errorByComponent).map((e) => e.componentId)
|
||||
$: hasError = componentWithErrors.includes(component.id)
|
||||
|
||||
console.log('component', component)
|
||||
</script>
|
||||
|
||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||
@@ -88,7 +90,7 @@
|
||||
'h-full bg-white/40 outline-1',
|
||||
$hoverStore === component.id && $mode !== 'preview' ? 'outline outline-blue-600' : '',
|
||||
selected && $mode !== 'preview' ? 'outline outline-indigo-600' : '',
|
||||
component.softWrap || hasError ? '' : 'overflow-auto',
|
||||
ccomponents[component.type].softWrap || hasError ? '' : 'overflow-auto',
|
||||
$mode != 'preview' ? 'cursor-pointer' : '',
|
||||
'relative z-auto',
|
||||
$app.css?.['app']?.['component']?.class
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
function handlePaste(event: KeyboardEvent) {
|
||||
push(history, $app)
|
||||
|
||||
if (tempGridItem) {
|
||||
if (tempGridItem != undefined) {
|
||||
if (
|
||||
$focusedGrid &&
|
||||
getAllSubgridsAndComponentIds($app, tempGridItem.data)[0].includes(
|
||||
@@ -169,11 +169,13 @@
|
||||
grid.splice(idx, 1)
|
||||
}
|
||||
|
||||
insertNewGridItem($app, tempGridItem.data, $focusedGrid, true)
|
||||
const gridItem = tempGridItem
|
||||
insertNewGridItem($app, (id) => ({ ...gridItem.data, id }), $focusedGrid, tempGridItem.id)
|
||||
copiedGridItem = tempGridItem
|
||||
tempGridItem = undefined
|
||||
} else if (copiedGridItem) {
|
||||
insertNewGridItem($app, copiedGridItem.data, $focusedGrid, false)
|
||||
const gridItem = copiedGridItem
|
||||
insertNewGridItem($app, (id) => ({ ...gridItem.data, id }), $focusedGrid)
|
||||
}
|
||||
|
||||
$worldStore = $worldStore
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,38 +1,40 @@
|
||||
import type { AppComponent } from "."
|
||||
import type { AppComponent } from '.'
|
||||
|
||||
export function defaultCode(component: string, language: string): string | undefined {
|
||||
return DEFAULT_CODES[component]?.[language]
|
||||
}
|
||||
|
||||
export const DEFAULT_CODES: Partial<Record<AppComponent['type'], Record<'deno' | 'python3', string>>> = {
|
||||
export const DEFAULT_CODES: Partial<
|
||||
Record<AppComponent['type'], Record<'deno' | 'python3', string>>
|
||||
> = {
|
||||
tablecomponent: {
|
||||
deno: `export async function main() {
|
||||
return [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "A cell with a long name",
|
||||
"age": 42
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "A briefer cell",
|
||||
"age": 84
|
||||
}
|
||||
]
|
||||
}`,
|
||||
return [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "A cell with a long name",
|
||||
"age": 42
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "A briefer cell",
|
||||
"age": 84
|
||||
}
|
||||
]
|
||||
}`,
|
||||
python3: `def main():
|
||||
return [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "A cell with a long name",
|
||||
"age": 42
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "A briefer cell",
|
||||
"age": 84
|
||||
}
|
||||
]`
|
||||
return [
|
||||
{
|
||||
"id": 1,
|
||||
"name": "A cell with a long name",
|
||||
"age": 42
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "A briefer cell",
|
||||
"age": 84
|
||||
}
|
||||
]`
|
||||
},
|
||||
textcomponent: {
|
||||
deno: `export async function main() {
|
||||
@@ -322,4 +324,4 @@ return "smile";
|
||||
python3: `def main():
|
||||
return "smile"`
|
||||
}
|
||||
} as const
|
||||
} as const
|
||||
|
||||
@@ -3,9 +3,14 @@
|
||||
import { getContext } from 'svelte'
|
||||
import { fade, slide } from 'svelte/transition'
|
||||
import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore'
|
||||
import { components as componentsRecord, COMPONENT_SETS, type AppComponent } from '../component'
|
||||
import {
|
||||
components as componentsRecord,
|
||||
COMPONENT_SETS,
|
||||
type AppComponent,
|
||||
type TypedComponent
|
||||
} from '../component'
|
||||
import ListItem from './ListItem.svelte'
|
||||
import { insertNewGridItem } from '../appUtils'
|
||||
import { appComponentFromType, insertNewGridItem } from '../appUtils'
|
||||
import { X } from 'lucide-svelte'
|
||||
import { push } from '$lib/history'
|
||||
import { flip } from 'svelte/animate'
|
||||
@@ -15,13 +20,16 @@
|
||||
|
||||
const { history } = getContext<AppEditorContext>('AppEditorContext')
|
||||
|
||||
function addComponent(appComponentType: AppComponent['type']): void {
|
||||
function addComponent(appComponentType: TypedComponent['type']): void {
|
||||
push(history, $app)
|
||||
|
||||
$dirtyStore = true
|
||||
|
||||
const data = componentsRecord[appComponentType].data
|
||||
const id = insertNewGridItem($app, data, $focusedGrid)
|
||||
const id = insertNewGridItem(
|
||||
$app,
|
||||
appComponentFromType(appComponentType) as (id: string) => AppComponent,
|
||||
$focusedGrid
|
||||
)
|
||||
|
||||
$selectedComponent = id
|
||||
$worldStore = $worldStore
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
import type { ComponentCssProperty } from '../../types'
|
||||
|
||||
export let name: string
|
||||
export let value: ComponentCssProperty | undefined
|
||||
export let value: ComponentCssProperty = {}
|
||||
export let forceStyle: boolean = false
|
||||
export let forceClass: boolean = false
|
||||
|
||||
function reset(property: keyof ComponentCssProperty) {
|
||||
if (value) {
|
||||
@@ -19,7 +21,7 @@
|
||||
</div>
|
||||
{#if value}
|
||||
<div class="border-l border-gray-400/80 py-1 pl-3.5 mt-1 ml-0.5">
|
||||
{#if value.style !== undefined}
|
||||
{#if value.style !== undefined || forceStyle}
|
||||
<label class="block pb-2">
|
||||
<div class="text-xs font-medium pb-0.5"> Style </div>
|
||||
<div class="relative">
|
||||
@@ -43,7 +45,7 @@
|
||||
</div>
|
||||
</label>
|
||||
{/if}
|
||||
{#if value.class !== undefined}
|
||||
{#if value.class !== undefined || forceClass}
|
||||
<label class="block">
|
||||
<div class="text-xs font-medium pb-0.5"> Tailwind classes </div>
|
||||
<div class="relative">
|
||||
|
||||
@@ -1,27 +1,24 @@
|
||||
<script lang="ts">
|
||||
import { onMount, getContext } from 'svelte'
|
||||
import { LayoutDashboardIcon, MousePointer2, CurlyBraces } from 'lucide-svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import { LayoutDashboardIcon, MousePointer2, CurlyBraces, X } from 'lucide-svelte'
|
||||
import SimpleEditor from '$lib/components/SimpleEditor.svelte'
|
||||
import { emptyString } from '$lib/utils'
|
||||
import { Tab, TabContent, Tabs } from '../../../common'
|
||||
import type { AppViewerContext } from '../../types'
|
||||
import ListItem from './ListItem.svelte'
|
||||
import { isOpenStore } from './store'
|
||||
import CssProperty from './CssProperty.svelte'
|
||||
import { components, type AppComponent } from '../component'
|
||||
import { slide } from 'svelte/transition'
|
||||
import { ccomponents, components, type AppComponent, type TypedComponent } from '../component'
|
||||
|
||||
const STATIC_ELEMENTS = ['app'] as const
|
||||
const TITLE_PREFIX = 'Css.' as const
|
||||
const SHOW_UNUSED_ID = 'Setting.ShowUnused' as const
|
||||
|
||||
type CustomCSSType = (typeof STATIC_ELEMENTS)[number] | AppComponent['type']
|
||||
type CustomCSSType = (typeof STATIC_ELEMENTS)[number] | keyof typeof components
|
||||
|
||||
interface CustomCSSEntry {
|
||||
type: CustomCSSType
|
||||
name: string
|
||||
icon: any
|
||||
ids: string[]
|
||||
ids: { id: string; forceStyle: boolean; forceClass: boolean }[]
|
||||
}
|
||||
|
||||
const { app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
@@ -55,64 +52,21 @@
|
||||
type: 'app',
|
||||
name: 'App',
|
||||
icon: LayoutDashboardIcon,
|
||||
ids: ['viewer', 'grid', 'component']
|
||||
ids: ['viewer', 'grid', 'component'].map((id) => ({ id, forceStyle: true, forceClass: true }))
|
||||
},
|
||||
...Object.values(components).map(({ name, icon, data: { type, customCss } }) => ({
|
||||
type,
|
||||
...Object.entries(ccomponents).map(([type, { name, icon, customCss }]) => ({
|
||||
type: type as keyof typeof components,
|
||||
name,
|
||||
icon,
|
||||
ids: Object.keys(customCss ?? {}) ?? []
|
||||
ids: Object.entries(customCss).map(([id, v]) => ({
|
||||
id,
|
||||
forceStyle: v?.style != undefined,
|
||||
forceClass: v?.['class'] != undefined
|
||||
}))
|
||||
}))
|
||||
]
|
||||
let isCustom: Record<string, boolean> = Object.fromEntries(
|
||||
Object.keys(entries).map((k) => [k, false])
|
||||
)
|
||||
|
||||
let newCss = $app.css ?? {}
|
||||
entries.forEach((e) => {
|
||||
if (!newCss[e.type]) {
|
||||
isCustom[e.type] = true
|
||||
newCss[e.type] = {}
|
||||
}
|
||||
e.ids.forEach((id) => {
|
||||
if (!newCss[e.type][id]) {
|
||||
newCss[e.type][id] = components?.[e.type]?.data?.customCss?.[id] ?? { class: '', style: '' }
|
||||
}
|
||||
})
|
||||
e.ids
|
||||
.map((id) => newCss[e.type][id].class != '' || newCss[e.type][id].style != '')
|
||||
.forEach((c) => {
|
||||
if (c) {
|
||||
isCustom[e.type] = true
|
||||
}
|
||||
})
|
||||
})
|
||||
//@ts-ignore
|
||||
$app.css = newCss
|
||||
|
||||
$: staticComponents = entries.filter(({ type }) => STATIC_ELEMENTS.includes(type as any))
|
||||
$: usedComponents = Object.keys(
|
||||
$app.grid.reduce((acc, { data }) => {
|
||||
acc[data.type] = true
|
||||
return acc
|
||||
}, {})
|
||||
)
|
||||
.map((type) => entries.find((entry) => entry.type === type))
|
||||
.filter(Boolean) as CustomCSSEntry[]
|
||||
$: unusedComponents = entries.filter(({ type }) => {
|
||||
return (
|
||||
!STATIC_ELEMENTS.includes(type as any) && !usedComponents.find((entry) => entry.type === type)
|
||||
)
|
||||
})
|
||||
|
||||
onMount(() => {
|
||||
isOpenStore.addItems(
|
||||
[{ name: 'App' }, ...Object.values(components)].map((component) => {
|
||||
return { [TITLE_PREFIX + component.name]: false }
|
||||
})
|
||||
)
|
||||
isOpenStore.addItems([{ [SHOW_UNUSED_ID]: false }])
|
||||
})
|
||||
entries.sort((a, b) => a.name.localeCompare(b.name))
|
||||
let search = ''
|
||||
</script>
|
||||
|
||||
<Tabs selected="ui" on:selected={(e) => switchTab(e.detail === 'json')} class="relative">
|
||||
@@ -130,9 +84,38 @@
|
||||
</Tab>
|
||||
<div slot="content" class="h-full overflow-y-auto">
|
||||
<TabContent value="ui">
|
||||
{#each [...staticComponents, ...usedComponents] as { type, name, icon, ids }}
|
||||
<div class="sticky top-0 left-0 w-full bg-white p-2">
|
||||
<div class="relative">
|
||||
<input
|
||||
bind:value={search}
|
||||
class="px-2 pb-1 border border-gray-300 rounded-sm {search ? 'pr-8' : ''}"
|
||||
placeholder="Search..."
|
||||
/>
|
||||
{#if search}
|
||||
<button
|
||||
class="absolute right-2 top-1/2 transform -translate-y-1/2 hover:bg-gray-200 rounded-full p-0.5"
|
||||
on:click|stopPropagation|preventDefault={() => (search = '')}
|
||||
>
|
||||
<X size="14" />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{#each search != '' ? entries.filter((x) => x.name
|
||||
.toLowerCase()
|
||||
.includes(search.toLowerCase())) : entries as { type, name, icon, ids } (name)}
|
||||
{#if ids.length > 0}
|
||||
<ListItem title={name} prefix={TITLE_PREFIX}>
|
||||
<ListItem
|
||||
title={name}
|
||||
prefix={TITLE_PREFIX}
|
||||
on:open={(e) => {
|
||||
if ($app.css != undefined) {
|
||||
if (e.detail && $app.css[type] == undefined) {
|
||||
$app.css[type] = Object.fromEntries(ids.map(({ id }) => [id, {}]))
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div slot="title" class="flex items-center">
|
||||
<svelte:component this={icon} size={18} />
|
||||
<span class="ml-1">
|
||||
@@ -140,13 +123,14 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="pb-2">
|
||||
{#each ids as id}
|
||||
{#each ids as { id, forceStyle, forceClass }}
|
||||
<div class="mb-3">
|
||||
{#if $app?.css?.[type][id]}
|
||||
{#if $app?.css?.[type]}
|
||||
<CssProperty
|
||||
{forceClass}
|
||||
{forceStyle}
|
||||
name={id}
|
||||
bind:value={$app.css[type][id]}
|
||||
on:focus={() => (isCustom[type] = true)}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
@@ -155,43 +139,6 @@
|
||||
</ListItem>
|
||||
{/if}
|
||||
{/each}
|
||||
<div class="px-1 my-4">
|
||||
<button
|
||||
on:click|preventDefault|stopPropagation={() => isOpenStore.toggle(SHOW_UNUSED_ID)}
|
||||
class="w-full text-xs text-gray-500 text-center font-medium hover:underline p-2"
|
||||
>
|
||||
{$isOpenStore[SHOW_UNUSED_ID] ? 'Hide' : 'Show'} unused components
|
||||
</button>
|
||||
</div>
|
||||
{#if $isOpenStore[SHOW_UNUSED_ID]}
|
||||
<div transition:slide|local={{ duration: 300 }}>
|
||||
{#each unusedComponents as { type, name, icon, ids }}
|
||||
{#if ids.length > 0}
|
||||
<ListItem title={name} prefix={TITLE_PREFIX}>
|
||||
<div slot="title" class="flex items-center">
|
||||
<svelte:component this={icon} size={18} />
|
||||
<span class="ml-1">
|
||||
{name}
|
||||
</span>
|
||||
</div>
|
||||
<div class="pb-2">
|
||||
{#each ids as id}
|
||||
<div class="mb-3">
|
||||
{#if $app?.css?.[type][id]}
|
||||
<CssProperty
|
||||
name={id}
|
||||
bind:value={$app.css[type][id]}
|
||||
on:focus={() => (isCustom[type] = true)}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</ListItem>
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
</TabContent>
|
||||
<TabContent value="json">
|
||||
{#if !emptyString(jsonError)}
|
||||
|
||||
@@ -2,12 +2,17 @@
|
||||
import { slide } from 'svelte/transition'
|
||||
import { ChevronDown } from 'lucide-svelte'
|
||||
import { isOpenStore } from './store'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
|
||||
export let title: string
|
||||
export let prefix: string | undefined = undefined
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
$: storeTitle = prefix + title
|
||||
$: isOpen = prefix ? $isOpenStore[storeTitle] : true
|
||||
|
||||
$: dispatch('open', isOpen)
|
||||
</script>
|
||||
|
||||
<section class="pt-1 pb-2 px-1">
|
||||
|
||||
@@ -206,6 +206,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- {inlineScript.content} -->
|
||||
|
||||
<div class="border h-full">
|
||||
{#if inlineScript.language != 'frontend'}
|
||||
<Editor
|
||||
@@ -215,6 +217,7 @@
|
||||
bind:code={inlineScript.content}
|
||||
fixedOverflowWidgets={true}
|
||||
cmdEnterAction={async () => {
|
||||
inlineScript.content = editor?.getCode() ?? ''
|
||||
runLoading = true
|
||||
await $runnableComponents[id]?.()
|
||||
runLoading = false
|
||||
|
||||
+28
-21
@@ -2,41 +2,48 @@
|
||||
import { Button } from '$lib/components/common'
|
||||
import { faPlus, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import type { StaticAppInput } from '../../inputType'
|
||||
import type { InputType, StaticAppInput, StaticInput } from '../../inputType'
|
||||
import { staticValues } from '../componentsPanel/componentStaticValues'
|
||||
import SubTypeEditor from './SubTypeEditor.svelte'
|
||||
|
||||
type ArrayComponentInput = Extract<StaticAppInput, { fieldType: 'array' }>
|
||||
export let componentInput: StaticInput<any[]>
|
||||
export let subFieldType: InputType | undefined = undefined
|
||||
export let optionValuesKey: keyof typeof staticValues | undefined = undefined
|
||||
|
||||
export let componentInput: ArrayComponentInput
|
||||
const dispatch = createEventDispatcher()
|
||||
|
||||
function addElementByType() {
|
||||
console.log('ADD')
|
||||
if (!Array.isArray(componentInput.value)) {
|
||||
componentInput.value = []
|
||||
}
|
||||
if (componentInput.subFieldType && componentInput.value) {
|
||||
if (componentInput.subFieldType === 'boolean') {
|
||||
componentInput.value.push(false)
|
||||
} else if (componentInput.subFieldType === 'number') {
|
||||
componentInput.value.push(0)
|
||||
} else if (componentInput.subFieldType === 'object') {
|
||||
componentInput.value.push({})
|
||||
} else if (componentInput.subFieldType === 'labeledresource') {
|
||||
componentInput.value.push({ value: '', label: '' })
|
||||
let value: any[] = componentInput.value
|
||||
if (subFieldType) {
|
||||
if (subFieldType === 'boolean') {
|
||||
value.push(false)
|
||||
} else if (subFieldType === 'number') {
|
||||
value.push(0)
|
||||
} else if (subFieldType === 'object') {
|
||||
value.push({})
|
||||
} else if (subFieldType === 'labeledresource') {
|
||||
value.push({ value: '', label: '' })
|
||||
} else if (
|
||||
componentInput.subFieldType === 'text' ||
|
||||
componentInput.subFieldType === 'textarea' ||
|
||||
subFieldType === 'text' ||
|
||||
subFieldType === 'textarea' ||
|
||||
// TODO: Add support for these types
|
||||
componentInput.subFieldType === 'date' ||
|
||||
componentInput.subFieldType === 'time' ||
|
||||
componentInput.subFieldType === 'datetime'
|
||||
subFieldType === 'date' ||
|
||||
subFieldType === 'time' ||
|
||||
subFieldType === 'datetime'
|
||||
) {
|
||||
componentInput.value.push('')
|
||||
} else if (componentInput.subFieldType === 'select') {
|
||||
componentInput.value.push(staticValues[componentInput.optionValuesKey][0])
|
||||
value.push('')
|
||||
} else if (subFieldType === 'select' && optionValuesKey) {
|
||||
value.push(staticValues[optionValuesKey][0])
|
||||
}
|
||||
} else {
|
||||
value.push('')
|
||||
}
|
||||
|
||||
console.log(value, componentInput.value)
|
||||
componentInput = componentInput
|
||||
}
|
||||
|
||||
@@ -55,7 +62,7 @@
|
||||
{#if Array.isArray(componentInput.value)}
|
||||
{#each componentInput.value as value, index (index)}
|
||||
<div class="flex flex-row gap-2 items-center relative">
|
||||
<SubTypeEditor bind:componentInput bind:value />
|
||||
<SubTypeEditor {subFieldType} bind:componentInput bind:value />
|
||||
|
||||
<div class="absolute top-1 right-1">
|
||||
<Button
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import Button from '$lib/components/common/button/Button.svelte'
|
||||
import { faChevronDown, faChevronUp, faCopy, faTrashAlt } from '@fortawesome/free-solid-svg-icons'
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppEditorContext, AppViewerContext } from '../../types'
|
||||
import type { AppEditorContext, AppViewerContext, RichConfiguration } from '../../types'
|
||||
import PanelSection from './common/PanelSection.svelte'
|
||||
import InputsSpecsEditor from './InputsSpecsEditor.svelte'
|
||||
import TableActions from './TableActions.svelte'
|
||||
@@ -17,7 +17,7 @@
|
||||
import AlignmentEditor from './AlignmentEditor.svelte'
|
||||
import RunnableInputEditor from './inputEditor/RunnableInputEditor.svelte'
|
||||
import TemplateEditor from '$lib/components/TemplateEditor.svelte'
|
||||
import type { AppComponent } from '../component'
|
||||
import { ccomponents, components, type AppComponent } from '../component'
|
||||
import CssProperty from '../componentsPanel/CssProperty.svelte'
|
||||
import GridTab from './GridTab.svelte'
|
||||
import { deleteGridItem } from '../appUtils'
|
||||
@@ -76,6 +76,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const initialConfiguration = ccomponents[component.type].initialData.configuration
|
||||
const componentInput: RichConfiguration | undefined =
|
||||
ccomponents[component.type].initialData.componentInput
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={keydown} />
|
||||
@@ -107,7 +111,13 @@
|
||||
|
||||
<div class="flex flex-col w-full gap-2 my-2">
|
||||
{#if component.componentInput.type === 'static'}
|
||||
<StaticInputEditor bind:componentInput={component.componentInput} />
|
||||
<StaticInputEditor
|
||||
fieldType={componentInput?.fieldType}
|
||||
subFieldType={componentInput?.subFieldType}
|
||||
format={componentInput?.format}
|
||||
bind:componentInput={component.componentInput}
|
||||
noVariablePicker
|
||||
/>
|
||||
{:else if component.componentInput.type === 'template' && component.componentInput !== undefined}
|
||||
<div class="py-1 min-h-[28px] rounded border border-1 border-gray-500">
|
||||
<TemplateEditor
|
||||
@@ -121,6 +131,7 @@
|
||||
<ConnectedInputEditor bind:componentInput={component.componentInput} />
|
||||
{:else if component.componentInput?.type === 'runnable' && component.componentInput !== undefined}
|
||||
<RunnableInputEditor
|
||||
appComponent={component}
|
||||
bind:appInput={component.componentInput}
|
||||
defaultUserInput={component.type == 'formcomponent' ||
|
||||
component.type == 'formbuttoncomponent'}
|
||||
@@ -158,11 +169,12 @@
|
||||
{/key}
|
||||
</PanelSection>
|
||||
{/if}
|
||||
{#if Object.values(component.configuration).length > 0}
|
||||
<PanelSection title={`Configuration (${Object.values(component.configuration).length})`}>
|
||||
{#if Object.values(initialConfiguration).length > 0}
|
||||
<PanelSection title={`Configuration (${Object.values(initialConfiguration).length})`}>
|
||||
<InputsSpecsEditor
|
||||
{rowColumns}
|
||||
id={component.id}
|
||||
inputSpecsConfiguration={initialConfiguration}
|
||||
bind:inputSpecs={component.configuration}
|
||||
userInputEnabled={false}
|
||||
/>
|
||||
@@ -184,7 +196,7 @@
|
||||
|
||||
<div class="grow shrink" />
|
||||
|
||||
{#if Object.keys(component.customCss ?? {}).length > 0}
|
||||
{#if Object.keys(ccomponents[component.type].customCss ?? {}).length > 0}
|
||||
<PanelSection title="Custom CSS">
|
||||
<div slot="action">
|
||||
<Button
|
||||
@@ -198,10 +210,15 @@
|
||||
</div>
|
||||
{#if viewCssOptions}
|
||||
<div transition:slide|local>
|
||||
{#each Object.keys(component.customCss ?? {}) as name}
|
||||
{#if component?.customCss?.[name]}
|
||||
{#each Object.keys(ccomponents[component.type].customCss ?? {}) as name}
|
||||
{#if component?.customCss != undefined}
|
||||
<div class="w-full mb-2">
|
||||
<CssProperty {name} bind:value={component.customCss[name]} />
|
||||
<CssProperty
|
||||
forceStyle={ccomponents[component.type].customCss[name].style != undefined}
|
||||
forceClass={ccomponents[component.type].customCss[name].class != undefined}
|
||||
{name}
|
||||
bind:value={component.customCss[name]}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
import UploadInputEditor from './inputEditor/UploadInputEditor.svelte'
|
||||
import { getContext } from 'svelte'
|
||||
import type { AppViewerContext, RichConfiguration } from '../../types'
|
||||
import type { InputType } from '../../inputType'
|
||||
import type { staticValues } from '../componentsPanel/componentStaticValues'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: RichConfiguration
|
||||
@@ -21,31 +23,37 @@
|
||||
export let userInputEnabled: boolean = false
|
||||
export let shouldCapitalize: boolean = true
|
||||
export let resourceOnly = false
|
||||
export let tooltip: string | undefined = undefined
|
||||
export let onlyStatic: boolean = false
|
||||
export let fieldType: InputType
|
||||
export let subFieldType: InputType | undefined
|
||||
export let format: string | undefined
|
||||
export let optionValuesKeys: keyof typeof staticValues | undefined
|
||||
|
||||
const { connectingInput } = getContext<AppViewerContext>('AppViewerContext')
|
||||
</script>
|
||||
|
||||
{#if componentInput.ctype == undefined}
|
||||
{#if !(resourceOnly && (componentInput.fieldType !== 'object' || !componentInput.format?.startsWith('resource-')))}
|
||||
{#if !(resourceOnly && (fieldType !== 'object' || !format?.startsWith('resource-')))}
|
||||
<div class="flex flex-col gap-1">
|
||||
<div class="flex justify-between items-end gap-1">
|
||||
<span class="text-sm font-semibold truncate">
|
||||
{shouldCapitalize ? capitalize(addWhitespaceBeforeCapitals(key)) : key}
|
||||
{#if componentInput.tooltip}
|
||||
{#if tooltip}
|
||||
<Tooltip>
|
||||
{componentInput.tooltip}
|
||||
{tooltip}
|
||||
</Tooltip>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
<div class="flex gap-x-2 gap-y-1 flex-wrap justify-end items-center">
|
||||
<Badge color="blue">
|
||||
{componentInput.fieldType === 'array' && componentInput.subFieldType
|
||||
? `${capitalize(fieldTypeToTsType(componentInput.subFieldType))}[]`
|
||||
: capitalize(fieldTypeToTsType(componentInput.fieldType))}
|
||||
{fieldType === 'array' && subFieldType
|
||||
? `${capitalize(fieldTypeToTsType(subFieldType))}[]`
|
||||
: capitalize(fieldTypeToTsType(fieldType))}
|
||||
</Badge>
|
||||
|
||||
{#if !componentInput.onlyStatic && componentInput.type != 'eval'}
|
||||
{#if !onlyStatic && componentInput.type != 'eval'}
|
||||
<ToggleButtonGroup
|
||||
bind:selected={componentInput.type}
|
||||
on:selected={(e) => {
|
||||
@@ -68,7 +76,7 @@
|
||||
/>
|
||||
<svelte:fragment slot="text">Static</svelte:fragment>
|
||||
</Popover>
|
||||
{#if userInputEnabled && !componentInput.format?.startsWith('resource-')}
|
||||
{#if userInputEnabled && !format?.startsWith('resource-')}
|
||||
<Popover placement="bottom" notClickable disapperTimoout={0}>
|
||||
<ToggleButton
|
||||
position="center"
|
||||
@@ -112,7 +120,13 @@
|
||||
{:else if componentInput.type === 'row'}
|
||||
<RowInputEditor bind:componentInput />
|
||||
{:else if componentInput.type === 'static'}
|
||||
<StaticInputEditor bind:componentInput />
|
||||
<StaticInputEditor
|
||||
{fieldType}
|
||||
{subFieldType}
|
||||
{optionValuesKeys}
|
||||
{format}
|
||||
bind:componentInput
|
||||
/>
|
||||
{:else if componentInput.type === 'eval'}
|
||||
<EvalInputEditor {hasRows} {id} bind:componentInput />
|
||||
{:else if componentInput.type === 'upload'}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
<script lang="ts">
|
||||
import type {
|
||||
ConnectedAppInput,
|
||||
RowAppInput,
|
||||
StaticAppInput,
|
||||
UserAppInput
|
||||
} from '../../inputType'
|
||||
import type { RichConfigurations } from '../../types'
|
||||
|
||||
import InputsSpecEditor from './InputsSpecEditor.svelte'
|
||||
|
||||
export let id: string
|
||||
export let inputSpecs: RichConfigurations
|
||||
export let inputSpecsConfiguration: RichConfigurations = inputSpecs
|
||||
export let userInputEnabled: boolean = false
|
||||
export let shouldCapitalize: boolean = true
|
||||
export let rowColumns = false
|
||||
@@ -18,8 +14,10 @@
|
||||
|
||||
{#if inputSpecs}
|
||||
<div class="w-full flex flex-col gap-4">
|
||||
{#each Object.keys(inputSpecs) as k}
|
||||
{#each Object.keys(inputSpecsConfiguration) as k}
|
||||
{#if inputSpecs[k].ctype == undefined}
|
||||
{@const meta = inputSpecsConfiguration?.[k]}
|
||||
<!-- {JSON.stringify(meta)} -->
|
||||
<InputsSpecEditor
|
||||
key={k}
|
||||
bind:componentInput={inputSpecs[k]}
|
||||
@@ -28,6 +26,12 @@
|
||||
{shouldCapitalize}
|
||||
{resourceOnly}
|
||||
hasRows={rowColumns}
|
||||
fieldType={meta?.['fieldType']}
|
||||
subFieldType={meta?.['subFieldType']}
|
||||
format={meta?.['format']}
|
||||
optionValuesKeys={meta?.['optionValuesKeys']}
|
||||
tooltip={meta?.['tooltip']}
|
||||
onlyStatic={meta?.['onlyStatic']}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import type { ResultAppInput } from '../../inputType'
|
||||
import type { AppViewerContext } from '../../types'
|
||||
import { clearResultAppInput } from '../../utils'
|
||||
import type { AppComponent } from '../component'
|
||||
import InlineScriptEditorDrawer from '../inlineScriptsPanel/InlineScriptEditorDrawer.svelte'
|
||||
import ComponentTriggerList from './triggerLists/ComponentTriggerList.svelte'
|
||||
|
||||
@@ -13,6 +14,7 @@
|
||||
|
||||
export let appInput: ResultAppInput
|
||||
let inlineScriptEditorDrawer: InlineScriptEditorDrawer
|
||||
export let appComponent: AppComponent
|
||||
|
||||
function edit() {
|
||||
if (appInput.runnable?.type === 'runnableByName') {
|
||||
@@ -68,7 +70,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{#if appInput.runnable?.type === 'runnableByName' && appInput.runnable.inlineScript}
|
||||
<ComponentTriggerList fields={appInput.fields} />
|
||||
<ComponentTriggerList {appComponent} fields={appInput.fields} />
|
||||
{/if}
|
||||
{#if appInput.runnable?.type === 'runnableByName' && !appInput.runnable.inlineScript}
|
||||
<span class="text-xs text-gray-500">
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
<script lang="ts">
|
||||
import type { StaticAppInput } from '../../inputType'
|
||||
import type { InputType, StaticInput } from '../../inputType'
|
||||
import StaticInputEditor from './inputEditor/StaticInputEditor.svelte'
|
||||
|
||||
export let value: any
|
||||
export let componentInput: StaticAppInput
|
||||
export let componentInput: StaticInput<any>
|
||||
export let subFieldType: InputType | undefined
|
||||
|
||||
let fakeComponentInput: StaticAppInput = {
|
||||
let fakeComponentInput: StaticInput<any> = {
|
||||
...componentInput,
|
||||
value,
|
||||
// We don't support array of arrays
|
||||
// @ts-ignore
|
||||
fieldType: componentInput.subFieldType
|
||||
value
|
||||
}
|
||||
|
||||
// Bubble up changes to the real componentInput
|
||||
$: fakeComponentInput && (value = fakeComponentInput.value)
|
||||
</script>
|
||||
|
||||
<StaticInputEditor bind:componentInput={fakeComponentInput} />
|
||||
<StaticInputEditor
|
||||
noVariablePicker
|
||||
fieldType={subFieldType}
|
||||
bind:componentInput={fakeComponentInput}
|
||||
/>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import { getContext } from 'svelte'
|
||||
import { Icon } from 'svelte-awesome'
|
||||
import type { AppViewerContext, BaseAppComponent } from '../../types'
|
||||
import { appComponentFromType } from '../appUtils'
|
||||
import type { ButtonComponent } from '../component'
|
||||
import PanelSection from './common/PanelSection.svelte'
|
||||
import TableActionLabel from './TableActionLabel.svelte'
|
||||
@@ -19,71 +20,10 @@
|
||||
function addComponent() {
|
||||
const actionId = getNextId(components.map((x) => x.id.split('_')[1]))
|
||||
|
||||
const newComponent: BaseAppComponent & ButtonComponent = {
|
||||
id: `${id}_${actionId}`,
|
||||
type: 'buttoncomponent',
|
||||
configuration: {
|
||||
label: {
|
||||
type: 'static',
|
||||
value: 'Action',
|
||||
fieldType: 'text'
|
||||
},
|
||||
color: {
|
||||
fieldType: 'select',
|
||||
type: 'static',
|
||||
value: 'dark',
|
||||
optionValuesKey: 'buttonColorOptions'
|
||||
},
|
||||
size: {
|
||||
fieldType: 'select',
|
||||
type: 'static',
|
||||
value: 'xs',
|
||||
optionValuesKey: 'buttonSizeOptions'
|
||||
},
|
||||
disabled: {
|
||||
fieldType: 'boolean',
|
||||
type: 'eval',
|
||||
expr: 'false',
|
||||
tooltip: "Disabled based on a predicate. Use `row` to access the current row's data"
|
||||
},
|
||||
goto: {
|
||||
tooltip: 'Go to an url on success if not empty',
|
||||
fieldType: 'text',
|
||||
type: 'static',
|
||||
value: ''
|
||||
},
|
||||
gotoNewTab: {
|
||||
tooltip: 'Go to create a new tab',
|
||||
fieldType: 'boolean',
|
||||
type: 'static',
|
||||
value: true
|
||||
},
|
||||
beforeIcon: {
|
||||
type: 'static',
|
||||
value: undefined,
|
||||
fieldType: 'icon-select',
|
||||
onlyStatic: true
|
||||
},
|
||||
afterIcon: {
|
||||
type: 'static',
|
||||
value: undefined,
|
||||
fieldType: 'icon-select',
|
||||
onlyStatic: true
|
||||
}
|
||||
},
|
||||
componentInput: {
|
||||
type: 'runnable',
|
||||
fieldType: 'any',
|
||||
fields: {},
|
||||
runnable: undefined,
|
||||
value: undefined
|
||||
},
|
||||
recomputeIds: undefined,
|
||||
customCss: {
|
||||
button: { style: '', class: '' }
|
||||
} as const
|
||||
const newComponent = {
|
||||
...appComponentFromType('buttoncomponent')(`${id}_${actionId}`),
|
||||
recomputeIds: []
|
||||
}
|
||||
|
||||
components = [...components, newComponent]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import ColorPicker, { ChromeVariant } from 'svelte-awesome-color-picker'
|
||||
import type { AppInput, StaticInput } from '../../../inputType'
|
||||
import type { StaticInput } from '../../../inputType'
|
||||
|
||||
export let componentInput: StaticInput<string> & Extract<AppInput, { fieldType: 'color' }>
|
||||
export let componentInput: StaticInput<string>
|
||||
let isOpen = false
|
||||
</script>
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
import { Popup } from '../../../../common'
|
||||
import { fade } from 'svelte/transition'
|
||||
|
||||
export let componentInput: StaticInput<string> & Extract<AppInput, { fieldType: 'icon-select' }>
|
||||
export let componentInput: StaticInput<string>
|
||||
let anchor: HTMLElement
|
||||
let loading = false
|
||||
let items: { label: string; icon: any }[]
|
||||
|
||||
+3
-1
@@ -1,17 +1,19 @@
|
||||
<script lang="ts">
|
||||
import type { ResultAppInput } from '$lib/components/apps/inputType'
|
||||
import { isScriptByNameDefined, isScriptByPathDefined } from '$lib/components/apps/utils'
|
||||
import type { AppComponent } from '../../component'
|
||||
import RunnableSelector from '../mainInput/RunnableSelector.svelte'
|
||||
import SelectedRunnable from '../SelectedRunnable.svelte'
|
||||
|
||||
export let appInput: ResultAppInput
|
||||
export let defaultUserInput = false
|
||||
export let appComponent: AppComponent
|
||||
|
||||
$: isRunnableSelected = isScriptByPathDefined(appInput) || isScriptByNameDefined(appInput)
|
||||
</script>
|
||||
|
||||
{#if isRunnableSelected}
|
||||
<SelectedRunnable bind:appInput />
|
||||
<SelectedRunnable {appComponent} bind:appInput />
|
||||
{:else}
|
||||
<RunnableSelector {defaultUserInput} bind:appInput />
|
||||
{/if}
|
||||
|
||||
+35
-28
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import Toggle from '$lib/components/Toggle.svelte'
|
||||
import { staticValues } from '../../componentsPanel/componentStaticValues'
|
||||
import type { StaticAppInput } from '../../../inputType'
|
||||
import type { InputType, StaticInput } from '../../../inputType'
|
||||
import ArrayStaticInputEditor from '../ArrayStaticInputEditor.svelte'
|
||||
import ResourcePicker from '$lib/components/ResourcePicker.svelte'
|
||||
import JsonEditor from './JsonEditor.svelte'
|
||||
@@ -12,7 +12,12 @@
|
||||
import { Icon } from 'svelte-awesome'
|
||||
import { faDollarSign } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
export let componentInput: StaticAppInput | undefined
|
||||
export let componentInput: StaticInput<any> | undefined
|
||||
export let fieldType: InputType | undefined = undefined
|
||||
export let subFieldType: InputType | undefined = undefined
|
||||
export let optionValuesKeys: keyof typeof staticValues | undefined = undefined
|
||||
export let format: string | undefined = undefined
|
||||
export let noVariablePicker: boolean = false
|
||||
|
||||
const { onchange } = getContext<AppViewerContext>('AppViewerContext')
|
||||
const { pickVariableCallback } = getContext<AppEditorContext>('AppEditorContext')
|
||||
@@ -21,25 +26,25 @@
|
||||
</script>
|
||||
|
||||
{#if componentInput?.type === 'static'}
|
||||
{#if componentInput.fieldType === 'number'}
|
||||
{#if fieldType === 'number'}
|
||||
<input on:keydown|stopPropagation type="number" bind:value={componentInput.value} />
|
||||
{:else if componentInput.fieldType === 'textarea'}
|
||||
{:else if fieldType === 'textarea'}
|
||||
<textarea on:keydown|stopPropagation bind:value={componentInput.value} />
|
||||
{:else if componentInput.fieldType === 'date'}
|
||||
{:else if fieldType === 'date'}
|
||||
<input on:keydown|stopPropagation type="date" bind:value={componentInput.value} />
|
||||
{:else if componentInput.fieldType === 'boolean'}
|
||||
{:else if fieldType === 'boolean'}
|
||||
<Toggle bind:checked={componentInput.value} />
|
||||
{:else if componentInput.fieldType === 'select'}
|
||||
{:else if fieldType === 'select' && optionValuesKeys}
|
||||
<select on:keydown|stopPropagation on:keydown|stopPropagation bind:value={componentInput.value}>
|
||||
{#each staticValues[componentInput.optionValuesKey] || [] as option}
|
||||
{#each staticValues[optionValuesKeys] || [] as option}
|
||||
<option value={option}>
|
||||
{option}
|
||||
</option>
|
||||
{/each}
|
||||
</select>
|
||||
{:else if componentInput.fieldType === 'icon-select'}
|
||||
{:else if fieldType === 'icon-select'}
|
||||
<IconSelectInput bind:componentInput />
|
||||
{:else if componentInput.fieldType === 'labeledresource'}
|
||||
{:else if fieldType === 'labeledresource'}
|
||||
{#if componentInput?.value && typeof componentInput?.value == 'object' && 'label' in componentInput?.value}
|
||||
<div class="flex flex-col gap-1 w-full">
|
||||
<input
|
||||
@@ -65,10 +70,10 @@
|
||||
{:else}
|
||||
Inconsistent labeled resource object
|
||||
{/if}
|
||||
{:else if componentInput.fieldType === 'color'}
|
||||
{:else if fieldType === 'color'}
|
||||
<ColorInput bind:componentInput />
|
||||
{:else if componentInput.fieldType === 'object'}
|
||||
{#if componentInput?.format?.startsWith('resource-')}
|
||||
{:else if fieldType === 'object'}
|
||||
{#if format?.startsWith('resource-')}
|
||||
<ResourcePicker
|
||||
initialValue={componentInput.value?.split('$res:')[1] || ''}
|
||||
on:change={(e) => {
|
||||
@@ -81,8 +86,8 @@
|
||||
}
|
||||
}
|
||||
}}
|
||||
resourceType={componentInput.format.split('-').length > 1
|
||||
? componentInput.format.substring('resource-'.length)
|
||||
resourceType={format.split('-').length > 1
|
||||
? format.substring('resource-'.length)
|
||||
: undefined}
|
||||
/>
|
||||
{:else}
|
||||
@@ -93,8 +98,8 @@
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{:else if componentInput.fieldType === 'array'}
|
||||
<ArrayStaticInputEditor bind:componentInput on:deleteArrayItem />
|
||||
{:else if fieldType === 'array'}
|
||||
<ArrayStaticInputEditor {subFieldType} bind:componentInput on:deleteArrayItem />
|
||||
{:else}
|
||||
<div class="flex gap-1">
|
||||
<input
|
||||
@@ -103,18 +108,20 @@
|
||||
placeholder="Static value"
|
||||
bind:value={componentInput.value}
|
||||
/>
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="min-w-min min-h-[34px] items-center leading-4 px-3 text-gray-600 cursor-pointer border border-gray-700 rounded center-center"
|
||||
on:click={() => {
|
||||
$pickVariableCallback = (variable) => {
|
||||
if (componentInput) {
|
||||
componentInput.value = `$var:${variable}`
|
||||
{#if !noVariablePicker}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="min-w-min min-h-[34px] items-center leading-4 px-3 text-gray-600 cursor-pointer border border-gray-700 rounded center-center"
|
||||
on:click={() => {
|
||||
$pickVariableCallback = (variable) => {
|
||||
if (componentInput) {
|
||||
componentInput.value = `$var:${variable}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}}
|
||||
><Icon data={faDollarSign} />
|
||||
</div>
|
||||
}}
|
||||
><Icon data={faDollarSign} />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
+9
-15
@@ -7,29 +7,23 @@
|
||||
} from '$lib/components/apps/inputType'
|
||||
import type { AppViewerContext } from '$lib/components/apps/types'
|
||||
import { getContext } from 'svelte'
|
||||
import { findGridItem } from '../../appUtils'
|
||||
import type { AppComponent } from '../../component'
|
||||
import TriggerBadgesList from './TriggerBadgesList.svelte'
|
||||
import { getDependencies } from './triggerListUtils'
|
||||
|
||||
const { selectedComponent, app } = getContext<AppViewerContext>('AppViewerContext')
|
||||
const { selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
|
||||
export let fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
||||
export let appComponent: AppComponent
|
||||
|
||||
$: gridItem = $selectedComponent ? findGridItem($app, $selectedComponent) : undefined
|
||||
|
||||
$: onClick =
|
||||
gridItem?.data.type &&
|
||||
['buttoncomponent', 'formbuttoncomponent', 'formcomponent'].includes(gridItem?.data.type)
|
||||
|
||||
$: if (gridItem) {
|
||||
console.log(gridItem?.data.configuration.triggerOnAppLoad)
|
||||
}
|
||||
const onClick = ['buttoncomponent', 'formbuttoncomponent', 'formcomponent'].includes(
|
||||
appComponent.type
|
||||
)
|
||||
|
||||
$: onLoad =
|
||||
!onClick ||
|
||||
(gridItem?.data.configuration.triggerOnAppLoad.ctype === undefined &&
|
||||
// TODO: Type and value are not in sync.
|
||||
// @ts-ignore
|
||||
gridItem?.data.configuration.triggerOnAppLoad.value)
|
||||
(appComponent.configuration.triggerOnAppLoad.ctype === undefined &&
|
||||
appComponent.configuration.triggerOnAppLoad.type == 'static' &&
|
||||
appComponent.configuration.triggerOnAppLoad.value)
|
||||
</script>
|
||||
|
||||
<TriggerBadgesList
|
||||
|
||||
@@ -156,8 +156,6 @@
|
||||
on:pointerup={pointerup}
|
||||
onTop={item.id == onTopId}
|
||||
id={item.id}
|
||||
resizable={item[getComputedCols] && item[getComputedCols].resizable}
|
||||
draggable={item[getComputedCols] && item[getComputedCols].draggable}
|
||||
{xPerPx}
|
||||
{yPerPx}
|
||||
width={Math.min(getComputedCols, item[getComputedCols] && item[getComputedCols].w) *
|
||||
@@ -167,8 +165,6 @@
|
||||
top={(item[getComputedCols] && item[getComputedCols].y) * yPerPx + gapY}
|
||||
left={(item[getComputedCols] && item[getComputedCols].x) * xPerPx + gapX}
|
||||
item={item[getComputedCols]}
|
||||
min={item[getComputedCols] && item[getComputedCols].min}
|
||||
max={item[getComputedCols] && item[getComputedCols].max}
|
||||
cols={getComputedCols}
|
||||
{gapX}
|
||||
{gapY}
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
export let left
|
||||
export let top
|
||||
|
||||
export let resizable
|
||||
export let draggable
|
||||
|
||||
export let id
|
||||
export let container
|
||||
|
||||
@@ -22,9 +19,6 @@
|
||||
export let gapY
|
||||
export let item
|
||||
|
||||
export let max
|
||||
export let min
|
||||
|
||||
export let cols
|
||||
|
||||
export let nativeContainer
|
||||
@@ -195,10 +189,6 @@
|
||||
if (shadow) {
|
||||
shadow.x = Math.max(Math.min(gridX, cols - shadow.w), 0)
|
||||
shadow.y = Math.max(gridY, 0)
|
||||
|
||||
if (max.y) {
|
||||
shadow.y = Math.min(shadow.y, max.y)
|
||||
}
|
||||
}
|
||||
repaint(undefined, false)
|
||||
}
|
||||
@@ -283,19 +273,13 @@
|
||||
|
||||
// Get max col number
|
||||
let maxWidth = cols - shadow.x
|
||||
maxWidth = Math.min(max.w, maxWidth) || maxWidth
|
||||
maxWidth = maxWidth
|
||||
|
||||
// Limit bound
|
||||
newSize.width = Math.max(
|
||||
Math.min(newSize.width, maxWidth * xPerPx - gapX * 2),
|
||||
min.w * xPerPx - gapX * 2
|
||||
)
|
||||
newSize.width = Math.min(newSize.width, maxWidth * xPerPx - gapX * 2)
|
||||
|
||||
newSize.height = Math.max(newSize.height, min.h * yPerPx - gapY * 2)
|
||||
newSize.height = newSize.height
|
||||
|
||||
if (max.h) {
|
||||
newSize.height = Math.min(newSize.height, max.h * yPerPx - gapY * 2)
|
||||
}
|
||||
// Limit col & row
|
||||
shadow.w = Math.round((newSize.width + gapX * 2) / xPerPx)
|
||||
shadow.h = Math.round((newSize.height + gapY * 2) / yPerPx)
|
||||
@@ -316,7 +300,7 @@
|
||||
|
||||
<div
|
||||
draggable={false}
|
||||
on:pointerdown={item && item.customDragger ? null : draggable && pointerdown}
|
||||
on:pointerdown={pointerdown}
|
||||
class="svlt-grid-item"
|
||||
class:svlt-grid-active={active || (trans && rect)}
|
||||
style="width: {active ? newSize.width : width}px; height:{active
|
||||
@@ -329,9 +313,7 @@
|
||||
: `transition: transform 0.1s, opacity 0.1s; transform: translate(${left}px, ${top}px); `} "
|
||||
>
|
||||
<slot movePointerDown={pointerdown} {resizePointerDown} />
|
||||
{#if resizable && !item.customResizer}
|
||||
<div class="svlt-grid-resizer" on:pointerdown={resizePointerDown} />
|
||||
{/if}
|
||||
<div class="svlt-grid-resizer" on:pointerdown={resizePointerDown} />
|
||||
</div>
|
||||
|
||||
{#if (active || trans) && shadow}
|
||||
|
||||
+1
-7
@@ -9,13 +9,7 @@ export interface Positon {
|
||||
}
|
||||
|
||||
interface ItemLayout extends Size, Positon {
|
||||
fixed?: boolean
|
||||
resizable?: boolean
|
||||
draggable?: boolean
|
||||
customDragger?: boolean
|
||||
customResizer?: boolean
|
||||
min?: Size
|
||||
max?: Size
|
||||
fixed: boolean
|
||||
}
|
||||
|
||||
export type FilledItem<T> = { [width: number]: Required<ItemLayout>; data: T; id: string }
|
||||
|
||||
@@ -1,43 +1,39 @@
|
||||
import { makeMatrixFromItems } from "./matrix";
|
||||
import { findFreeSpaceForItem, normalize, adjust } from "./item";
|
||||
import { getRowsCount } from "./other";
|
||||
import { makeMatrixFromItems } from './matrix'
|
||||
import { findFreeSpaceForItem, normalize, adjust } from './item'
|
||||
import { getRowsCount } from './other'
|
||||
|
||||
function makeItem(item) {
|
||||
const { min = { w: 1, h: 1 }, max } = item;
|
||||
return {
|
||||
fixed: false,
|
||||
resizable: !item.fixed,
|
||||
draggable: !item.fixed,
|
||||
customDragger: false,
|
||||
customResizer: false,
|
||||
min: {
|
||||
w: Math.max(1, min.w),
|
||||
h: Math.max(1, min.h),
|
||||
},
|
||||
max: { ...max },
|
||||
...item,
|
||||
};
|
||||
const { min = { w: 1, h: 1 }, max } = item
|
||||
return {
|
||||
fixed: false,
|
||||
min: {
|
||||
w: Math.max(1, min.w),
|
||||
h: Math.max(1, min.h)
|
||||
},
|
||||
max: { ...max },
|
||||
...item
|
||||
}
|
||||
}
|
||||
|
||||
const gridHelp = {
|
||||
normalize(items, col) {
|
||||
return normalize(items, col);
|
||||
},
|
||||
normalize(items, col) {
|
||||
return normalize(items, col)
|
||||
},
|
||||
|
||||
adjust(items, col) {
|
||||
return adjust(items, col);
|
||||
},
|
||||
adjust(items, col) {
|
||||
return adjust(items, col)
|
||||
},
|
||||
|
||||
item(obj) {
|
||||
return makeItem(obj);
|
||||
},
|
||||
item(obj) {
|
||||
return makeItem(obj)
|
||||
},
|
||||
|
||||
findSpace(item, items, cols) {
|
||||
let matrix = makeMatrixFromItems(items, getRowsCount(items, cols), cols);
|
||||
findSpace(item, items, cols) {
|
||||
let matrix = makeMatrixFromItems(items, getRowsCount(items, cols), cols)
|
||||
|
||||
let position = findFreeSpaceForItem(matrix, item[cols]);
|
||||
return position;
|
||||
},
|
||||
};
|
||||
let position = findFreeSpaceForItem(matrix, item[cols])
|
||||
return position
|
||||
}
|
||||
}
|
||||
|
||||
export default gridHelp;
|
||||
export default gridHelp
|
||||
|
||||
@@ -3,12 +3,13 @@ import type { Preview } from '$lib/gen'
|
||||
import type { History } from '$lib/history'
|
||||
|
||||
import type { Writable } from 'svelte/store'
|
||||
import type { AppComponent } from './editor/component/components'
|
||||
import type { AppComponent, components } from './editor/component/components'
|
||||
import type {
|
||||
AppInput,
|
||||
ConnectedAppInput,
|
||||
ConnectedInput,
|
||||
EvalAppInput,
|
||||
ResultAppInput,
|
||||
RowAppInput,
|
||||
StaticAppInput,
|
||||
UploadAppInput,
|
||||
@@ -27,7 +28,6 @@ export type Aligned = {
|
||||
|
||||
export interface GeneralAppInput {
|
||||
onlyStatic?: boolean
|
||||
evaluatedValue?: boolean
|
||||
tooltip?: string
|
||||
}
|
||||
|
||||
@@ -36,33 +36,42 @@ export type ComponentCssProperty = {
|
||||
style?: string
|
||||
}
|
||||
|
||||
export type ComponentCustomCSS<T extends string = string> = Record<T, ComponentCssProperty>
|
||||
export type ComponentCustomCSS<T extends keyof typeof components> = Partial<
|
||||
(typeof components)[T]['customCss']
|
||||
>
|
||||
|
||||
export type Configuration = GeneralAppInput &
|
||||
(StaticAppInput | ConnectedAppInput | UserAppInput | RowAppInput | EvalAppInput | UploadAppInput)
|
||||
export type Configuration =
|
||||
| StaticAppInput
|
||||
| ConnectedAppInput
|
||||
| UserAppInput
|
||||
| RowAppInput
|
||||
| EvalAppInput
|
||||
| UploadAppInput
|
||||
| ResultAppInput
|
||||
|
||||
export type RichConfiguration =
|
||||
| (Configuration & { ctype?: undefined })
|
||||
export type StaticConfiguration = GeneralAppInput & StaticAppInput
|
||||
export type RichConfigurationT<T> =
|
||||
| (T & { ctype?: undefined })
|
||||
| {
|
||||
ctype: 'oneOf'
|
||||
selected: string
|
||||
configuration: Record<string, Record<string, Configuration>>
|
||||
configuration: Record<string, Record<string, T>>
|
||||
}
|
||||
| { ctype: 'group'; title: string; configuration: Record<string, Configuration> }
|
||||
| { ctype: 'group'; title: string; configuration: Record<string, T> }
|
||||
|
||||
export type RichConfiguration = RichConfigurationT<Configuration>
|
||||
export type RichConfigurations = Record<string, RichConfiguration>
|
||||
|
||||
export type StaticRichConfigurations = Record<
|
||||
string,
|
||||
RichConfigurationT<GeneralAppInput & (StaticAppInput | EvalAppInput)>
|
||||
>
|
||||
|
||||
export interface BaseAppComponent extends Partial<Aligned> {
|
||||
id: ComponentID
|
||||
componentInput: AppInput | undefined
|
||||
configuration: RichConfigurations
|
||||
customCss?: ComponentCustomCSS
|
||||
/**
|
||||
* If `true` then the wrapper will allow items to flow outside of it's borders.
|
||||
*
|
||||
* *For example when the component has a popup like `Select`*
|
||||
*/
|
||||
softWrap?: boolean
|
||||
customCss?: Record<string, ComponentCssProperty>
|
||||
// Number of subgrids
|
||||
numberOfSubgrids?: number
|
||||
}
|
||||
@@ -102,7 +111,9 @@ export type App = {
|
||||
fields: Record<string, StaticAppInput | ConnectedAppInput | RowAppInput | UserAppInput>
|
||||
autoRefresh?: boolean
|
||||
}>
|
||||
css?: Record<'viewer' | 'grid' | AppComponent['type'], ComponentCustomCSS>
|
||||
css?: Partial<
|
||||
Record<'viewer' | 'grid' | AppComponent['type'], Record<string, ComponentCssProperty>>
|
||||
>
|
||||
subgrids?: Record<string, GridItem[]>
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { Schema } from '$lib/common'
|
||||
import { FlowService, ScriptService } from '$lib/gen'
|
||||
import { inferArgs } from '$lib/infer'
|
||||
import { emptySchema } from '$lib/utils'
|
||||
import type { AppComponent } from './editor/component'
|
||||
import type { AppComponent, components } from './editor/component'
|
||||
import type { App, ComponentCssProperty, ComponentCustomCSS, GridItem } from './types'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import type { AppInput, InputType, ResultAppInput, StaticAppInput } from './inputType'
|
||||
@@ -230,29 +230,29 @@ export function toKebabCase(text: string) {
|
||||
return text.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
|
||||
}
|
||||
|
||||
export function concatCustomCss<T extends string = string>(
|
||||
appCss?: ComponentCustomCSS<T>,
|
||||
componentCss?: ComponentCustomCSS<T>
|
||||
): Record<T, ComponentCssProperty> | undefined {
|
||||
export function concatCustomCss<T extends Record<string, ComponentCssProperty>>(
|
||||
appCss?: Record<string, ComponentCssProperty>,
|
||||
componentCss?: T
|
||||
): T | undefined {
|
||||
if (!componentCss) return undefined
|
||||
|
||||
const customStyle = {} as Record<T, ComponentCssProperty>
|
||||
Object.keys(componentCss).forEach((key) => {
|
||||
const k = key as keyof typeof componentCss
|
||||
return Object.fromEntries(
|
||||
Object.entries(componentCss).map(([key, v]) => {
|
||||
// This is the general style of the component type
|
||||
const appStyle = appCss?.[key]?.style?.trim() || ''
|
||||
const appEnding = appStyle?.endsWith(';') || !appStyle ? ' ' : '; '
|
||||
|
||||
// This is the general style of the component type
|
||||
const appStyle = appCss?.[k]?.style?.trim() || ''
|
||||
const appEnding = appStyle?.endsWith(';') || !appStyle ? ' ' : '; '
|
||||
// This is the custom style of the component instance
|
||||
const compStyle = v?.style?.trim() || ''
|
||||
const compEnding = compStyle?.endsWith(';') || !compStyle ? ' ' : ';'
|
||||
|
||||
// This is the custom style of the component instance
|
||||
const compStyle = componentCss[k]?.style?.trim() || ''
|
||||
const compEnding = compStyle?.endsWith(';') || !compStyle ? ' ' : ';'
|
||||
|
||||
customStyle[k] = {
|
||||
style: (appStyle + appEnding + compStyle + compEnding).trim(),
|
||||
class: twMerge(appCss?.[k]?.class, componentCss[k]?.class)
|
||||
}
|
||||
})
|
||||
|
||||
return customStyle
|
||||
return [
|
||||
key,
|
||||
{
|
||||
style: (appStyle + appEnding + compStyle + compEnding).trim(),
|
||||
class: twMerge(appCss?.[key]?.class, v?.class)
|
||||
}
|
||||
]
|
||||
})
|
||||
) as T
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@
|
||||
grid: [],
|
||||
fullscreen: false,
|
||||
unusedInlineScripts: [],
|
||||
hiddenInlineScripts: []
|
||||
hiddenInlineScripts: [],
|
||||
css: {}
|
||||
}
|
||||
|
||||
if (nodraft) {
|
||||
|
||||
Reference in New Issue
Block a user