Fixes
All checks were successful
Gitea Actions / Run-Tests-On-Arm64 (push) Successful in 30m28s
Gitea Actions / Run-Tests-On-Amd64 (push) Successful in 51m9s
Gitea Actions / Merge (push) Successful in 2m4s

This commit is contained in:
Thomas Peterson 2025-06-24 09:43:29 +02:00
parent f4fdc051b5
commit a41ed9cb53
68 changed files with 1584 additions and 235 deletions

View File

@ -64,10 +64,10 @@ server {
try_files $uri @sfFront;
}
#location /w2p/ {
# proxy_pass http://tp:8080/w2p/;
# proxy_temp_path /tmp/proxy;
#}
location /w2p/ {
proxy_pass http://tp:8080/w2p/;
proxy_temp_path /tmp/proxy;
}
location @sfFront { # Symfony
if ($request_method = 'OPTIONS') {

View File

@ -41,8 +41,9 @@ class Barcode extends Node
$compiler->raw(
'
$options = new \PSC\System\SettingsBundle\Barcode\QRGdWithLogoOptions();
//$options->version = -1;
$options->eccLevel = \chillerlan\QRCode\Common\EccLevel::M;
$options->version = -1;
$options->versionMax = 40;
$options->eccLevel = \chillerlan\QRCode\Common\EccLevel::H;
$options->outputType = \chillerlan\QRCode\Output\QROutputInterface::CUSTOM;
if(isset($_options["cmyk"]) && $_options["cmyk"] == true) {
$options->outputInterface = \PSC\System\SettingsBundle\Barcode\QRImagickCMYK::class;

View File

@ -2,7 +2,7 @@
namespace PSC\System\UpdateBundle\Migrations;
class Version20250613181212 extends Base
class Version20250613181223 extends Base
{
public function migrateDatabase(): void
{
@ -11,7 +11,7 @@ class Version20250613181212 extends Base
$this->entityManager->getConnection()->exec("alter table article modify column a6_xmlpageobjectsfile varchar(255) default null;");
$this->entityManager->getConnection()->exec("alter table article modify column layouterid varchar(255) default null;");
$this->entityManager->getConnection()->exec("alter table article modify column resale int(1) default null;");
$this->entityManager->getConnection()->exec("alter table article modify column a6_resale_price float(20,2) default null;");
$this->entityManager->getConnection()->exec("alter table article modify column a6_resale_price float(20,2) default 0;");
$this->entityManager->getConnection()->exec("alter table article modify column render_new_preview_image int(1) default null;");
$this->entityManager->getConnection()->exec("alter table article modify column render_new_preview_pdf int(1) default null;");
$this->entityManager->getConnection()->exec("alter table article modify column render_new_preview_gallery int(1) default null;");

View File

@ -5,7 +5,7 @@
"name": "my-vue-app",
"dependencies": {
"@tailwindcss/vite": "^4.1.10",
"@vueuse/core": "^13.3.0",
"@vueuse/core": "^13.4.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-vue-next": "^0.514.0",
@ -304,11 +304,11 @@
"@vue/tsconfig": ["@vue/tsconfig@0.7.0", "", { "peerDependencies": { "typescript": "5.x", "vue": "^3.4.0" }, "optionalPeers": ["typescript", "vue"] }, "sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg=="],
"@vueuse/core": ["@vueuse/core@13.3.0", "", { "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "13.3.0", "@vueuse/shared": "13.3.0" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-uYRz5oEfebHCoRhK4moXFM3NSCd5vu2XMLOq/Riz5FdqZMy2RvBtazdtL3gEcmDyqkztDe9ZP/zymObMIbiYSg=="],
"@vueuse/core": ["@vueuse/core@13.4.0", "", { "dependencies": { "@types/web-bluetooth": "^0.0.21", "@vueuse/metadata": "13.4.0", "@vueuse/shared": "13.4.0" }, "peerDependencies": { "vue": "^3.5.0" } }, "sha512-OnK7zW3bTq/QclEk17+vDFN3tuAm8ONb9zQUIHrYQkkFesu3WeGUx/3YzpEp+ly53IfDAT9rsYXgGW6piNZC5w=="],
"@vueuse/metadata": ["@vueuse/metadata@13.3.0", "", {}, "sha512-42IzJIOYCKIb0Yjv1JfaKpx8JlCiTmtCWrPxt7Ja6Wzoq0h79+YVXmBV03N966KEmDEESTbp5R/qO3AB5BDnGw=="],
"@vueuse/metadata": ["@vueuse/metadata@13.4.0", "", {}, "sha512-CPDQ/IgOeWbqItg1c/pS+Ulum63MNbpJ4eecjFJqgD/JUCJ822zLfpw6M9HzSvL6wbzMieOtIAW/H8deQASKHg=="],
"@vueuse/shared": ["@vueuse/shared@13.3.0", "", { "peerDependencies": { "vue": "^3.5.0" } }, "sha512-L1QKsF0Eg9tiZSFXTgodYnu0Rsa2P0En2LuLrIs/jgrkyiDuJSsPZK+tx+wU0mMsYHUYEjNsuE41uqqkuR8VhA=="],
"@vueuse/shared": ["@vueuse/shared@13.4.0", "", { "peerDependencies": { "vue": "^3.5.0" } }, "sha512-+AxuKbw8R1gYy5T21V5yhadeNM7rJqb4cPaRI9DdGnnNl3uqXh+unvQ3uCaA2DjYLbNr1+l7ht/B4qEsRegX6A=="],
"alien-signals": ["alien-signals@1.0.13", "", {}, "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg=="],

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue + TS</title>
<title>Calc</title>
</head>
<body>
<div id="app" class="w-screen h-screen"></div>

View File

@ -10,7 +10,7 @@
},
"dependencies": {
"@tailwindcss/vite": "^4.1.10",
"@vueuse/core": "^13.3.0",
"@vueuse/core": "^13.4.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-vue-next": "^0.514.0",

View File

@ -13,42 +13,28 @@ import { Main } from '@/components/app/main'
</script>
<template>
<ResizablePanelGroup
id="handle-demo-group-1"
direction="horizontal"
class="h-full w-full"
>
<ResizablePanel id="" :default-size="25">
<div class="flex flex-col h-full p-6">
<Library />
<Debug />
</div>
</ResizablePanel>
<ResizableHandle id="" with-handle />
<ResizablePanel id="" :default-size="75">
<ResizablePanelGroup id="" direction="vertical">
<ResizablePanel id="" :default-size="75">
<ResizablePanelGroup id="" direction="horizontal">
<ResizablePanel id="" :default-size="75">
<div class="flex h-full p-6">
<Main />
</div>
</ResizablePanel>
<ResizableHandle id="" with-handle />
<ResizablePanel id="" :default-size="25">
<div class="flex h-full p-6">
<ElementProperties />
</div>
</ResizablePanel>
</ResizablePanelGroup>
</ResizablePanel>
<ResizableHandle id="" with-handle />
<ResizablePanel id="" :default-size="25">
<ElementDependency />
</ResizablePanel>
</ResizablePanelGroup>
</ResizablePanel>
</ResizablePanelGroup>
<div class="w-scree h-screen">
<ResizablePanelGroup
id="handle-demo-group-1"
direction="horizontal"
class="h-full w-full"
>
<ResizablePanel id="" :default-size="15">
<div class="flex flex-col gap-2 h-full">
<Library />
<Debug />
</div>
</ResizablePanel>
<ResizableHandle id="" with-handle />
<ResizablePanel id="" :default-size="85">
<div class="flex h-full p-6 bg-slate-50">
<Main />
</div>
</ResizablePanel>
</ResizablePanelGroup>
<ElementProperties />
<ElementDependency />
</div>
</template>
<style scoped>

View File

@ -16,8 +16,10 @@ function restoreJson() {
<template>
<div class="p-1">
<Textarea v-model="store.json"/>
<Button v-on:click="loadJson()">Load Json</Button>
<Button v-on:click="restoreJson()">Restore Json</Button>
<Textarea v-model="store.json" class="h-50"/>
<div class="flex flex-row mt-2 gap-1">
<Button class="grow" v-on:click="loadJson()">Load Json</Button>
<Button class="grow" v-on:click="restoreJson()">Restore Json</Button>
</div>
</div>
</template>

View File

@ -21,8 +21,9 @@ const store = useElementStore()
</script>
<template>
<div class="d-flex bg-slate-50 m-1 flex-wrap p-1 relative" v-for="border in borders" :key="border.uuid">
<div class="flex flex-row gap-1">
<div class="flex flex-col" v-for="border in borders" :key="border.uuid">
<div class="flex flex-row items-center gap-2 border-l-3 border-black pt-1">
<span class="w-5 flex-none"><hr class="bg-black h-1 border-0"/></span>
<Input v-model="border.formula" placeholder="Formula"/>
<Input v-model="border.calcValue" placeholder="CalcValue"/>
<Input v-model="border.value" placeholder="Value"/>

View File

@ -22,7 +22,7 @@ function addBorder(dep) {
</script>
<template>
<div v-bind:class="{ 'invisible': store.isShowPropierties === false }" class=" w-full m-2 p-2">
<div class=" w-full">
<Border :borders="dependency.borders" />
</div>
</template>

View File

@ -21,8 +21,9 @@ function addBorder(dep) {
</script>
<template>
<div class="d-flex flex-wrap p-2 relative" v-for="dep in dependencys" :key="dep.uuid">
<div class="flex flex-row gap-1">
<div class="d-flex flex-wrap relative ml-5 mr-5" v-for="dep in dependencys" :key="dep.uuid">
<div class="flex flex-row gap-2 border-l-3 border-black pt-1">
<span class="w-2 flex-none"></span>
<Select v-model="dep.relation">
<SelectTrigger class="w-[180px]">
<SelectValue placeholder="Select Relation" />

View File

@ -1,21 +1,55 @@
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { useElementStore } from '@/stores/Items'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { Dependency } from '.'
import { default as DepModel } from '../../../model/Dependency.ts'
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog'
const store = useElementStore()
let openModal = ref(false)
function addDependency(event) {
store.getActiveItem.addDependency(new DepModel());
}
store.$subscribe((mutation, state) => {
if(state.showDependency) {
openModal.value = true
}
})
watch(openModal, (newOpenModal) => {
if(newOpenModal === false) {
store.setShowDependency(false)
}
})
</script>
<template>
<div v-bind:class="{ 'invisible': store.isShowPropierties === false }" class="overflow-auto h-full w-full m-2 p-2">
<Button v-on:click="addDependency($event)">Add Dependency</Button>
<Dependency :dependencys="store.getActiveItem.dependencys" />
</div>
<Dialog class="w-full h-full" v-model:open="openModal">
<DialogContent class="h-full">
<DialogHeader>
<DialogTitle>Dependencys</DialogTitle>
<DialogDescription>
</DialogDescription>
</DialogHeader>
<div class="overflow-auto h-full w-full">
<Button v-on:click="addDependency($event)">Add Dependency</Button>
<Dependency :dependencys="store.getActiveItem.dependencys" />
</div>
<DialogFooter>
</DialogFooter>
</DialogContent>
</Dialog>
</template>

View File

@ -1,19 +1,99 @@
<script lang="ts" setup>
import { useElementStore } from '@/stores/Items';
import InputElement from '@/model/InputElement';
import InputElementProperties from '../properties/InputElement.vue';
import { useElementStore } from '@/stores/Items'
import InputElement from '@/model/InputElement'
import SelectElement from '@/model/SelectElement'
import HiddenElement from '@/model/HiddenElement'
import TextElement from '@/model/TextElement'
import Row from '@/model/Row'
import TextareaElement from '@/model/TextareaElement'
import HeadlineElement from '@/model/HeadlineElement'
import InputElementProperties from '../properties/InputElement.vue'
import SelectElementProperties from '../properties/SelectElement.vue'
import HiddenElementProperties from '../properties/HiddenElement.vue'
import TextElementProperties from '../properties/TextElement.vue'
import TextareaElementProperties from '../properties/TextareaElement.vue'
import HeadlineElementProperties from '../properties/HeadlineElement.vue'
import RowProperties from '../properties/RowElement.vue'
import { ref, watch } from 'vue'
import {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from '@/components/ui/sheet'
let openModal = ref(false)
let emit = defineEmits(['update:modelValue']);
const store = useElementStore()
store.$subscribe((mutation, state) => {
if(state.showProperties) {
openModal.value = true
}
})
watch(openModal, (newOpenModal) => {
if(newOpenModal === false) {
store.setShowProperties(false)
}
})
</script>
<template>
<div v-bind:class="{ 'invisible': store.isShowPropierties === false }" class="flex flex-col w-full m-2">
<InputElementProperties
v-if="store.getActiveItem.type === 2"
v-model="store.getActiveItem as InputElement"
>
</InputElementProperties>
<Sheet v-model:open="openModal">
<SheetContent>
<SheetHeader>
<SheetTitle>Properties</SheetTitle>
<SheetDescription>
</SheetDescription>
</SheetHeader>
<div class="flex flex-col w-full m-2">
<HeadlineElementProperties
v-if="store.getActiveItem.type === 6"
v-model="store.getActiveItem as HeadlineElement"
>
</HeadlineElementProperties>
</div>
<RowProperties
v-if="store.getActiveItem.type === 7"
v-model="store.getActiveItem as Row"
>
</RowProperties>
<TextareaElementProperties
v-if="store.getActiveItem.type === 5"
v-model="store.getActiveItem as TextareaElement"
>
</TextareaElementProperties>
<TextElementProperties
v-if="store.getActiveItem.type === 4"
v-model="store.getActiveItem as TextElement"
>
</TextElementProperties>
<SelectElementProperties
v-if="store.getActiveItem.type === 3"
v-model="store.getActiveItem as SelectElement"
>
</SelectElementProperties>
<InputElementProperties
v-if="store.getActiveItem.type === 2"
v-model="store.getActiveItem as InputElement"
>
</InputElementProperties>
<HiddenElementProperties
v-if="store.getActiveItem.type === 1"
v-model="store.getActiveItem as HiddenElement"
>
</HiddenElementProperties>
</div>
</SheetContent>
</Sheet>
</template>

View File

@ -0,0 +1,3 @@
<template>
<div class="p-5 m-2 h-full text-center">Empty</div>
</template>

View File

@ -0,0 +1,32 @@
<script lang="ts" setup>
import HeadlineElement from '@/model/HeadlineElement';
import { computed } from 'vue';
import { Input } from '@/components/ui/input'
import { SquareDot } from 'lucide-vue-next';
const props = defineProps({
modelValue: HeadlineElement
})
let emit = defineEmits(['update:modelValue']);
const theModel = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
});
</script>
<template>
<div class="flex gap-2 flex-row items-center content-center">
<SquareDot />
<h1 v-if="theModel.variant == 1" class="text-4xl">{{theModel.default}}</h1>
<h6 v-else-if="theModel.variant == 6" class="text-base">{{theModel.default}}</h6>
<h5 v-else-if="theModel.variant == 5" class="text-lg">{{theModel.default}}</h5>
<h4 v-else-if="theModel.variant == 4" class="text-xl">{{theModel.default}}</h4>
<h3 v-else-if="theModel.variant == 3" class="text-2xl">{{theModel.default}}</h3>
<h2 v-else-if="theModel.variant == 2" class="text-3xl">{{theModel.default}}</h2>
<h1 v-else class="text-4xl">{{theModel.default}}</h1>
</div>
</template>

View File

@ -0,0 +1,26 @@
<script lang="ts" setup>
import HiddenElement from '@/model/HiddenElement';
import { computed } from 'vue';
import { Input } from '@/components/ui/input'
import { SquareDashed } from 'lucide-vue-next';
const props = defineProps({
modelValue: HiddenElement
})
let emit = defineEmits(['update:modelValue']);
const theModel = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
});
</script>
<template>
<div class="flex gap-2 flex-row">
<SquareDashed />
<label>{{theModel?.id}}</label>
</div>
</template>

View File

@ -2,6 +2,7 @@
import InputElement from '@/model/InputElement';
import { computed } from 'vue';
import { Input } from '@/components/ui/input'
import { SquarePen } from 'lucide-vue-next';
const props = defineProps({
modelValue: InputElement
@ -18,8 +19,9 @@ const theModel = computed({
</script>
<template>
<div class="">
<label>{{theModel?.name}}</label>
<Input :placeholder="theModel?.placeholder" :value="theModel?.value" :name="theModel?.name" :id="theModel?.id" :required="theModel?.required"/>
<div class="flex gap-2 flex-row items-center">
<SquarePen class="flex-none" />
<label class="w-60 flex-inital">{{theModel?.name}}</label>
<Input :placeholder="theModel?.placeholder" :value="theModel?.default" :name="theModel?.name" :id="theModel?.id" :required="theModel?.required"/>
</div>
</template>

View File

@ -0,0 +1,86 @@
<script lang="ts" setup>
import Row from '@/model/Row';
import Column from '@/model/Column';
import { ref, computed } from 'vue';
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { SquareDashed } from 'lucide-vue-next';
import EmptyElementForm from './EmptyElementForm.vue'
import { RenderElements } from './../renderelements'
import { useElementStore } from '@/stores/Items'
import Parser from '@/lib/parser'
import { CirclePlus } from 'lucide-vue-next';
const props = defineProps({
modelValue: Row
})
let emit = defineEmits(['update:modelValue']);
const dragUuid = ref("");
const store = useElementStore()
const theModel = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
});
const onDrop = (event: DragEvent, targetUuid: string, column: Column) => {
dragUuid.value = ""
if(event.dataTransfer?.getData('mode') == "sort") {
let item = store.cutItem(store.getSourceDragUuid)
column.items.push(item)
store.setDragMode("")
event.stopImmediatePropagation()
}
if(store.getDragMode == "insert") {
const itemId = Number(event.dataTransfer?.getData('itemId'));
column.items.push(Parser.getModelForType(itemId))
store.setDragMode("")
event.stopImmediatePropagation()
}
}
const dragEnter = (event: DragEvent, uuid: string) => {
dragUuid.value = uuid
event.stopImmediatePropagation()
if(store.getDragMode == "sort" && uuid != store.getSourceDragUuid) {
event.stopImmediatePropagation()
}
}
const dragLeaveEmpty = (event: DragEvent, uuid: string) => {
dragUuid.value = ""
event.stopImmediatePropagation()
}
const dragEnterEmpty = (event: DragEvent, uuid: string) => {
dragUuid.value = uuid
event.stopImmediatePropagation()
if(store.getDragMode == "sort" && uuid != store.getSourceDragUuid) {
event.stopImmediatePropagation()
}
}
</script>
<template>
<div class="flex gap-2 flex-col">
<div class="w-full flex flex-row gap-1" v-if="theModel!.columns.length > 0">
<div class="grow border p-1 bg-white" v-for="col in theModel!.columns">
<div class="h-8 group items-center content-justify w-full mb-2" v-if="col.items.length == 0" @drop="onDrop($event, theModel!.uuid, col)" @dragleave="dragLeaveEmpty($event, col.uuid)" @dragenter="dragEnterEmpty($event, col.uuid)"> <div class="inline-flex items-center justify-center w-full pointer-events-none">
<hr class="w-64 h-px my-2 bg-gray-200 border-0 dark:bg-gray-700 transition duration-200 pointer-events-none" :class="{ 'bg-orange-500': dragUuid == col.uuid }" >
<span class="absolute px-3 font-medium text-gray-900 bg-white dark:text-white dark:bg-gray-900 pointer-events-none"><CirclePlus :class="{ 'text-orange-500': dragUuid == col.uuid }" class="transition duration-200 pointer-events-none" /></span>
</div>
</div>
<RenderElements
@drop="onDrop($event, theModel!.uuid, col)"
v-if="col.items.length > 0"
v-bind:items="col.items"/>
</div>
</div>
<EmptyElementForm
v-if="theModel!.columns.length == 0"/>
</div>
</template>

View File

@ -0,0 +1,48 @@
<script lang="ts" setup>
import SelectElement from '@/model/SelectElement'
import { computed } from 'vue'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectLabel,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import { SquareParking, SquareChevronDown, SquareDashed } from 'lucide-vue-next';
const props = defineProps({
modelValue: SelectElement
})
let emit = defineEmits(['update:modelValue'])
const theModel = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
})
</script>
<template>
<div class="flex gap-2 flex-row items-center">
<SquareChevronDown class="flex-none" />
<label class="w-60 flex-inital">{{theModel?.name}}</label>
<div class="w-full">
<Select :modelValue="theModel?.default">
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem v-for="option in theModel?.options" :key="option.uuid" :value="option.id">
{{option.name}}
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
</div>
</template>

View File

@ -0,0 +1,26 @@
<script lang="ts" setup>
import TextElement from '@/model/TextElement';
import { computed } from 'vue';
import { Input } from '@/components/ui/input'
import { SquareParking } from 'lucide-vue-next';
const props = defineProps({
modelValue: TextElement
})
let emit = defineEmits(['update:modelValue']);
const theModel = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
});
</script>
<template>
<div class="flex gap-2 flex-row">
<SquareParking />
<p>{{theModel?.default}}</p>
</div>
</template>

View File

@ -0,0 +1,27 @@
<script lang="ts" setup>
import TextareaElement from '@/model/TextareaElement';
import { computed } from 'vue';
import { Textarea } from '@/components/ui/textarea'
import { SquareMenu } from 'lucide-vue-next';
const props = defineProps({
modelValue: TextareaElement
})
let emit = defineEmits(['update:modelValue']);
const theModel = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
});
</script>
<template>
<div class="flex gap-2 flex-row">
<SquareMenu class="flex-none" />
<label class="w-60 flex-inital">{{theModel?.name}}</label>
<Textarea :value="theModel?.default" :name="theModel?.name" :id="theModel?.id"/>
</div>
</template>

View File

@ -1,22 +1,47 @@
<script setup lang="ts">
import { useElementStore } from '@/stores/Items'
import { Input } from '@/components/ui/input'
import { SquareParking, SquareDot, SquareMenu, SquarePen, SquareChevronDown, SquareDashed } from 'lucide-vue-next';
const store = useElementStore()
function startDrag(event: DragEvent, item: string) {
event.dataTransfer!.dropEffect = 'move';
event.dataTransfer!.effectAllowed = 'move';
event.dataTransfer?.setData('itemId', item);
event.dataTransfer.dropEffect = 'move';
event.dataTransfer.effectAllowed = 'move';
event.dataTransfer.setData('itemId', item);
store.setDragMode("insert")
}
</script>
<template>
<div class="flex flex-col m-2">
<div id="input" class="w-full" draggable="true" @dragstart="startDrag($event, '2')" @dragenter.prevent @dragover.prevent>
<Input />
<div class="flex flex-col p-3 gap-3 overflow-auto">
<div id="headline" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '6')" @dragenter.prevent @dragover.prevent>
<SquareDot />
<span>Headline</span>
</div>
<div id="text" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '4')" @dragenter.prevent @dragover.prevent>
<SquareParking />
<span>Text</span>
</div>
<div id="textarea" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '5')" @dragenter.prevent @dragover.prevent>
<SquareMenu />
<span>Textarea</span>
</div>
<div id="input" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '2')" @dragenter.prevent @dragover.prevent>
<SquarePen />
<span>Input</span>
</div>
<div id="select" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '3')" @dragenter.prevent @dragover.prevent>
<SquareChevronDown />
<span>Select</span>
</div>
<div id="hidden" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '1')" @dragenter.prevent @dragover.prevent>
<SquareDashed />
<span>Hidden</span>
</div>
<div id="row" class="border-1 p-2 w-full flex flex-row gap-2" draggable="true" @dragstart="startDrag($event, '7')" @dragenter.prevent @dragover.prevent>
<SquareDashed />
<span>Row</span>
</div>
</div>
</template>

