Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion frontend/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ declare module 'vue' {
LucideChevronUp: typeof import('~icons/lucide/chevron-up')['default']
LucideFlaskConical: typeof import('~icons/lucide/flask-conical')['default']
LucidePaperclip: typeof import('~icons/lucide/paperclip')['default']
LucidePlus: typeof import('~icons/lucide/plus')['default']
LucideRepeat: typeof import('~icons/lucide/repeat')['default']
LucideX: typeof import('~icons/lucide/x')['default']
MarginHandler: typeof import('./src/components/MarginHandler.vue')['default']
MarkdownEditor: typeof import('./src/components/AppLayout/MarkdownEditor.vue')['default']
MissingComponent: typeof import('./src/components/MissingComponent.vue')['default']
Expand All @@ -92,7 +94,6 @@ declare module 'vue' {
ProxyDialog: typeof import('./src/components/ProxyComponents/ProxyDialog.vue')['default']
PublishButton: typeof import('./src/components/PublishButton.vue')['default']
Repeater: typeof import('./src/components/AppLayout/Repeater.vue')['default']
RepeaterContextProvider: typeof import('./src/components/AppLayout/RepeaterContextProvider.vue')['default']
ResourceDialog: typeof import('./src/components/ResourceDialog.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
Expand All @@ -101,6 +102,7 @@ declare module 'vue' {
SectionContainer: typeof import('./src/components/SectionContainer.vue')['default']
SettingItem: typeof import('./src/components/SettingItem.vue')['default']
SlotIcon: typeof import('./src/components/Icons/SlotIcon.vue')['default']
SlotScopeProvider: typeof import('./src/components/SlotScopeProvider.vue')['default']
SplitView: typeof import('./src/components/AppLayout/SplitView.vue')['default']
StudioCanvas: typeof import('./src/components/StudioCanvas.vue')['default']
StudioComponent: typeof import('./src/components/StudioComponent.vue')['default']
Expand Down
26 changes: 10 additions & 16 deletions frontend/src/components/AppComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,13 @@
:key="slotName"
v-slot:[slotName]="slotProps"
>
<template v-if="Array.isArray(slot.slotContent)">
<SlotScopeProvider :scope="slotProps">
<AppComponent
v-for="slotBlock in slot.slotContent"
:block="slotBlock"
:key="slotBlock.componentId"
v-bind="slotProps"
/>
</template>
<template v-else-if="isHTML(slot.slotContent)">
<component :is="{ template: slot.slotContent }" v-bind="slotProps" />
</template>
<template v-else v-bind="slotProps">
{{ slot.slotContent }}
</template>
</SlotScopeProvider>
</template>

<AppComponent v-for="child in block?.children" :key="child.componentId" :block="child" />
Expand All @@ -61,19 +54,20 @@ import Block from "@/utils/block"
import { computed, onMounted, ref, useAttrs, inject, type ComputedRef, h } from "vue"
import type { ComponentPublicInstance } from "vue"
import { createResource } from "frappe-ui"
import { getComponentRoot, isHTML, isObjectEmpty } from "@/utils/helpers"
import { getComponentRoot, isObjectEmpty } from "@/utils/helpers"
import { useScreenSize } from "@/utils/useScreenSize"
import { isDynamicValue } from "@/utils/code"
import { resolveEventListener } from "@/utils/eventModifiers"
import useComponentInstance from "@/utils/useComponentInstance"

import useCodeStore from "@/stores/codeStore"
import { toast } from "frappe-ui"
import type { RepeaterContext } from "@/types"
import type { SlotScope } from "@/types"
import type { Field } from "@/types/ComponentEvent"
import type { DataResult } from "@/types/Studio/StudioResource"

import StudioComponentRenderer from "@/components/StudioComponentRenderer.vue"
import SlotScopeProvider from "@/components/SlotScopeProvider.vue"
import { customVueComponentsRegistry } from "@/globals"
import MissingComponent from "@/components/MissingComponent.vue"

Expand Down Expand Up @@ -110,12 +104,12 @@ const classes = computed(() => {
})

const codeStore = useCodeStore()
const repeaterContext = inject<ComputedRef<RepeaterContext> | null>("repeaterContext", null)
const slotScope = inject<ComputedRef<SlotScope> | null>("slotScope", null)
const componentContext = inject<ComputedRef | null>("componentContext", null)

const evaluationContext = computed(() => {
return {
...repeaterContext?.value,
...slotScope?.value,
...componentContext?.value,
}
})
Expand Down Expand Up @@ -204,7 +198,7 @@ function getEventHandler(event: any): Listener | undefined {
}
} else if (event.action === "Run Script") {
return (...eventArgs: any[]) => {
codeStore.executeUserScript(event.script, repeaterContext?.value, componentContext?.value, eventArgs)
codeStore.executeUserScript(event.script, slotScope?.value, componentContext?.value, eventArgs)
}
}
}
Expand Down Expand Up @@ -237,7 +231,7 @@ const handleSuccess = (event: any) => (data: DataResult) => {
return codeStore.handleSuccess(
event.on_success_script,
data,
repeaterContext?.value,
slotScope?.value,
componentContext?.value,
event.eventArgs,
)
Expand All @@ -253,7 +247,7 @@ const handleError = (event: any) => (error: any) => {
return codeStore.handleError(
event.on_error_script,
error,
repeaterContext?.value,
slotScope?.value,
componentContext?.value,
event.eventArgs,
)
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/AppLayout/Repeater.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
{{ emptyStateMessage || "No data" }}
</div>
<template v-else v-for="(dataItem, dataIndex) in data" :key="dataItem?.[dataKey] || dataIndex">
<RepeaterContextProvider :dataItem="dataItem" :dataIndex="dataIndex" :dataKey="dataKey">
<SlotScopeProvider :scope="{ dataItem, dataIndex, dataKey }">
<slot v-bind="{ dataItem, dataKey, dataIndex }"></slot>
</RepeaterContextProvider>
</SlotScopeProvider>
</template>
</div>
</template>

<script setup lang="ts">
import RepeaterContextProvider from "@/components/AppLayout/RepeaterContextProvider.vue"
import SlotScopeProvider from "@/components/SlotScopeProvider.vue"
import type { RepeaterProps } from "@/types/studio_components/Repeater"

defineProps<RepeaterProps>()
Expand Down
21 changes: 0 additions & 21 deletions frontend/src/components/AppLayout/RepeaterContextProvider.vue

This file was deleted.

12 changes: 0 additions & 12 deletions frontend/src/components/ComponentContextMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,14 @@ import { ref, Ref } from "vue"
import { vOnClickOutside } from "@vueuse/components"
import ContextMenu from "@/components/ContextMenu.vue"
import Block from "@/utils/block"
import useStudioStore from "@/stores/studioStore"
import useCanvasStore from "@/stores/canvasStore"
import useComponentEditorStore from "@/stores/componentEditorStore"
import type { ContextMenuOption } from "@/types"
import { isObjectEmpty } from "@/utils/helpers"
import { getBlockCopy, getComponentBlock } from "@/utils/serializer"
import getBlockTemplate from "@/utils/blockTemplate"
import FormDialog from "@/components/FormDialog.vue"
import { toast } from "frappe-ui"

const store = useStudioStore()
const canvasStore = useCanvasStore()

const contextMenuVisible = ref(false)
Expand Down Expand Up @@ -129,15 +126,6 @@ const contextMenuOptions: ContextMenuOption[] = [
return !block.value.isRoot() && Boolean(block.value.getParentBlock())
},
},
{
label: "Edit Slot",
action: () => {
store.showSlotEditorDialog = true
},
condition: () =>
!isObjectEmpty(block.value.componentSlots) &&
block.value.isSlotEditable(canvasStore.activeCanvas?.selectedSlot),
},
{
label: "Save as Component",
action: () => {
Expand Down
31 changes: 2 additions & 29 deletions frontend/src/components/ComponentEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,8 @@
class="pointer-events-none fixed ring-2 ring-inset ring-outline-purple-5"
:class="isSlotSelected(slot.slotId) ? 'opacity-100' : 'opacity-65'"
:style="{
// set min height and width so that slots without content are visible
minWidth: `calc(${12}px * ${canvasProps.scale})`,
minHeight: `calc(${12}px * ${canvasProps.scale})`,
minWidth: `calc(${20}px * ${canvasProps.scale})`,
minHeight: `calc(${20}px * ${canvasProps.scale})`,
}"
>
<span
Expand All @@ -60,39 +59,13 @@
</div>
</template>
</div>

<Dialog
v-if="canvasStore.activeCanvas?.selectedSlot?.slotId"
v-model="store.showSlotEditorDialog"
class="overscroll-none"
:title="`Edit #${canvasStore.activeCanvas?.selectedSlot?.slotName} slot for ${block.componentName}`"
size="3xl"
>
<template #default>
<Code
:modelValue="block.getSlotContent(canvasStore.activeCanvas?.selectedSlot?.slotName) || ''"
language="html"
height="60vh"
:showSaveButton="true"
@save="
(val) => {
if (!canvasStore.activeCanvas?.selectedSlot) return
props.block.updateSlot(canvasStore.activeCanvas?.selectedSlot?.slotName, val)
store.showSlotEditorDialog = false
}
"
/>
</template>
</Dialog>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, Ref, watchEffect, nextTick, inject, watch } from "vue"
import { Dialog } from "frappe-ui"
import BoxResizer from "@/components/BoxResizer.vue"
import PaddingHandler from "@/components/PaddingHandler.vue"
import MarginHandler from "@/components/MarginHandler.vue"
import Code from "@/components/Code.vue"
import LucideRepeat from "~icons/lucide/repeat"

import Block from "@/utils/block"
Expand Down
13 changes: 5 additions & 8 deletions frontend/src/components/ComponentLayers.vue
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@
:style="{ paddingLeft: `${childIndent}px` }"
>
<FeatherIcon
v-if="isSlotExpandable(slot, element)"
v-if="isSlotExpandable(slot)"
:name="isSlotExpanded(slot) ? 'chevron-down' : 'chevron-right'"
class="h-3 w-3"
@click.stop="toggleSlotExpanded(slot)"
Expand All @@ -134,7 +134,7 @@
<span class="min-h-[1em] min-w-[2em] truncate" :title="slot.slotName">#{{ slotName }}</span>
</div>

<div v-if="Array.isArray(slot.slotContent) && isSlotExpanded(slot)">
<div v-if="isSlotExpanded(slot)">
<ComponentLayers :blocks="slot.slotContent" ref="slotLayer" :indent="slotIndent" />
</div>
</div>
Expand Down Expand Up @@ -258,8 +258,8 @@ const isSlotExpanded = (slot: Slot) => {
return expandedSlots.value.has(slot.slotId)
}

const isSlotExpandable = (slot: Slot, block: Block) => {
return !block.isSlotEditable(slot) && slot.slotContent?.length > 0
const isSlotExpandable = (slot: Slot) => {
return slot.slotContent.length > 0
}

const toggleSlotExpanded = (slot: Slot) => {
Expand Down Expand Up @@ -429,10 +429,7 @@ const moveBlockAdjacent = (draggedBlock: Block, targetBlock: Block, position: "b
draggedBlock.parentBlock = targetParent
if (targetBlock.isSlotBlock()) {
draggedBlock.parentSlotName = targetBlock.parentSlotName
let slotContent = targetParent.getSlotContent(targetBlock.parentSlotName!)
if (Array.isArray(slotContent)) {
slotContent.splice(insertIndex, 0, draggedBlock)
}
targetParent.getSlotContent(targetBlock.parentSlotName!)?.splice(insertIndex, 0, draggedBlock)
} else {
delete draggedBlock.parentSlotName
targetParent.children.splice(insertIndex, 0, draggedBlock)
Expand Down
Loading
Loading