Skip to content

Commit 99fc69f

Browse files
fix: UX enhancements (#240)
closes: #229
1 parent 9143f34 commit 99fc69f

File tree

13 files changed

+233
-123
lines changed

13 files changed

+233
-123
lines changed

frontend/src/App.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,10 @@ const isDark = useDark({
8080
8181
[id^="headlessui-menu-items"],
8282
[id^="headlessui-combobox-options"] {
83-
@apply bg-surface-gray-1;
83+
@apply bg-surface-white;
84+
@apply dark:bg-surface-gray-1;
85+
@apply text-text-icons-gray-7;
86+
8487
@apply overflow-y-auto;
8588
-ms-overflow-style: none; /* IE and Edge */
8689
scrollbar-width: none;

frontend/src/components/BlockEditor.vue

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,43 +13,22 @@
1313
:class="getStyleClasses">
1414
<PaddingHandler
1515
:data-block-id="block.blockId"
16-
v-if="
17-
isBlockSelected &&
18-
!resizing &&
19-
!editable &&
20-
!blockController.multipleBlocksSelected() &&
21-
!block.isSVG()
22-
"
16+
v-show="showPaddingHandler"
2317
:target-block="block"
2418
:target="target"
2519
:on-update="updateTracker"
2620
:disable-handlers="false"
2721
:breakpoint="breakpoint" />
2822
<MarginHandler
29-
v-if="
30-
isBlockSelected &&
31-
!block.isRoot() &&
32-
!resizing &&
33-
!editable &&
34-
!blockController.multipleBlocksSelected()
35-
"
23+
v-show="showMarginHandler"
3624
:target-block="block"
3725
:target="target"
3826
:on-update="updateTracker"
3927
:disable-handlers="false"
4028
:breakpoint="breakpoint" />
4129
<BorderRadiusHandler
4230
:data-block-id="block.blockId"
43-
v-if="
44-
isBlockSelected &&
45-
!block.isRoot() &&
46-
!block.isText() &&
47-
!block.isHTML() &&
48-
!block.isSVG() &&
49-
!editable &&
50-
!resizing &&
51-
!blockController.multipleBlocksSelected()
52-
"
31+
v-if="showBorderRadiusHandler"
5332
:target-block="block"
5433
:target="target" />
5534
<BoxResizer v-if="showResizer" :targetBlock="block" @resizing="resizing = $event" :target="target" />
@@ -114,6 +93,41 @@ const guides = setGuides(props.target, canvasProps);
11493
const moving = ref(false);
11594
const preventCLick = ref(false);
11695
96+
const showPaddingHandler = computed(() => {
97+
return (
98+
isBlockSelected.value &&
99+
!resizing.value &&
100+
!props.editable &&
101+
!blockController.multipleBlocksSelected() &&
102+
!props.block.isSVG() &&
103+
!props.block.isText()
104+
);
105+
});
106+
107+
const showMarginHandler = computed(() => {
108+
return (
109+
isBlockSelected.value &&
110+
!props.block.isRoot() &&
111+
!resizing.value &&
112+
!props.editable &&
113+
!blockController.multipleBlocksSelected() &&
114+
!props.block.isText()
115+
);
116+
});
117+
118+
const showBorderRadiusHandler = computed(() => {
119+
return (
120+
isBlockSelected &&
121+
!props.block.isRoot() &&
122+
!props.block.isText() &&
123+
!props.block.isHTML() &&
124+
!props.block.isSVG() &&
125+
!props.editable &&
126+
!resizing &&
127+
!blockController.multipleBlocksSelected()
128+
);
129+
});
130+
117131
watchEffect(() => {
118132
props.block.getStyle("top");
119133
props.block.getStyle("left");
@@ -189,6 +203,11 @@ const handleClick = (ev: MouseEvent) => {
189203
preventCLick.value = false;
190204
return;
191205
}
206+
207+
if (props.block.isText() || props.block.isButton() || props.block.isLink()) {
208+
store.editableBlock = props.block;
209+
}
210+
192211
const editorWrapper = editor.value;
193212
editorWrapper.classList.add("pointer-events-none");
194213
let element = document.elementFromPoint(ev.x, ev.y) as HTMLElement;

frontend/src/components/BlockLayers.vue

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
</span>
7373
</span>
7474
<div v-show="canShowChildLayer(element)">
75-
<BlockLayers :blocks="element.children" ref="childLayer" :indent="childIndent" />
75+
<BlockLayers :blocks="element.children" :ref="childLayer" :indent="childIndent" />
7676
</div>
7777
</div>
7878
</BlockContextMenu>
@@ -91,8 +91,15 @@ import BlockContextMenu from "./BlockContextMenu.vue";
9191
import BlockLayers from "./BlockLayers.vue";
9292
import BlocksIcon from "./Icons/Blocks.vue";
9393
94+
type LayerInstance = InstanceType<typeof BlockLayers>;
95+
9496
const store = useStore();
95-
const childLayer = ref<InstanceType<typeof BlockLayers> | null>(null);
97+
const childLayers = ref<LayerInstance[]>([]);
98+
const childLayer = (el) => {
99+
if (el) {
100+
childLayers.value.push(el);
101+
}
102+
};
96103
97104
const props = defineProps({
98105
blocks: {
@@ -123,19 +130,39 @@ const isExpanded = (block: Block) => {
123130
return expandedLayers.value.has(block.blockId);
124131
};
125132
133+
// TODO: Refactor this!
126134
const toggleExpanded = (block: Block) => {
127-
const blockIndex = props.blocks.findIndex((b) => b.blockId === block.blockId);
128-
if (blockIndex === -1) {
129-
childLayer.value?.toggleExpanded(block);
135+
if (block.isRoot()) {
130136
return;
131137
}
132-
if (isExpanded(block) && !block.isRoot()) {
138+
if (!blockExits(block)) {
139+
const child = childLayers.value.find((layer) => layer.blockExitsInTree(block)) as LayerInstance;
140+
if (child) {
141+
child.toggleExpanded(block);
142+
}
143+
}
144+
if (isExpanded(block)) {
133145
expandedLayers.value.delete(block.blockId);
134146
} else {
135147
expandedLayers.value.add(block.blockId);
136148
}
137149
};
138150
151+
// @ts-ignore
152+
const isExpandedInTree = (block: Block) => {
153+
if (!blockExits(block)) {
154+
const child = childLayers.value.find((layer) => layer.blockExitsInTree(block)) as LayerInstance;
155+
if (child) {
156+
return child.isExpandedInTree(block);
157+
}
158+
}
159+
return isExpanded(block);
160+
};
161+
162+
const blockExits = (block: Block) => {
163+
return props.blocks.find((b) => b.blockId === block.blockId);
164+
};
165+
139166
const canShowChildLayer = (block: Block) => {
140167
return (
141168
((isExpanded(block) && block.hasChildren()) || (block.canHaveChildren() && !block.hasChildren())) &&
@@ -161,15 +188,29 @@ watch(
161188
},
162189
);
163190
191+
// @ts-ignore
164192
const updateParent = (event) => {
165193
event.item.__draggable_context.element.parentBlock = store.activeCanvas?.findBlock(
166194
event.to.closest("[data-block-layer-id]").dataset.blockLayerId,
167195
);
168196
};
169197
198+
const blockExitsInTree = (block: Block) => {
199+
if (blockExits(block)) {
200+
return true;
201+
}
202+
for (const layer of childLayers.value) {
203+
if (layer.blockExitsInTree(block)) {
204+
return true;
205+
}
206+
}
207+
return false;
208+
};
209+
170210
defineExpose({
171-
isExpanded,
172211
toggleExpanded,
212+
isExpandedInTree,
213+
blockExitsInTree,
173214
});
174215
</script>
175216
<style>

frontend/src/components/BlockProperties.vue

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,7 @@
2828
</div>
2929
</div>
3030
<div v-else>
31-
<p class="mt-2 text-center text-sm text-gray-600 dark:text-zinc-500">
32-
Select a block to edit properties.
33-
</p>
31+
<p class="mt-2 text-center text-sm text-gray-600 dark:text-zinc-500">Select a block to edit properties</p>
3432
</div>
3533
</template>
3634
<script setup lang="ts">

frontend/src/components/BuilderBlock.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
<!-- prettier-ignore -->
2828
<BlockEditor
2929
ref="editor"
30+
v-show="!isEditable"
3031
v-if="loadEditor"
3132
:block="block"
3233
:breakpoint="breakpoint"
@@ -231,6 +232,12 @@ const triggerContextMenu = (e: MouseEvent) => {
231232
232233
const handleClick = (e: MouseEvent) => {
233234
if (isEditable.value) return;
235+
if (store.preventClick) {
236+
e.stopPropagation();
237+
e.preventDefault();
238+
store.preventClick = false;
239+
return;
240+
}
234241
selectBlock(e);
235242
e.stopPropagation();
236243
e.preventDefault();

frontend/src/components/BuilderCanvas.vue

Lines changed: 58 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ import {
8585
getBlockInstance,
8686
getBlockObject,
8787
getNumberFromPx,
88-
isCtrlOrCmd,
8988
isTargetEditable,
9089
uploadImage,
9190
} from "@/utils/helpers";
@@ -428,68 +427,66 @@ function setEvents() {
428427
});
429428
430429
useEventListener(document, "keydown", (ev: KeyboardEvent) => {
431-
if (isTargetEditable(ev)) {
432-
return;
433-
}
434-
if (ev.shiftKey && ev.key === "ArrowLeft") {
435-
if (isCtrlOrCmd(ev)) {
436-
if (selectedBlocks.value.length) {
437-
const selectedBlock = selectedBlocks.value[0];
438-
store.activeLayers?.toggleExpanded(selectedBlock);
439-
return;
440-
}
441-
}
442-
if (selectedBlocks.value.length) {
443-
const selectedBlock = selectedBlocks.value[0];
444-
const parentBlock = selectedBlock.getParentBlock();
445-
if (parentBlock) {
446-
selectionTrail.push(selectedBlock.blockId);
447-
maintainTrail = true;
448-
store.selectBlock(parentBlock, null, true, true);
449-
maintainTrail = false;
450-
}
451-
}
452-
}
453-
if (ev.shiftKey && ev.key === "ArrowRight") {
454-
const blockId = selectionTrail.pop();
455-
if (blockId) {
456-
const block = findBlock(blockId);
457-
if (block) {
458-
maintainTrail = true;
459-
store.selectBlock(block, null, true, true);
460-
maintainTrail = false;
461-
}
462-
} else {
463-
if (selectedBlocks.value.length) {
464-
const selectedBlock = selectedBlocks.value[0];
465-
if (selectedBlock.children && selectedBlock.isVisible()) {
466-
let child = selectedBlock.children[0];
467-
while (child && !child.isVisible()) {
468-
child = child.getSiblingBlock("next") as Block;
469-
if (!child) {
470-
break;
471-
}
472-
}
473-
child && store.selectBlock(child, null, true, true);
474-
}
475-
}
476-
}
477-
}
478-
if (ev.shiftKey && ev.key === "ArrowUp") {
479-
if (selectedBlocks.value.length) {
480-
let sibling = selectedBlocks.value[0].getSiblingBlock("previous");
481-
if (sibling) {
482-
store.selectBlock(sibling, null, true, true);
483-
}
430+
if (isTargetEditable(ev) || selectedBlocks.value.length !== 1) return;
431+
432+
const selectedBlock = selectedBlocks.value[0];
433+
434+
const selectBlock = (block: Block | null) => {
435+
if (block) store.selectBlock(block, null, true, true);
436+
return !!block;
437+
};
438+
439+
const selectSibling = (direction: "previous" | "next", fallback: () => void) => {
440+
selectBlock(selectedBlock.getSiblingBlock(direction)) || fallback();
441+
};
442+
443+
const selectParent = () => selectBlock(selectedBlock.getParentBlock());
444+
445+
const selectFirstChild = () => selectBlock(selectedBlock.children[0]);
446+
447+
const selectNextSiblingOrParent = () => {
448+
let sibling = selectedBlock.getSiblingBlock("next");
449+
let parentBlock = selectedBlock.getParentBlock();
450+
while (!sibling && parentBlock) {
451+
sibling = parentBlock.getSiblingBlock("next");
452+
parentBlock = parentBlock.getParentBlock();
484453
}
485-
}
486-
if (ev.shiftKey && ev.key === "ArrowDown") {
487-
if (selectedBlocks.value.length) {
488-
let sibling = selectedBlocks.value[0].getSiblingBlock("next");
489-
if (sibling) {
490-
store.selectBlock(sibling, null, true, true);
491-
}
454+
selectBlock(sibling);
455+
};
456+
457+
const selectLastChildInTree = (block: Block) => {
458+
let currentBlock = block;
459+
while (store.activeLayers?.isExpandedInTree(currentBlock)) {
460+
const lastChild = currentBlock.getLastChild() as Block;
461+
if (!lastChild) break;
462+
currentBlock = lastChild;
492463
}
464+
selectBlock(currentBlock);
465+
};
466+
467+
switch (ev.key) {
468+
case "ArrowLeft":
469+
store.activeLayers?.isExpandedInTree(selectedBlock)
470+
? store.activeLayers.toggleExpanded(selectedBlock)
471+
: selectSibling("previous", selectParent);
472+
break;
473+
case "ArrowRight":
474+
selectedBlock.hasChildren() && selectedBlock.isVisible()
475+
? (store.activeLayers?.toggleExpanded(selectedBlock), selectFirstChild())
476+
: selectNextSiblingOrParent();
477+
break;
478+
case "ArrowUp":
479+
selectBlock(selectedBlock.getSiblingBlock("previous"))
480+
? selectLastChildInTree(selectedBlock.getSiblingBlock("previous") as Block)
481+
: selectParent();
482+
break;
483+
case "ArrowDown":
484+
store.activeLayers?.isExpandedInTree(selectedBlock) &&
485+
selectedBlock.hasChildren() &&
486+
selectedBlock.isVisible()
487+
? selectFirstChild()
488+
: selectNextSiblingOrParent();
489+
break;
493490
}
494491
});
495492
}

0 commit comments

Comments
 (0)