@platecms/delta-vue 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +7 -0
- package/__generated__/fragment-masking.ts +87 -0
- package/__generated__/gql.ts +24 -0
- package/__generated__/graphql.ts +3125 -0
- package/__generated__/index.ts +2 -0
- package/codegen.config.ts +23 -0
- package/eslint.config.mjs +43 -0
- package/package.json +6 -6
- package/project.json +54 -0
- package/src/components/ExperienceComponent.vue +26 -0
- package/src/components/GridPlacement.vue +16 -0
- package/src/components/RenderLibraryComponent.vue +30 -0
- package/src/components/RootExperienceComponentProvider.vue +16 -0
- package/src/components/atoms/icon/FontAwesomeIcon.vue +21 -0
- package/src/components/editor/EditorExperienceComponent.vue +36 -0
- package/src/components/editor/EditorGridPlacement.vue +86 -0
- package/src/components/editor/EditorRootExperienceComponent.vue +17 -0
- package/src/components/editor/controls/EditorControlsContainer.vue +120 -0
- package/src/components/placeholders/EmptyGridPlacements.vue +62 -0
- package/src/components/placeholders/MissingExperienceComponent.vue +21 -0
- package/src/createDelta.ts +16 -0
- package/src/defineComponent.ts +37 -0
- package/src/index.ts +69 -0
- package/src/router/index.ts +19 -0
- package/src/styles.css +1 -0
- package/src/views/ExperienceEditorView.vue +137 -0
- package/src/views/ExperiencePreviewView.vue +32 -0
- package/src/views/ExperienceView.vue +61 -0
- package/src/views/NotFoundView.vue +27 -0
- package/src/vue-shims.d.ts +5 -0
- package/tsconfig.json +25 -0
- package/tsconfig.lib.json +25 -0
- package/tsconfig.spec.json +22 -0
- package/vite.config.ts +59 -0
- package/ExperienceEditorView-EkCJdeah.js +0 -4
- package/ExperienceEditorView-RJb7Vinf.cjs +0 -1
- package/ExperiencePreviewView-BnPvMCAn.js +0 -4
- package/ExperiencePreviewView-Bx0rYgZ0.cjs +0 -1
- package/ExperienceView-C0KQHjrZ.js +0 -4
- package/ExperienceView-DJZtUHn2.cjs +0 -1
- package/components/ExperienceComponent.vue.d.ts +0 -22
- package/components/GridPlacement.vue.d.ts +0 -6
- package/components/RenderLibraryComponent.vue.d.ts +0 -26
- package/components/RootExperienceComponentProvider.vue.d.ts +0 -21
- package/components/atoms/icon/FontAwesomeIcon.vue.d.ts +0 -8
- package/components/editor/EditorExperienceComponent.vue.d.ts +0 -9
- package/components/editor/EditorGridPlacement.vue.d.ts +0 -10
- package/components/editor/EditorRootExperienceComponent.vue.d.ts +0 -7
- package/components/editor/controls/EditorControlsContainer.vue.d.ts +0 -24
- package/components/placeholders/EmptyGridPlacements.vue.d.ts +0 -9
- package/components/placeholders/MissingExperienceComponent.vue.d.ts +0 -6
- package/createDelta.d.ts +0 -2
- package/defineComponent.d.ts +0 -10
- package/index.cjs +0 -53
- package/index.css +0 -1
- package/index.d.ts +0 -31
- package/index.js +0 -10869
- package/router/index.d.ts +0 -4
- package/views/ExperienceEditorView.vue.d.ts +0 -2
- package/views/ExperiencePreviewView.vue.d.ts +0 -2
- package/views/ExperienceView.vue.d.ts +0 -2
- package/views/NotFoundView.vue.d.ts +0 -2
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { CodegenConfig } from "@graphql-codegen/cli";
|
|
2
|
+
|
|
3
|
+
if (import.meta.env.VITE_OATHKEEPER_ENDPOINT === undefined || import.meta.env.CODEGEN_COOKIE === undefined) {
|
|
4
|
+
throw new Error("Missing 'VITE_OATHKEEPER_ENDPOINT' and/or 'CODEGEN_COOKIE' environment variables");
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
const CONFIG: CodegenConfig = {
|
|
8
|
+
overwrite: true,
|
|
9
|
+
schema: {
|
|
10
|
+
[import.meta.env.VITE_OATHKEEPER_ENDPOINT]: {
|
|
11
|
+
headers: {
|
|
12
|
+
Cookie: import.meta.env.CODEGEN_COOKIE,
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
generates: {
|
|
17
|
+
"./packages/delta-vue/__generated__/": {
|
|
18
|
+
preset: "client",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default CONFIG;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineConfigWithVueTs,
|
|
3
|
+
vueTsConfigs,
|
|
4
|
+
} from '@vue/eslint-config-typescript'
|
|
5
|
+
import { globalIgnores } from 'eslint/config'
|
|
6
|
+
import { FlatCompat } from "@eslint/eslintrc";
|
|
7
|
+
import { dirname } from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
import baseConfig from "../../eslint.base.config.mjs";
|
|
10
|
+
import js from "@eslint/js";
|
|
11
|
+
import pluginVue from 'eslint-plugin-vue'
|
|
12
|
+
|
|
13
|
+
const compat = new FlatCompat({
|
|
14
|
+
baseDirectory: dirname(fileURLToPath(import.meta.url)),
|
|
15
|
+
recommendedConfig: js.configs.recommended,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
export default defineConfigWithVueTs(
|
|
19
|
+
js.configs.recommended,
|
|
20
|
+
...baseConfig,
|
|
21
|
+
pluginVue.configs['flat/essential'],
|
|
22
|
+
vueTsConfigs.recommended,
|
|
23
|
+
...compat.extends(
|
|
24
|
+
"@vue/eslint-config-prettier/skip-formatting",
|
|
25
|
+
),
|
|
26
|
+
{
|
|
27
|
+
languageOptions: {
|
|
28
|
+
parserOptions: {
|
|
29
|
+
project: "packages/delta-vue/tsconfig.*?.json",
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
files: ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx", "**/*.vue"],
|
|
35
|
+
rules: {
|
|
36
|
+
"vue/multi-word-component-names": "off",
|
|
37
|
+
"@typescript-eslint/naming-convention": "off",
|
|
38
|
+
"@typescript-eslint/strict-boolean-expressions": "off",
|
|
39
|
+
"@typescript-eslint/no-use-before-define": "off",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
globalIgnores(["**/dist", "__generated__/**/*", "**/vite.config.*.timestamp*", "**/vitest.config.*.timestamp*", "package.json", "**/*.json"]),
|
|
43
|
+
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platecms/delta-vue",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Plugin to connect to the Plate Delta CMS in a Vue application.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"publishConfig": {
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"./style.css": "./style.css"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@platecms/delta-cast": "0.
|
|
27
|
-
"@platecms/delta-castscript": "0.
|
|
28
|
-
"@platecms/delta-client": "0.
|
|
29
|
-
"@platecms/delta-plate-resource-notation": "0.
|
|
26
|
+
"@platecms/delta-cast": "0.7.0",
|
|
27
|
+
"@platecms/delta-castscript": "0.7.0",
|
|
28
|
+
"@platecms/delta-client": "0.7.0",
|
|
29
|
+
"@platecms/delta-plate-resource-notation": "0.7.0",
|
|
30
30
|
"@graphql-codegen/cli": "5.0.7",
|
|
31
31
|
"@graphql-typed-document-node/core": "3.2.0",
|
|
32
32
|
"axios": "1.11.0",
|
|
@@ -47,4 +47,4 @@
|
|
|
47
47
|
"@apollo/client": "3.13.9",
|
|
48
48
|
"defu": "6.1.4"
|
|
49
49
|
}
|
|
50
|
-
}
|
|
50
|
+
}
|
package/project.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "delta-vue",
|
|
3
|
+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
|
4
|
+
"sourceRoot": "packages/delta-vue/src",
|
|
5
|
+
"projectType": "library",
|
|
6
|
+
"tags": [
|
|
7
|
+
"package",
|
|
8
|
+
"delta-vue"
|
|
9
|
+
],
|
|
10
|
+
"// targets": "to see all targets run: nx show project @platecms/delta-vue --web",
|
|
11
|
+
"targets": {
|
|
12
|
+
"codegen": {
|
|
13
|
+
"outputs": [
|
|
14
|
+
"{projectRoot}/app/graphql/generated.ts"
|
|
15
|
+
],
|
|
16
|
+
"command": "graphql-codegen --config {projectRoot}/codegen.config.ts"
|
|
17
|
+
},
|
|
18
|
+
"build": {
|
|
19
|
+
"executor": "@nx/vite:build",
|
|
20
|
+
"outputs": [
|
|
21
|
+
"{options.outputPath}"
|
|
22
|
+
],
|
|
23
|
+
"defaultConfiguration": "production",
|
|
24
|
+
"options": {
|
|
25
|
+
"outputPath": "generated/dist/{projectRoot}"
|
|
26
|
+
},
|
|
27
|
+
"configurations": {
|
|
28
|
+
"development": {
|
|
29
|
+
"mode": "development"
|
|
30
|
+
},
|
|
31
|
+
"production": {
|
|
32
|
+
"mode": "production"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"deploy": {
|
|
37
|
+
"executor": "nx:run-commands",
|
|
38
|
+
"dependsOn": [
|
|
39
|
+
"build"
|
|
40
|
+
],
|
|
41
|
+
"configurations": {
|
|
42
|
+
"dev": {
|
|
43
|
+
"command": "is-ci && echo 'Not deployed on dev.'"
|
|
44
|
+
},
|
|
45
|
+
"acc": {
|
|
46
|
+
"command": "echo 'Packages will be published via nx release publish'"
|
|
47
|
+
},
|
|
48
|
+
"prod": {
|
|
49
|
+
"command": "is-ci && echo 'Not deployed on prod.'"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {sortBy} from "lodash";
|
|
3
|
+
import type {ExperienceComponent} from "../../__generated__/graphql";
|
|
4
|
+
import RenderLibraryComponent from "./RenderLibraryComponent.vue";
|
|
5
|
+
import GridPlacement from "./GridPlacement.vue";
|
|
6
|
+
|
|
7
|
+
defineProps<{
|
|
8
|
+
experienceComponent: ExperienceComponent
|
|
9
|
+
}>()
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<slot name="render-component">
|
|
14
|
+
<RenderLibraryComponent
|
|
15
|
+
:building-block="experienceComponent.buildingBlock"
|
|
16
|
+
:building-block-field-fulfillments="experienceComponent.buildingBlockFieldFulfillments"
|
|
17
|
+
/>
|
|
18
|
+
</slot>
|
|
19
|
+
|
|
20
|
+
<slot name="grid-placements">
|
|
21
|
+
<GridPlacement v-for="gridPlacement in sortBy(experienceComponent.grid?.gridPlacements, 'row')" :grid-placement="gridPlacement" :key="gridPlacement.prn" />
|
|
22
|
+
</slot>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<style scoped>
|
|
26
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type {GridPlacement} from "../../__generated__/graphql";
|
|
3
|
+
import ExperienceComponent from "./ExperienceComponent.vue";
|
|
4
|
+
|
|
5
|
+
defineProps<{
|
|
6
|
+
gridPlacement: GridPlacement
|
|
7
|
+
}>()
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<ExperienceComponent :experience-component="gridPlacement.experienceComponent" />
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<style scoped>
|
|
15
|
+
|
|
16
|
+
</style>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import {type Component, computed, inject} from "vue";
|
|
3
|
+
import type {BuildingBlock, BuildingBlockFieldFulfillment} from "../../__generated__/graphql";
|
|
4
|
+
|
|
5
|
+
const library = inject<{ [key: string]: Component }>('library')
|
|
6
|
+
|
|
7
|
+
const props = withDefaults(
|
|
8
|
+
defineProps<{
|
|
9
|
+
buildingBlock?: BuildingBlock
|
|
10
|
+
buildingBlockFieldFulfillments?: BuildingBlockFieldFulfillment[]
|
|
11
|
+
}>(), {
|
|
12
|
+
buildingBlockFieldFulfillments: () => []
|
|
13
|
+
}
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
const currentComponent = computed(() => {
|
|
17
|
+
if(!library || !props.buildingBlock) return undefined;
|
|
18
|
+
|
|
19
|
+
return library[props.buildingBlock.slug]
|
|
20
|
+
})
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<template>
|
|
24
|
+
<component v-if="currentComponent" :is="currentComponent" :building-block="buildingBlock" :building-block-field-fulfillments="buildingBlockFieldFulfillments" />
|
|
25
|
+
<slot name="missing-component" :data="buildingBlock" v-else-if="buildingBlock" />
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<style scoped>
|
|
29
|
+
|
|
30
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type {ExperienceComponent} from "../../__generated__/graphql";
|
|
3
|
+
import ExperienceComponentComponent from "./ExperienceComponent.vue";
|
|
4
|
+
|
|
5
|
+
defineProps<{
|
|
6
|
+
rootExperienceComponent: ExperienceComponent
|
|
7
|
+
}>();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<slot>
|
|
12
|
+
<ExperienceComponentComponent v-if="rootExperienceComponent" :experience-component="rootExperienceComponent" />
|
|
13
|
+
</slot>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<style scoped></style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue';
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
icon: [string, string]
|
|
6
|
+
className?: string
|
|
7
|
+
size?: string
|
|
8
|
+
spin?: boolean
|
|
9
|
+
}>()
|
|
10
|
+
|
|
11
|
+
const iconStyle = computed(() => {
|
|
12
|
+
return props.icon[0] === 'fas' ? 'fa-solid' : 'fa-light'
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<template>
|
|
18
|
+
<i
|
|
19
|
+
:class="`${iconStyle} fa-${icon[1]} ${className ?? ''} ${size && size !== 'md' ? `text-${size}` : 'text-[16px]'} ${spin ? 'fa-spin' : ''}`"
|
|
20
|
+
></i>
|
|
21
|
+
</template>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import {
|
|
3
|
+
type Draft,
|
|
4
|
+
} from "@platecms/delta-client/utils"
|
|
5
|
+
import {sortBy} from "lodash";
|
|
6
|
+
import type {ExperienceComponent, GridPlacement} from "../../../__generated__/graphql";
|
|
7
|
+
import {inject} from "vue";
|
|
8
|
+
import EditorControlsContainer from "./controls/EditorControlsContainer.vue";
|
|
9
|
+
import RenderLibraryComponent from "../RenderLibraryComponent.vue";
|
|
10
|
+
import MissingExperienceComponent from "../placeholders/MissingExperienceComponent.vue";
|
|
11
|
+
import EditorGridPlacement from "./EditorGridPlacement.vue";
|
|
12
|
+
|
|
13
|
+
defineProps<{
|
|
14
|
+
rows?: number
|
|
15
|
+
experienceComponent: Draft<ExperienceComponent>
|
|
16
|
+
gridPlacement?: Draft<GridPlacement>
|
|
17
|
+
}>()
|
|
18
|
+
|
|
19
|
+
const blacklist = inject<string[]>('blacklist', [])
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<EditorControlsContainer v-if="experienceComponent?.buildingBlock && !blacklist.includes(experienceComponent.buildingBlock.slug)" :rows="rows" :row="gridPlacement?.row" :experience-component="experienceComponent">
|
|
24
|
+
<RenderLibraryComponent :building-block="experienceComponent.buildingBlock" :building-block-field-fulfillments="experienceComponent.buildingBlockFieldFulfillments">
|
|
25
|
+
<template v-slot:missing-component="slotProps">
|
|
26
|
+
<MissingExperienceComponent v-if="slotProps.data" :building-block="slotProps.data" />
|
|
27
|
+
</template>
|
|
28
|
+
</RenderLibraryComponent>
|
|
29
|
+
</EditorControlsContainer>
|
|
30
|
+
|
|
31
|
+
<EditorGridPlacement v-for="gridPlacement in sortBy(experienceComponent.grid?.gridPlacements, 'row')" :grid-placement="gridPlacement as Draft<GridPlacement>" :rows="experienceComponent?.grid?.gridPlacements.length" :key="gridPlacement.prn" />
|
|
32
|
+
</template>
|
|
33
|
+
|
|
34
|
+
<style scoped>
|
|
35
|
+
|
|
36
|
+
</style>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {throttle} from "lodash";
|
|
3
|
+
import {ref, inject} from "vue";
|
|
4
|
+
import type { Ref } from "vue";
|
|
5
|
+
import {WindowConnector, ConnectorEventType, type Draft} from "@platecms/delta-client/utils"
|
|
6
|
+
import type { ExperienceComponentCreateEvent } from "@platecms/delta-client/utils"
|
|
7
|
+
import type {BuildingBlock, ExperienceComponent, GridPlacement} from "../../../__generated__/graphql";
|
|
8
|
+
import RenderLibraryComponent from "../RenderLibraryComponent.vue";
|
|
9
|
+
import MissingExperienceComponent from "../placeholders/MissingExperienceComponent.vue";
|
|
10
|
+
import EditorExperienceComponent from "./EditorExperienceComponent.vue";
|
|
11
|
+
|
|
12
|
+
const props = defineProps<{
|
|
13
|
+
rows?: number
|
|
14
|
+
gridPlacement: Draft<GridPlacement>
|
|
15
|
+
}>()
|
|
16
|
+
|
|
17
|
+
const buildingBlockToCreate = inject<Ref<BuildingBlock | undefined>>('buildingBlockToCreate')
|
|
18
|
+
const connector = inject<WindowConnector>('connector')
|
|
19
|
+
const mode = inject<Ref<'edit' | 'drag'>>('mode')
|
|
20
|
+
|
|
21
|
+
const isInsideTarget = ref(false)
|
|
22
|
+
|
|
23
|
+
const mousePosition: Ref<'bottom' | 'top' | undefined> = ref(undefined)
|
|
24
|
+
|
|
25
|
+
const target = ref<HTMLElement | undefined>(undefined)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
const updateMode = inject<(mode: 'edit' | 'drag' | 'preview') => void>('updateMode')
|
|
29
|
+
const throttleHandleMouseOver = throttle(handleMouseOver, 250)
|
|
30
|
+
|
|
31
|
+
function handleMouseOver(event: MouseEvent) {
|
|
32
|
+
if(!isInsideTarget.value || !target.value) return
|
|
33
|
+
|
|
34
|
+
const targetRectangle = target.value.getBoundingClientRect();
|
|
35
|
+
|
|
36
|
+
// const x = event.clientX - targetRectangle.left;
|
|
37
|
+
const y = event.clientY - targetRectangle.top;
|
|
38
|
+
|
|
39
|
+
mousePosition.value = y > Math.ceil(targetRectangle.height / 2) ? 'bottom' : 'top';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function handleMouseUp() {
|
|
43
|
+
if(mousePosition.value === undefined || mode?.value !== 'drag') return
|
|
44
|
+
|
|
45
|
+
const index = props.gridPlacement.row + (mousePosition.value === 'bottom' ? 1 : 0)
|
|
46
|
+
|
|
47
|
+
connector?.send({ type: ConnectorEventType.EXPERIENCE_COMPONENT_CREATE, payload: { index: index > -1 ? index : 0 } } as ExperienceComponentCreateEvent)
|
|
48
|
+
if(updateMode) updateMode('edit')
|
|
49
|
+
mousePosition.value = undefined
|
|
50
|
+
}
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<template>
|
|
54
|
+
<div
|
|
55
|
+
ref="target"
|
|
56
|
+
@mouseup="handleMouseUp"
|
|
57
|
+
@mouseenter="() => isInsideTarget = true"
|
|
58
|
+
@mouseleave="() => {
|
|
59
|
+
isInsideTarget = false
|
|
60
|
+
mousePosition = undefined
|
|
61
|
+
}"
|
|
62
|
+
@mousemove="throttleHandleMouseOver"
|
|
63
|
+
>
|
|
64
|
+
<div v-if="isInsideTarget && mode === 'drag' && mousePosition === 'top'" class="dv:animate-pulse dv:outline-2 dv:outline-offset-2 dv:outline-gray-800 dv:outline-dashed">
|
|
65
|
+
<RenderLibraryComponent :building-block="buildingBlockToCreate">
|
|
66
|
+
<template v-slot:missing-component="slotProps">
|
|
67
|
+
<MissingExperienceComponent v-if="slotProps.data" :building-block="slotProps.data" />
|
|
68
|
+
</template>
|
|
69
|
+
</RenderLibraryComponent>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<EditorExperienceComponent :experience-component="gridPlacement.experienceComponent as Draft<ExperienceComponent>" :grid-placement="gridPlacement" :rows="rows" />
|
|
73
|
+
|
|
74
|
+
<div v-if="isInsideTarget && mode === 'drag' && mousePosition === 'bottom'" class="dv:animate-pulse dv:outline-2 dv:outline-offset-2 dv:outline-gray-800 dv:outline-dashed">
|
|
75
|
+
<RenderLibraryComponent :building-block="buildingBlockToCreate">
|
|
76
|
+
<template v-slot:missing-component="slotProps">
|
|
77
|
+
<MissingExperienceComponent v-if="slotProps.data" :building-block="slotProps.data" />
|
|
78
|
+
</template>
|
|
79
|
+
</RenderLibraryComponent>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</template>
|
|
83
|
+
|
|
84
|
+
<style scoped>
|
|
85
|
+
|
|
86
|
+
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type {ExperienceComponent} from "../../../__generated__/graphql";
|
|
3
|
+
import { type Draft } from "@platecms/delta-client/utils";
|
|
4
|
+
import EditorExperienceComponent from "./EditorExperienceComponent.vue";
|
|
5
|
+
|
|
6
|
+
defineProps<{
|
|
7
|
+
rootExperienceComponent: Draft<ExperienceComponent>
|
|
8
|
+
}>();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<EditorExperienceComponent v-if="rootExperienceComponent" :experience-component="rootExperienceComponent" />
|
|
13
|
+
</template>
|
|
14
|
+
|
|
15
|
+
<style scoped>
|
|
16
|
+
|
|
17
|
+
</style>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import {inject} from "vue";
|
|
3
|
+
import {
|
|
4
|
+
ConnectorEventType,
|
|
5
|
+
type Draft,
|
|
6
|
+
type ExperienceComponentEditEvent,
|
|
7
|
+
type ExperienceComponentRemoveEvent,
|
|
8
|
+
GridPlacementDownEvent,
|
|
9
|
+
GridPlacementUpEvent,
|
|
10
|
+
WindowConnector
|
|
11
|
+
} from "@platecms/delta-client/utils"
|
|
12
|
+
import type {ExperienceComponent} from "../../../../__generated__/graphql";
|
|
13
|
+
import FontAwesomeIcon from '../../atoms/icon/FontAwesomeIcon.vue';
|
|
14
|
+
|
|
15
|
+
const connector = inject<WindowConnector>('connector')
|
|
16
|
+
const mode = inject<'edit' | 'drag' | 'preview'>('mode', 'preview')
|
|
17
|
+
|
|
18
|
+
defineProps<{
|
|
19
|
+
rows?: number
|
|
20
|
+
row?: number
|
|
21
|
+
experienceComponent: Draft<ExperienceComponent>
|
|
22
|
+
}>()
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
<template>
|
|
26
|
+
<div class="dv:relative dv:group/controls dv:hover:outline-2 dv:outline-gray-800 dv:hover:-outline-offset-2 dv:hover:bg-gray-200 hover:dv:outline-gray-800 hover:dv:outline-dashed dv:z-40 dv:cursor-pointer">
|
|
27
|
+
<slot />
|
|
28
|
+
|
|
29
|
+
<div class="dv:hidden dv:group-hover/controls:flex dv:absolute dv:z-50 dv:top-0 dv:w-full dv:items-center dv:justify-center">
|
|
30
|
+
<div class="dv:rounded-b-md dv:bg-gray-800 dv:px-6 dv:py-2 dv:text-white dv:text-xs">
|
|
31
|
+
<p>
|
|
32
|
+
{{ experienceComponent.buildingBlock?.slug ?? 'No slug' }}
|
|
33
|
+
</p>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
<div v-if="experienceComponent.isDraft" class="delta-snapshot-ignore dv:absolute dv:top-4 dv:right-4">
|
|
37
|
+
<div class="dv:px-3 dv:h-8 dv:bg-gray-800 dv:text-white dv:text-xs dv:flex dv:flex-col dv:gap-2 dv:items-center dv:justify-center dv:rounded-full">
|
|
38
|
+
<p>
|
|
39
|
+
Draft
|
|
40
|
+
</p>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
<div v-if="mode === 'edit'" class="delta-snapshot-ignore dv:absolute dv:left-4 dv:top-4 dv:flex dv:gap-2 dv:z-50">
|
|
44
|
+
<!-- Edit button -->
|
|
45
|
+
<div
|
|
46
|
+
@click="connector?.send({
|
|
47
|
+
type: ConnectorEventType.EXPERIENCE_COMPONENT_EDIT,
|
|
48
|
+
payload: {
|
|
49
|
+
uuid: experienceComponent.uuid,
|
|
50
|
+
prn: experienceComponent.prn
|
|
51
|
+
}
|
|
52
|
+
} as ExperienceComponentEditEvent)"
|
|
53
|
+
class="dv:opacity-0 dv:group-hover/controls:opacity-100 dv:transition-all dv:duration-300 dv:bg-gray-800 dv:w-8 dv:h-8 dv:flex dv:items-center dv:justify-center dv:rounded-sm dv:cursor-pointer"
|
|
54
|
+
>
|
|
55
|
+
<FontAwesomeIcon :icon="['fal', 'pencil']" />
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<!-- Remove button -->
|
|
59
|
+
<div
|
|
60
|
+
@click="connector?.send({
|
|
61
|
+
type: ConnectorEventType.EXPERIENCE_COMPONENT_REMOVE,
|
|
62
|
+
payload: {
|
|
63
|
+
uuid: experienceComponent.uuid,
|
|
64
|
+
prn: experienceComponent.prn
|
|
65
|
+
}
|
|
66
|
+
} as ExperienceComponentRemoveEvent)"
|
|
67
|
+
class="delta-snapshot-ignore dv:opacity-0 dv:group-hover/controls:opacity-100 dv:transition-all dv:duration-300 dv:bg-gray-800 dv:w-8 dv:h-8 dv:flex dv:items-center dv:justify-center dv:rounded-sm dv:cursor-pointer"
|
|
68
|
+
>
|
|
69
|
+
<FontAwesomeIcon :icon="['fal', 'trash-can']" />
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<!-- Move Up button -->
|
|
73
|
+
<div
|
|
74
|
+
v-if="(row ?? 1) > 1"
|
|
75
|
+
@click="connector?.send({
|
|
76
|
+
type: ConnectorEventType.GRID_PLACEMENT_UP,
|
|
77
|
+
payload: {
|
|
78
|
+
uuid: experienceComponent.uuid,
|
|
79
|
+
prn: experienceComponent.prn
|
|
80
|
+
}
|
|
81
|
+
} as GridPlacementUpEvent)"
|
|
82
|
+
class="dv:opacity-0 dv:group-hover/controls:opacity-100 dv:transition-all dv:duration-300 dv:bg-gray-800 dv:w-8 dv:h-8 dv:flex dv:items-center dv:justify-center dv:rounded-sm dv:cursor-pointer"
|
|
83
|
+
>
|
|
84
|
+
<FontAwesomeIcon :icon="['fal', 'arrow-up']" />
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<!-- Move Down button -->
|
|
88
|
+
<div
|
|
89
|
+
v-if="(row ?? 1) <( (rows ?? 1))"
|
|
90
|
+
@click="connector?.send({
|
|
91
|
+
type: ConnectorEventType.GRID_PLACEMENT_DOWN,
|
|
92
|
+
payload: {
|
|
93
|
+
uuid: experienceComponent.uuid,
|
|
94
|
+
prn: experienceComponent.prn
|
|
95
|
+
}
|
|
96
|
+
} as GridPlacementDownEvent)"
|
|
97
|
+
class="dv:opacity-0 dv:group-hover/controls:opacity-100 dv:transition-all dv:duration-300 dv:bg-gray-800 dv:w-8 dv:h-8 dv:flex dv:items-center dv:justify-center dv:rounded-sm dv:cursor-pointer"
|
|
98
|
+
>
|
|
99
|
+
<FontAwesomeIcon :icon="['fal', 'arrow-down']" />
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div class="dv:opacity-0 dv:group-hover/controls:opacity-100 dv:transition-all dv:duration-300 dv:bg-gray-800 dv:w-8 dv:h-8 dv:flex dv:items-center dv:justify-center dv:rounded-sm dv:cursor-pointer">
|
|
103
|
+
<p class="text-white">
|
|
104
|
+
{{ row }}
|
|
105
|
+
</p>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
|
|
109
|
+
<!-- Hidden element to create snapshots -->
|
|
110
|
+
<div class="delta-snapshot-ignore dv:absolute dv:left-4 dv:top-0 dv:h-full dv:flex dv:items-center dv:justify-center">
|
|
111
|
+
<div class="dv:opacity-0 dv:transition-all dv:duration-300 dv:bg-gray-800 dv:w-8 dv:h-8 dv:flex dv:items-center dv:justify-center dv:rounded-sm dv:cursor-pointer">
|
|
112
|
+
<FontAwesomeIcon :icon="['fal', 'arrow-from-line']" />
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</template>
|
|
117
|
+
|
|
118
|
+
<style scoped>
|
|
119
|
+
|
|
120
|
+
</style>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import {
|
|
3
|
+
ConnectorEventType,
|
|
4
|
+
type ExperienceComponentCreateEvent,
|
|
5
|
+
WindowConnector
|
|
6
|
+
} from "@platecms/delta-client/utils"
|
|
7
|
+
import {type Component, computed, inject, ref} from "vue";
|
|
8
|
+
import type {BuildingBlock} from "../../../__generated__/graphql";
|
|
9
|
+
const props = withDefaults(defineProps<{
|
|
10
|
+
type?: 'content-experience' | 'blueprint',
|
|
11
|
+
buildingBlockToCreate?: BuildingBlock
|
|
12
|
+
}>(), {
|
|
13
|
+
type: 'content-experience'
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
const isInsidePlaceholder = ref(false)
|
|
17
|
+
const connector = inject<WindowConnector>('connector')
|
|
18
|
+
const library = inject<{ [key: string]: Component }>('library')
|
|
19
|
+
|
|
20
|
+
const currentComponent = computed(() => {
|
|
21
|
+
if(!library || !props.buildingBlockToCreate) return undefined;
|
|
22
|
+
|
|
23
|
+
return library[props.buildingBlockToCreate.slug]
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
function handleMouseUp() {
|
|
27
|
+
connector?.send({ type: ConnectorEventType.EXPERIENCE_COMPONENT_CREATE, payload: { index: 0 } } as ExperienceComponentCreateEvent)
|
|
28
|
+
isInsidePlaceholder.value = false
|
|
29
|
+
}
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<template>
|
|
33
|
+
<div @mouseenter="isInsidePlaceholder = true" @mouseleave="isInsidePlaceholder = false" @mouseup="handleMouseUp()">
|
|
34
|
+
<component v-if="currentComponent && isInsidePlaceholder" :is="currentComponent" :building-block="buildingBlockToCreate" :building-block-field-fulfillments="[]" class="dv:animate-pulse" />
|
|
35
|
+
|
|
36
|
+
<div v-else class="dv:p-4 dv:h-screen dv:w-full">
|
|
37
|
+
<div class="dv:border dv:border-dashed dv:border-[#705ED9] dv:h-full dv:w-full dv:flex dv:flex-col dv:gap-4 dv:items-center dv:justify-center dv:bg-[#EAEAFA] dv:rounded-md">
|
|
38
|
+
<svg width="39" height="39" viewBox="0 0 39 39" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
39
|
+
<rect x="0.5" y="9.5" width="29" height="29" rx="4.5" stroke="#705ED9" stroke-dasharray="2 2"/>
|
|
40
|
+
<rect x="9.5" y="0.5" width="29" height="29" rx="4.5" fill="#EAEAFA" stroke="#705ED9"/>
|
|
41
|
+
</svg>
|
|
42
|
+
|
|
43
|
+
<p v-if="type === 'content-experience'" class="dv:text-center dv:text-[#705ED9]">
|
|
44
|
+
Drag experience components from the sidebar to begin <br>
|
|
45
|
+
or add a template
|
|
46
|
+
</p>
|
|
47
|
+
|
|
48
|
+
<p v-else class="dv:text-center dv:text-[#705ED9]">
|
|
49
|
+
Drag experience components from the sidebar to begin
|
|
50
|
+
</p>
|
|
51
|
+
|
|
52
|
+
<button v-if="type === 'content-experience'" @click="connector?.send({ type: ConnectorEventType.BLUEPRINT_OVERLAY_OPEN, payload: null })" class="dv:bg-gradient-to-bl dv:from-primary dv:to-primary-tint dv:px-6 dv:py-3 dv:rounded-md dv:text-white dv:font-medium">
|
|
53
|
+
Use template
|
|
54
|
+
</button>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<style scoped>
|
|
61
|
+
|
|
62
|
+
</style>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import type {BuildingBlock} from "../../../__generated__/graphql";
|
|
3
|
+
|
|
4
|
+
defineProps<{
|
|
5
|
+
buildingBlock: BuildingBlock
|
|
6
|
+
}>()
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<div class="dv:w-full dv:p-4">
|
|
11
|
+
<div class="dv:h-64 dv:flex dv:items-center dv:justify-center dv:border-2 dv:border-dashed">
|
|
12
|
+
<p>
|
|
13
|
+
Missing component: {{ buildingBlock.slug }}
|
|
14
|
+
</p>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<style scoped>
|
|
20
|
+
|
|
21
|
+
</style>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Delta } from "./index";
|
|
2
|
+
import { Component, markRaw } from "vue";
|
|
3
|
+
import { DeltaComponent } from "./defineComponent";
|
|
4
|
+
|
|
5
|
+
export function createDelta(): Delta {
|
|
6
|
+
const delta: Delta = markRaw({
|
|
7
|
+
install(app) {
|
|
8
|
+
app.provide("delta", delta);
|
|
9
|
+
app.config.globalProperties.$delta = delta;
|
|
10
|
+
},
|
|
11
|
+
|
|
12
|
+
components: markRaw<Record<string, DeltaComponent<Component>>>({}),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
return delta;
|
|
16
|
+
}
|