Skip to content

Commit

Permalink
we got tree
Browse files Browse the repository at this point in the history
  • Loading branch information
scratchuz4k committed Jun 25, 2024
1 parent 659e94c commit 95341b4
Show file tree
Hide file tree
Showing 8 changed files with 301 additions and 8 deletions.
1 change: 1 addition & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
<body class="h-full">
<div id="app"></div>
<script type="module" src="/src/main.js"></script>

</body>
</html>
62 changes: 60 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
"build-storybook": "storybook build"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-regular-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/vue-fontawesome": "^3.0.8",
"@headlessui/vue": "^1.7.22",
"@heroicons/vue": "^2.1.3",
"@tailwindcss/forms": "^0.5.7",
Expand Down
15 changes: 10 additions & 5 deletions src/App.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup>
import { ref } from 'vue'
const items = [
const items = ref([
{
component: 'template',
children: [
Expand Down Expand Up @@ -35,7 +35,7 @@ const items = [
component: 'row',
children: [
{
component: 'column',
component: 'column2',
children: [
{
configs: { label: 'Username', name: 'username' },
Expand All @@ -44,7 +44,7 @@ const items = [
]
},
{
component: 'column',
component: 'column1',
children: [
{
configs: { label: 'Password', name: 'password' },
Expand All @@ -62,11 +62,16 @@ const items = [
}
]
}
]
])
const value = ref({ "name": "adaaaw", "username": "adw", "password": "wdd" })
</script>

<template>
<builder v-model="value" :design="items"></builder>
<!-- <builder v-model="value" :design="items"></builder> -->
<tree v-model="items">
<template v-slot="{ element }">{{ element.component }}</template>
</tree>

{{ items }}
</template>
70 changes: 70 additions & 0 deletions src/components/misc/Tree.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<template>
<ul class="trees">
<template v-for="(item, index) in props.modelValue">
<TreeContent v-model="props.modelValue[index]" :parent="props.modelValue" :index="index">
<template v-slot="{ element }">
<slot :element="element"></slot>
</template>
</TreeContent>
</template>
</ul>
</template>
<script setup>
const props = defineProps({
modelValue: Array
})
</script>

<style>
ul,
li {
list-style: none;
margin: 0;
padding: 0
}
label {
font-weight: normal
}
/*Tree*/
.trees {
margin-left: 10px;
}
.trees li {
border-left: dotted 1px #bcbec0;
padding: 1px 0 1px 25px;
position: relative
}
.trees li>label {
position: relative;
left: -11px
}
.trees li:before {
content: "";
width: 13px;
height: 1px;
border-bottom: dotted 1px #bcbec0;
position: absolute;
top: 14px;
left: 0
}
.trees li:last-child:after {
content: "";
position: absolute;
width: 2px;
height: 13px;
left: -1px;
bottom: 0px;
}
.trees li input {
margin-right: 5px;
margin-left: 5px
}
</style>
126 changes: 126 additions & 0 deletions src/components/misc/TreeContent.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<template>
<li
:class="[dragged.item === props.modelValue ? 'selected' : '', props.modelValue.children && props.modelValue.children.length ? 'has-child' : '']">
<div @dragstart="dragStart($event)" style="cursor: pointer;display: flex; align-items: center;">
<div draggable="true" @dragover="dragOverParent($event)" @drop="drop($event, props.parent, props.index + 1)"
style="width: 5px;" @dragleave="dragEndParent()">
<button style="margin-left: -8px;"
:class="{ 'hide': !(props.modelValue.children && props.modelValue.children.length) }"
@click="() => show = !show">
<font-awesome-icon v-if="show" :icon="['fas', 'square-minus']" />
<font-awesome-icon v-else :icon="['fas', 'square-plus']" />
</button>
</div>
<div style="cursor: pointer;display: flex; align-items: center;" draggable="true" @dragleave="dragEnd()"
@dragover="dragOver($event)" @drop="drop($event, props.modelValue, 0)">
<input type="checkbox" checked style="width: 14px;height: 14px;">
<slot :element="props.modelValue"></slot>
</div>
</div>
<ul v-if="showPlaceHolder">
<li>
<div style="border: dotted 1px #bcbec0;background:antiquewhite;height:20px"></div>
</li>
</ul>
<ul v-if="show" v-for="(child, childIndex) in props.modelValue.children">
<TreeContent v-model="props.modelValue.children[childIndex]" :parent="props.modelValue" :index="childIndex">
<template v-slot="{ element }">
<slot :element="element"></slot>
</template>
</TreeContent>
</ul>
</li>
<li v-if="showParentPlaceHolder">
<div style="border: dotted 1px #bcbec0;background:antiquewhite;height:20px"></div>
</li>
</template>
<script setup>
import { ref } from 'vue'
import useTree from '../../composables/useTree'
const {
dragged
} = useTree()
const props = defineProps({
index: Number,
parent: Object,
modelValue: Object
})
const showParentPlaceHolder = ref(false)
const showPlaceHolder = ref(false)
const show = ref(true)
const dragStart = (event) => {
show.value = false;
dragged.item = props.modelValue;
dragged.index = props.index;
dragged.parent = props.parent;
event.dataTransfer.effectAllowed = 'move';
}
const dragEnd = () => {
showPlaceHolder.value = false
}
const dragEndParent = () => {
showParentPlaceHolder.value = false
}
const dragOver = (event) => {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
showPlaceHolder.value = true
}
const dragOverParent = () => {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
showParentPlaceHolder.value = true
}
const drop = (event, item, index) => {
event.preventDefault();
showParentPlaceHolder.value = false
showPlaceHolder.value = false
if (item === dragged.item) {
return
}
show.value = true;
if (Object.keys(dragged.parent).includes("children")) {
dragged.parent.children.splice(dragged.index, 1)
}
if (Array.isArray(dragged.parent)) {
dragged.parent.splice(dragged.index, 1)
}
if (Array.isArray(item)) {
item.splice(index, 0, dragged.item)
} else {
if (Object.keys(item).includes("children")) {
item.children.splice(index, 0, dragged.item)
} else {
item.children = []
item.children.splice(index, 0, dragged.item)
}
}
dragged.item = null;
dragged.parent = null;
dragged.index = null;
}
</script>

<style scoped>
.hide {
opacity: 0;
pointer-events: none;
}
.selected {
background-color: azure;
}
</style>
21 changes: 21 additions & 0 deletions src/composables/useTree.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { reactive } from 'vue'


const dragged = reactive({
item: null,
index: null,
parent: null,
})

const temp = reactive({
item: null,
index: null,
parent: null,
})

export default function useTree() {
return {
dragged,
temp
}
}
10 changes: 9 additions & 1 deletion src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,12 @@ export const components = {
},
};

createApp(App).use(components).mount('#app')
import { library } from "@fortawesome/fontawesome-svg-core";
import { fas } from "@fortawesome/free-solid-svg-icons";
import { far } from "@fortawesome/free-regular-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";

library.add(fas);
library.add(far);

createApp(App).component("font-awesome-icon", FontAwesomeIcon).use(components).mount('#app')

0 comments on commit 95341b4

Please sign in to comment.