apps improvements (row size, text options)

This commit is contained in:
Ruben Fiszel
2023-01-01 06:24:21 +01:00
parent e2d44ca654
commit ef72e570e6
20 changed files with 196 additions and 130 deletions
-1
View File
@@ -49,7 +49,6 @@
"svelte-grid": "^5.1.1",
"svelte-heros": "^2.3.5",
"svelte-highlight": "^6.2.1",
"svelte-markdown": "^0.2.3",
"svelte-overlay": "^1.4.1",
"svelte-popperjs": "^1.3.2",
"svelte-preprocess": "^5.0.0",
@@ -1,35 +1,68 @@
<script lang="ts">
import SvelteMarkdown from 'svelte-markdown'
import type { AppInput } from '../../inputType'
import AlignWrapper from '../helpers/AlignWrapper.svelte'
import InputValue from '../helpers/InputValue.svelte'
import RunnableWrapper from '../helpers/RunnableWrapper.svelte'
export let id: string
export let componentInput: AppInput | undefined
export let horizontalAlignment: 'left' | 'center' | 'right' | undefined = undefined
export let verticalAlignment: 'top' | 'center' | 'bottom' | undefined = undefined
export let configuration: Record<string, AppInput>
export const staticOutputs: string[] = ['result', 'loading']
let extraStyle: string | undefined = undefined
let result: string | undefined = undefined
let style: 'Title' | 'Subtitle' | 'Body' | 'Caption' | 'Label' | undefined = undefined
function getComponent() {
switch (style) {
case 'Title':
return 'h1'
case 'Subtitle':
return 'h3'
case 'Body':
return 'p'
case 'Caption':
return 'p'
case 'Label':
return 'label'
default:
return 'p'
}
}
function getClasses() {
switch (style) {
case 'Caption':
return 'text-sm italic text-gray-500'
case 'Label':
return 'font-semibold text-sm'
default:
return ''
}
}
let component = 'p'
let classes = ''
$: style && (component = getComponent())
$: style && (classes = getClasses())
</script>
<InputValue {id} input={configuration.extraStyle} bind:value={extraStyle} />
<InputValue {id} input={configuration.style} bind:value={style} />
<RunnableWrapper bind:componentInput {id} bind:result>
<AlignWrapper {horizontalAlignment} {verticalAlignment}>
{#if result === ''}
{#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="prose-sm">
<SvelteMarkdown source={String(result)} />
</div>
{:else}<svelte:element this={component} class="whitespace-pre {classes}" style={extraStyle}
>{String(result)}</svelte:element
>
{/if}
</AlignWrapper>
</RunnableWrapper>
<style>
.prose-sm p {
margin: 0px !important;
}
</style>
@@ -82,7 +82,7 @@
$: mounted && ($worldStore = buildWorld($staticOutputs, $worldStore))
$: previewing = $mode === 'preview'
$: width = $breakpoint === 'sm' ? 'w-[640px]' : 'w-full'
$: width = $breakpoint === 'sm' ? 'min-w-[400px] max-w-[656px]' : 'min-w-[657px] w-full'
let selectedTab: 'insert' | 'settings' = 'insert'
$: if ($selectedComponent) {
@@ -108,24 +108,19 @@
<Pane size={64}>
<SplitPanesWrapper horizontal>
<Pane size={70}>
<div class="bg-gray-100 w-full p-4 h-full overflow-auto">
<div
class={classNames(
'bg-gray-100 mx-auto w-full relative min-h-full',
app.fullscreen ? '' : 'max-w-6xl'
)}
>
{#if $appStore.grid}
<div class={classNames('px-2 pb-2 w-full h-full bg-white', width)}>
<GridEditor {policy} />
</div>
{/if}
{#if $connectingInput.opened}
<div
class="absolute top-0 left-0 w-full h-full bg-black border-2 bg-opacity-25 z-1 flex justify-center items-center"
/>
{/if}
</div>
<div
class="bg-gray-100 w-full h-full overflow-auto {app.fullscreen ? '' : 'max-w-6xl'}"
>
{#if $appStore.grid}
<div class={classNames('p-4 mx-auto', width)}>
<GridEditor {policy} />
</div>
{/if}
{#if $connectingInput.opened}
<div
class="absolute top-0 left-0 w-full h-full bg-black border-2 bg-opacity-25 z-1 flex justify-center items-center"
/>
{/if}
</div>
</Pane>
<Pane size={30}>
@@ -160,7 +155,7 @@
{#if $selectedComponent !== undefined}
<SettingsPanel />
{:else}
<div class="p-4 text-sm">No component selected.</div>
<div class="p-4 min-w-[150px] text-sm">No component selected.</div>
{/if}
</TabContent>
<TabContent value="insert">
@@ -3,10 +3,11 @@
import { page } from '$app/stores'
import { Drawer, DrawerContent } from '$lib/components/common'
import Button from '$lib/components/common/button/Button.svelte'
import { dirtyStore } from '$lib/components/common/confirmationModal/dirtyStore'
import ToggleButton from '$lib/components/common/toggleButton/ToggleButton.svelte'
import ToggleButtonGroup from '$lib/components/common/toggleButton/ToggleButtonGroup.svelte'
import Path from '$lib/components/Path.svelte'
import Toggle from '$lib/components/Toggle.svelte'
import Tooltip from '$lib/components/Tooltip.svelte'
import { AppService, Policy } from '$lib/gen'
import { userStore, workspaceStore } from '$lib/stores'
import { faExternalLink, faSave } from '@fortawesome/free-solid-svg-icons'
@@ -57,6 +58,7 @@
}
async function save() {
$dirtyStore = false
if ($page.params.path == undefined) {
drawerOpen = true
return
@@ -107,7 +109,7 @@
</DrawerContent>
</Drawer>
<div class="border-b flex flex-row justify-between py-1 px-4 items-center">
<div class="border-b flex flex-row justify-between py-1 gap-1 gap-y-2 px-4 items-center flex-wrap">
<input class="text-sm w-64" bind:value={title} />
<div class="flex gap-8 items-center">
<div>
@@ -133,8 +135,13 @@
</div>
<ToggleButtonGroup bind:selected={$app.fullscreen}>
<ToggleButton position="left" value={false} size="xs">Centered</ToggleButton>
<ToggleButton position="right" value={true} size="xs">Full Width</ToggleButton>
<ToggleButton position="left" value={false} size="xs"
>Centered &nbsp; <Tooltip
>The max width is 1168px and the content stay centered instead of taking the full page
width</Tooltip
></ToggleButton
>
<ToggleButton position="right" value={true} size="xs">Full</ToggleButton>
</ToggleButtonGroup>
</div>
<div class="flex flex-row gap-4 justify-end">
@@ -24,7 +24,7 @@
on:click={() => jsonViewerDrawer.toggleDrawer()}
>
<Icon data={faFileExport} scale={0.6} class="inline mr-2" />
Export JSON
JSON
</Button>
<Drawer bind:this={jsonViewerDrawer} size="800px">
@@ -53,12 +53,12 @@
})
$: mounted && ($worldStore = buildWorld($staticOutputs, undefined))
$: width = $breakpoint === 'sm' ? 'w-[640px]' : 'w-full '
$: width = $breakpoint === 'sm' ? 'max-w-[640px]' : 'w-full '
</script>
<div class="h-full w-full {app.fullscreen ? '' : 'max-w-6xl'} px-4 mx-auto">
{#if $appStore.grid}
<div class={classNames('mx-auto h-full', width)}>
<div class={classNames('mx-auto pb-4', width)}>
<GridEditor {policy} />
</div>
{/if}
@@ -15,9 +15,10 @@
<span
class={classNames(
'px-2 text-2xs py-0.5 font-bold rounded-t-sm w-fit absolute z-50',
'px-2 text-2xs font-bold rounded-t-sm w-fit absolute z-50',
selected ? 'bg-indigo-500/90 text-white' : 'bg-gray-200/60 text-gray-500'
)}
style="padding-top: 1px; padding-bottom: 1px;"
>
{component.id}
</span>
@@ -25,18 +26,18 @@
{#if pointerdown || selected || hover}
<button
class={classNames(
'text-white px-1 text-2xs py-0.5 font-bold rounded-t-sm w-fit absolute right-10 z-50 cursor-pointer',
' hover:bg-gray-800',
selected ? 'bg-gray-600/90' : 'bg-gray-600/80'
'text-gray-800 px-1 text-2xs py-0.5 font-bold rounded-t-sm w-fit absolute right-10 z-50 cursor-pointer',
' hover:bg-gray-300',
selected ? 'bg-gray-200/80' : 'bg-gray-200/60'
)}
on:click={() => {
dispatch('lock')
}}
>
{#if locked}
<Anchor size={16} class="text-orange-500" />
<Anchor size={14} class="text-orange-500" />
{:else}
<Anchor size={16} />
<Anchor size={14} />
{/if}
</button>
{/if}
@@ -45,8 +46,8 @@
<span
on:mousedown|stopPropagation|capture
class={classNames(
'text-white px-1 text-2xs py-0.5 font-bold rounded-t-sm w-fit absolute right-20 z-50 cursor-move',
'bg-gray-600/80'
)}><Move size={16} /></span
'text-gray-600 px-1 text-2xs py-0.5 font-bold rounded-t-sm w-fit absolute right-16 z-50 cursor-move',
'bg-gray-200/60'
)}><Move size={14} /></span
>
{/if}
@@ -100,7 +100,7 @@
}
</script>
<div class="bg-white h-full relative">
<div class="bg-white px-2 relative">
<div class="w-full flex justify-between border-b px-4 py-2 mb-4 items-center gap-4">
<h2>{$app.title}</h2>
<RecomputeAllComponents />
@@ -112,7 +112,7 @@
<Grid
bind:items={$app.grid}
let:dataItem
rowHeight={46}
rowHeight={23}
cols={columnConfiguration}
fastStart={true}
on:pointerup={({ detail }) => selectComponent(detail.id)}
@@ -19,7 +19,7 @@
function getMinDimensionsByComponent(componentType: AppComponent['type'], column: number): Size {
// Dimensions key formula: <mobile width>:<mobile height>-<desktop width>:<desktop height>
const dimensions: Record<`${number}:${number}-${number}:${number}`, AppComponent['type'][]> = {
'1:1-2:1': [
'1:2-2:2': [
'buttoncomponent',
'textcomponent',
'checkboxcomponent',
@@ -29,7 +29,7 @@
'passwordinputcomponent',
'dateinputcomponent'
],
'2:6-4:6': ['barchartcomponent', 'piechartcomponent', 'formcomponent', 'displaycomponent'],
'2:12-4:12': ['barchartcomponent', 'piechartcomponent', 'formcomponent', 'displaycomponent'],
'3:6-6:8': ['tablecomponent']
}
// Finds the key that is associated with the component type and extracts the dimensions from it
@@ -74,8 +74,17 @@
y: 0
}
let newData: AppComponent = JSON.parse(JSON.stringify(appComponent))
Object.values(newData.configuration).forEach((x) => {
if (x.type == 'static') {
x.value = x.defaultValue
}
})
if (newData?.componentInput?.type == 'static') {
newData.componentInput.value = newData.componentInput.defaultValue
}
const newItem: GridItem = {
data: JSON.parse(JSON.stringify(appComponent)),
data: newData,
id: id
}
@@ -6,5 +6,6 @@ export const staticValues = {
buttonColorOptions,
buttonSizeOptions: ['xs', 'sm', 'md', 'lg', 'xl'],
tableSearchOptions: ['Component', 'Runnable', 'Disabled'],
chartThemeOptions: ['theme1', 'theme2', 'theme3']
chartThemeOptions: ['theme1', 'theme2', 'theme3'],
textStyleOptions: ['Title', 'Subtitle', 'Body', 'Label', 'Caption']
} as const
@@ -122,21 +122,21 @@ const buttons: ComponentSet = {
configuration: {
label: {
type: 'static',
value: 'Lorem ipsum',
value: undefined,
fieldType: 'text',
defaultValue: 'Lorem ipsum'
},
color: {
fieldType: 'select',
type: 'static',
value: 'blue',
value: undefined,
optionValuesKey: 'buttonColorOptions',
defaultValue: 'blue'
},
size: {
fieldType: 'select',
type: 'static',
value: 'xs',
value: undefined,
optionValuesKey: 'buttonSizeOptions',
defaultValue: 'xs'
}
@@ -193,11 +193,27 @@ const display: ComponentSet = {
type: 'textcomponent',
componentInput: {
type: 'static',
value: 'Lorem ipsum',
fieldType: 'textarea',
defaultValue: 'Lorem ipsum'
defaultValue: 'Lorem ipsum',
value: undefined
},
configuration: {
style: {
fieldType: 'select',
type: 'static',
value: undefined,
optionValuesKey: 'textStyleOptions',
defaultValue: 'Body'
},
extraStyle:
{
type: 'static',
fieldType: 'text',
defaultValue: '',
value: undefined
},
},
configuration: {},
card: false
},
{
@@ -207,13 +223,13 @@ const display: ComponentSet = {
search: {
fieldType: 'select',
type: 'static',
value: 'Disabled',
value: undefined,
optionValuesKey: 'tableSearchOptions',
defaultValue: 'Disabled'
},
pagination: {
type: 'static',
value: false,
value: undefined,
fieldType: 'boolean',
defaultValue: false
}
@@ -234,18 +250,7 @@ const display: ComponentSet = {
age: 42
}
],
value: [
{
id: 1,
name: 'Lorem ipsum',
age: 42
},
{
id: 2,
name: 'Lorem ipsum',
age: 42
}
]
value: undefined
},
card: true,
actionButtons: []
@@ -256,7 +261,7 @@ const display: ComponentSet = {
configuration: {
theme: {
type: 'static',
value: 'theme1',
value: undefined,
fieldType: 'select',
optionValuesKey: 'chartThemeOptions',
defaultValue: 'theme1'
@@ -275,7 +280,7 @@ const display: ComponentSet = {
fieldType: 'array',
subFieldType: 'number',
defaultValue: [25, 50, 25],
value: [25, 50, 25]
value: undefined
},
card: true
},
@@ -285,14 +290,14 @@ const display: ComponentSet = {
configuration: {
theme: {
type: 'static',
value: 'theme1',
value: undefined,
fieldType: 'select',
optionValuesKey: 'chartThemeOptions',
defaultValue: 'theme1'
},
labels: {
type: 'static',
value: ['Lorem ipsum', 'Lorem ipsum', 'Lorem ipsum'],
value: undefined,
fieldType: 'array',
subFieldType: 'text',
defaultValue: ['Lorem ipsum', 'Lorem ipsum', 'Lorem ipsum']
@@ -303,7 +308,7 @@ const display: ComponentSet = {
fieldType: 'array',
subFieldType: 'number',
defaultValue: [25, 50, 25],
value: [25, 50, 25]
value: undefined
},
card: true
},
@@ -314,7 +319,7 @@ const display: ComponentSet = {
type: 'static',
fieldType: 'text',
defaultValue: 'Lorem Ipsum',
value: 'Lorem Ipsum'
value: undefined
},
configuration: {},
card: false
@@ -36,7 +36,7 @@
</script>
<PanelSection noPadding titlePadding="px-4 pt-2" title="Outputs">
<div class="overflow-auto border-t w-full relative flex flex-col gap-2 px-4">
<div class="overflow-auto min-w-[150px] border-t w-full relative flex flex-col gap-2 px-4">
{#each Object.entries($staticOutputs) as [componentId, outputs] (componentId)}
{#if outputs.length > 0 && $worldStore?.outputsById[componentId]}
<div class="flex flex-row justify-between w-full -mb-2">
@@ -66,7 +66,7 @@
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class={classNames(
'w-full py-2 border relative',
'w-full py-2 border relative overflow-auto',
$selectedComponent === componentId ? 'border border-blue-500 ' : ''
)}
>
@@ -16,38 +16,43 @@
{#if component.verticalAlignment !== undefined}
<PanelSection title="Alignment">
{#if component.horizontalAlignment}
<div class="w-full text-xs font-semibold">Horizontal</div>
<div class="w-full">
<ToggleButtonGroup bind:selected={component.horizontalAlignment}>
<ToggleButton position="left" value="left" size="xs">
<AlignStartVertical size={16} />
</ToggleButton>
<ToggleButton position="center" value="center" size="xs">
<AlignCenterVertical size={16} />
</ToggleButton>
<ToggleButton position="right" value="right" size="xs">
<AlignEndVertical size={16} />
</ToggleButton>
</ToggleButtonGroup>
</div>
{/if}
{#if component.type !== 'formcomponent' && component.verticalAlignment}
<div class="w-full text-xs font-semibold">Vertical</div>
<div class="w-full">
<ToggleButtonGroup bind:selected={component.verticalAlignment}>
<ToggleButton position="left" value="top" size="xs">
<AlignStartHorizontal size={16} />
</ToggleButton>
<ToggleButton position="center" value="center" size="xs">
<AlignCenterHorizontal size={16} />
</ToggleButton>
<ToggleButton position="right" value="bottom" size="xs">
<AlignEndHorizontal size={16} />
</ToggleButton>
</ToggleButtonGroup>
</div>
{/if}
<div class="flex flex-wrap gap-2">
{#if component.horizontalAlignment}
<div class="flex flex-col gap-0.5">
<div class="text-xs font-semibold">Horizontal</div>
<div>
<ToggleButtonGroup bind:selected={component.horizontalAlignment}>
<ToggleButton position="left" value="left" size="xs">
<AlignStartVertical size={16} />
</ToggleButton>
<ToggleButton position="center" value="center" size="xs">
<AlignCenterVertical size={16} />
</ToggleButton>
<ToggleButton position="right" value="right" size="xs">
<AlignEndVertical size={16} />
</ToggleButton>
</ToggleButtonGroup>
</div>
</div>
{/if}
{#if component.type !== 'formcomponent' && component.verticalAlignment}
<div class="flex flex-col gap-0.5">
<div class="text-xs font-semibold">Vertical</div>
<div>
<ToggleButtonGroup bind:selected={component.verticalAlignment}>
<ToggleButton position="left" value="top" size="xs">
<AlignStartHorizontal size={16} />
</ToggleButton>
<ToggleButton position="center" value="center" size="xs">
<AlignCenterHorizontal size={16} />
</ToggleButton>
<ToggleButton position="right" value="bottom" size="xs">
<AlignEndHorizontal size={16} />
</ToggleButton>
</ToggleButtonGroup>
</div>
</div>
{/if}
</div>
</PanelSection>
{/if}
@@ -12,10 +12,12 @@
}
const brackets = '${}'
let clientWidth: number
</script>
{#if componentInput.fieldType !== 'any'}
<div class="w-full overflow-x-auto">
<div class="w-full overflow-x-auto" bind:clientWidth>
<ToggleButtonGroup bind:selected={componentInput.type}>
{#if componentInput.fieldType === 'textarea'}
<ToggleButton position="left" value="template" size="xs" disable={disableStatic}>
@@ -29,7 +31,9 @@
size="xs"
disable={disableStatic}
>
<span class="hidden lg:block"> Static </span>
{#if clientWidth > 250}
<span class="hidden lg:block"> Static </span>
{/if}
</ToggleButton>
{/if}
@@ -39,10 +43,14 @@
startIcon={{ icon: faArrowRight }}
size="xs"
>
<span class="hidden lg:block"> Connected </span>
{#if clientWidth > 250}
<span class="hidden lg:block"> Connected </span>
{/if}
</ToggleButton>
<ToggleButton position="right" value="runnable" startIcon={{ icon: faCode }} size="xs">
<span class="hidden lg:block"> Computed </span>
{#if clientWidth > 250}
<span class="hidden lg:block"> Computed </span>
{/if}
</ToggleButton>
</ToggleButtonGroup>
</div>
@@ -90,11 +90,9 @@ declare const ${k} = ${JSON.stringify(v)};
</script>
{#if component}
<div class="flex flex-col w-full divide-y">
<div class="flex flex-col min-w-[150px] w-full divide-y">
{#if component.componentInput}
<PanelSection
title={component.componentInput.fieldType === 'any' ? 'Runnable' : 'Component input'}
>
<PanelSection title={component.componentInput.fieldType === 'any' ? 'Runnable' : 'Input'}>
<svelte:fragment slot="action">
<span
class={classNames(
@@ -69,7 +69,7 @@
ButtonType.SpacingClasses[spacingSize],
'focus:ring-2 font-semibold',
'duration-200 rounded-md',
'justify-center items-center text-center whitespace-nowrap inline-flex truncate',
'justify-center items-center text-center whitespace-nowrap inline-flex',
btnClasses,
disabled ? 'bg-gray-300' : ''
),
@@ -9,6 +9,7 @@
faEdit,
faEye,
faFileExport,
faPen,
faShare,
faTrashAlt
} from '@fortawesome/free-solid-svg-icons'
@@ -74,10 +75,15 @@
btnClasses="!text-gray-700 !bg-transparent hover:!bg-gray-400/20 !p-[6px]"
dropdownItems={[
{
displayName: 'View app',
displayName: 'View',
icon: faEye,
href: `/apps/get/${path}`
},
{
displayName: 'Edit',
icon: faPen,
href: `/apps/edit/${path}?nodraft=true`
},
{
displayName: 'Move',
icon: faFileExport,
@@ -6,7 +6,6 @@
import Drawer from '$lib/components/common/drawer/Drawer.svelte'
import DrawerContent from '$lib/components/common/drawer/DrawerContent.svelte'
import SimpleEditor from '$lib/components/SimpleEditor.svelte'
import { Icon } from 'svelte-awesome'
import { importStore } from '../apps/store'
import { LayoutDashboard } from 'lucide-svelte'
@@ -15,7 +14,7 @@
async function importJson() {
$importStore = JSON.parse(pendingJson)
await goto('/apps/add')
await goto('/apps/add?nodraft=true')
drawer?.closeDrawer?.()
}
</script>
@@ -57,7 +57,7 @@
<ul class="w-full">
{#each keys as key, index}
<li class="pt-1">
<button on:click={() => selectProp(key)}>
<button on:click={() => selectProp(key)} class="whitespace-nowrap">
{#if topLevelNode}
<Badge baseClass="border border-blue-600" color="indigo">{key}</Badge>
{:else}
@@ -82,7 +82,7 @@
}
afterNavigate((n) => {
if (n.to?.url.pathname.startsWith('/apps')) {
if (n.to?.url.pathname.startsWith('/apps') && innerWidth >= 768) {
isCollapsed = true
}
})