View File

@ -8,7 +8,6 @@ const store = useElementStore()
function onDrop(event: DragEvent) {
if(store.dragMode == "insert") {
const itemType = Number(event.dataTransfer?.getData('itemId'));
store.addElement(Parser.getModelForType(itemType))
store.clearSelection()
}
@ -16,7 +15,7 @@ function onDrop(event: DragEvent) {
</script>
<template>
<div class="border m-4 p-4 rounded-xl w-full h-full bg-[radial-gradient(#e5e7eb_1px,transparent_1px)] [background-size:16px_16px]" @drop="onDrop($event)" @dragover.prevent>
<div class="border m-1 p-4 rounded-xl w-full h-full shadow bg-white" @drop="onDrop($event)" @dragover.prevent>
<RenderElements v-bind:items="store.getItems" />
</div>
</template>

View File

@ -0,0 +1,63 @@
<script lang="ts" setup>
import HeadlineElement from '@/model/HeadlineElement';
import { computed } from 'vue';
import { Input } from '@/components/ui/input'
import { Checkbox } from '@/components/ui/checkbox'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
const props = defineProps({
modelValue: HeadlineElement
})
let emit = defineEmits(['update:modelValue']);
const theModel = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
});
</script>
<template>
<label>ID</label>
<Input v-model="theModel!.id" />
<label>Default</label>
<Input v-model="theModel!.default"/>
<label>Name</label>
<Input v-model="theModel!.name"/>
<label>Variant</label>
<Select v-model="theModel!.variant">
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="1">
Headline 1
</SelectItem>
<SelectItem value="2">
Headline 2
</SelectItem>
<SelectItem value="3">
Headline 3
</SelectItem>
<SelectItem value="4">
Headline 4
</SelectItem>
<SelectItem value="5">
Headline 5
</SelectItem>
<SelectItem value="6">
Headline 6
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</template>

