Files
windmill/frontend/src/lib/components/apps/editor/settingsPanel/StylePanel.svelte
Henri Courdent 3f94fc0b86 grammar errors (#3583)
* Grammar errors

* Grammar errors
2024-04-22 14:00:28 +02:00

281 lines
8.3 KiB
Svelte

<script lang="ts">
import { Tab, TabContent } from '$lib/components/common'
import { sendUserToast } from '$lib/toast'
import { getContext } from 'svelte'
import type { AppViewerContext, ComponentCssProperty } from '../../types'
import { ccomponents, components } from '../component'
import CssProperty from '../componentsPanel/CssProperty.svelte'
import { quickStyleProperties } from '../componentsPanel/quickStyleProperties'
import Tabs from '$lib/components/common/tabs/Tabs.svelte'
import ConfirmationModal from '$lib/components/common/confirmationModal/ConfirmationModal.svelte'
import Badge from '$lib/components/common/badge/Badge.svelte'
import Button from '$lib/components/common/button/Button.svelte'
import { enterpriseLicense } from '$lib/stores'
import Tooltip from '$lib/components/Tooltip.svelte'
import { customisationByComponent, hasStyleValue } from '../componentsPanel/cssUtils'
import CssMigrationModal from './CSSMigrationModal.svelte'
import CssPropertyWrapper from './CssPropertyWrapper.svelte'
import { onMount } from 'svelte'
import { findComponentSettings } from '../appUtils'
const { app, cssEditorOpen, selectedComponent } = getContext<AppViewerContext>('AppViewerContext')
$: component = findComponentSettings($app, $selectedComponent?.[0])?.item?.data
let tab: 'local' | 'global' = 'local'
let overrideGlobalCSS: (() => void) | undefined = undefined
let overrideLocalCSS: (() => void) | undefined = undefined
$: type = component?.type
let migrationModal: CssMigrationModal | undefined = undefined
$: customCssByComponentType =
component?.type && $app.css
? Object.entries($app.css[component.type] || {}).map(([id, v]) => ({
id,
forceStyle: v?.style != undefined,
forceClass: v?.['class'] != undefined
}))
: undefined
function copyLocalToGlobal(name: string, value: ComponentCssProperty | undefined) {
if (!value) {
sendUserToast('No local CSS to copy')
} else {
const type = component?.type
if (!type) return
if (hasStyleValue($app.css?.[type]?.[name])) {
overrideGlobalCSS = () => {
$app.css![type]![name] = JSON.parse(JSON.stringify(value))
app.set($app)
}
} else {
if (!$app.css![type]) {
initGlobalCss()
}
$app.css![type]![name] = JSON.parse(JSON.stringify(value))
app.set($app)
sendUserToast('Global CSS copied')
}
}
}
function copyGlobalToLocal(id: string, value: any) {
if (!value) {
sendUserToast('No global CSS to copy')
} else {
if (hasStyleValue(value)) {
overrideLocalCSS = () => {
component!.customCss![id] = JSON.parse(JSON.stringify(value))
app.set($app)
}
} else {
component!.customCss![id] = JSON.parse(JSON.stringify(value))
app.set($app)
sendUserToast('Local CSS copied')
}
}
}
function initGlobalCss() {
// If the global css is not initialised, we initialise it.
// Should only happen once per app
if (!$app.css) {
$app.css = {}
}
// If the global css for this component type is not initialised, we initialise it.
// Should only happen once per component type
if (
$app.css &&
component &&
!$app.css[component.type]?.style &&
components[component.type] &&
$app.css[component.type] === undefined
) {
$app.css[component.type] = JSON.parse(JSON.stringify(components[component.type].customCss))
app.set($app)
}
}
function getSelector(key: string) {
return customisationByComponent
.find((c) => c.components.includes(component?.type ?? ''))
?.selectors.find((s) => {
return s.customCssKey === key
})?.selector
}
onMount(() => {
initGlobalCss()
})
</script>
{#if component}
{#key component?.id}
<div class="px-2 flex gap-1 flex-col w-full pb-4">
{#if !$cssEditorOpen}
<Button
color="light"
size="xs2"
variant="border"
on:click={() => {
$cssEditorOpen = true
}}
>
<div class="flex flex-row gap-1 text-xs items-center">
Open theme editor{$enterpriseLicense === undefined ? ' (EE only)' : ''}
<Tooltip light>
You can also use the App CSS Editor to customise the CSS of all components.
</Tooltip>
</div>
</Button>
{:else}
<div />
{/if}
{#if $enterpriseLicense !== undefined}
<Button
color="light"
size="xs2"
variant="border"
on:click={() => {
migrationModal?.open()
}}
>
Convert to global CSS
</Button>
{/if}
</div>
<Tabs bind:selected={tab}>
<Tab value="local" size="xs">
<div class="flex flex-row gap-2 items-center">
ID
<Badge color="indigo" size="xs">
{component?.id}
</Badge>
<Tooltip light>
You can customise the CSS and the classes of this component instance. These
customisations will only be applied to this component. You can also apply
custom classes set on the Global styling panel.
</Tooltip>
</div>
</Tab>
<Tab value="global" size="xs">
<div class="flex flex-row gap-2 items-center">
Global: {type ? ccomponents[type].name : ''}
<Tooltip light>
You can customise the CSS and the classes of all components of this type. These
customisations will be applied to all components of this type.
</Tooltip>
</div>
</Tab>
<svelte:fragment slot="content">
<TabContent value="local">
{#if component && component.customCss !== undefined}
<div class="flex-col flex gap-4 divide-y">
{#each Object.keys(ccomponents[component.type].customCss ?? {}) as name}
<div class="w-full">
<CssProperty
quickStyleProperties={quickStyleProperties?.[component.type]?.[name]}
forceStyle={ccomponents[component.type].customCss[name].style !== undefined}
forceClass={ccomponents[component.type].customCss[name].class !== undefined}
tooltip={ccomponents[component.type].customCss[name].tooltip}
{name}
wmClass={getSelector(name)}
componentType={component.type}
bind:value={component.customCss[name]}
on:change={() => app.set($app)}
shouldDisplayRight={hasStyleValue(component.customCss[name])}
on:right={() => {
copyLocalToGlobal(name, component?.customCss?.[name])
tab = 'global'
}}
overridding={hasStyleValue($app.css?.[component.type]?.[name]) &&
hasStyleValue(component.customCss[name])}
/>
</div>
{/each}
</div>
{/if}
</TabContent>
<TabContent value="global">
{#if type}
{#each customCssByComponentType ?? [] as { id, forceStyle, forceClass }}
<div class="w-full">
{#if $app.css && type && $app.css[type] && component?.customCss}
<CssPropertyWrapper
{forceStyle}
{forceClass}
{id}
bind:property={$app.css[type]}
on:left={() => {
copyGlobalToLocal(
id,
component?.type ? $app?.css?.[component?.type]?.[id] : undefined
)
tab = 'local'
}}
overriden={hasStyleValue(component.customCss[id])}
wmClass={getSelector(id)}
/>
{/if}
</div>
{/each}
{/if}
</TabContent>
</svelte:fragment>
</Tabs>
<ConfirmationModal
title="Confirm overriding global CSS"
confirmationText="Override global CSS"
open={Boolean(overrideGlobalCSS)}
on:confirmed={() => {
if (overrideGlobalCSS) {
overrideGlobalCSS()
overrideGlobalCSS = undefined
}
sendUserToast('Global CSS overridden')
}}
on:canceled={() => {
overrideGlobalCSS = undefined
}}
>
<div class="text-primary pb-2">
The global CSS for this component already exists. Do you want to override it?
</div>
</ConfirmationModal>
<ConfirmationModal
title="Confirm overriding local CSS"
confirmationText="Override local CSS"
open={Boolean(overrideLocalCSS)}
on:confirmed={() => {
if (overrideLocalCSS) {
overrideLocalCSS()
overrideLocalCSS = undefined
}
sendUserToast('Local CSS overridden')
}}
on:canceled={() => {
overrideLocalCSS = undefined
}}
>
<div class="text-primary pb-2">
The local CSS for this component already exists. Do you want to override it?
</div>
</ConfirmationModal>
<CssMigrationModal bind:this={migrationModal} bind:component />
{/key}
{:else}
<span class="text-sm text-secondary mx-2">Select a component to style it in this panel</span>
{/if}