feat(frontend): add indicator when a component is locked (#4296)

* feat(frontend): add indicator when a component is locked

* feat(frontend): add indicator when a component is locked

* feat(frontend): improve interactivity

* feat(frontend): fix how the lock overlay renders

* feat(frontend): use builin detection

* feat(frontend): fix zIndex

* feat(frontend): update the shadow when dragged over a locked component
This commit is contained in:
Faton Ramadani
2024-08-29 11:14:04 +02:00
committed by GitHub
parent 543a8e98fc
commit d9b358bcc2
6 changed files with 73 additions and 16 deletions
+20
View File
@@ -124,3 +124,23 @@ svelte-virtual-list-contents > * + * {
.nonmain-editor .cursor.monaco-mouse-cursor-text {
width: 1px !important;
}
.bg-locked {
background-image: repeating-linear-gradient(
-45deg,
rgba(128, 128, 128, 0.2),
rgba(128, 128, 128, 0.2) 10px,
rgba(192, 192, 192, 0.2) 10px,
rgba(192, 192, 192, 0.2) 20px
);
}
.bg-locked-hover {
background-image: repeating-linear-gradient(
-45deg,
rgba(255, 99, 71, 0.2),
rgba(255, 99, 71, 0.2) 10px,
rgba(255, 69, 58, 0.2),
rgba(255, 69, 58, 0.2) 20px
);
}
@@ -136,6 +136,7 @@
}}
let:dataItem
let:hidden
let:overlapped
cols={columnConfiguration}
>
<ComponentWrapper
@@ -176,6 +177,7 @@
on:fillHeight={() => {
handleFillHeight(dataItem.id)
}}
overlapped={overlapped !== undefined}
/>
</GridEditorMenu>
</ComponentWrapper>
@@ -193,10 +195,6 @@
{/if}
<style global>
.svlt-grid-shadow {
/* Back shadow */
background: #93c4fdd0 !important;
}
.svlt-grid-active {
opacity: 1 !important;
}
@@ -8,6 +8,7 @@
import type { AppEditorContext, AppViewerContext } from '../../types'
import ComponentHeader from '../ComponentHeader.svelte'
import type { AppComponent } from './components'
import { Lock } from 'lucide-svelte'
import AppMultiSelect from '../../components/inputs/AppMultiSelect.svelte'
import AppMultiSelectV2 from '../../components/inputs/AppMultiSelectV2.svelte'
@@ -87,8 +88,9 @@
export let render: boolean
export let hidden: boolean
export let fullHeight: boolean
export let overlapped: boolean = false
const { mode, app, hoverStore, connectingInput } =
const { mode, app, hoverStore, connectingInput, selectedComponent } =
getContext<AppViewerContext>('AppViewerContext')
const editorContext = getContext<AppEditorContext>('AppEditorContext')
@@ -96,6 +98,8 @@
$: ismoving =
movingcomponents != undefined && $mode == 'dnd' && $movingcomponents?.includes(component.id)
const componentActive = editorContext?.componentActive
let initializing: boolean | undefined = undefined
let errorHandledByComponent: boolean = false
let componentContainerHeight: number = 0
@@ -129,10 +133,25 @@
}
}}
on:mouseout|stopPropagation={mouseOut}
class="h-full flex flex-col w-full component {initializing
? 'overflow-hidden h-0'
: ''} {hidden && $mode === 'preview' ? 'hidden' : ''} "
class={twMerge(
'h-full flex flex-col w-full component relative',
initializing ? 'overflow-hidden h-0' : '',
hidden && $mode === 'preview' ? 'hidden' : ''
)}
>
{#if locked && componentActive && $componentActive && $selectedComponent?.[0] !== component.id}
<div
class={twMerge(
'absolute inset-0 bg-locked center-center flex-col z-50',
overlapped ? 'bg-locked-hover' : ''
)}
>
<div class="bg-surface p-2 shadow-sm rounded-md flex center-center flex-col gap-2">
<Lock size={24} class="text-primary " />
<div class="text-xs">Locked. The component cannot be moved.</div>
</div>
</div>
{/if}
{#if $mode !== 'preview'}
<ComponentHeader
on:mouseover={() => {
@@ -114,8 +114,10 @@
...shadows[id]
}
}
let { items, overlap } = moveItem(activeItem, sortedItems, getComputedCols)
sortedItems = moveItem(activeItem, sortedItems, getComputedCols)
sortedItems = items
overlapped = overlap ? id : undefined
}
}
@@ -173,6 +175,7 @@
}
})
}
let overlapped: string | undefined = undefined
</script>
<div class="svlt-grid-container" style="height: {containerHeight}px" bind:this={container}>
@@ -202,9 +205,10 @@
{sensor}
container={scroller}
nativeContainer={container}
{overlapped}
>
{#if item[getComputedCols]}
<slot dataItem={item} hidden={false} />
<slot dataItem={item} hidden={false} {overlapped} />
{/if}
</MoveResize>
{/if}
@@ -2,6 +2,7 @@
import { createEventDispatcher, getContext, onMount } from 'svelte'
import type { AppEditorContext, AppViewerContext } from '../types'
import { writable } from 'svelte/store'
import { twMerge } from 'tailwind-merge'
const dispatch = createEventDispatcher()
@@ -26,6 +27,7 @@
export let nativeContainer
export let onTop
export let shadow: { x: number; y: number; w: number; h: number } | undefined = undefined
export let overlapped: string | undefined = undefined
const ctx = getContext<AppEditorContext>('AppEditorContext')
const { mode } = getContext<AppViewerContext>('AppViewerContext')
@@ -382,7 +384,10 @@
{#if xPerPx > 0 && (active || trans) && shadow}
<div
class="svlt-grid-shadow shadow-active"
class={twMerge(
'svlt-grid-shadow shadow-active',
overlapped ? 'svlte-grid-shadow-forbidden' : ''
)}
style="width: {shadow.w * xPerPx - gapX * 2}px; height: {shadow.h * yPerPx -
gapY * 2}px; transform: translate({shadow.x * xPerPx + gapX}px, {shadow.y * yPerPx +
gapY}px); "
@@ -460,10 +465,13 @@
.svlt-grid-shadow {
position: absolute;
background: red;
will-change: transform;
background: pink;
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
background: #93c4fdd0;
}
.svlte-grid-shadow-forbidden {
background: rgba(255, 99, 71, 0.2) !important;
}
</style>
@@ -133,7 +133,12 @@ export function moveItem(active, items, cols) {
const fixed = closeObj.find((value) => value[cols].fixed)
// If found fixed, reset the active to its original position
if (fixed) return items
if (fixed) {
return {
items: items,
overlap: true
}
}
// Update items
items = updateItem(items, active, item, cols)
@@ -171,7 +176,10 @@ export function moveItem(active, items, cols) {
})
// Return result
return tempItems
return {
items: tempItems,
overlap: false
}
}
// Helper function
@@ -181,7 +189,7 @@ export function normalize(items, col) {
result.forEach((value) => {
const getItem = value[col]
if (!getItem.static) {
result = moveItem(getItem, result, col)
result = moveItem(getItem, result, col).items
}
})