View File

@ -0,0 +1,27 @@
<script lang="ts" setup>
import HiddenElement from '@/model/HiddenElement';
import { computed } from 'vue';
import { Input } from '@/components/ui/input'
import { Checkbox } from '@/components/ui/checkbox'
const props = defineProps({
modelValue: HiddenElement
})
let emit = defineEmits(['update:modelValue']);
const theModel = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
});
</script>
<template>
<label>ID</label>
<Input v-model="theModel!.id" />
<label>Default</label>
<Input v-model="theModel!.default"/>
<label>Name</label>
<Input v-model="theModel!.name"/>
</template>

View File

@ -22,8 +22,8 @@ const theModel = computed({
<Input v-model="theModel!.id" />
<label>Placeholder</label>
<Input v-model="theModel!.placeholder"/>
<label>Value</label>
<Input v-model="theModel!.value"/>
<label>Default</label>
<Input v-model="theModel!.default"/>
<label>Name</label>
<Input v-model="theModel!.name"/>
<Checkbox v-model="theModel!.required"/>

View File

@ -0,0 +1,29 @@
<script lang="ts" setup>
import Option from '@/model/select/Option';
import { computed } from 'vue';
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { Dependency } from '../elementdependency'
import { default as DepModel } from '../../../model/Dependency.ts'
const props = defineProps({
option: Option,
})
function addDependency(option) {
option.addDependency(new DepModel());
}
</script>
<template>
<div class="flex flex-row gap-1">
<label>ID</label>
<Input v-model="option.id" />
<label>Name</label>
<Input v-model="option.name"/>
<Button v-on:click="addDependency(option)">Add Dependency</Button>
</div>
<Dependency :dependencys="option.dependencys" />
</template>

View File

@ -0,0 +1,27 @@
<script lang="ts" setup>
import Row from '@/model/Row'
import Column from '@/model/Column'
import { computed } from 'vue'
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
const props = defineProps({
modelValue: Row
})
let emit = defineEmits(['update:modelValue'])
const theModel = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
})
function addColumn(row: Row) {
row.addColumn(new Column())
}
</script>
<template>
<Button v-on:click="addColumn(theModel)">add Column</Button>
</template>

