fix(frontend): Add more app custom css (#1229)

* fix(frontend): Add container custom css

* fix(frontend): Add form custom css

* fix(frontend): Add form button custom css

* feat(frontend): Add css quick reset button

* feat(frontend): Filter component css by usage

* fix(frontend): Save state of unused component display

* fix(frontend): Add pie chart custom css

* fix(frontend): Add bar chart custom css

* fix(frontend): Update vega lite and plotly loading

* fix(frontend): Add html and timeseries custom css

* fix(frontend): Add scatter chart custom css

* fix(frontend): Add table custom css

* fix(frontend): Revert container custom styles

* fix(frontend): Add toggle custom css

* fix(frontend): Add text input custom css

* fix(frontend): Update

* fix(frontend): Remove undefined css customizations
This commit is contained in:
Ádám Kovács
2023-02-28 09:21:56 +01:00
committed by GitHub
parent 2244e83b9d
commit a4e4d188ad
33 changed files with 572 additions and 239 deletions
+48 -62
View File
@@ -30,7 +30,7 @@
"svelte-autosize": "^1.0.1",
"svelte-chartjs": "^3.1.0",
"svelte-portal": "^2.2.0",
"svelte-select": "^5.0.2",
"svelte-select": "^5.3.1",
"tailwind-merge": "^1.9.1",
"vscode-ws-jsonrpc": "^2.0.1"
},
@@ -604,16 +604,16 @@
}
},
"node_modules/@floating-ui/core": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.0.5.tgz",
"integrity": "sha512-iDdOsaCHZH/0FM0yNBYt+cJxJF9S5jrYWNtDZOiDFMiZ7uxMJ/71h8eTwoVifEAruv9p9rlMPYCGIgMjOz95FQ=="
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.2.1.tgz",
"integrity": "sha512-LSqwPZkK3rYfD7GKoIeExXOyYx6Q1O4iqZWwIehDNuv3Dv425FIAE8PRwtAx1imEolFTHgBEcoFHm9MDnYgPCg=="
},
"node_modules/@floating-ui/dom": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.1.0.tgz",
"integrity": "sha512-TSogMPVxbRe77QCj1dt8NmRiJasPvuc+eT5jnJ6YpLqgOD2zXc5UA3S1qwybN+GVCDNdKfpKy1oj8RpzLJvh6A==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.1.tgz",
"integrity": "sha512-Rt45SmRiV8eU+xXSB9t0uMYiQ/ZWGE/jumse2o3i5RGlyvcbqOF4q+1qBnzLE2kZ5JGhq0iMkcGXUKbFe7MpTA==",
"dependencies": {
"@floating-ui/core": "^1.0.5"
"@floating-ui/core": "^1.2.1"
}
},
"node_modules/@fortawesome/fontawesome-common-types": {
@@ -2458,7 +2458,8 @@
"node_modules/dedent-js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz",
"integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ=="
"integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==",
"dev": true
},
"node_modules/deep-extend": {
"version": "0.6.0",
@@ -3873,6 +3874,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
"dev": true,
"dependencies": {
"tslib": "^2.0.3"
}
@@ -4268,6 +4270,7 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
"dev": true,
"dependencies": {
"lower-case": "^2.0.2",
"tslib": "^2.0.3"
@@ -4502,6 +4505,7 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
"integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
"dev": true,
"dependencies": {
"no-case": "^3.0.4",
"tslib": "^2.0.3"
@@ -6206,25 +6210,12 @@
}
},
"node_modules/svelte-floating-ui": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/svelte-floating-ui/-/svelte-floating-ui-1.1.6.tgz",
"integrity": "sha512-lJfrc34+xSxKs+5AtnYj32uRIjaxGjhT92cOiNL3zEqaJ755JxUqXCf6tk+9G1wkCuqkK9A8tscVBsyY3iLmVQ==",
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/svelte-floating-ui/-/svelte-floating-ui-1.2.8.tgz",
"integrity": "sha512-8Ifi5CD2Ui7FX7NjJRmutFtXjrB8T/FMNoS2H8P81t5LHK4I9G4NIs007rLWG/nRl7y+zJUXa3tWuTjYXw/O5A==",
"dependencies": {
"@floating-ui/dom": "^1.0.4",
"svelte2tsx": "^0.5.11"
}
},
"node_modules/svelte-floating-ui/node_modules/svelte2tsx": {
"version": "0.5.23",
"resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.5.23.tgz",
"integrity": "sha512-jYFnugTQRFmUpvLXPQrKzVYcW5ErT+0QCxg027Zx9BuvYefMZFuoBSTDYe7viPEFGrPPiLgT2m7f5n9khE7f7Q==",
"dependencies": {
"dedent-js": "^1.0.1",
"pascal-case": "^3.1.1"
},
"peerDependencies": {
"svelte": "^3.24",
"typescript": "^4.1.2"
"@floating-ui/core": "^1.1.0",
"@floating-ui/dom": "^1.1.0"
}
},
"node_modules/svelte-highlight": {
@@ -6348,12 +6339,12 @@
"dev": true
},
"node_modules/svelte-select": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/svelte-select/-/svelte-select-5.0.2.tgz",
"integrity": "sha512-SsyIwcRVl38041xk7HoPCAew8D6ypTrMvoNcwOgAEWz9Yycgd/uZ58gMSubxSDtkW/ohuYmmHf5OlGCKIqn9Cw==",
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/svelte-select/-/svelte-select-5.3.1.tgz",
"integrity": "sha512-TKlH22FEOr/KYNX4dzBJntNzeI0v0eZYU3VEo2uz/gar6xZdhQ3KT81hvD595GfSB7wiFdYc9SO42wrcgm9W4Q==",
"dependencies": {
"@floating-ui/dom": "^1.0.10",
"svelte-floating-ui": "1.1.6"
"@floating-ui/dom": "^1.2.1",
"svelte-floating-ui": "1.2.8"
}
},
"node_modules/svelte-splitpanes": {
@@ -6691,6 +6682,7 @@
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -7486,16 +7478,16 @@
}
},
"@floating-ui/core": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.0.5.tgz",
"integrity": "sha512-iDdOsaCHZH/0FM0yNBYt+cJxJF9S5jrYWNtDZOiDFMiZ7uxMJ/71h8eTwoVifEAruv9p9rlMPYCGIgMjOz95FQ=="
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.2.1.tgz",
"integrity": "sha512-LSqwPZkK3rYfD7GKoIeExXOyYx6Q1O4iqZWwIehDNuv3Dv425FIAE8PRwtAx1imEolFTHgBEcoFHm9MDnYgPCg=="
},
"@floating-ui/dom": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.1.0.tgz",
"integrity": "sha512-TSogMPVxbRe77QCj1dt8NmRiJasPvuc+eT5jnJ6YpLqgOD2zXc5UA3S1qwybN+GVCDNdKfpKy1oj8RpzLJvh6A==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.1.tgz",
"integrity": "sha512-Rt45SmRiV8eU+xXSB9t0uMYiQ/ZWGE/jumse2o3i5RGlyvcbqOF4q+1qBnzLE2kZ5JGhq0iMkcGXUKbFe7MpTA==",
"requires": {
"@floating-ui/core": "^1.0.5"
"@floating-ui/core": "^1.2.1"
}
},
"@fortawesome/fontawesome-common-types": {
@@ -8781,7 +8773,8 @@
"dedent-js": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dedent-js/-/dedent-js-1.0.1.tgz",
"integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ=="
"integrity": "sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==",
"dev": true
},
"deep-extend": {
"version": "0.6.0",
@@ -9869,6 +9862,7 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
"integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==",
"dev": true,
"requires": {
"tslib": "^2.0.3"
}
@@ -10173,6 +10167,7 @@
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
"integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==",
"dev": true,
"requires": {
"lower-case": "^2.0.2",
"tslib": "^2.0.3"
@@ -10344,6 +10339,7 @@
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
"integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==",
"dev": true,
"requires": {
"no-case": "^3.0.4",
"tslib": "^2.0.3"
@@ -11539,23 +11535,12 @@
}
},
"svelte-floating-ui": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/svelte-floating-ui/-/svelte-floating-ui-1.1.6.tgz",
"integrity": "sha512-lJfrc34+xSxKs+5AtnYj32uRIjaxGjhT92cOiNL3zEqaJ755JxUqXCf6tk+9G1wkCuqkK9A8tscVBsyY3iLmVQ==",
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/svelte-floating-ui/-/svelte-floating-ui-1.2.8.tgz",
"integrity": "sha512-8Ifi5CD2Ui7FX7NjJRmutFtXjrB8T/FMNoS2H8P81t5LHK4I9G4NIs007rLWG/nRl7y+zJUXa3tWuTjYXw/O5A==",
"requires": {
"@floating-ui/dom": "^1.0.4",
"svelte2tsx": "^0.5.11"
},
"dependencies": {
"svelte2tsx": {
"version": "0.5.23",
"resolved": "https://registry.npmjs.org/svelte2tsx/-/svelte2tsx-0.5.23.tgz",
"integrity": "sha512-jYFnugTQRFmUpvLXPQrKzVYcW5ErT+0QCxg027Zx9BuvYefMZFuoBSTDYe7viPEFGrPPiLgT2m7f5n9khE7f7Q==",
"requires": {
"dedent-js": "^1.0.1",
"pascal-case": "^3.1.1"
}
}
"@floating-ui/core": "^1.1.0",
"@floating-ui/dom": "^1.1.0"
}
},
"svelte-highlight": {
@@ -11621,12 +11606,12 @@
"dev": true
},
"svelte-select": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/svelte-select/-/svelte-select-5.0.2.tgz",
"integrity": "sha512-SsyIwcRVl38041xk7HoPCAew8D6ypTrMvoNcwOgAEWz9Yycgd/uZ58gMSubxSDtkW/ohuYmmHf5OlGCKIqn9Cw==",
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/svelte-select/-/svelte-select-5.3.1.tgz",
"integrity": "sha512-TKlH22FEOr/KYNX4dzBJntNzeI0v0eZYU3VEo2uz/gar6xZdhQ3KT81hvD595GfSB7wiFdYc9SO42wrcgm9W4Q==",
"requires": {
"@floating-ui/dom": "^1.0.10",
"svelte-floating-ui": "1.1.6"
"@floating-ui/dom": "^1.2.1",
"svelte-floating-ui": "1.2.8"
}
},
"svelte-splitpanes": {
@@ -11877,7 +11862,8 @@
"typescript": {
"version": "4.9.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz",
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg=="
"integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==",
"dev": true
},
"uglify-js": {
"version": "3.16.3",
+1 -1
View File
@@ -82,7 +82,7 @@
"svelte-autosize": "^1.0.1",
"svelte-chartjs": "^3.1.0",
"svelte-portal": "^2.2.0",
"svelte-select": "^5.0.2",
"svelte-select": "^5.3.1",
"tailwind-merge": "^1.9.1",
"vscode-ws-jsonrpc": "^2.0.1"
},
@@ -8,6 +8,7 @@
import Select from 'svelte-select'
import AppConnect from './AppConnect.svelte'
import ResourceEditor from './ResourceEditor.svelte'
import { SELECT_INPUT_DEFAULT_STYLE } from '../defaults'
const dispatch = createEventDispatcher()
let resources: Resource[] = []
@@ -59,12 +60,13 @@
<div class="flex flex-row gap-x-1 w-full">
<Select
listAutoWidth={false}
--height="34px"
value={collection.find((x) => x.value == value)}
bind:justValue={value}
items={collection}
class="text-clip grow min-w-0"
placeholder="{resourceType} resource"
inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles}
containerStyles={SELECT_INPUT_DEFAULT_STYLE.containerStyles}
/>
{#if value && value != ''}
<Button variant="border" size="xs" on:click={() => resourceEditor?.initEdit?.(value ?? '')}>
@@ -11,6 +11,7 @@
import { Button, Drawer, DrawerContent } from './common'
import HighlightCode from './HighlightCode.svelte'
import FlowPathViewer from './flows/content/FlowPathViewer.svelte'
import { SELECT_INPUT_DEFAULT_STYLE } from '../defaults'
export let initialPath: string | undefined = undefined
export let scriptPath: string | undefined = undefined
@@ -87,6 +88,8 @@
bind:justValue={scriptPath}
{items}
placeholder="Pick a {itemKind}"
inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles}
containerStyles={SELECT_INPUT_DEFAULT_STYLE.containerStyles}
/>
{/if}
+17 -4
View File
@@ -1,5 +1,6 @@
<script lang="ts">
import { createEventDispatcher } from 'svelte'
import { twMerge } from 'tailwind-merge'
export let options: {
left?: string
@@ -7,6 +8,8 @@
} = {}
export let checked: boolean = false
export let disabled = false
export let textClass = ''
export let textStyle = ''
export let size: 'sm' | 'xs' = 'sm'
const id = (Math.random() + 1).toString(36).substring(10)
@@ -22,7 +25,13 @@
>
{#if Boolean(options?.left)}
<span
class="mr-2 text-sm font-medium duration-200 {disabled ? 'text-gray-600' : 'text-gray-900'}"
class={twMerge(
'ml-2 font-medium duration-200',
disabled ? 'text-gray-500' : 'text-gray-900',
size === 'xs' ? 'text-xs' : 'text-sm',
textClass
)}
style={textStyle}
>
{options?.left}
</span>
@@ -51,9 +60,13 @@
</div>
{#if Boolean(options?.right)}
<span
class="ml-2 text-sm font-medium duration-200
{disabled ? 'text-gray-500' : 'text-gray-900'}
{size === 'xs' ? 'text-xs' : 'text-sm'}"
class={twMerge(
'ml-2 font-medium duration-200',
disabled ? 'text-gray-500' : 'text-gray-900',
size === 'xs' ? 'text-xs' : 'text-sm',
textClass
)}
style={textStyle}
>
{options?.right}
</span>
@@ -5,7 +5,8 @@
import { Icon } from 'svelte-awesome'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext } from '../../types'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
import type RunnableComponent from '../helpers/RunnableComponent.svelte'
@@ -17,10 +18,11 @@
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 const staticOutputs: string[] = ['loading', 'result']
const { runnableComponents, worldStore } = getContext<AppEditorContext>('AppEditorContext')
const { app, runnableComponents, worldStore } = getContext<AppEditorContext>('AppEditorContext')
let labelValue: string = 'Default label'
let color: ButtonType.Color
@@ -47,6 +49,8 @@
isLoading = value
}
})
$: css = concatCustomCss($app.css?.formcomponent, customCss)
</script>
<InputValue {id} input={configuration.goto} bind:value={goto} />
@@ -64,9 +68,13 @@
autoRefresh={false}
forceSchemaDisplay={true}
runnableClass="!block"
runnableStyle={css?.container.style}
>
<AlignWrapper {horizontalAlignment}>
<div class="flex flex-col gap-2 px-4 w-full">
<div
class="flex flex-col gap-2 px-4 w-full {css?.container?.class ?? ''}"
style={css?.container?.style ?? ''}
>
<div>
{#if noInputs}
<div class="text-gray-600 italic text-sm my-4">
@@ -84,7 +92,8 @@
{#if !noInputs}
<Button
loading={isLoading}
btnClasses="my-1"
btnClasses="my-1 {css?.button?.class ?? ''}"
style={css?.button?.style ?? ''}
on:pointerdown={(e) => {
e?.stopPropagation()
window.dispatchEvent(new Event('pointerup'))
@@ -5,13 +5,14 @@
import { Icon } from 'svelte-awesome'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext } from '../../types'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
import type RunnableComponent from '../helpers/RunnableComponent.svelte'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
import Portal from 'svelte-portal'
import Modal from '$lib/components/common/modal/Modal.svelte'
import { concatCustomCss } from '../../utils'
export let id: string
export let componentInput: AppInput | undefined
@@ -20,10 +21,11 @@
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 const staticOutputs: string[] = ['loading', 'result']
const { runnableComponents, worldStore } = getContext<AppEditorContext>('AppEditorContext')
const { app, runnableComponents, worldStore } = getContext<AppEditorContext>('AppEditorContext')
let labelValue: string = 'Default label'
let color: ButtonType.Color
@@ -35,6 +37,8 @@
let ownClick: boolean = false
let errors: Record<string, string> = {}
let open: boolean = false
$: errorsMessage = Object.values(errors)
.filter((x) => x != '')
.join('\n')
@@ -62,7 +66,7 @@
$: loading = isLoading && ownClick
let open: boolean = false
$: css = concatCustomCss($app?.css?.formbuttoncomponent, customCss)
</script>
<InputValue {id} input={configuration.label} bind:value={labelValue} />
@@ -79,6 +83,8 @@
<Modal
{open}
title={labelValue}
class={css?.popup.class}
style={css?.popup.style}
on:canceled={() => {
open = false
}}
@@ -148,6 +154,8 @@
{disabled}
{size}
{color}
btnClasses={css?.button?.class ?? ''}
style={css?.button?.style ?? ''}
on:click={(e) => {
open = true
}}
@@ -15,13 +15,18 @@
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
import type { AppInput } from '../../inputType'
import InputValue from '../helpers/InputValue.svelte'
import { concatCustomCss } from '../../utils'
import { getContext } from 'svelte'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: Record<string, AppInput>
export let initializing: boolean | undefined = undefined
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
export const staticOutputs: string[] = ['loading', 'result']
const { app } = getContext<AppEditorContext>('AppEditorContext')
ChartJS.register(
Title,
@@ -77,17 +82,21 @@
}
]
}
$: css = concatCustomCss($app.css?.barchartcomponent, customCss)
</script>
<InputValue {id} input={configuration.theme} bind:value={theme} />
<InputValue {id} input={configuration.line} bind:value={lineChart} />
<RunnableWrapper flexWrap autoRefresh bind:componentInput {id} bind:initializing bind:result>
{#if result}
{#if lineChart}
<Line {data} options={lineOptions} />
{:else}
<Bar {data} options={barOptions} />
<div class="w-full h-full {css?.container?.class ?? ''}" style={css?.container?.style ?? ''}>
{#if result}
{#if lineChart}
<Line {data} options={lineOptions} />
{:else}
<Bar {data} options={barOptions} />
{/if}
{/if}
{/if}
</div>
</RunnableWrapper>
@@ -1,16 +1,23 @@
<script lang="ts">
import { getContext } from 'svelte'
import type { AppInput } from '../../inputType'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
export let id: string
export let componentInput: AppInput | undefined
export let initializing: boolean | undefined = undefined
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
export const staticOutputs: string[] = ['result', 'loading']
const { app } = getContext<AppEditorContext>('AppEditorContext')
let result: string | undefined = undefined
let h: number | undefined = undefined
let w: number | undefined = undefined
$: css = concatCustomCss($app.css?.htmlcomponent, customCss)
</script>
<div
@@ -25,8 +32,8 @@
{#key result}
<iframe
frameborder="0"
style="height: {h}px; width: {w}px"
class="p-0"
style="height: {h}px; width: {w}px; {css?.container?.style ?? ''}"
class="p-0 {css?.container?.class ?? ''}"
title="sandbox"
srcdoc={result
? '<scr' + `ipt type="application/javascript" src="/tailwind.js"></script>` + result
@@ -14,13 +14,18 @@
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
import type { AppInput } from '../../inputType'
import InputValue from '../helpers/InputValue.svelte'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import { getContext } from 'svelte'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: Record<string, AppInput>
export let initializing: boolean | undefined = undefined
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
export const staticOutputs: string[] = ['loading', 'result']
const { app } = getContext<AppEditorContext>('AppEditorContext')
ChartJS.register(
Title,
@@ -60,17 +65,21 @@
}
]
}
$: css = concatCustomCss($app.css?.piechartcomponent, customCss)
</script>
<InputValue {id} input={configuration.theme} bind:value={theme} />
<InputValue {id} input={configuration.doughnutStyle} bind:value={doughnut} />
<RunnableWrapper flexWrap autoRefresh bind:componentInput {id} bind:initializing bind:result>
{#if result}
{#if doughnut}
<Doughnut {data} {options} />
{:else}
<Pie {data} {options} />
<div class="w-full h-full {css?.container?.class ?? ''}" style={css?.container?.style ?? ''}>
{#if result}
{#if doughnut}
<Doughnut {data} {options} />
{:else}
<Pie {data} {options} />
{/if}
{/if}
{/if}
</div>
</RunnableWrapper>
@@ -17,16 +17,21 @@
import Scatter from 'svelte-chartjs/Scatter.svelte'
import InputValue from '../helpers/InputValue.svelte'
import type { ChartOptions, ChartData } from 'chart.js'
import { concatCustomCss } from '../../utils'
import { getContext } from 'svelte'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: Record<string, AppInput>
export let initializing: boolean | undefined = undefined
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
let zoomable = false
let pannable = false
export const staticOutputs: string[] = ['loading', 'result']
const { app } = getContext<AppEditorContext>('AppEditorContext')
ChartJS.register(
Title,
@@ -66,13 +71,17 @@
$: data = {
datasets: result ?? []
} as ChartData<'scatter', (number | Point)[], unknown>
$: css = concatCustomCss($app.css?.scatterchartcomponent, customCss)
</script>
<InputValue {id} input={configuration.zoomable} bind:value={zoomable} />
<InputValue {id} input={configuration.pannable} bind:value={pannable} />
<RunnableWrapper flexWrap autoRefresh bind:componentInput {id} bind:initializing bind:result>
{#if result}
<Scatter {data} {options} />
{/if}
<div class="w-full h-full {css?.container?.class ?? ''}" style={css?.container?.style ?? ''}>
{#if result}
<Scatter {data} {options} />
{/if}
</div>
</RunnableWrapper>
@@ -20,13 +20,18 @@
import { Scatter } from 'svelte-chartjs'
import InputValue from '../helpers/InputValue.svelte'
import type { ChartOptions, ChartData } from 'chart.js'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { getContext } from 'svelte'
import { concatCustomCss } from '../../utils'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: Record<string, AppInput>
export let initializing: boolean | undefined = undefined
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
export const staticOutputs: string[] = ['loading', 'result']
const { app } = getContext<AppEditorContext>('AppEditorContext')
let logarithmicScale = false
let zoomable = false
@@ -80,6 +85,8 @@
$: data = {
datasets: result ?? []
} as ChartData<'scatter', (number | Point)[], unknown>
$: css = concatCustomCss($app.css?.timeseriescomponent, customCss)
</script>
<InputValue {id} input={configuration.logarithmicScale} bind:value={logarithmicScale} />
@@ -87,7 +94,9 @@
<InputValue {id} input={configuration.pannable} bind:value={pannable} />
<RunnableWrapper flexWrap autoRefresh bind:componentInput {id} bind:initializing bind:result>
{#if result}
<Scatter {data} {options} />
{/if}
<div class="w-full h-full {css?.container?.class ?? ''}" style={css?.container?.style ?? ''}>
{#if result}
<Scatter {data} {options} />
{/if}
</div>
</RunnableWrapper>
@@ -1,12 +1,11 @@
<script lang="ts">
import { Loader2 } from 'lucide-svelte'
import { onMount } from 'svelte'
import type { AppInput } from '../../inputType'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: Record<string, AppInput>
// export let configuration: Record<string, AppInput>
export let initializing: boolean | undefined = undefined
export const staticOutputs: string[] = ['result', 'loading']
@@ -42,11 +41,6 @@
<div class="w-full h-full" bind:clientHeight={h} bind:clientWidth={w}>
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
{#if !Plotly}
<div class="p-2">
<Loader2 class="animate-spin" />
</div>
{/if}
<div on:pointerdown bind:this={divEl} />
</RunnableWrapper>
</div>
@@ -1,5 +1,4 @@
<script lang="ts">
import { Loader2 } from 'lucide-svelte'
import { onMount } from 'svelte'
import type { AppInput } from '../../inputType'
import InputValue from '../helpers/InputValue.svelte'
@@ -54,11 +53,6 @@
<div class="w-full h-full" bind:clientHeight={h} bind:clientWidth={w}>
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
{#if !vegaEmbed}
<div class="p-2">
<Loader2 class="animate-spin" />
</div>
{/if}
<div on:pointerdown bind:this={divEl} />
</RunnableWrapper>
</div>
@@ -1,7 +1,7 @@
<script lang="ts">
import { getContext, onMount } from 'svelte'
import type { Output } from '../../../rx'
import type { AppEditorContext, BaseAppComponent } from '../../../types'
import type { AppEditorContext, BaseAppComponent, ComponentCustomCSS } from '../../../types'
import InputValue from '../../helpers/InputValue.svelte'
import type { AppInput } from '../../../inputType'
import RunnableWrapper from '../../helpers/RunnableWrapper.svelte'
@@ -14,12 +14,17 @@
import { tableOptions } from './tableOptions'
import Alert from '$lib/components/common/alert/Alert.svelte'
import type { ButtonComponent } from '../../../editor/component'
import { concatCustomCss } from '../../../utils'
import { twMerge } from 'tailwind-merge'
export let id: string
export let componentInput: AppInput | undefined
export let configuration: Record<string, AppInput>
export let actionButtons: (BaseAppComponent & ButtonComponent)[]
export let initializing: boolean | undefined = undefined
export let customCss:
| ComponentCustomCSS<'container' | 'tableHeader' | 'tableBody' | 'tableFooter'>
| undefined = undefined
export const staticOutputs: string[] = [
'selectedRow',
@@ -51,8 +56,11 @@
let table = createSvelteTable(options)
const { worldStore, staticOutputs: staticOutputsStore } =
getContext<AppEditorContext>('AppEditorContext')
const {
app,
worldStore,
staticOutputs: staticOutputsStore
} = getContext<AppEditorContext>('AppEditorContext')
let selectedRowIndex = -1
@@ -133,13 +141,22 @@
}
$: result && rerender()
$: css = concatCustomCss($app.css?.tablecomponent, customCss)
</script>
<InputValue {id} input={configuration.search} bind:value={search} />
<RunnableWrapper flexWrap bind:componentInput {id} bind:initializing bind:result>
{#if Array.isArray(result) && result.every(isObject)}
<div class="border border-gray-300 shadow-sm divide-y divide-gray-300 flex flex-col h-full">
<div
class={twMerge(
'border border-gray-300 shadow-sm divide-y divide-gray-300 h-full',
css?.container?.class ?? '',
'flex flex-col'
)}
style={css?.container?.style ?? ''}
>
{#if search !== 'Disabled'}
<div class="px-2 py-1">
<div class="flex items-center">
@@ -152,7 +169,14 @@
<div class="overflow-x-auto flex-1 w-full">
<table class="relative w-full border-b border-b-gray-200">
<thead class="sticky top-0 z-40 bg-gray-50 text-left">
<thead
class={twMerge(
'bg-gray-50 text-left',
css?.tableHeader?.class ?? '',
'sticky top-0 z-40'
)}
style={css?.tableHeader?.style ?? ''}
>
{#each $table.getHeaderGroups() as headerGroup}
<tr class="divide-x">
{#each headerGroup.headers as header}
@@ -178,7 +202,10 @@
</tr>
{/each}
</thead>
<tbody class="divide-y divide-gray-200 bg-white ">
<tbody
class={twMerge('divide-y divide-gray-200 bg-white', css?.tableBody?.class ?? '')}
style={css?.tableBody?.style ?? ''}
>
{#each $table.getRowModel().rows as row, rowIndex (row.id)}
<tr
class={classNames(
@@ -235,7 +262,13 @@
</table>
</div>
<AppTableFooter paginationEnabled={pagination} {result} {table} />
<AppTableFooter
paginationEnabled={pagination}
{result}
{table}
class={css?.tableFooter.class}
style={css?.tableFooter.style}
/>
</div>
{:else if result != undefined}
<Alert title="Parsing issues" type="error" size="xs">
@@ -4,6 +4,7 @@
import type { Table } from '@tanstack/svelte-table'
import { ChevronLeft, ChevronRight } from 'lucide-svelte'
import type { Readable } from 'svelte/store'
import { twMerge } from 'tailwind-merge'
import { tableOptions } from './tableOptions'
type T = Record<string, any>
@@ -11,6 +12,9 @@
export let result: Array<T>
export let paginationEnabled: boolean = false
export let table: Readable<Table<T>>
let c = ''
export { c as class }
export let style = ''
function downloadResultAsJSON() {
const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(result))
@@ -23,7 +27,10 @@
}
</script>
<div class="px-2 py-1 text-xs flex flex-row gap-2 items-center justify-between">
<div
class={twMerge('px-2 py-1 text-xs gap-2 items-center justify-between', c, 'flex flex-row')}
{style}
>
{#if paginationEnabled && result.length > (tableOptions.initialState?.pagination?.pageSize ?? 25)}
<div class="flex items-center gap-2 flex-row">
<Button
@@ -25,6 +25,7 @@
export let defaultUserInput = false
export let flexWrap = false
export let wrapperClass = ''
export let wrapperStyle = ''
export let initializing: boolean | undefined = undefined
export let gotoUrl: string | undefined = undefined
@@ -270,7 +271,7 @@
bind:this={testJobLoader}
/>
<div class="h-full flex relative flex-row flex-wrap {wrapperClass}">
<div class="h-full flex relative flex-row flex-wrap {wrapperClass}" style={wrapperStyle}>
{#if !initializing && autoRefresh === true}
<div class="flex absolute top-1 right-1">
<RefreshButton componentId={id} />
@@ -18,6 +18,7 @@
export let defaultUserInput = false
export let flexWrap = false
export let runnableClass = ''
export let runnableStyle = ''
export let goto: string | undefined = undefined
const { staticExporter, noBackend } = getContext<AppEditorContext>('AppEditorContext')
@@ -55,6 +56,7 @@
{forceSchemaDisplay}
{initializing}
wrapperClass={runnableClass}
wrapperStyle={runnableStyle}
>
<slot />
</RunnableComponent>
@@ -3,7 +3,8 @@
import { getContext } from 'svelte'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext } from '../../types'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
@@ -11,8 +12,9 @@
export let configuration: Record<string, AppInput>
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let customCss: ComponentCustomCSS<'text'> | undefined = undefined
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
export const staticOutputs: string[] = ['result']
@@ -27,6 +29,8 @@
}
$: defaultValue != undefined && outputs?.result.set(defaultValue)
$: css = concatCustomCss($app.css?.checkboxcomponent, customCss)
</script>
<InputValue {id} input={configuration.label} bind:value={labelValue} />
@@ -40,6 +44,8 @@
}}
checked={defaultValue}
options={{ right: labelValue }}
textClass={css?.text?.class ?? ''}
textStyle={css?.text?.style ?? ''}
on:change={(e) => {
outputs.result.set(e.detail)
}}
@@ -3,17 +3,20 @@
import Select from 'svelte-select'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext } from '../../types'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
import { SELECT_INPUT_DEFAULT_STYLE } from '../../../../defaults'
export const staticOutputs: string[] = ['result']
export let id: string
export let configuration: Record<string, AppInput>
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
const { worldStore, connectingInput, selectedComponent } =
const { app, worldStore, connectingInput, selectedComponent } =
getContext<AppEditorContext>('AppEditorContext')
let items: { label: string; value: any }[]
let multiple: boolean = false
@@ -65,6 +68,8 @@
} catch (_) {}
outputs?.result.set(result)
}
$: css = concatCustomCss($app.css?.selectcomponent, customCss)
</script>
<InputValue {id} input={configuration.items} bind:value={items} />
@@ -72,13 +77,15 @@
<InputValue {id} input={configuration.placeholder} bind:value={placeholder} />
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
<div class="app-select w-full" style="height: 34px" on:pointerdown|stopPropagation>
<div class="app-select w-full mx-0.5" style="height: 34px" on:pointerdown|stopPropagation>
<Select
--height="34px"
{multiple}
on:clear={onChange}
on:change={onChange}
items={listItems}
class={css?.input?.class ?? ''}
inputStyles={SELECT_INPUT_DEFAULT_STYLE.inputStyles}
containerStyles={SELECT_INPUT_DEFAULT_STYLE.containerStyles + css?.input.style}
{value}
{placeholder}
on:click={() => {
@@ -2,7 +2,8 @@
import { getContext } from 'svelte'
import type { AppInput } from '../../inputType'
import type { Output } from '../../rx'
import type { AppEditorContext } from '../../types'
import type { AppEditorContext, ComponentCustomCSS } from '../../types'
import { concatCustomCss } from '../../utils'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputDefaultValue from '../helpers/InputDefaultValue.svelte'
import InputValue from '../helpers/InputValue.svelte'
@@ -12,8 +13,9 @@
export let inputType = 'text'
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export const staticOutputs: string[] = ['result']
export let customCss: ComponentCustomCSS<'input'> | undefined = undefined
const { worldStore } = getContext<AppEditorContext>('AppEditorContext')
const { app, worldStore } = getContext<AppEditorContext>('AppEditorContext')
let input: HTMLInputElement
let placeholder: string | undefined = undefined
@@ -28,6 +30,8 @@
}
$: input && handleInput()
$: css = concatCustomCss($app.css?.textinputcomponent, customCss)
</script>
<InputValue {id} input={configuration.placeholder} bind:value={placeholder} />
@@ -36,7 +40,8 @@
<AlignWrapper {verticalAlignment}>
<input
class="mx-0.5"
class="mx-0.5 {css?.input?.class ?? ''}"
style={css?.input?.style ?? ''}
on:focus={(e) => {
e?.stopPropagation()
window.dispatchEvent(new Event('pointerup'))
@@ -6,4 +6,4 @@ export { default as AppNumberInput } from './AppNumberInput.svelte'
export { default as AppRangeInput } from './AppRangeInput.svelte'
export { default as AppSelect } from './AppSelect.svelte'
export { default as AppSliderInputs } from './AppSliderInputs.svelte'
export { default as AppTextInput } from './AppTextInput.svelte'
export { default as AppTextInput } from './AppTextInput.svelte'
@@ -2,12 +2,14 @@
import { getContext } from 'svelte'
import SubGridEditor from '../../editor/SubGridEditor.svelte'
import type { AppInput } from '../../inputType'
import type { AppEditorContext, GridItem } from '../../types'
import type { AppEditorContext, ComponentCustomCSS, GridItem } from '../../types'
import { concatCustomCss } from '../../utils'
import InputValue from '../helpers/InputValue.svelte'
export let id: string
export let configuration: Record<string, AppInput>
export let componentContainerHeight: number
export let customCss: ComponentCustomCSS<'container'> | undefined = undefined
let noPadding: boolean | undefined = undefined
@@ -24,6 +26,8 @@
}
$: $selectedComponent === id && onFocus()
$: css = concatCustomCss($app.css?.containercomponent, customCss)
</script>
<InputValue {id} input={configuration.noPadding} bind:value={noPadding} />
@@ -32,6 +36,8 @@
{#if $app.subgrids?.[`${id}-0`]}
<SubGridEditor
{noPadding}
class={css?.container.class}
style={css?.container.style}
bind:subGrid={$app.subgrids[`${id}-0`]}
containerHeight={componentContainerHeight}
on:focus={() => {
@@ -2,12 +2,16 @@
import { classNames } from '$lib/utils'
import { createEventDispatcher, getContext } from 'svelte'
import Grid from '@windmill-labs/svelte-grid'
import { twMerge } from 'tailwind-merge'
import { columnConfiguration, isFixed, toggleFixed } from '../gridUtils'
import type { AppEditorContext, GridItem } from '../types'
import Component from './component/Component.svelte'
import { findGridItem } from './appUtils'
export let containerHeight: number
let classes = ''
export { classes as class }
export let style = ''
export let noPadding = false
//export let id: string
export let subGrid: GridItem[] = []
@@ -64,12 +68,11 @@
bind:this={container}
>
<div
class:px-2={!noPadding}
class="py-2 overflow-auto {$connectingInput?.opened ? '' : ''}"
class={twMerge('py-2 overflow-auto', classes ?? '', noPadding ? 'px-0' : 'px-2')}
on:pointerdown|stopPropagation={onpointerdown}
on:pointerleave={onpointerup}
on:pointerup={onpointerup}
style="height: {containerHeight}px;"
style="height: {containerHeight}px; {style ?? ''}"
>
<div>
<Grid
@@ -175,6 +175,9 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
onlyStatic: true
}
},
customCss: {
container: { class: '', style: '' }
} as const,
componentInput: undefined,
card: false,
numberOfSubgrids: 1
@@ -336,7 +339,10 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
value: ''
}
},
customCss: {},
customCss: {
container: { class: '', style: '' },
button: { class: '', style: '' }
} as const,
card: true
}
},
@@ -377,7 +383,10 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
optionValuesKey: 'buttonSizeOptions'
}
},
customCss: {},
customCss: {
button: { class: '', style: '' },
popup: { class: '', style: '' }
} as const,
card: true
}
},
@@ -408,7 +417,9 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
fieldType: 'object',
value: { data: [25, 50, 25], labels: ['Pie', 'Charts', '<3'] }
},
customCss: {},
customCss: {
container: { class: '', style: '' }
} as const,
card: true
}
},
@@ -439,7 +450,9 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
fieldType: 'object',
value: { data: [25, 50, 25], labels: ['Bar', 'Charts', '<3'] }
},
customCss: {},
customCss: {
container: { class: '', style: '' }
} as const,
card: true
}
},
@@ -462,7 +475,9 @@ Hello \${ctx.username}
</h1>`
},
configuration: {},
customCss: {},
customCss: {
container: { class: '', style: '' }
} as const,
card: false
}
},
@@ -604,7 +619,9 @@ Hello \${ctx.username}
}
]
},
customCss: {},
customCss: {
container: { class: '', style: '' }
} as const,
card: true
}
},
@@ -654,7 +671,9 @@ Hello \${ctx.username}
}
]
},
customCss: {},
customCss: {
container: { class: '', style: '' }
} as const,
card: true
}
},
@@ -691,7 +710,12 @@ Hello \${ctx.username}
}
]
},
customCss: {},
customCss: {
container: { class: '', style: '' },
tableHeader: { class: '', style: '' },
tableBody: { class: '', style: '' },
tableFooter: { class: '', style: '' }
} as const,
card: true,
actionButtons: []
}
@@ -747,7 +771,7 @@ Hello \${ctx.username}
]
},
customCss: {},
card: true,
card: true
}
},
checkboxcomponent: {
@@ -772,7 +796,9 @@ Hello \${ctx.username}
fieldType: 'boolean'
}
},
customCss: {},
customCss: {
text: { class: '', style: '' }
} as const,
card: false
}
},
@@ -799,7 +825,9 @@ Hello \${ctx.username}
fieldType: 'text'
}
},
customCss: {},
customCss: {
input: { class: '', style: '' }
} as const,
card: false
}
},
@@ -835,7 +863,9 @@ Hello \${ctx.username}
onlyStatic: true
}
},
customCss: {},
customCss: {
input: { style: '' }
} as const,
card: false,
softWrap: true
}
@@ -865,17 +895,17 @@ Hello \${ctx.username}
min: {
type: 'static',
value: undefined,
fieldType: 'number',
fieldType: 'number'
},
max: {
type: 'static',
value: undefined,
fieldType: 'number',
fieldType: 'number'
},
step: {
type: 'static',
value: 1,
fieldType: 'number',
fieldType: 'number'
}
},
customCss: {},
@@ -943,17 +973,17 @@ Hello \${ctx.username}
max: {
type: 'static',
value: 42,
fieldType: 'number',
fieldType: 'number'
},
defaultValue: {
type: 'static',
value: 20,
fieldType: 'number',
fieldType: 'number'
},
step: {
type: 'static',
value: 1,
fieldType: 'number',
fieldType: 'number'
}
},
customCss: {},
@@ -974,27 +1004,27 @@ Hello \${ctx.username}
min: {
type: 'static',
value: 0,
fieldType: 'number',
fieldType: 'number'
},
max: {
type: 'static',
value: 42,
fieldType: 'number',
fieldType: 'number'
},
defaultLow: {
type: 'static',
value: 10,
fieldType: 'number',
fieldType: 'number'
},
defaultHigh: {
type: 'static',
value: 20,
fieldType: 'number',
fieldType: 'number'
},
step: {
type: 'static',
value: 1,
fieldType: 'number',
fieldType: 'number'
}
},
customCss: {},
@@ -1,34 +1,59 @@
<script lang="ts">
import type { ComponentCssProperty } from "../../types"
import { X } from 'lucide-svelte'
import { fade } from 'svelte/transition'
import { addWhitespaceBeforeCapitals } from '../../../../utils'
import type { ComponentCssProperty } from '../../types'
export let name: string
export let value: ComponentCssProperty | undefined
function reset(property: keyof ComponentCssProperty) {
if (value) {
value[property] = ''
}
}
</script>
<div class="text-sm font-semibold text-gray-500 capitalize pt-2">
{name}
{addWhitespaceBeforeCapitals(name)}
</div>
{#if value}
<div class="border-l border-gray-400/80 py-1 pl-3.5 mt-1 ml-0.5">
<label class="block pb-2">
<div class="text-xs font-medium pb-0.5">
Style
</div>
<input
type="text"
bind:value={value.style}
on:focus
/>
</label>
<label class="block">
<div class="text-xs font-medium pb-0.5">
Tailwind classes
</div>
<input
type="text"
bind:value={value.class}
on:focus
/>
</label>
{#if value.style !== undefined}
<label class="block pb-2">
<div class="text-xs font-medium pb-0.5"> Style </div>
<div class="relative">
<input type="text" class="!pr-7" bind:value={value.style} on:focus />
{#if value?.style}
<button
transition:fade={{ duration: 100 }}
class="absolute z-10 top-1.5 right-1 rounded-full p-1 duration-200 hover:bg-gray-200"
aria-label="Remove styles"
on:click|preventDefault|stopPropagation={() => reset('style')}
>
<X size={14} />
</button>
{/if}
</div>
</label>
{/if}
{#if value.class !== undefined}
<label class="block">
<div class="text-xs font-medium pb-0.5"> Tailwind classes </div>
<div class="relative">
<input type="text" class="!pr-7" bind:value={value.class} on:focus />
{#if value?.class}
<button
transition:fade={{ duration: 100 }}
class="absolute z-10 top-1.5 right-1 rounded-full p-1 duration-200 hover:bg-gray-200"
aria-label="Remove classes"
on:click|preventDefault|stopPropagation={() => reset('class')}
>
<X size={14} />
</button>
{/if}
</div>
</label>
{/if}
</div>
{/if}
{/if}
@@ -9,15 +9,21 @@
import { isOpenStore } from './store'
import CssProperty from './CssProperty.svelte'
import { components, type AppComponent } from '../component'
import { slide } from 'svelte/transition'
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']
interface CustomCSSEntry {
type: 'app' | AppComponent['type'];
name: string;
icon: any;
ids: string[];
type: CustomCSSType
name: string
icon: any
ids: string[]
}
const TITLE_PREFIX = 'Css.' as const
const { app } = getContext<AppEditorContext>('AppEditorContext')
let rawCode = ''
@@ -51,7 +57,7 @@
icon: LayoutDashboardIcon,
ids: ['viewer', 'grid', 'component']
},
...Object.values(components).map(({ name, icon, data: { type, customCss }}) => ({
...Object.values(components).map(({ name, icon, data: { type, customCss } }) => ({
type,
name,
icon,
@@ -70,7 +76,7 @@
}
e.ids.forEach((id) => {
if (!newCss[e.type][id]) {
newCss[e.type][id] = { style: '', class: '' }
newCss[e.type][id] = components?.[e.type]?.data?.customCss?.[id] ?? { class: '', style: '' }
}
})
e.ids
@@ -84,20 +90,32 @@
//@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 => {
[{ name: 'App' }, ...Object.values(components)].map((component) => {
return { [TITLE_PREFIX + component.name]: false }
})
)
isOpenStore.addItems([{ [SHOW_UNUSED_ID]: false }])
})
</script>
<Tabs
selected="ui"
on:selected={(e) => switchTab(e.detail === 'json')}
class="relative"
>
<Tabs selected="ui" on:selected={(e) => switchTab(e.detail === 'json')} class="relative">
<Tab value="ui" size="xs" class="grow">
<div class="m-1 center-center">
<MousePointer2 size={16} />
@@ -112,7 +130,7 @@
</Tab>
<div slot="content" class="h-full overflow-y-auto">
<TabContent value="ui">
{#each entries as { type, name, icon, ids }}
{#each [...staticComponents, ...usedComponents] as { type, name, icon, ids }}
{#if ids.length > 0}
<ListItem title={name} prefix={TITLE_PREFIX}>
<div slot="title" class="flex items-center">
@@ -137,6 +155,44 @@
</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]}
{JSON.stringify($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)}
@@ -10,7 +10,7 @@
$: isOpen = $isOpenStore[storeTitle]
</script>
<section class="mt-1 mb-2 px-1">
<section class="pt-1 pb-2 px-1">
<button
on:click|preventDefault={() => isOpenStore.toggle(storeTitle)}
class="w-full flex justify-between items-center text-gray-700 px-2 py-1
@@ -166,7 +166,7 @@
<PanelSection title="Custom CSS">
{#each Object.keys(component.customCss ?? {}) as name}
{#if component?.customCss?.[name]}
<div class="mb-2">
<div class="w-full mb-2">
<CssProperty {name} bind:value={component.customCss[name]} />
</div>
{/if}
+2 -2
View File
@@ -30,8 +30,8 @@ export interface GeneralAppInput {
}
export type ComponentCssProperty = {
class: string
style: string
class?: string
style?: string
}
export type ComponentCustomCSS<T extends string = string> = Record<T, ComponentCssProperty>
+131 -41
View File
@@ -3,49 +3,14 @@ import { FlowService, ScriptService } from '$lib/gen'
import { inferArgs } from '$lib/infer'
import { emptySchema } from '$lib/utils'
import type { AppComponent } from './editor/component'
import type { App, ComponentCssProperty, ComponentCustomCSS, GridItem } from './types'
import { getRecommendedDimensionsByComponent } from './editor/component'
import { gridColumns } from './gridUtils'
import gridHelp from '@windmill-labs/svelte-grid/src/utils/helper'
import { twMerge } from 'tailwind-merge'
import type { AppInput, InputType, ResultAppInput, StaticAppInput } from './inputType'
import type { Output } from './rx'
import type { App, GridItem } from './types'
/*
export function deleteComponent(
subgrid: string | undefined,
component: AppComponent,
app: App,
staticOutputs: Record<string, any>,
runnableComponents: Record<string, any>
) {
if (parentItems) {
let index = parentItems.findIndex((item) => item.data?.id === component.id)
if (index != -1) {
parentItems.splice(index, 1)
}
}
delete staticOutputs[component.id]
delete runnableComponents[component.id]
if (
component.componentInput?.type === 'runnable' &&
component.componentInput?.runnable?.type === 'runnableByName'
) {
const { name, inlineScript } = component.componentInput.runnable
if (inlineScript) {
if (!app.unusedInlineScripts) {
app.unusedInlineScripts = []
}
app.unusedInlineScripts.push({
name,
inlineScript
})
}
}
}
*/
import { getNextId } from '../flows/flowStateUtils'
export function allItems(
grid: GridItem[],
@@ -273,3 +238,128 @@ export function toPascalCase(text: string) {
export function toKebabCase(text: string) {
return text.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
}
export function findParent(root: GridItem[], id: string): GridItem | undefined {
for (const a of root) {
if (a.id === id) {
return a
}
if (a.data.subGrids) {
// Recursively search the sub-grids
for (const subGrid of a.data.subGrids) {
const result = findParent(subGrid, id)
if (result) {
return result
}
}
}
}
return undefined
}
export function insertNewGridItem(
root: GridItem[],
id: string,
subGridIndex: number,
newId: string,
data: AppComponent
): GridItem[] {
const parentA = findParent(root, id)
if (!parentA) {
throw new Error(`Parent A object with ID ${id} not found.`)
}
const subGrid = parentA.data.subGrids[subGridIndex]
if (!subGrid) {
throw new Error(`Sub-grid with index ${subGridIndex} not found.`)
}
const newItem = createNewGridItem(subGrid ?? [], newId, data)
subGrid.push(newItem)
return root
}
// The grid is needed to find a space for the new component
export function createNewGridItem(grid: GridItem[], id: string, data: AppComponent): GridItem {
const appComponent = data
appComponent.id = id
const newComponent = {
fixed: false,
resizable: true,
draggable: true,
customDragger: false,
customResizer: false,
x: 0,
y: 0
}
let newData: AppComponent = JSON.parse(JSON.stringify(appComponent))
const newItem: GridItem = {
data: newData,
id: id
}
gridColumns.forEach((column) => {
const rec = getRecommendedDimensionsByComponent(appComponent.type, column)
newItem[column] = {
...newComponent,
min: { w: 1, h: 1 },
max: { w: column, h: 100 },
w: rec.w,
h: rec.h
}
const position = gridHelp.findSpace(newItem, grid, column) as { x: number; y: number }
newItem[column] = { ...newItem[column], ...position }
})
return newItem
}
function recursiveGetIds(gridItem: GridItem): string[] {
const subGrids = gridItem.data.subGrids ?? []
const subGridIds = subGrids
.map((subGrid: GridItem[]) => subGrid.map(recursiveGetIds))
.flat(Infinity)
return [gridItem.data.id, ...subGridIds]
}
export function getNextGridItemId(grid: GridItem[] = []): string {
const gridItemIds = grid.map(recursiveGetIds).flat()
const id = getNextId(gridItemIds)
return id
}
export function concatCustomCss<T extends string = string>(
appCss?: ComponentCustomCSS<T>,
componentCss?: ComponentCustomCSS<T>
): Record<T, ComponentCssProperty> | undefined {
if (!componentCss) return undefined
const customStyle = {} as Record<T, ComponentCssProperty>
Object.keys(componentCss).forEach((key) => {
const k = key as keyof typeof componentCss
// 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 = 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
}
@@ -1,12 +1,15 @@
<script lang="ts">
import { classNames } from '$lib/utils'
import { createEventDispatcher } from 'svelte'
import { fade } from 'svelte/transition'
import Button from '../button/Button.svelte'
import Badge from '../badge/Badge.svelte'
import { twMerge } from 'tailwind-merge'
export let title: string
export let open: boolean = false
let c: string = ''
export { c as class }
export let style = ''
const dispatch = createEventDispatcher()
@@ -40,7 +43,7 @@
role="dialog"
>
<div
class={classNames(
class={twMerge(
'fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity',
open ? 'ease-out duration-300 opacity-100' : 'ease-in duration-200 opacity-0'
)}
@@ -49,12 +52,14 @@
<div class="fixed inset-0 z-10 overflow-y-auto">
<div class="flex min-h-full items-center justify-center p-4">
<div
class={classNames(
class={twMerge(
'relative transform overflow-hidden rounded-lg bg-white px-4 pt-5 pb-4 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-lg sm:p-6',
c,
open
? 'ease-out duration-300 opacity-100 translate-y-0 sm:scale-100'
: 'ease-in duration-200 opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95'
)}
{style}
>
<div class="flex">
<div class="ml-4 text-left flex-1">
+5
View File
@@ -0,0 +1,5 @@
export const SELECT_INPUT_DEFAULT_STYLE = {
inputStyles: 'border-radius: 0;',
containerStyles:
'--height: 34px; --padding: 0 0 0 8px; --font-size: 0.875rem; --border: 1px solid #d1d5db;'
} as const