mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-06 16:02:23 +00:00
feat(frontend): add markdown component (#1959)
* feat(frontend): add markdown component * feat(frontend): add markdown component * feat(frontend): switch library to fix build * feat(frontend): fix md display * feat(frontend): add a compact prop * feat(frontend): Size as list
This commit is contained in:
Generated
+1850
-37
File diff suppressed because it is too large
Load Diff
@@ -98,6 +98,7 @@
|
||||
"svelte-autosize": "^1.0.1",
|
||||
"svelte-chartjs": "^3.1.0",
|
||||
"svelte-dnd-action": "^0.9.22",
|
||||
"svelte-exmarkdown": "^2.1.0",
|
||||
"svelte-portal": "^2.2.0",
|
||||
"svelte-timezone-picker": "^2.0.3",
|
||||
"tailwind-merge": "^1.13.2",
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte'
|
||||
import { initConfig, initOutput } from '../../editor/appUtils'
|
||||
import type { AppInput } from '../../inputType'
|
||||
import type { AppViewerContext, ComponentCustomCSS, RichConfigurations } from '../../types'
|
||||
import { concatCustomCss } from '../../utils'
|
||||
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
|
||||
import Markdown from 'svelte-exmarkdown'
|
||||
import { classNames } from '$lib/utils'
|
||||
import { components } from '../../editor/component'
|
||||
import ResolveConfig from '../helpers/ResolveConfig.svelte'
|
||||
|
||||
export let id: string
|
||||
export let componentInput: AppInput | undefined
|
||||
export let initializing: boolean | undefined = undefined
|
||||
export let customCss: ComponentCustomCSS<'mardowncomponent'> | undefined = undefined
|
||||
export let render: boolean
|
||||
export let configuration: RichConfigurations
|
||||
|
||||
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
|
||||
|
||||
const resolvedConfig = initConfig(
|
||||
components['mardowncomponent'].initialData.configuration,
|
||||
configuration
|
||||
)
|
||||
|
||||
const outputs = initOutput($worldStore, id, {
|
||||
result: undefined,
|
||||
loading: false
|
||||
})
|
||||
|
||||
let result: string | undefined = undefined
|
||||
|
||||
$: css = concatCustomCss($app.css?.mardowncomponent, customCss)
|
||||
|
||||
const proseMapping = {
|
||||
sm: 'prose-sm',
|
||||
Default: 'prose-base',
|
||||
lg: 'prose-lg',
|
||||
xl: 'prose-xl',
|
||||
'2xl': 'prose-2xl'
|
||||
}
|
||||
</script>
|
||||
|
||||
{#each Object.keys(components['mardowncomponent'].initialData.configuration) as key (key)}
|
||||
<ResolveConfig
|
||||
{id}
|
||||
{key}
|
||||
bind:resolvedConfig={resolvedConfig[key]}
|
||||
configuration={configuration[key]}
|
||||
/>
|
||||
{/each}
|
||||
|
||||
<div
|
||||
on:pointerdown={(e) => {
|
||||
e?.preventDefault()
|
||||
}}
|
||||
class={classNames(
|
||||
'h-full w-full overflow-y-auto prose',
|
||||
resolvedConfig?.size ? proseMapping[resolvedConfig.size] : '',
|
||||
css?.container?.class
|
||||
)}
|
||||
>
|
||||
<RunnableWrapper
|
||||
{outputs}
|
||||
{render}
|
||||
autoRefresh
|
||||
{componentInput}
|
||||
{id}
|
||||
bind:initializing
|
||||
bind:result
|
||||
>
|
||||
{#if result}
|
||||
{#key result}
|
||||
<Markdown md={result} />
|
||||
{/key}
|
||||
{/if}
|
||||
</RunnableWrapper>
|
||||
</div>
|
||||
@@ -13,3 +13,4 @@ export { default as AppText } from './AppText.svelte'
|
||||
export { default as AppTimeseries } from './AppTimeseries.svelte'
|
||||
export { default as PlotlyHtml } from './PlotlyHtml.svelte'
|
||||
export { default as VegaLiteHtml } from './VegaLiteHtml.svelte'
|
||||
export { default as AppMarkdown } from './AppMarkdown.svelte'
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
AppScatterChart,
|
||||
AppTimeseries,
|
||||
AppHtml,
|
||||
AppMarkdown,
|
||||
AppSliderInputs,
|
||||
AppFormButton,
|
||||
VegaLiteHtml,
|
||||
@@ -205,6 +206,15 @@
|
||||
componentInput={component.componentInput}
|
||||
{render}
|
||||
/>
|
||||
{:else if component.type === 'mardowncomponent'}
|
||||
<AppMarkdown
|
||||
id={component.id}
|
||||
customCss={component.customCss}
|
||||
bind:initializing
|
||||
componentInput={component.componentInput}
|
||||
configuration={component.configuration}
|
||||
{render}
|
||||
/>
|
||||
{:else if component.type === 'vegalitecomponent'}
|
||||
<VegaLiteHtml
|
||||
configuration={component.configuration}
|
||||
|
||||
@@ -39,7 +39,8 @@ import {
|
||||
Download,
|
||||
PanelLeft,
|
||||
PanelTopInactive,
|
||||
ListIcon
|
||||
ListIcon,
|
||||
Heading1
|
||||
} from 'lucide-svelte'
|
||||
import type {
|
||||
Aligned,
|
||||
@@ -73,6 +74,7 @@ export type CurrencyComponent = BaseComponent<'currencycomponent'>
|
||||
export type SliderComponent = BaseComponent<'slidercomponent'>
|
||||
export type RangeComponent = BaseComponent<'rangecomponent'>
|
||||
export type HtmlComponent = BaseComponent<'htmlcomponent'>
|
||||
export type MarkdownComponent = BaseComponent<'mardowncomponent'>
|
||||
export type VegaLiteComponent = BaseComponent<'vegalitecomponent'>
|
||||
export type PlotlyComponent = BaseComponent<'plotlycomponent'>
|
||||
export type TimeseriesComponent = BaseComponent<'timeseriescomponent'>
|
||||
@@ -154,6 +156,7 @@ export type TypedComponent =
|
||||
| BarChartComponent
|
||||
| TimeseriesComponent
|
||||
| HtmlComponent
|
||||
| MarkdownComponent
|
||||
| TableComponent
|
||||
| TextComponent
|
||||
| ButtonComponent
|
||||
@@ -277,7 +280,8 @@ export const selectOptions = {
|
||||
'polarArea',
|
||||
'radar',
|
||||
'scatter'
|
||||
] as ChartType[]
|
||||
] as ChartType[],
|
||||
prose: ['sm', 'Default', 'lg', 'xl', '2xl']
|
||||
}
|
||||
const labels = {
|
||||
none: 'Do nothing',
|
||||
@@ -1006,6 +1010,37 @@ Hello \${ctx.username}
|
||||
configuration: {}
|
||||
}
|
||||
},
|
||||
mardowncomponent: {
|
||||
name: 'Markdown',
|
||||
icon: Heading1,
|
||||
documentationLink: `${documentationBaseUrl}#html`,
|
||||
dims: '1:2-1:2' as AppComponentDimensions,
|
||||
customCss: {
|
||||
container: { class: '', style: '' }
|
||||
},
|
||||
initialData: {
|
||||
componentInput: {
|
||||
type: 'static',
|
||||
fieldType: 'template',
|
||||
value: `# This is a header
|
||||
## This is a subheader
|
||||
This is a paragraph.
|
||||
|
||||
* This is a list
|
||||
* With two items`
|
||||
},
|
||||
configuration: {
|
||||
size: {
|
||||
fieldType: 'select',
|
||||
type: 'static',
|
||||
selectOptions: selectOptions.prose,
|
||||
value: 'Default',
|
||||
onlyStatic: true,
|
||||
tooltip: 'See Tailwind documentation: https://tailwindcss.com/docs/typography-plugin'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
vegalitecomponent: {
|
||||
name: 'Vega Lite',
|
||||
icon: PieChart,
|
||||
|
||||
@@ -58,6 +58,7 @@ const display: ComponentSet = {
|
||||
'imagecomponent',
|
||||
'mapcomponent',
|
||||
'htmlcomponent',
|
||||
'mardowncomponent',
|
||||
'pdfcomponent',
|
||||
'displaycomponent',
|
||||
'jobidlogcomponent',
|
||||
|
||||
@@ -570,6 +570,9 @@ export const quickStyleProperties: Record<
|
||||
backgroundGrouping
|
||||
]
|
||||
},
|
||||
mardowncomponent: {
|
||||
container: containerDefaultProps
|
||||
},
|
||||
iconcomponent: {
|
||||
container: containerDefaultProps,
|
||||
icon: [
|
||||
|
||||
Reference in New Issue
Block a user