View File

@ -0,0 +1,97 @@
<script lang="ts" setup>
import SelectElement from '@/model/SelectElement';
import Option from '@/model/select/Option';
import { computed } from 'vue';
import { Input } from '@/components/ui/input'
import { Button } from '@/components/ui/button'
import { Checkbox } from '@/components/ui/checkbox'
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select'
import OptionElement from './OptionElement.vue'
import {
Dialog,
DialogContent,
DialogClose,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from '@/components/ui/dialog'
const props = defineProps({
modelValue: SelectElement
})
let emit = defineEmits(['update:modelValue']);
const theModel = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
});
function addOption(obj) {
obj.addOption(new Option(String(obj.options.length + 1)));
}
</script>
<template>
<label>ID</label>
<Input v-model="theModel!.id" />
<label>Default</label>
<Input v-model="theModel!.default"/>
<label>Name</label>
<Input v-model="theModel!.name"/>
<label>Mode</label>
<Select v-model="theModel!.mode">
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="normal">
Normal
</SelectItem>
<SelectItem value="paperdb">
PaperDB
</SelectItem>
<SelectItem value="colordb">
ColorDB
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
<label>Container</label>
<Input v-model="theModel!.container"/>
<Dialog >
<DialogTrigger>
<Button class="mt-2">Edit Options</Button>
</DialogTrigger>
<DialogContent class="min-w-full grid-rows-[auto_minmax(0,1fr)_auto] p-4 max-h-[90dvh]">
<DialogHeader>
<DialogTitle>Edit Options</DialogTitle>
<DialogDescription>
<Button v-on:click="addOption(theModel)">Add Option</Button>
</DialogDescription>
</DialogHeader>
<div class="w-full grid overflow-y-auto px-6">
<div class="d-flex flex-wrap p-2 relative" v-for="opt in theModel.options" :key="opt.uuid">
<OptionElement :option="opt"/>
</div>
</div>
<DialogFooter>
<DialogClose as-child>
<Button type="button" variant="secondary">
Close
</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
</template>

View File

@ -0,0 +1,27 @@
<script lang="ts" setup>
import TextElement from '@/model/TextElement';
import { computed } from 'vue';
import { Input } from '@/components/ui/input'
import { Checkbox } from '@/components/ui/checkbox'
const props = defineProps({
modelValue: TextElement
})
let emit = defineEmits(['update:modelValue']);
const theModel = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
});
</script>
<template>
<label>ID</label>
<Input v-model="theModel!.id" />
<label>Default</label>
<Input v-model="theModel!.default"/>
<label>Name</label>
<Input v-model="theModel!.name"/>
</template>

View File

@ -0,0 +1,28 @@
<script lang="ts" setup>
import TextareaElement from '@/model/TextareaElement';
import { computed } from 'vue';
import { Input } from '@/components/ui/input'
import { Textarea } from '@/components/ui/textarea'
import { Checkbox } from '@/components/ui/checkbox'
const props = defineProps({
modelValue: TextareaElement
})
let emit = defineEmits(['update:modelValue']);
const theModel = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
});
</script>
<template>
<label>ID</label>
<Input v-model="theModel!.id" />
<label>Name</label>
<Input v-model="theModel!.name"/>
<label>Default</label>
<Textarea v-model="theModel!.default"/>
</template>

View File

