feat(frontend): Component control (#1293)

* fix(frontend): fix app tabs

* fix(frontend): app controls

* fix(frontend): app controls

* fix(frontend): align output panel

* fix(frontend): clean up

* fix(frontend): refactor events

* fix(frontend): fix display

* fix(frontend): fix indentation

* fix(frontend): merge main
This commit is contained in:
Faton Ramadani
2023-03-16 12:42:10 +01:00
committed by GitHub
parent 00927210fd
commit bd927a27ed
13 changed files with 105 additions and 103 deletions
@@ -70,7 +70,6 @@
{#if $app.subgrids?.[`${id}-${index}`]}
<SubGridEditor
visible={render}
noYPadding
{id}
shouldHighlight={$focusedGrid?.subGridIndex === index}
class={css?.container.class}
@@ -1,6 +1,6 @@
<script lang="ts">
import { Tab, Tabs } from '$lib/components/common'
import { getContext, onMount } from 'svelte'
import { getContext } from 'svelte'
import { initOutput } from '../../editor/appUtils'
import SubGridEditor from '../../editor/SubGridEditor.svelte'
import type { AppInput } from '../../inputType'
@@ -80,9 +80,7 @@
}
$: selected && handleTabSelection()
$: selectedIndex = tabs?.indexOf(selected) ?? -1
$: css = concatCustomCss($app.css?.tabscomponent, customCss)
let subgridWidth: number | undefined = undefined
@@ -131,7 +129,8 @@
<div bind:clientWidth={subgridWidth} class="w-full">
{#if $app.subgrids}
{#each tabs ?? [] as res, i}<SubGridEditor
{#each tabs ?? [] as res, i}
<SubGridEditor
{id}
visible={render && i === selectedIndex}
bind:subGrid={$app.subgrids[`${id}-${i}`]}
@@ -141,7 +140,8 @@
on:focus={() => {
$selectedComponent = id
}}
/>{/each}
/>
{/each}
{/if}
</div>
</div>
@@ -93,7 +93,8 @@
stateId: writable(0),
parentWidth: writable(0),
state: writable({}),
componentControl: writable({})
componentControl: writable({}),
hoverStore: writable(undefined)
})
setContext<AppEditorContext>('AppEditorContext', {
@@ -67,7 +67,8 @@
stateId: writable(0),
parentWidth,
state: writable({}),
componentControl: writable({})
componentControl: writable({}),
hoverStore: writable(undefined)
})
setContext<AppEditorContext>('AppEditorContext', {
@@ -6,6 +6,7 @@
import Popover from '$lib/components/Popover.svelte'
import { Alert, Button } from '$lib/components/common'
import type { AppComponent } from './component'
import { twMerge } from 'tailwind-merge'
export let component: AppComponent
export let selected: boolean
@@ -26,63 +27,61 @@
}
</script>
<span
title={`Id: ${component.id}`}
class={classNames(
'px-2 text-2xs font-bold w-fit absolute shadow -top-1 -left-2 border z-50',
selected
? 'bg-indigo-500/90 border-blue-500 text-white'
: 'bg-gray-200/90 border-gray-300 text-gray-500'
)}
style="padding-top: 1px; padding-bottom: 1px;"
>
{component.id}
</span>
{#if pointerdown || selected || hover}
<button
title="Lock Position"
class={classNames(
'text-gray-800 px-1 text-2xs py-0.5 font-bold w-fit shadow border border-gray-300 absolute -top-1 right-[2.5rem] z-50 cursor-pointer',
' hover:bg-gray-300',
selected ? 'bg-gray-200/80' : 'bg-gray-200/80'
)}
on:click={() => dispatch('lock')}
on:pointerdown|stopPropagation
>
{#if locked}
<Anchor aria-label="Unlock position" size={14} class="text-orange-500" />
{:else}
<Anchor aria-label="Lock position" size={14} />
{/if}
</button>
<button
title="Expand"
class={classNames(
'text-gray-800 px-1 text-2xs py-0.5 font-bold w-fit shadow border border-gray-300 absolute -top-1 right-[4.5rem] z-50 cursor-pointer',
' hover:bg-gray-300',
selected ? 'bg-gray-200/80' : 'bg-gray-200/80'
)}
on:click={() => dispatch('expand')}
on:pointerdown|stopPropagation
>
<Expand aria-label="Expand position" size={14} />
</button>
{/if}
{#if selected || hover}
<span
title="Move"
on:mousedown|stopPropagation|capture
class={classNames(
'text-gray-600 px-1 text-2xs py-0.5 font-bold rounded-t-sm w-fit absolute border border-gray-300 -top-1 shadow right-[0.5rem] z-50 cursor-move',
'bg-gray-200/80'
title={`Id: ${component.id}`}
class={twMerge(
'px-2 text-2xs font-semibold w-fit absolute shadow -top-[9px] -left-[8px] border rounded-sm z-50',
selected
? 'bg-indigo-500/90 border-indigo-600 text-white'
: 'bg-blue-500/90 border-blue-600 text-white'
)}
>
<Move size={14} />
{component.id}
</span>
{/if}
{#if selected}
<div class="top-[-9px] -right-[8px] flex flex-row absolute gap-1.5 z-50">
<button
title="Expand"
class={classNames(
'px-1 text-2xs py-0.5 font-bold w-fit border cursor-pointer rounded-sm',
'bg-indigo-100 text-indigo-600 border-indigo-500 hover:bg-indigo-200 hover:text-indigo-800'
)}
on:click={() => dispatch('expand')}
on:pointerdown|stopPropagation
>
<Expand aria-label="Expand position" size={14} />
</button>
<button
title="Lock Position"
class={classNames(
'px-1 text-2xs py-0.5 font-bold w-fit border rounded-sm cursor-pointer',
'bg-indigo-100 text-indigo-600 border-indigo-500 hover:bg-indigo-200 hover:text-indigo-800'
)}
on:click={() => dispatch('lock')}
on:pointerdown|stopPropagation
>
{#if locked}
<Anchor aria-label="Unlock position" size={14} class="text-orange-500" />
{:else}
<Anchor aria-label="Lock position" size={14} />
{/if}
</button>
<span
title="Move"
on:mousedown|stopPropagation|capture
class={classNames(
'px-1 text-2xs py-0.5 font-bold w-fit border cursor-move rounded-sm',
'bg-indigo-100 text-indigo-600 border-indigo-500 hover:bg-indigo-200 hover:text-indigo-800'
)}
>
<Move size={14} />
</span>
</div>
{/if}
{#if error}
{@const json = JSON.parse(JSON.stringify(error.error))}
<span
@@ -87,7 +87,7 @@
style="height: {containerHeight}px; {style ?? ''}"
>
{#if $mode !== 'preview'}
<div class={highlight ? 'border-gray-400 border border-dashed' : ''}>
<div class={highlight ? 'border-gray-400 border border-dashed min-h-full' : ''}>
<Grid
items={subGrid}
on:redraw={(e) => {
@@ -47,9 +47,8 @@
export let pointerdown: boolean = false
export let render: boolean
const { mode, connectingInput, app, errorByComponent } =
const { mode, app, errorByComponent, hoverStore } =
getContext<AppViewerContext>('AppViewerContext')
let hover = false
let initializing: boolean | undefined = undefined
let componentContainerHeight: number = 0
@@ -57,14 +56,23 @@
$: hasError = componentWithErrors.includes(component.id)
</script>
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
<div
on:pointerenter={() => (hover = true)}
on:pointerleave={() => (hover = false)}
on:mouseover|stopPropagation={() => {
if (component.id !== $hoverStore) {
$hoverStore = component.id
}
}}
on:mouseout|stopPropagation={() => {
if ($hoverStore !== undefined) {
$hoverStore = undefined
}
}}
class="h-full flex flex-col w-full component {initializing ? 'overflow-hidden h-0' : ''}"
>
{#if $mode !== 'preview'}
<ComponentHeader
{hover}
hover={$hoverStore === component.id}
{pointerdown}
{component}
{selected}
@@ -77,10 +85,9 @@
<div
class={twMerge(
'h-full bg-white/40',
selected && $mode !== 'preview' ? 'border border-blue-500' : '',
!selected && $mode !== 'preview' ? 'border-gray-100' : '',
$mode !== 'preview' && !$connectingInput.opened ? 'hover:border-blue-500' : '',
'h-full bg-white/40 outline-1',
$hoverStore === component.id && $mode !== 'preview' ? 'outline outline-blue-600' : '',
selected && $mode !== 'preview' ? 'outline outline-indigo-600' : '',
component.softWrap || hasError ? '' : 'overflow-auto',
$mode != 'preview' ? 'cursor-pointer' : '',
'relative z-auto',
@@ -1,5 +1,4 @@
<script lang="ts">
import ObjectViewer from '$lib/components/propertyPicker/ObjectViewer.svelte'
import { X } from 'lucide-svelte'
import { getContext, setContext } from 'svelte'
import { writable } from 'svelte/store'
@@ -33,7 +32,7 @@
<div class="relative">
<input
bind:value={$search}
class="px-2 py-1 border border-gray-300 rounded-sm {search ? 'pr-8' : ''}"
class="px-2 pb-1 border border-gray-300 rounded-sm {search ? 'pr-8' : ''}"
placeholder="Search outputs..."
/>
{#if search}
@@ -53,7 +52,7 @@
<div class="flex flex-col gap-4">
<div>
<span class="text-sm font-bold p-2">State & Context</span>
<span class="text-xs font-bold p-2">State & Context</span>
<OutputHeader id={'ctx'} name={'App Context'} first color="blue">
<ComponentOutputViewer
@@ -4,8 +4,6 @@
import BackgroundScriptOutput from './BackgroundScriptOutput.svelte'
const { app } = getContext<AppViewerContext>('AppViewerContext')
export let expanded: boolean = false
</script>
{#each $app.hiddenInlineScripts as action, index}
@@ -9,7 +9,7 @@
import StaticInputEditor from './inputEditor/StaticInputEditor.svelte'
import ConnectedInputEditor from './inputEditor/ConnectedInputEditor.svelte'
import Badge from '$lib/components/common/badge/Badge.svelte'
import { capitalize, classNames } from '$lib/utils'
import { capitalize, classNames, getModifierKey } from '$lib/utils'
import { buildExtraLib, fieldTypeToTsType } from '../../utils'
import Recompute from './Recompute.svelte'
import Tooltip from '$lib/components/Tooltip.svelte'
@@ -222,34 +222,23 @@
<Kbd>Del</Kbd>
</Button>
</div>
<div class="flex flex-col">
<div
><span class="text-gray-600 text-xs mr-2">Copy:</span><Kbd>CTRL+C</Kbd> + <Kbd
>CTRL+V</Kbd
></div
>
<!-- <Button
size="xs"
color="dark"
startIcon={{ icon: faCopy }}
on:click={() => {
if (component) {
duplicateElement(component.id)
}
}}
>
Duplicate component: {component.id}
</Button> -->
<div
><span class="text-gray-600 text-xs mr-2">Move:</span><Kbd>CTRL+X</Kbd> + <Kbd
>CTRL+V</Kbd
></div
>
<div
><span class="text-gray-600 text-xs mr-2">Navigate:</span><Kbd>&leftarrow;</Kbd><Kbd
>&uparrow;</Kbd
><Kbd>&rightarrow;</Kbd><Kbd>ESC</Kbd></div
>
<div class="flex flex-col gap-1">
<div>
<span class="text-gray-600 text-xs mr-2"> Copy:</span>
<Kbd>{getModifierKey()}</Kbd>+<Kbd>C</Kbd>,
<Kbd>{getModifierKey()}</Kbd>+<Kbd>V</Kbd>
</div>
<div>
<span class="text-gray-600 text-xs mr-2">Move: </span>
<Kbd>{getModifierKey()}</Kbd>+<Kbd>X</Kbd>,
<Kbd>{getModifierKey()}</Kbd>+<Kbd>V</Kbd>
</div>
<div>
<span class="text-gray-600 text-xs mr-2">Navigate:</span>
<Kbd>&leftarrow;</Kbd>
<Kbd>&uparrow;</Kbd><Kbd>&rightarrow;</Kbd>
<Kbd>ESC</Kbd>
</div>
</div>
</PanelSection>
{/if}
@@ -1,6 +1,6 @@
<script lang="ts">
import { getContainerHeight } from './utils/container'
import { moveItemsAroundItem, moveItem, getItemById, specifyUndefinedColumns } from './utils/item'
import { moveItem, getItemById, specifyUndefinedColumns } from './utils/item'
import { onMount, createEventDispatcher } from 'svelte'
import { getColumn, throttle } from './utils/other'
import MoveResize from './MoveResize.svelte'
@@ -141,6 +141,7 @@ export type AppViewerContext = {
}
>
>
hoverStore: Writable<string | undefined>
}
export type AppEditorContext = {
+8
View File
@@ -705,3 +705,11 @@ export function throttle<T>(func: (...args: any[]) => T, wait: number) {
}
}
}
export function isMac(): boolean {
return navigator.userAgent.indexOf('Mac OS X') !== -1
}
export function getModifierKey(): string {
return isMac() ? '⌘' : 'CTRL'
}