Skip to content

Commit c1eb7f8

Browse files
authored
feat(devtools): init layout editor (#4363)
* feat(devtools): init layout editor * raw * fix: update component path when code updated * feat: add delete node toolbar button * chore: improve ui * imrpove ui and bug fixes * chore(devtools): refactor use component * raw * fix(devtools): handle source file correctly * fix(devtools): correctly show slots * fix(devtools): save selected app-tree-item by name * fix(devtools): remove possible dup attributes caused by v-bind and static assignment
1 parent 8794018 commit c1eb7f8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1253
-320
lines changed

packages/compiler/devtools/client/ui/Devtools.vue

Lines changed: 82 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,43 @@
33
<div :style="colorsToCSSVariable(colors)" class="vuestic-devtools">
44
<Overlay
55
@click="onHoveredElementClick"
6-
@wheel="onWheel"
7-
@mousemove="onMouseMove"
8-
@mousedown="onMouseDown"
9-
@mouseup="onMouseUp"
6+
v-on="appTransformListeners"
107
/>
11-
<Outline :node="element" :thickness="1" background="outlinePrimaryBackground" />
12-
<Outline :node="hoveredElement" :thickness="1" dashed />
8+
<Outline :node="hoveredElement" :thickness="1" dashed />
139
<Outline v-for="element in elementsWithTargetVNode" :node="element" :thickness="1" color="outlineSecondary" background="outlineSecondaryBackground" />
10+
<Outline :node="element" :thickness="1" background="outlinePrimaryBackground" />
11+
12+
<!-- Removed for now -->
13+
<!-- <Toolbar :node="element">
14+
<VaCard>
15+
<VaDropdown placement="top-start">
16+
<template #anchor>
17+
<VaButton icon="auto_awesome" size="small" preset="primary" />
18+
</template>
19+
20+
<VaDropdownContent>
21+
<VaInput placeholder="Change label to email" label="AI prompt" />
22+
</VaDropdownContent>
23+
</VaDropdown>
24+
</VaCard>
25+
</Toolbar> -->
26+
27+
<DraggableWindow default-position="top-left">
28+
<VaCard outlined>
29+
<AppToolbar />
30+
</VaCard>
31+
</DraggableWindow>
1432

15-
<DraggableWindow default-position="bottom-left">
16-
<VaCard class="vuestic-devtools__left-sidebar">
33+
<DraggableWindow default-position="top-left" :offset-y="45">
34+
<VaCard class="vuestic-devtools__left-sidebar" outlined>
1735
<VaScrollContainer vertical horizontal>
1836
<AppTree />
1937
</VaScrollContainer>
2038
</VaCard>
2139
</DraggableWindow>
2240

2341
<DraggableWindow default-position="top-right" v-if="element">
24-
<VaCard class="vuestic-devtools__right-sidebar">
42+
<VaCard class="vuestic-devtools__right-sidebar" outlined>
2543
<ComponentView />
2644
</VaCard>
2745
</DraggableWindow>
@@ -36,6 +54,8 @@ import Overlay from './components/base/Overlay.vue'
3654
import ComponentView from './components/ComponentView.vue'
3755
import DraggableWindow from './components/base/DraggableWindow.vue'
3856
import AppTree from './components/AppTree.vue'
57+
import AppToolbar from './components/AppToolbar.vue'
58+
import Toolbar from './components/base/Toolbar.vue'
3959
4060
import { VaCard, useToast, useColors, VaScrollContainer } from 'vuestic-ui'
4161
@@ -45,18 +65,17 @@ import { useOutlines } from './composables/useOutlines'
4565
import { EDIT_MODE_CLASS } from '../../shared/CONST'
4666
import { useEvent } from './composables/base/useEvent'
4767
import { useComponent } from './composables/useComponent'
48-
import { useAppTree, useSelectedAppTreeItem } from './composables/useAppTree/index'
68+
import { useAppTree } from './composables/useAppTree/index'
4969
50-
useAppTree()
70+
const { selectAppTreeItem, selectedAppTreeItem } = useAppTree()
5171
5272
const isEditMode = ref(false)
5373
5474
const { notify } = useToast()
5575
5676
const { colorsToCSSVariable, colors } = useColors()
57-
const { zoom, translate, onWheel, onMouseDown, onMouseMove, onMouseUp } = useAppTransform()
77+
const { zoom, translate, listeners: appTransformListeners } = useAppTransform()
5878
59-
const { selectAppTreeItem, selectedAppTreeItem } = useSelectedAppTreeItem()
6079
6180
watchEffect(() => {
6281
if (isEditMode.value) {
@@ -110,7 +129,7 @@ const recalculateOutlines = useOutlines()
110129
watch(isEditMode, () => {
111130
if (isEditMode.value) {
112131
const LEFT_SIDEBAR_WIDTH = 300
113-
const RIGHT_SIDEBAR_WIDTH = 500
132+
const RIGHT_SIDEBAR_WIDTH = 400
114133
const PADDING = 50
115134
116135
zoom.value = ((window.innerWidth - ((LEFT_SIDEBAR_WIDTH + RIGHT_SIDEBAR_WIDTH + PADDING))) * 100 / window.innerWidth) / 100
@@ -145,16 +164,63 @@ const elementsWithTargetVNode = computed(() => {
145164
})
146165
</script>
147166

148-
<style lang="scss" scoped>
167+
<style lang="scss">
168+
body {
169+
position: relative;
170+
}
171+
149172
.vuestic-devtools {
150173
&__right-sidebar {
151-
max-width: 600px;
174+
width: 400px;
152175
box-sizing: border-box;
176+
height: calc(100vh - 1rem);
153177
}
154178
155179
&__left-sidebar {
156180
width: 300px;
157181
box-sizing: border-box;
182+
// 45 px offset from toolbar
183+
height: calc(100vh - 45px - 1rem);
184+
}
185+
186+
.va-card {
187+
background: none !important;
188+
position: relative;
189+
z-index: 1;
190+
backdrop-filter: blur(20px);
191+
192+
&::before {
193+
content: '';
194+
position: absolute;
195+
top: 0;
196+
left: 0;
197+
right: 0;
198+
bottom: 0;
199+
z-index: -1;
200+
background: var(--va-background-secondary);
201+
pointer-events: none;
202+
opacity: 0.5;
203+
}
204+
}
205+
}
206+
207+
.vuestic-devtools__dropdown_content {
208+
background: none !important;
209+
position: relative;
210+
z-index: 1;
211+
backdrop-filter: blur(5px);
212+
213+
&::before {
214+
content: '';
215+
position: absolute;
216+
top: 0;
217+
left: 0;
218+
right: 0;
219+
bottom: 0;
220+
z-index: -1;
221+
background: var(--va-background-secondary);
222+
pointer-events: none;
223+
opacity: 0.5;
158224
}
159225
}
160226
</style>
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<script setup lang="ts">
2+
import { ref } from 'vue';
3+
import { VaDivider, VaButton, VaDropdown, VaDropdownContent } from 'vuestic-ui';
4+
import LayoutEditor from './toolbar/LayoutEditor.vue';
5+
import ComponentSelect from './toolbar/ComponentSelect.vue';
6+
import { useComponent } from '../composables/useComponent';
7+
import History from './History.vue';
8+
9+
const { source } = useComponent()
10+
11+
const isLoading = ref(false)
12+
13+
const onSave = async () => {
14+
isLoading.value = true
15+
await source.update(source.value!)
16+
isLoading.value = false
17+
}
18+
19+
const removeComponent = async () => {
20+
try {
21+
isLoading.value = true
22+
await source.remove()
23+
} finally {
24+
isLoading.value = false
25+
}
26+
}
27+
</script>
28+
29+
<template>
30+
<div class="va-devtools-toolbar">
31+
<History />
32+
<!-- TODO: No need in dedicated save button ideally -->
33+
<VaButton icon="save" preset="secondary" @click="onSave" :loading="isLoading" />
34+
<VaDivider vertical/>
35+
<VaDropdown :close-on-content-click="false" :keep-anchor-width="false" :offset="4" content-class="vuestic-devtools__dropdown_content" stick-to-edges>
36+
<template #anchor>
37+
<VaButton preset="secondary" icon="add"></VaButton>
38+
</template>
39+
40+
<template #default="{ hide }">
41+
<VaDropdownContent background="backgroundElement" class="app-toolbar__content">
42+
<ComponentSelect @component-added="hide" />
43+
</VaDropdownContent>
44+
</template>
45+
</VaDropdown>
46+
47+
<VaButton preset="secondary" icon="delete" @click="removeComponent()" :loading="isLoading"></VaButton>
48+
</div>
49+
</template>
50+
51+
<style lang="scss">
52+
.va-devtools-toolbar {
53+
width: max-content !important;
54+
display: flex;
55+
56+
.va-divider {
57+
margin: 0;
58+
}
59+
}
60+
</style>

packages/compiler/devtools/client/ui/components/AppTree.vue

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import AppTreeItemComponent from './AppTreeItem.vue'
55
import { ref, computed } from 'vue'
66
7-
const appTree = useAppTree()
7+
const { appTree } = useAppTree()
88
99
const filter = ref('')
1010
@@ -41,28 +41,36 @@
4141
</script>
4242

4343
<template>
44-
<div v-if="appTree" class="app-tree">
44+
<div v-if="appTree" class="va-devtools-app-tree">
4545
<VaInput v-model="filter" inner-label style="width: 100%" placeholder="Search">
4646
<template #prependInner>
4747
<VaIcon name="search" />
4848
</template>
4949
</VaInput>
5050

51-
<div v-if="filter.length <= 0" class="app-tree-items">
51+
<div v-if="filter.length <= 0" class="va-devtools-app-tree__items">
5252
<div v-for="node in appTree">
5353
<AppTreeItemComponent :item="node" />
5454
</div>
5555
</div>
5656
<template v-else>
57-
<div v-for="node in foundItems" class="app-tree-items">
57+
<div v-for="node in foundItems" class="va-devtools-app-tree__items">
5858
<AppTreeItemComponent :item="node" />
5959
</div>
6060
</template>
6161
</div>
6262
</template>
6363

6464
<style lang="scss" scoped>
65-
.app-tree-items {
66-
padding: 0.5rem 1rem;
65+
.va-devtools-app-tree {
66+
display: flex;
67+
flex-direction: column;
68+
height: 100%;
69+
70+
&__items {
71+
flex: 1;
72+
padding: 0.5rem 1rem;
73+
overflow: auto;
74+
}
6775
}
6876
</style>

packages/compiler/devtools/client/ui/components/AppTreeItem.vue

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
<script setup lang="ts">
22
import { computed } from 'vue'
33
import { VaButton } from 'vuestic-ui'
4-
import { useSelectedAppTreeItem, type AppTreeItem } from '../composables/useAppTree'
5-
import { useComponent } from '../composables/useComponent';
4+
import { useAppTree, type AppTreeItem } from '../composables/useAppTree'
65
76
const props = defineProps<{
87
item: AppTreeItem
@@ -12,7 +11,7 @@
1211
name: 'AppTreeItem'
1312
})
1413
15-
const { selectAppTreeItem, selectedAppTreeItem } = useSelectedAppTreeItem()
14+
const { selectAppTreeItem, selectedAppTreeItem } = useAppTree()
1615
1716
const setTargetElement = () => {
1817
if ('text' in props.item) {

0 commit comments

Comments
 (0)