feat(frontend): app textcomponent editable + tooltip

This commit is contained in:
Ruben Fiszel
2023-03-16 02:34:39 +01:00
parent eebc6ddee6
commit 4db0e0a762
8 changed files with 66 additions and 29 deletions
@@ -577,6 +577,10 @@
})
}
export function focus() {
editor?.focus()
}
onMount(() => {
if (browser) {
loadMonaco()
@@ -8,10 +8,10 @@
import InputValue from '../helpers/InputValue.svelte'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
import { twMerge } from 'tailwind-merge'
import type { AppViewerContext, ComponentCustomCSS } from '../../types'
import type { AppEditorContext, AppViewerContext, ComponentCustomCSS } from '../../types'
import { getContext } from 'svelte'
import ResizeWrapper from '../helpers/ResizeWrapper.svelte'
import { initOutput } from '../../editor/appUtils'
import Tooltip from '$lib/components/Tooltip.svelte'
export let id: string
export let componentInput: AppInput | undefined
@@ -22,7 +22,9 @@
export let customCss: ComponentCustomCSS<'text'> | undefined = undefined
export let render: boolean
const { app, worldStore } = getContext<AppViewerContext>('AppViewerContext')
const { app, worldStore, mode } = getContext<AppViewerContext>('AppViewerContext')
const { ontextfocus } = getContext<AppEditorContext>('AppEditorContext')
initOutput($worldStore, id, {
result: undefined,
@@ -32,7 +34,7 @@
let result: string | undefined = undefined
let style: 'Title' | 'Subtitle' | 'Body' | 'Caption' | 'Label' | undefined = undefined
let copyButton: boolean
let fitContent = false
let tooltip: string = ''
function getComponent() {
switch (style) {
@@ -70,17 +72,27 @@
<InputValue {id} input={configuration.style} bind:value={style} />
<InputValue {id} input={configuration.copyButton} bind:value={copyButton} />
<InputValue {id} input={configuration.fitContent} bind:value={fitContent} />
<InputValue {id} input={configuration.tooltip} bind:value={tooltip} />
<RunnableWrapper {render} {componentInput} {id} bind:initializing bind:result>
<ResizeWrapper {id} shouldWrap={fitContent}>
<div class="h-full w-full overflow-hidden">
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
{#if !result || result === ''}
<div class="text-gray-400 bg-gray-100 flex justify-center items-center h-full w-full">
No text
</div>
{:else}
<div class="flex flex-wrap gap-2 pb-0.5 overflow-x-auto">
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="flex flex-wrap gap-2 pb-0.5 {$mode === 'dnd' && componentInput?.type == 'template'
? 'cursor-text'
: ''}"
on:click={() => {
if ($mode === 'dnd' && componentInput?.type == 'template') {
$ontextfocus?.()
}
}}
>
<svelte:element
this={component}
class={twMerge(
@@ -92,17 +104,26 @@
style={[$app.css?.['textcomponent']?.['text']?.style, customCss?.text?.style].join(';')}
>
{String(result)}
{#if tooltip != ''}
<Tooltip>{tooltip}</Tooltip>
{/if}
{#if copyButton && result}
<Popover notClickable>
<Button
variant="border"
size="xs"
color="dark"
btnClasses="!p-1"
on:click={() => copyToClipboard(result)}
>
<Clipboard size={14} strokeWidth={2} />
</Button>
<svelte:fragment slot="text">Copy to clipboard</svelte:fragment>
</Popover>
{/if}
</svelte:element>
{#if copyButton && result}
<Popover notClickable>
<Button size="xs" btnClasses="!px-2" on:click={() => copyToClipboard(result)}>
<Clipboard size={14} strokeWidth={2} />
</Button>
<svelte:fragment slot="text">Copy to clipboard</svelte:fragment>
</Popover>
{/if}
</div>
{/if}
</AlignWrapper>
</ResizeWrapper>
</div>
</RunnableWrapper>
@@ -5,7 +5,7 @@
export let id: string
export let shouldWrap: boolean = false
const { app, breakpoint } = getContext<AppViewerContext>('AppViewerContext')
const { app, breakpoint, mode } = getContext<AppViewerContext>('AppViewerContext')
$: gridItem = findGridItem($app, id)
@@ -16,13 +16,12 @@
const wrapperHeight = wrapper.getBoundingClientRect().height
const width = $breakpoint === 'sm' ? 3 : 12
gridItem[width].h = Math.ceil(wrapperHeight / 36)
gridItem = gridItem
}
}
</script>
{#if shouldWrap}
<div bind:this={wrapper}>
{#if shouldWrap && $mode !== 'preview'}
<div class="h-full w-full" bind:this={wrapper}>
<slot />
</div>
{:else}
@@ -98,7 +98,8 @@
setContext<AppEditorContext>('AppEditorContext', {
history,
pickVariableCallback
pickVariableCallback,
ontextfocus: writable(undefined)
})
let timeout: NodeJS.Timeout | undefined = undefined
@@ -72,7 +72,8 @@
setContext<AppEditorContext>('AppEditorContext', {
history: undefined,
pickVariableCallback: writable(undefined)
pickVariableCallback: writable(undefined),
ontextfocus: writable(undefined)
})
let ncontext = context
@@ -205,7 +205,7 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
icon: Type,
dims: '1:1-3:1',
data: {
softWrap: false,
softWrap: true,
horizontalAlignment: 'left',
verticalAlignment: 'top',
id: '',
@@ -229,11 +229,12 @@ export const components: Record<AppComponent['type'], AppComponentConfig> = {
fieldType: 'boolean',
onlyStatic: true
},
fitContent: {
tooltip: {
type: 'static',
value: false,
fieldType: 'boolean',
onlyStatic: true
value: '',
fieldType: 'text',
onlyStatic: true,
tooltip: 'Tooltip text if not empty'
}
},
customCss: {
@@ -33,10 +33,14 @@
export let noGrid = false
export let duplicateMoveAllowed = true
let editor: TemplateEditor | undefined = undefined
const { app, runnableComponents, selectedComponent, worldStore, focusedGrid, stateId, state } =
getContext<AppViewerContext>('AppViewerContext')
const { history } = getContext<AppEditorContext>('AppEditorContext')
const { history, ontextfocus } = getContext<AppEditorContext>('AppEditorContext')
$: editor && ($ontextfocus = () => editor?.focus())
function removeGridElement() {
push(history, $app)
@@ -109,7 +113,12 @@
<StaticInputEditor bind:componentInput={component.componentInput} />
{:else if component.componentInput.type === 'template' && component.componentInput !== undefined}
<div class="py-1 min-h-[28px] rounded border border-1 border-gray-500">
<TemplateEditor fontSize={12} bind:code={component.componentInput.eval} {extraLib} />
<TemplateEditor
bind:this={editor}
fontSize={12}
bind:code={component.componentInput.eval}
{extraLib}
/>
</div>
{:else if component.componentInput.type === 'connected' && component.componentInput !== undefined}
<ConnectedInputEditor bind:componentInput={component.componentInput} />
@@ -142,6 +142,7 @@ export type AppViewerContext = {
export type AppEditorContext = {
history: History<App> | undefined
pickVariableCallback: Writable<((path: string) => void) | undefined>
ontextfocus: Writable<(() => void) | undefined>
}
export type FocusedGrid = { parentComponentId: string; subGridIndex: number }