@ -1,11 +1,24 @@
<script lang="ts" setup>
import BaseElement from '@/model/BaseElement';
import InputElementForm from '../elements/InputElementForm.vue'
import InputElement from '@/model/InputElement';
import { useElementStore } from '@/stores/Items';
import type { PropType } from 'vue';
import HiddenElementForm from '../elements/HiddenElementForm.vue'
import HeadlineElementForm from '../elements/HeadlineElementForm.vue'
import TextElementForm from '../elements/TextElementForm.vue'
import TextareaElementForm from '../elements/TextareaElementForm.vue'
import SelectElementForm from '../elements/SelectElementForm.vue'
import RowElementForm from '../elements/RowElementForm.vue'
import InputElement from '@/model/InputElement'
import HiddenElement from '@/model/HiddenElement'
import TextElement from '@/model/TextElement'
import TextareaElement from '@/model/TextareaElement'
import HeadlineElement from '@/model/HeadlineElement'
import Row from '@/model/Row'
import SelectElement from '@/model/SelectElement'
import { useElementStore } from '@/stores/Items'
import type { PropType } from 'vue'
import Parser from '@/lib/parser'
import { Settings, Trash, Move } from 'lucide-vue-next';
import { Settings, Trash, Move, CirclePlus, Waypoints } from 'lucide-vue-next';
import { ref } from 'vue'
const props = defineProps({
items: Array as PropType<BaseElement[]>
@ -13,38 +26,38 @@ const props = defineProps({
const store = useElementStore()
const elementFocus = (event: Event, item: BaseElement) => {
store.changeFocus(item.uuid)
store.setShowProperties(true)
store.setActiveItem(item)
event.stopImmediatePropagation()
}
const dragUuid = ref("");
const startDrag = (event: DragEvent, uuid: string) => {
event.dataTransfer!.dropEffect = 'move';
event.dataTransfer!.effectAllowed = 'move';
event.dataTransfer?.setData('mode', "sort");
event.dataTransfer!.dropEffect = 'move'
event.dataTransfer!.effectAllowed = 'move'
event.dataTransfer?.setData('mode', "sort")
store.setDragMode("sort")
store.setSourceDragUuid(uuid)
event.stopImmediatePropagation()
}
const dragLeave = (event: DragEvent, uuid: string) => {
dragUuid.value = ""
event.stopImmediatePropagation()
}
const dragEnter = (event: DragEvent, uuid: string) => {
dragUuid.value = uuid
if(store.getDragMode == "sort" && uuid != store.getSourceDragUuid) {
store.moveItemBefore(store.getSourceDragUuid, uuid)
event.stopImmediatePropagation()
}
}
const stopDrag = (event: DragEvent, uuid: string) => {
dragUuid.value = ""
if(event.dataTransfer?.getData('mode') == "sort") {
store.moveItemBefore(store.getSourceDragUuid, uuid)
store.setDragMode("")
event.stopImmediatePropagation()
}
if(store.dragMode == "insert") {
const itemType = Number(event.dataTransfer?.getData('itemId'));
const itemType = Number(event.dataTransfer?.getData('itemId'))
store.addElementAfter(Parser.getModelForType(itemType), uuid)
store.clearSelection()
event.stopImmediatePropagation()
@ -59,27 +72,62 @@ const editElementProperties = (item: BaseElement) => {
store.setShowProperties(true)
store.setActiveItem(item)
}
const editElementDependency = (item: BaseElement) => {
store.setShowDependency(true)
store.setActiveItem(item)
}
</script>
<template>
<div class="flex flex-col gap-2">
<div class="d-flex bg-slate-50 flex-wrap p-2 relative" @dragenter="dragEnter($event, item.uuid)" @drop="stopDrag($event, item.uuid)" v-on:click="elementFocus($event, item)" v-bind:class="{ 'border border-rose-500': item.isFocused === true }" v-for="item in items" :key="item.uuid">
<InputElementForm
v-if="item.type === 2"
v-model="item as InputElement"
/>
<div class="absolute size-14 -right-15 top-0 flex-col" v-bind:class="{ invisible: item.isFocused === false }">
<div @dragstart="startDrag($event, item.uuid)" draggable="true" class="size-10 flex items-center justify-center m-1 bg-gray-500 rounded-full text-white border p-1 cursor-pointer">
<Move />
<div class="overflow-auto h-full">
<div class="flex flex-col gap-2">
<div class="d-flex flex flex-col relative items-center " v-for="item in items" v-if="items.length > 0" :key="item.uuid">
<div class="h-8 group w-full mb-2" @dragleave.self="dragLeave($event, item.uuid)" @dragenter.self="dragEnter($event, item.uuid)" @drop="stopDrag($event, item.uuid)">
<div class="inline-flex items-center justify-center w-full pointer-events-none">
<hr class="w-64 h-px my-2 bg-gray-200 border-0 dark:bg-gray-700 transition duration-200 pointer-events-none" :class="{ 'bg-orange-500': dragUuid == item.uuid }" >
<span class="absolute px-3 font-medium text-gray-900 -translate-x-1/2 bg-white left-1/2 dark:text-white dark:bg-gray-900 pointer-events-none"><CirclePlus :class="{ 'text-orange-500': dragUuid == item.uuid }" class="transition duration-200 pointer-events-none" /></span>
</div>
</div>
<div v-on:click="editElementProperties(item)" class="size-10 flex items-center justify-center m-1 bg-gray-500 rounded-full text-white border p-1 cursor-pointer">
<Settings />
</div>
<div v-on:click="deleteItem(item)" class="size-10 flex items-center justify-center m-1 bg-red-500 rounded-full text-white border p-1 cursor-pointer">
<Trash />
<div @dragstart="startDrag($event, item.uuid)" draggable="true" class="w-full flex flex-row border-1 border-slate-200 border-dashed p-2 hover:bg-gray-100 transition duration-500" v-bind:class="{ ' bg-slate-50': item.isFocused === true }">
<div class="m-2 cursor-pointer">
<Move />
</div>
<div class="grow content-center items-center">
<InputElementForm
v-if="item.type === 2"
v-model="item as InputElement"
/>
<SelectElementForm
v-if="item.type === 3"
v-model="item as SelectElement"
/>
<TextElementForm
v-if="item.type === 4"
v-model="item as TextElement"
/>
<TextareaElementForm
v-if="item.type === 5"
v-model="item as TextareaElement"
/>
<HeadlineElementForm
v-if="item.type === 6"
v-model="item as HeadlineElement"
/>
<RowElementForm
v-if="item.type === 7"
v-model="item as Row"
/>
</div>
<div v-on:click="editElementDependency(item)" class="m-2 cursor-pointer">
<Waypoints />
</div>
<div v-on:click="editElementProperties(item)" class="m-2 cursor-pointer">
<Settings />
</div>
<div v-on:click="deleteItem(item)" class="text-red-500 m-2 cursor-pointer">
<Trash />
</div>
</div>
</div>
</div>

View File

@ -29,7 +29,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits)
v-bind="forwarded"
:class="
cn(
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200',
props.class,
)"
>

View File

@ -0,0 +1,17 @@
<script setup lang="ts">
import { DialogRoot, type DialogRootEmits, type DialogRootProps, useForwardPropsEmits } from 'reka-ui'
const props = defineProps<DialogRootProps>()
const emits = defineEmits<DialogRootEmits>()
const forwarded = useForwardPropsEmits(props, emits)
</script>
<template>
<DialogRoot
data-slot="sheet"
v-bind="forwarded"
>
<slot />
</DialogRoot>
</template>

View File

@ -0,0 +1,14 @@
<script setup lang="ts">
import { DialogClose, type DialogCloseProps } from 'reka-ui'
const props = defineProps<DialogCloseProps>()
</script>
<template>
<DialogClose
data-slot="sheet-close"
v-bind="props"
>
<slot />
</DialogClose>
</template>

View File

@ -0,0 +1,63 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { X } from 'lucide-vue-next'
import {
DialogClose,
DialogContent,
type DialogContentEmits,
type DialogContentProps,
DialogPortal,
useForwardPropsEmits,
} from 'reka-ui'
import { cn } from '@/lib/utils'
import SheetOverlay from './SheetOverlay.vue'
interface SheetContentProps extends DialogContentProps {
class?: HTMLAttributes['class']
side?: 'top' | 'right' | 'bottom' | 'left'
}
defineOptions({
inheritAttrs: false,
})
const props = withDefaults(defineProps<SheetContentProps>(), {
side: 'right',
})
const emits = defineEmits<DialogContentEmits>()
const delegatedProps = reactiveOmit(props, 'class', 'side')
const forwarded = useForwardPropsEmits(delegatedProps, emits)
</script>
<template>
<DialogPortal>
<SheetOverlay />
<DialogContent
data-slot="sheet-content"
:class="cn(
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
side === 'right'
&& 'data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm',
side === 'left'
&& 'data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm',
side === 'top'
&& 'data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b',
side === 'bottom'
&& 'data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t',
props.class)"
v-bind="{ ...forwarded, ...$attrs }"
>
<slot />
<DialogClose
class="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none"
>
<X class="size-4" />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>
</DialogPortal>
</template>

View File

@ -0,0 +1,20 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { DialogDescription, type DialogDescriptionProps } from 'reka-ui'
import { cn } from '@/lib/utils'
const props = defineProps<DialogDescriptionProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = reactiveOmit(props, 'class')
</script>
<template>
<DialogDescription
data-slot="sheet-description"
:class="cn('text-muted-foreground text-sm', props.class)"
v-bind="delegatedProps"
>
<slot />
</DialogDescription>
</template>

View File

@ -0,0 +1,16 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{ class?: HTMLAttributes['class'] }>()
</script>
<template>
<div
data-slot="sheet-footer"
:class="cn('mt-auto flex flex-col gap-2 p-4', props.class)
"
>
<slot />
</div>
</template>

View File

@ -0,0 +1,15 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { cn } from '@/lib/utils'
const props = defineProps<{ class?: HTMLAttributes['class'] }>()
</script>
<template>
<div
data-slot="sheet-header"
:class="cn('flex flex-col gap-1.5 p-4', props.class)"
>
<slot />
</div>
</template>

View File

@ -0,0 +1,20 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { DialogOverlay, type DialogOverlayProps } from 'reka-ui'
import { cn } from '@/lib/utils'
const props = defineProps<DialogOverlayProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = reactiveOmit(props, 'class')
</script>
<template>
<DialogOverlay
data-slot="sheet-overlay"
:class="cn('data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', props.class)"
v-bind="delegatedProps"
>
<slot />
</DialogOverlay>
</template>

View File

@ -0,0 +1,20 @@
<script setup lang="ts">
import type { HTMLAttributes } from 'vue'
import { reactiveOmit } from '@vueuse/core'
import { DialogTitle, type DialogTitleProps } from 'reka-ui'
import { cn } from '@/lib/utils'
const props = defineProps<DialogTitleProps & { class?: HTMLAttributes['class'] }>()
const delegatedProps = reactiveOmit(props, 'class')
</script>
<template>
<DialogTitle
data-slot="sheet-title"
:class="cn('text-foreground font-semibold', props.class)"
v-bind="delegatedProps"
>
<slot />
</DialogTitle>
</template>

View File

@ -0,0 +1,14 @@
<script setup lang="ts">
import { DialogTrigger, type DialogTriggerProps } from 'reka-ui'
const props = defineProps<DialogTriggerProps>()
</script>
<template>
<DialogTrigger
data-slot="sheet-trigger"
v-bind="props"
>
<slot />
</DialogTrigger>
</template>

View File

@ -0,0 +1,8 @@
export { default as Sheet } from './Sheet.vue'
export { default as SheetClose } from './SheetClose.vue'
export { default as SheetContent } from './SheetContent.vue'
export { default as SheetDescription } from './SheetDescription.vue'
export { default as SheetFooter } from './SheetFooter.vue'
export { default as SheetHeader } from './SheetHeader.vue'
export { default as SheetTitle } from './SheetTitle.vue'
export { default as SheetTrigger } from './SheetTrigger.vue'

View File

@ -1,12 +1,33 @@
import type BaseElement from "../model/BaseElement"
import InputElement from "../model/InputElement"
import Row from "../model/Row"
import Column from "../model/Column"
import HiddenElement from "../model/HiddenElement"
import SelectElement from "../model/SelectElement"
import TextElement from "../model/TextElement"
import TextareaElement from "../model/TextareaElement"
import HeadlineElement from "../model/HeadlineElement"
export default class Parser {
static getModelForType(type: Number) : BaseElement {
switch(type) {
case 8:
return new Column
case 7:
return new Row
case 6:
return new HeadlineElement
case 5:
return new TextareaElement
case 4:
return new TextElement
case 3:
return new SelectElement
case 2:
return new InputElement
case 1:
return new HiddenElement
default:
return new InputElement
}

View File

@ -67,7 +67,10 @@ export default class BaseElement {
return null
}
deleteItem(item: BaseElement) {
getItem(existingUuid: string) {
return null
}
deleteItem(item: BaseElement) {
}
}

View File

@ -0,0 +1,77 @@
import BaseElement from "./BaseElement";
export default class Column extends BaseElement {
items: BaseElement[] = []
constructor() {
super()
this.type = 8
}
addItem(item: BaseElement) {
this.items.push(item)
}
public toJSON() {
return Object.assign(
super.toJSON(),
{
'items': this.items.reduce((result, item) => {
result.push(item.toJSON())
return result
}, [])
})
}
fromJSON(obj) {
super.fromJSON(obj)
obj.columns.map((d) => {
const column = new Column()
column.fromJSON(d)
this.columns.push(column)
})
}
getItem(existingUuid: string) {
let item: BaseElement|null = null;
this.items.some((element,indexArray) => {
if(element.uuid === existingUuid) {
return element
}
if(item === null) {
return element.getItem(existingUuid)
}
});
return item
}
cutItem(existingUuid: string) {
let item: BaseElement|null = null;
this.items.forEach((element,indexArray) => {
if(element.uuid === existingUuid) {
item = this.items.splice(indexArray, 1)[0]
return true
}
if(item === null) {
item = element.cutItem(existingUuid)
}
});
return item
}
insertItem(item: BaseElement, targetUuid: string): boolean {
let inserted = false;
for (let i = 0; i < this.items.length; ++i) {
if(this.items[i].uuid === targetUuid) {
this.items.splice(i, 0, item);
inserted = true;
return false
}
if(!inserted) {
this.items[i].insertItem(item, targetUuid)
}
}
return inserted
}
}

View File

@ -0,0 +1,30 @@
import BaseElement from "./BaseElement";
export default class HeadlineElement extends BaseElement {
default: string = ""
variant: string = "1"
name: string = ""
xmlType: string = "text"
constructor() {
super();
this.type = 6
}
public toJSON() {
return Object.assign(
super.toJSON(),
{
'default': this.default,
'name': this.name,
'variant': this.variant,
})
}
fromJSON(obj) {
super.fromJSON(obj)
this.name = obj.name
this.default = obj.default
this.variant = obj.variant
}
}

View File

@ -0,0 +1,27 @@
import BaseElement from "./BaseElement";
export default class HiddenElement extends BaseElement {
default: string = ""
name: string = ""
xmlType: string = "hidden"
constructor() {
super();
this.type = 1
}
public toJSON() {
return Object.assign(
super.toJSON(),
{
'default': this.default,
'name': this.name,
})
}
fromJSON(obj) {
super.fromJSON(obj)
this.name = obj.name
this.default = obj.default
}
}

View File

@ -1,7 +1,7 @@
import BaseElement from "./BaseElement";
export default class InputElement extends BaseElement {
value: string = ""
default: string = ""
placeholder: string = "Placeholder"
required: boolean = false
name: string = ""
@ -17,8 +17,7 @@ export default class InputElement extends BaseElement {
super.toJSON(),
{
'placeHolder': this.placeholder,
'xmlType': this.xmlType,
'value': this.value,
'default': this.default,
'name': this.name,
'required': this.required
})
@ -27,9 +26,8 @@ export default class InputElement extends BaseElement {
fromJSON(obj) {
super.fromJSON(obj)
this.name = obj.name
this.value = obj.value
this.default = obj.default
this.required = obj.required
this.xmlType = obj.xmlType
this.placeHolder = obj.placeHolder
}
}

View File

@ -0,0 +1,76 @@
import BaseElement from "./BaseElement";
import Column from "./Column.ts"
export default class Row extends BaseElement {
columns: Column[] = []
constructor() {
super()
this.type = 7
}
addColumn(column: Column) {
this.columns.push(column)
}
public toJSON() {
return Object.assign(
super.toJSON(),
{
'columns': this.columns.reduce((result, column) => {
result.push(column.toJSON())
return result
}, [])
})
}
cutItem(existingUuid: string) {
let item: BaseElement|null = null;
this.columns.some((col,indexArray) => {
item = col.cutItem(existingUuid)
if(item !== null) {
return true
}
});
return item
}
getItem(existingUuid: string) {
let item: BaseElement|null = null;
this.columns.some((col,indexArray) => {
item = col.getItem(existingUuid)
if(item !== null) {
return item;
}
});
return item
}
insertItem(item: BaseElement, targetUuid: string): boolean {
this.columns.some((col,indexArray) => {
item = col.insertItem(item, targetUuid)
if(item !== null) {
return true;
}
});
return false
}
insertItemInEmptyColumn(item: BaseElement, targetUuid: string, column: Column) {
if(this.uuid == targetUuid) {
column.items.push(item)
return true
}
return false
}
fromJSON(obj) {
super.fromJSON(obj)
obj.columns.map((d) => {
const column = new Column()
column.fromJSON(d)
this.columns.push(column)
})
}
}

View File

@ -0,0 +1,47 @@
import BaseElement from "./BaseElement";
import Option from "./select/Option.ts"
export default class SelectElement extends BaseElement {
default: string = ""
name: string = ""
xmlType: string = "select"
options: Option[] = []
mode: string = "normal"
container: string = ""
constructor() {
super()
this.type = 3
}
addOption(option: SelectElementOption) {
this.options.push(option)
}
public toJSON() {
return Object.assign(
super.toJSON(),
{
'default': this.default,
'mode': this.mode,
'container': this.container,
'options': this.options.reduce((result, opt) => {
result.push(opt.toJSON())
return result
}, []),
'name': this.name,
})
}
fromJSON(obj) {
super.fromJSON(obj)
this.name = obj.name
this.mode = obj.mode
this.container = obj.container
this.default = obj.default
obj.options.map((d) => {
const option = new Option()
option.fromJSON(d)
this.options.push(option)
})
}
}

View File

@ -0,0 +1,27 @@
import BaseElement from "./BaseElement";
export default class TextElement extends BaseElement {
default: string = ""
name: string = ""
xmlType: string = "text"
constructor() {
super();
this.type = 4
}
public toJSON() {
return Object.assign(
super.toJSON(),
{
'default': this.default,
'name': this.name,
})
}
fromJSON(obj) {
super.fromJSON(obj)
this.name = obj.name
this.default = obj.default
}
}

View File

@ -0,0 +1,27 @@
import BaseElement from "./BaseElement";
export default class TextareaElement extends BaseElement {
default: string = ""
name: string = ""
xmlType: string = "text"
constructor() {
super();
this.type = 5
}
public toJSON() {
return Object.assign(
super.toJSON(),
{
'default': this.default,
'name': this.name,
})
}
fromJSON(obj) {
super.fromJSON(obj)
this.name = obj.name
this.default = obj.default
}
}

View File

@ -0,0 +1,41 @@
import {v4 as uuidv4} from 'uuid'
import Dependency from '../Dependency.ts'
export default class Option {
uuid: string = "";
id: string = ""
name: string = ""
dependencys: Dependency[] = [];
constructor(id: string) {
this.uuid = uuidv4();
this.id = id;
}
addDependency(dep: Dependeny)
{
this.dependencys.push(dep)
}
toJSON() {
return {
'id': this.id,
'name': this.name,
'dependencys': this.dependencys.reduce((result, dep) => {
result.push(dep.toJSON())
return result
}, [])
}
}
fromJSON(obj) {
this.name = obj.name
this.id = obj.id
obj.dependencys.map((d) => {
const dep = new Dependency()
dep.fromJSON(d)
this.dependencys.push(dep)
})
}
}

View File

@ -10,15 +10,18 @@ export const useElementStore = defineStore('items', {
items: [] as BaseElement[],
activeItem: {} as BaseElement | {},
showProperties: false,
showDependency: false,
sourceDragUuid: "",
dragMode: "",
json: ""
json: "",
name: uuidv4(),
}),
getters: {
getCount: (state) => state.items.length,
getItems: (state) => state.items,
getActiveItem: (state) => state.activeItem as BaseElement,
isShowPropierties: (state) => state.showProperties,
isShowDependency: (state) => state.showDependency,
getSourceDragUuid: (state) => state.sourceDragUuid,
getDragMode: (state) => state.dragMode,
},
@ -33,19 +36,23 @@ export const useElementStore = defineStore('items', {
}, [])
this.json = JSON.stringify({
this.json = JSON.stringify([{
uuid: this.uuid,
name: this.name,
options: options
})
}])
},
parseJSON() {
this.items = []
let obj = JSON.parse(this.json)
this.name = obj.name
obj.options.map((obj) => {
const item = Parser.getModelForType(obj.type);
item.fromJSON(obj)
this.name = obj[0].name
if(obj[0].uuid) {
this.uuid = obj[0].uuid
}
obj[0].options.map((ob) => {
const item = Parser.getModelForType(ob.type);
item.fromJSON(ob)
this.addElement(item)
})
},
@ -60,6 +67,9 @@ export const useElementStore = defineStore('items', {
})
this.showProperties = false
},
setShowDependency(value: boolean) {
this.showDependency = value;
},
setShowProperties(value: boolean) {
this.showProperties = value;
},
@ -75,29 +85,48 @@ export const useElementStore = defineStore('items', {
this.items[i].deleteItem(item)
}
},
moveSortItemToEmptyElement(targetUuid: string, column: Number) {
const item = this.cutItem(this.items, this.sourceDragUuid);
moveSortItemToEmptyElement(targetUuid: string, column: Column) {
const item = this.cutItem(this.sourceDragUuid);
this.insertItemInEmptyColumn(this.items, item!, targetUuid, column)
},
moveItemBefore(dragUuid: string, targetUuid: string): boolean {
const item = this.cutItem(this.items, dragUuid);
return this.insertItem(this.items, item!, targetUuid)
const item = this.cutItem(dragUuid);
return this.insertItem(this.items, item, targetUuid)
},
addElementAfter(item: BaseElement, targetUuid: string) {
this.insertItem(this.items, item!, targetUuid)
this.insertItem(this.items, item, targetUuid)
},
setSourceDragUuid(uuid: string) {
this.sourceDragUuid = uuid
},
cutItem(items: BaseElement[], existingUuid: string) {
cutItem(existingUuid: string) {
let item: BaseElement|null = null;
items.forEach((element,indexArray) => {
this.items.some((element,indexArray) => {
if(element.uuid === existingUuid) {
item = items.splice(indexArray, 1)[0];
item = this.items.splice(indexArray, 1)[0]
return true
}
if(item === null) {
item = element.cutItem(existingUuid)
if(item !== null) {
return true
}
}
});
return item;
},
getItem(existingUuid: string) {
let item: BaseElement|null = null;
item = this.items.some((element,indexArray) => {
if(element.uuid === existingUuid) {
return element
}
if(item === null) {
item = element.getItem(existingUuid)
if(item !== null) {
return item
}
}
});
@ -118,7 +147,7 @@ export const useElementStore = defineStore('items', {
return inserted
},
insertItemInEmptyColumn(items: BaseElement[], item: BaseElement, targetUuid: string, column: Number): boolean {
insertItemInEmptyColumn(items: BaseElement[], item: BaseElement, targetUuid: string, column: Column): boolean {
let inserted = false;
for (let i = 0; i < items.length; ++i) {
inserted = items[i].insertItemInEmptyColumn(item, targetUuid, column)
@ -126,6 +155,7 @@ export const useElementStore = defineStore('items', {
return inserted
},
setDragMode(mode: string) {
this.dragMode = mode
}

View File

@ -14,7 +14,6 @@ $this->headScript()->prependFile('/'. $this->designPath . '/js/saxoprint.js');
</script>
<button onclick="sendHeight();">iFrame Höhe neu ermitteln</button>
<!--
<div class="md:flex mt-10 md:w-2/4 md:m-auto gap-10 ml-2 mr-2 md:mt-10">
<div class="md:w-1/2">

View File

@ -37,9 +37,9 @@
}
</style>
</head>
<body class="h-screen text-all font-lenzFont" x-data="{scrolledFromTop: false}" @scroll.window="window.pageYOffset > 60 ? scrolledFromTop = true: scrolledFromTop = false">
<body class="text-all font-lenzFont">
<div class="loading hidden absolute bg-white bg-opacity-60 z-40 h-full w-full flex items-center justify-center">
<div class="loading hidden absolute bg-white bg-opacity-60 z-40 w-full flex items-center justify-center">
<div class="flex items-center">
<span class="text-3xl mr-4">Loading</span>
<svg class="animate-spin h-8 w-8 text-gray-800" xmlns="http://www.w3.org/2000/svg" fill="none"
@ -79,11 +79,19 @@
<script>
function sendHeight() {
const height = document.body.scrollHeight;
parent.postMessage({ height: height }, "https://kalendercreator.de");
//alert('Sie sollten doch nicht drücken!');
parent.postMessage({ action: 'setHeight', data: {height: height} }, "*");
}
window.addEventListener("load", sendHeight);
window.addEventListener("resize", sendHeight);
<?php if($this->user): ?>
parent.postMessage({ action: 'setUsername', data: {username: '<?= $this->user->self_email ?>'} }, "*");
<?php else: ?>
parent.postMessage({ action: 'clearUsername', data: {} }, "*");
<?php endif; ?>
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

View File

@ -0,0 +1,3 @@
<script>
parent.postMessage({action: 'redirectLogin'}, '*');
</script>

View File

@ -0,0 +1,3 @@
<script>
parent.postMessage({action: 'redirectLogout'}, '*');
</script>

View File

@ -1,4 +1,4 @@
<div class="md:columns-2 md:w-2/4 w-3/4 m-auto mt-5">
<div class="md:columns-2 md:w-3/4 w-3/4 m-auto">
<div class="break-inside-avoid-column mb-5">
<h4 class="text-2xl text-highlight mb-4"><?php if(!$this->shop->private): ?><?php echo $this->translate('Wenn Sie bereits Kunde sind') ?><?php endif; ?></h4>
<div class="border border-slate-200 p-5">

View File

@ -1,6 +1,6 @@
<?= $this->partial ( 'user_tabs.phtml', array ('shop' => $this->shop, 'articlegroup' => $this->articlegroup, 'mode' => $this->mode, 'inworkCount' => $this->inworkCount, 'currency' => $this->currency, 'designPath' => $this->designPath ) );?>
<div class="w-3/4 md:w-2/4 m-auto">
<div class="w-3/4 m-auto">
<h2 class="mb-1 text-lg"><?php echo $this->translate('Rechnungsadressen')?></h2>
<div class="relative rounded-xl overflow-auto border bg-gray-200 border-gray-300">
<div class="shadow-sm overflow-hidden my-4 ">

View File

@ -1,6 +1,6 @@
<?= $this->partial ( 'user_tabs.phtml', array ('shop' => $this->shop, 'articlegroup' => $this->articlegroup, 'mode' => $this->mode, 'inworkCount' => $this->inworkCount, 'currency' => $this->currency, 'designPath' => $this->designPath ) );?>
<div class="w-3/4 md:w-2/4 m-auto">
<div class="w-3/4 m-auto">
<?php if(Zend_Auth::getInstance()->hasIdentity()==true): ?>
<?= $this->partial('completeform.phtml', array('buttonName' => 'Speichern', 'buttonClass' => '', 'form' => $this->form)) ?>
<?php endif; ?>

View File

@ -1,6 +1,6 @@
<?= $this->partial ( 'user_tabs.phtml', array ('shop' => $this->shop, 'articlegroup' => $this->articlegroup, 'mode' => $this->mode, 'inworkCount' => $this->inworkCount, 'currency' => $this->currency, 'designPath' => $this->designPath ) );?>
<div class="w-3/4 md:w-2/4 m-auto mt-5">
<div class="w-3/4 m-auto mt-5">
<?php if(Zend_Auth::getInstance()->hasIdentity()==true): ?>
<?php echo $this->paginationControl($this->paginator, 'Sliding', 'pagination.phtml'); ?>

View File

@ -1,6 +1,6 @@
<?= $this->partial ( 'user_tabs.phtml', array ('shop' => $this->shop, 'articlegroup' => $this->articlegroup, 'mode' => $this->mode, 'inworkCount' => $this->inworkCount, 'currency' => $this->currency, 'designPath' => $this->designPath ) );?>
<div class="w-3/4 md:w-2/4 m-auto">
<div class="w-3/4 m-auto">
<div class="border border-gray-300 bg-gray-200 p-2 flex" style="">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 mr-3">
<path stroke-linecap="round" stroke-linejoin="round" d="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" />
@ -8,7 +8,7 @@
<?php echo $this->translate('Hallo')?> <?php echo $this->user->self_firstname ?> <?php echo $this->user->self_lastname ?>, <?php echo $this->translate('verwalten Sie hier Ihr Benutzerkonto')?>
</div>
</div>
<div class="w-3/4 md:w-2/4 mt-4 md:flex md:space-x-2 m-auto">
<div class="w-3/4 mt-4 md:flex md:space-x-2 m-auto">
<div class="flex-1 border border-gray-300 bg-gray-200 p-2">
<h3 class="text-highlight text-lg"><?php echo $this->translate('Zur Startseite')?></h3>
<a class="underline font-bold" href="/"><?php echo $this->translate("Los geht's")?></a>

View File

@ -1,6 +1,6 @@
<?= $this->partial ( 'user_tabs.phtml', array ('shop' => $this->shop, 'articlegroup' => $this->articlegroup, 'mode' => $this->mode, 'inworkCount' => $this->inworkCount, 'currency' => $this->currency, 'designPath' => $this->designPath ) );?>
<div class="w-3/4 md:w-2/4 m-auto">
<div class="w-3/4 m-auto">
<div class="border border-gray-300 bg-gray-200 p-2 flex" style="">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 mr-3">
<path stroke-linecap="round" stroke-linejoin="round" d="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25" />
@ -9,7 +9,7 @@
</div>
</div>
<div class="w-3/4 md:w-2/4 m-auto">
<div class="w-3/4 m-auto">
<?php if(Zend_Auth::getInstance()->hasIdentity()==true): ?>
<?= $this->partial('completeform.phtml', array('buttonName' => 'Speichern', 'buttonClass' => '', 'form' => $this->form)) ?>
<?php endif; ?>

View File

@ -1,3 +1,3 @@
<div class="w-3/4 md:w-2/4 m-auto mt-5">
<div class="w-3/4 m-auto">
<?= $this->partial('completeform.phtml', array('buttonName' => 'Registrieren', 'buttonClass' => '', 'form' => $this->form)) ?>
</div>

View File

@ -1,4 +1,4 @@
<div class="md:w-2/4 w-3/4 m-auto mt-5">
<div class="md:w-2/4 w-3/4 m-auto">
<h1 class="text-lg mb-2"><?php echo $this->translate('Passwort vergessen?') ?></h1>

View File

@ -1,4 +1,4 @@
<div class="border border-gray-300 mt-10 md:w-2/4 mb-4 m-auto">
<div class="border border-gray-300 md:w-3/4 mb-4 m-auto">
<div class="bg-gray-200 divide-x md:flex w-full text-lg text-center">
<div class="flex-auto <?= ($this->mode == 1)? 'text-white border-gray-300 bg-lenzBlue':''; ?>"><a href="/user/myoverview"><?= $this->translate('Übersicht', 'text') ?></a></div>
<div class="flex-auto <?= ($this->mode == 2)? 'text-white border-gray-300 bg-lenzBlue':''; ?>"><a href="/user/mysettings"><?= $this->translate('Meine Einstellungen', 'text') ?></a></div>