Skip to content

Commit

Permalink
feat(devtools): init layout editor (#4363)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
m0ksem committed Aug 26, 2024
1 parent b1166f8 commit 64b138f
Show file tree
Hide file tree
Showing 49 changed files with 1,253 additions and 320 deletions.
98 changes: 82 additions & 16 deletions packages/compiler/devtools/client/ui/Devtools.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,43 @@
<div :style="colorsToCSSVariable(colors)" class="vuestic-devtools">
<Overlay
@click="onHoveredElementClick"
@wheel="onWheel"
@mousemove="onMouseMove"
@mousedown="onMouseDown"
@mouseup="onMouseUp"
v-on="appTransformListeners"
/>
<Outline :node="element" :thickness="1" background="outlinePrimaryBackground" />
<Outline :node="hoveredElement" :thickness="1" dashed />
<Outline :node="hoveredElement" :thickness="1" dashed />
<Outline v-for="element in elementsWithTargetVNode" :node="element" :thickness="1" color="outlineSecondary" background="outlineSecondaryBackground" />
<Outline :node="element" :thickness="1" background="outlinePrimaryBackground" />

<!-- Removed for now -->
<!-- <Toolbar :node="element">
<VaCard>
<VaDropdown placement="top-start">
<template #anchor>
<VaButton icon="auto_awesome" size="small" preset="primary" />
</template>
<VaDropdownContent>
<VaInput placeholder="Change label to email" label="AI prompt" />
</VaDropdownContent>
</VaDropdown>
</VaCard>
</Toolbar> -->

<DraggableWindow default-position="top-left">
<VaCard outlined>
<AppToolbar />
</VaCard>
</DraggableWindow>

<DraggableWindow default-position="bottom-left">
<VaCard class="vuestic-devtools__left-sidebar">
<DraggableWindow default-position="top-left" :offset-y="45">
<VaCard class="vuestic-devtools__left-sidebar" outlined>
<VaScrollContainer vertical horizontal>
<AppTree />
</VaScrollContainer>
</VaCard>
</DraggableWindow>

<DraggableWindow default-position="top-right" v-if="element">
<VaCard class="vuestic-devtools__right-sidebar">
<VaCard class="vuestic-devtools__right-sidebar" outlined>
<ComponentView />
</VaCard>
</DraggableWindow>
Expand All @@ -36,6 +54,8 @@ import Overlay from './components/base/Overlay.vue'
import ComponentView from './components/ComponentView.vue'
import DraggableWindow from './components/base/DraggableWindow.vue'
import AppTree from './components/AppTree.vue'
import AppToolbar from './components/AppToolbar.vue'
import Toolbar from './components/base/Toolbar.vue'
import { VaCard, useToast, useColors, VaScrollContainer } from 'vuestic-ui'
Expand All @@ -45,18 +65,17 @@ import { useOutlines } from './composables/useOutlines'
import { EDIT_MODE_CLASS } from '../../shared/CONST'
import { useEvent } from './composables/base/useEvent'
import { useComponent } from './composables/useComponent'
import { useAppTree, useSelectedAppTreeItem } from './composables/useAppTree/index'
import { useAppTree } from './composables/useAppTree/index'
useAppTree()
const { selectAppTreeItem, selectedAppTreeItem } = useAppTree()
const isEditMode = ref(false)
const { notify } = useToast()
const { colorsToCSSVariable, colors } = useColors()
const { zoom, translate, onWheel, onMouseDown, onMouseMove, onMouseUp } = useAppTransform()
const { zoom, translate, listeners: appTransformListeners } = useAppTransform()
const { selectAppTreeItem, selectedAppTreeItem } = useSelectedAppTreeItem()
watchEffect(() => {
if (isEditMode.value) {
Expand Down Expand Up @@ -110,7 +129,7 @@ const recalculateOutlines = useOutlines()
watch(isEditMode, () => {
if (isEditMode.value) {
const LEFT_SIDEBAR_WIDTH = 300
const RIGHT_SIDEBAR_WIDTH = 500
const RIGHT_SIDEBAR_WIDTH = 400
const PADDING = 50
zoom.value = ((window.innerWidth - ((LEFT_SIDEBAR_WIDTH + RIGHT_SIDEBAR_WIDTH + PADDING))) * 100 / window.innerWidth) / 100
Expand Down Expand Up @@ -145,16 +164,63 @@ const elementsWithTargetVNode = computed(() => {
})
</script>

<style lang="scss" scoped>
<style lang="scss">
body {
position: relative;
}
.vuestic-devtools {
&__right-sidebar {
max-width: 600px;
width: 400px;
box-sizing: border-box;
height: calc(100vh - 1rem);
}
&__left-sidebar {
width: 300px;
box-sizing: border-box;
// 45 px offset from toolbar
height: calc(100vh - 45px - 1rem);
}
.va-card {
background: none !important;
position: relative;
z-index: 1;
backdrop-filter: blur(20px);
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
background: var(--va-background-secondary);
pointer-events: none;
opacity: 0.5;
}
}
}
.vuestic-devtools__dropdown_content {
background: none !important;
position: relative;
z-index: 1;
backdrop-filter: blur(5px);
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -1;
background: var(--va-background-secondary);
pointer-events: none;
opacity: 0.5;
}
}
</style>
60 changes: 60 additions & 0 deletions packages/compiler/devtools/client/ui/components/AppToolbar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<script setup lang="ts">
import { ref } from 'vue';
import { VaDivider, VaButton, VaDropdown, VaDropdownContent } from 'vuestic-ui';
import LayoutEditor from './toolbar/LayoutEditor.vue';
import ComponentSelect from './toolbar/ComponentSelect.vue';
import { useComponent } from '../composables/useComponent';
import History from './History.vue';
const { source } = useComponent()
const isLoading = ref(false)
const onSave = async () => {
isLoading.value = true
await source.update(source.value!)
isLoading.value = false
}
const removeComponent = async () => {
try {
isLoading.value = true
await source.remove()
} finally {
isLoading.value = false
}
}
</script>

<template>
<div class="va-devtools-toolbar">
<History />
<!-- TODO: No need in dedicated save button ideally -->
<VaButton icon="save" preset="secondary" @click="onSave" :loading="isLoading" />
<VaDivider vertical/>
<VaDropdown :close-on-content-click="false" :keep-anchor-width="false" :offset="4" content-class="vuestic-devtools__dropdown_content" stick-to-edges>
<template #anchor>
<VaButton preset="secondary" icon="add"></VaButton>
</template>

<template #default="{ hide }">
<VaDropdownContent background="backgroundElement" class="app-toolbar__content">
<ComponentSelect @component-added="hide" />
</VaDropdownContent>
</template>
</VaDropdown>

<VaButton preset="secondary" icon="delete" @click="removeComponent()" :loading="isLoading"></VaButton>
</div>
</template>

<style lang="scss">
.va-devtools-toolbar {
width: max-content !important;
display: flex;
.va-divider {
margin: 0;
}
}
</style>
20 changes: 14 additions & 6 deletions packages/compiler/devtools/client/ui/components/AppTree.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import AppTreeItemComponent from './AppTreeItem.vue'
import { ref, computed } from 'vue'
const appTree = useAppTree()
const { appTree } = useAppTree()
const filter = ref('')
Expand Down Expand Up @@ -41,28 +41,36 @@
</script>

<template>
<div v-if="appTree" class="app-tree">
<div v-if="appTree" class="va-devtools-app-tree">
<VaInput v-model="filter" inner-label style="width: 100%" placeholder="Search">
<template #prependInner>
<VaIcon name="search" />
</template>
</VaInput>

<div v-if="filter.length <= 0" class="app-tree-items">
<div v-if="filter.length <= 0" class="va-devtools-app-tree__items">
<div v-for="node in appTree">
<AppTreeItemComponent :item="node" />
</div>
</div>
<template v-else>
<div v-for="node in foundItems" class="app-tree-items">
<div v-for="node in foundItems" class="va-devtools-app-tree__items">
<AppTreeItemComponent :item="node" />
</div>
</template>
</div>
</template>

<style lang="scss" scoped>
.app-tree-items {
padding: 0.5rem 1rem;
.va-devtools-app-tree {
display: flex;
flex-direction: column;
height: 100%;
&__items {
flex: 1;
padding: 0.5rem 1rem;
overflow: auto;
}
}
</style>
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import { VaButton } from 'vuestic-ui'
import { useSelectedAppTreeItem, type AppTreeItem } from '../composables/useAppTree'
import { useComponent } from '../composables/useComponent';
import { useAppTree, type AppTreeItem } from '../composables/useAppTree'
const props = defineProps<{
item: AppTreeItem
Expand All @@ -12,7 +11,7 @@
name: 'AppTreeItem'
})
const { selectAppTreeItem, selectedAppTreeItem } = useSelectedAppTreeItem()
const { selectAppTreeItem, selectedAppTreeItem } = useAppTree()
const setTargetElement = () => {
if ('text' in props.item) {
Expand Down
Loading

0 comments on commit 64b138f

Please sign in to comment.