@blokkli/editor 2.0.0-alpha.16 → 2.0.0-alpha.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/module.mjs +265 -83
- package/dist/modules/drupal/graphql/base/fragment.blokkliProps.graphql +1 -1
- package/dist/modules/drupal/graphql/features/comments.graphql +11 -8
- package/dist/modules/drupal/runtime/adapter/index.js +2 -2
- package/dist/runtime/blokkliPlugins/ItemAction/index.vue +1 -3
- package/dist/runtime/components/Blocks/FromLibrary/index.vue +4 -2
- package/dist/runtime/components/BlokkliEditable.vue +22 -4
- package/dist/runtime/components/BlokkliProvider.vue +29 -20
- package/dist/runtime/components/BlokkliProvider.vue.d.ts +2 -1
- package/dist/runtime/components/Edit/Actions/index.vue +9 -4
- package/dist/runtime/components/Edit/AnimationCanvas/index.vue +420 -25
- package/dist/runtime/components/Edit/ArtboardTooltip/index.vue +80 -0
- package/dist/runtime/components/Edit/ArtboardTooltip/index.vue.d.ts +32 -0
- package/dist/runtime/components/Edit/Banner/index.vue +51 -0
- package/dist/runtime/components/Edit/Banner/index.vue.d.ts +18 -0
- package/dist/runtime/components/Edit/EditIndicator.vue +118 -44
- package/dist/runtime/components/Edit/EditIndicator.vue.d.ts +3 -0
- package/dist/runtime/components/Edit/EditProvider.vue +79 -22
- package/dist/runtime/components/Edit/EditProvider.vue.d.ts +2 -0
- package/dist/runtime/components/Edit/Features/Analyze/Overlay/index.vue +19 -20
- package/dist/runtime/components/Edit/Features/BlockAddList/index.vue +1 -1
- package/dist/runtime/components/Edit/Features/CommandPalette/index.vue +2 -0
- package/dist/runtime/components/Edit/Features/Comments/AddForm/index.vue +35 -20
- package/dist/runtime/components/Edit/Features/Comments/AddForm/index.vue.d.ts +5 -3
- package/dist/runtime/components/Edit/Features/Comments/CommentInput/index.vue +29 -0
- package/dist/runtime/components/Edit/Features/Comments/CommentInput/index.vue.d.ts +13 -0
- package/dist/runtime/components/Edit/Features/Comments/Overlay/Item/index.vue +22 -16
- package/dist/runtime/components/Edit/Features/Comments/Overlay/Item/index.vue.d.ts +1 -0
- package/dist/runtime/components/Edit/Features/Comments/Overlay/index.vue +15 -6
- package/dist/runtime/components/Edit/Features/Comments/index.vue +20 -8
- package/dist/runtime/components/Edit/Features/Debug/Rects/index.vue +26 -35
- package/dist/runtime/components/Edit/Features/Debug/Renderer.vue +240 -0
- package/dist/runtime/components/Edit/Features/Debug/Renderer.vue.d.ts +6 -0
- package/dist/runtime/components/Edit/Features/Debug/index.vue +4 -165
- package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +1 -1
- package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +41 -37
- package/dist/runtime/components/Edit/Features/Edit/index.vue +1 -1
- package/dist/runtime/components/Edit/Features/EditableField/Overlay/Frame/index.vue +63 -3
- package/dist/runtime/components/Edit/Features/EditableField/Overlay/Plaintext/index.vue +13 -9
- package/dist/runtime/components/Edit/Features/EditableField/Overlay/index.vue +17 -76
- package/dist/runtime/components/Edit/Features/EditableField/index.vue +1 -1
- package/dist/runtime/components/Edit/Features/History/index.vue +5 -2
- package/dist/runtime/components/Edit/Features/Hover/Overlay/fragment.glsl +139 -0
- package/dist/runtime/components/Edit/Features/Hover/Overlay/index.vue +270 -0
- package/dist/runtime/components/Edit/Features/Hover/Overlay/index.vue.d.ts +6 -0
- package/dist/runtime/components/Edit/Features/Hover/Overlay/vertex.glsl +117 -0
- package/dist/runtime/components/Edit/Features/Hover/index.vue +25 -0
- package/dist/runtime/components/Edit/Features/Library/LibraryDialog/index.vue +19 -27
- package/dist/runtime/components/Edit/Features/Library/ReusableDialog/index.vue +27 -23
- package/dist/runtime/components/Edit/Features/Library/index.vue +2 -1
- package/dist/runtime/components/Edit/Features/MultiSelect/Overlay/index.vue +34 -27
- package/dist/runtime/components/Edit/Features/MultiSelect/index.vue +2 -4
- package/dist/runtime/components/Edit/Features/Options/Form/Item.vue +6 -1
- package/dist/runtime/components/Edit/Features/Options/Form/index.vue +1 -0
- package/dist/runtime/components/Edit/Features/Ownership/Renderer.vue +35 -0
- package/dist/runtime/components/Edit/Features/Ownership/Renderer.vue.d.ts +6 -0
- package/dist/runtime/components/Edit/Features/Ownership/index.vue +7 -25
- package/dist/runtime/components/Edit/Features/ProxyView/index.vue +5 -1
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/Overlay/index.vue +39 -74
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/Overlay/index.vue.d.ts +4 -2
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/fragment.glsl +106 -0
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/index.vue +417 -0
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/index.vue.d.ts +32 -0
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/vertex.glsl +102 -0
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/index.vue +33 -106
- package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue +88 -29
- package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue.d.ts +2 -0
- package/dist/runtime/components/Edit/Features/Selection/Overlay/vertex.glsl +11 -2
- package/dist/runtime/components/Edit/Features/Selection/index.vue +5 -12
- package/dist/runtime/components/Edit/Features/Translations/Banner/index.vue +17 -11
- package/dist/runtime/components/Edit/Features/Translations/index.vue +13 -16
- package/dist/runtime/components/Edit/Form/Text/index.vue +2 -1
- package/dist/runtime/components/Edit/Form/Text/index.vue.d.ts +1 -0
- package/dist/runtime/components/Edit/Indicators/index.vue +1 -1
- package/dist/runtime/components/Edit/Konami/Game/index.vue +5 -5
- package/dist/runtime/components/Edit/index.d.ts +5 -3
- package/dist/runtime/components/Edit/index.js +8 -4
- package/dist/runtime/composables/defineBlokkli.js +4 -2
- package/dist/runtime/css/output.css +1 -1
- package/dist/runtime/helpers/animationProvider.d.ts +34 -1
- package/dist/runtime/helpers/animationProvider.js +175 -48
- package/dist/runtime/helpers/composables/defineRenderer.d.ts +8 -0
- package/dist/runtime/helpers/composables/defineRenderer.js +8 -0
- package/dist/runtime/helpers/composables/useStickyToolbar.d.ts +4 -1
- package/dist/runtime/helpers/composables/useStickyToolbar.js +53 -35
- package/dist/runtime/helpers/dom/index.d.ts +1 -0
- package/dist/runtime/helpers/domProvider.d.ts +46 -0
- package/dist/runtime/helpers/domProvider.js +95 -6
- package/dist/runtime/helpers/editableProvider.d.ts +14 -0
- package/dist/runtime/helpers/editableProvider.js +144 -0
- package/dist/runtime/helpers/stateProvider.d.ts +6 -2
- package/dist/runtime/helpers/stateProvider.js +66 -3
- package/dist/runtime/helpers/storageProvider.d.ts +3 -2
- package/dist/runtime/helpers/storageProvider.js +6 -2
- package/dist/runtime/helpers/symbols.d.ts +1 -0
- package/dist/runtime/helpers/symbols.js +1 -0
- package/dist/runtime/helpers/uiProvider.d.ts +8 -1
- package/dist/runtime/helpers/uiProvider.js +34 -2
- package/dist/runtime/plugins/blokkliEditable.js +74 -3
- package/dist/runtime/types/index.d.ts +13 -1
- package/package.json +1 -1
- package/dist/runtime/components/Edit/DragInteractions/index.vue +0 -401
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/AddButtonsField.vue +0 -54
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/AddButtonsField.vue.d.ts +0 -14
- /package/dist/runtime/components/Edit/{DragInteractions → Features/Hover}/index.vue.d.ts +0 -0
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Teleport to="#bk-canvas-overlay">
|
|
3
|
+
<div
|
|
4
|
+
class="bk bk-add-button-tooltip"
|
|
5
|
+
:class="{ 'bk-is-field': tooltipData?.isField }"
|
|
6
|
+
:style="{
|
|
7
|
+
position: 'fixed',
|
|
8
|
+
left: (tooltipData?.x ?? 0) + 'px',
|
|
9
|
+
top: (tooltipData?.y ?? 0) + 'px',
|
|
10
|
+
transform: tooltipData?.transform ?? 'translate(0, 0)',
|
|
11
|
+
visibility: tooltipData ? 'visible' : 'hidden'
|
|
12
|
+
}"
|
|
13
|
+
>
|
|
14
|
+
{{ tooltipData?.text ?? "" }}
|
|
15
|
+
</div>
|
|
16
|
+
</Teleport>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script setup>
|
|
20
|
+
import onBlokkliEvent from "#blokkli/helpers/composables/onBlokkliEvent";
|
|
21
|
+
import defineRenderer from "#blokkli/helpers/composables/defineRenderer";
|
|
22
|
+
import { useBlokkli, computed, ref } from "#imports";
|
|
23
|
+
import { setBuffersAndAttributes, drawBufferInfo, setUniforms } from "twgl.js";
|
|
24
|
+
import vs from "./vertex.glsl?raw";
|
|
25
|
+
import fs from "./fragment.glsl?raw";
|
|
26
|
+
import { RectangleBufferCollector } from "#blokkli/helpers/webgl";
|
|
27
|
+
import { toShaderColor, getFieldKey } from "#blokkli/helpers";
|
|
28
|
+
import {
|
|
29
|
+
getChildrenOrientation,
|
|
30
|
+
determineCanAddChildren
|
|
31
|
+
} from "#blokkli/helpers/dropTargets";
|
|
32
|
+
import { isInternalBundle } from "#blokkli/helpers/bundles";
|
|
33
|
+
const { animation, theme, dom, selection, state, types, ui, $t } = useBlokkli();
|
|
34
|
+
const emptyFieldTooltips = ref([]);
|
|
35
|
+
const currentUuid = ref("");
|
|
36
|
+
const currentBundleLabel = ref("");
|
|
37
|
+
const currentSingleAllowedBundleLabel = ref(null);
|
|
38
|
+
const tooltipData = computed(() => {
|
|
39
|
+
if (hoveredCircle.value < 0) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const index = hoveredCircle.value;
|
|
43
|
+
const artboardX = circlePositions[index * 2];
|
|
44
|
+
const artboardY = circlePositions[index * 2 + 1];
|
|
45
|
+
if (artboardX === void 0 || artboardY === void 0) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const scale = ui.artboardScale.value;
|
|
49
|
+
const offset = ui.artboardOffset.value;
|
|
50
|
+
const screenX = artboardX * scale + offset.x;
|
|
51
|
+
const screenY = artboardY * scale + offset.y;
|
|
52
|
+
let transform;
|
|
53
|
+
let position;
|
|
54
|
+
let text;
|
|
55
|
+
let isField = false;
|
|
56
|
+
if (index === 0 || index === 1) {
|
|
57
|
+
const orientation = currentOrientation.value;
|
|
58
|
+
if (currentSingleAllowedBundleLabel.value) {
|
|
59
|
+
if (index === 0) {
|
|
60
|
+
text = $t("addButtonBundleBefore", 'Add "@bundle" before').replace(
|
|
61
|
+
"@bundle",
|
|
62
|
+
currentSingleAllowedBundleLabel.value
|
|
63
|
+
);
|
|
64
|
+
} else {
|
|
65
|
+
text = $t("addButtonBundleAfter", 'Add "@bundle" after').replace(
|
|
66
|
+
"@bundle",
|
|
67
|
+
currentSingleAllowedBundleLabel.value
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
if (index === 0) {
|
|
72
|
+
text = $t("addButtonBeforeBundle", "Add before...");
|
|
73
|
+
} else {
|
|
74
|
+
text = $t("addButtonAfterBundle", "Add after...");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (orientation === "horizontal") {
|
|
78
|
+
if (index === 0) {
|
|
79
|
+
transform = `translate(${TOOLTIP_MARGIN}px, -50%)`;
|
|
80
|
+
position = "right";
|
|
81
|
+
} else {
|
|
82
|
+
transform = `translate(calc(-100% - ${TOOLTIP_MARGIN}px), -50%)`;
|
|
83
|
+
position = "left";
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
if (index === 0) {
|
|
87
|
+
transform = `translate(-50%, ${TOOLTIP_MARGIN}px)`;
|
|
88
|
+
position = "bottom";
|
|
89
|
+
} else {
|
|
90
|
+
transform = `translate(-50%, calc(-100% - ${TOOLTIP_MARGIN}px))`;
|
|
91
|
+
position = "top";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
transform = `translate(-50%, calc(-100% - ${TOOLTIP_MARGIN}px))`;
|
|
96
|
+
position = "top";
|
|
97
|
+
isField = true;
|
|
98
|
+
const fieldIndex = index - 2;
|
|
99
|
+
text = emptyFieldTooltips.value[fieldIndex] || "Add to field";
|
|
100
|
+
}
|
|
101
|
+
return { x: screenX, y: screenY, transform, position, text, isField };
|
|
102
|
+
});
|
|
103
|
+
const emit = defineEmits(["toggle", "toggleField"]);
|
|
104
|
+
const gl = animation.gl();
|
|
105
|
+
const programInfo = gl ? animation.registerProgram("add-buttons", gl, [vs, fs]) : null;
|
|
106
|
+
const MAX_CIRCLES = 10;
|
|
107
|
+
const BUTTON_RADIUS = 12;
|
|
108
|
+
const TOOLTIP_MARGIN = 20;
|
|
109
|
+
let bufferInfo = null;
|
|
110
|
+
if (gl) {
|
|
111
|
+
class CircleBufferCollector extends RectangleBufferCollector {
|
|
112
|
+
}
|
|
113
|
+
const collector = new CircleBufferCollector(gl);
|
|
114
|
+
for (let i = 0; i < MAX_CIRCLES; i++) {
|
|
115
|
+
collector.addRectangle(
|
|
116
|
+
{
|
|
117
|
+
id: `circle-${i}`,
|
|
118
|
+
x: 0,
|
|
119
|
+
y: 0,
|
|
120
|
+
width: 40,
|
|
121
|
+
height: 40
|
|
122
|
+
},
|
|
123
|
+
i
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
bufferInfo = collector.createBufferInfo();
|
|
127
|
+
}
|
|
128
|
+
const circlePositions = new Float32Array(MAX_CIRCLES * 2);
|
|
129
|
+
const circleVisible = new Float32Array(MAX_CIRCLES);
|
|
130
|
+
const hoveredCircle = ref(-1);
|
|
131
|
+
const color = computed(() => {
|
|
132
|
+
return toShaderColor(theme.accent.value[600]);
|
|
133
|
+
});
|
|
134
|
+
const colorHover = computed(() => {
|
|
135
|
+
return toShaderColor(theme.accent.value[500]);
|
|
136
|
+
});
|
|
137
|
+
const colorField = computed(() => {
|
|
138
|
+
return toShaderColor(theme.accent.value[400]);
|
|
139
|
+
});
|
|
140
|
+
const colorFieldHover = computed(() => {
|
|
141
|
+
return toShaderColor(theme.accent.value[300]);
|
|
142
|
+
});
|
|
143
|
+
const orientationCache = /* @__PURE__ */ new Map();
|
|
144
|
+
const currentOrientation = ref("horizontal");
|
|
145
|
+
const blockStateCache = /* @__PURE__ */ new Map();
|
|
146
|
+
function getOrientationForUuid(uuid) {
|
|
147
|
+
let cached = orientationCache.get(uuid);
|
|
148
|
+
if (!cached) {
|
|
149
|
+
const block = dom.findBlock(uuid);
|
|
150
|
+
if (block) {
|
|
151
|
+
const field = dom.findField(block.hostUuid, block.hostFieldName);
|
|
152
|
+
if (field) {
|
|
153
|
+
cached = getChildrenOrientation(field.element);
|
|
154
|
+
orientationCache.set(uuid, cached);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return cached || "horizontal";
|
|
159
|
+
}
|
|
160
|
+
function getBlockState(uuid) {
|
|
161
|
+
let cached = blockStateCache.get(uuid);
|
|
162
|
+
if (!cached) {
|
|
163
|
+
let canShowBeforeAfter = false;
|
|
164
|
+
let singleAllowedBundleLabel = null;
|
|
165
|
+
const block = dom.findBlock(uuid);
|
|
166
|
+
if (!block) {
|
|
167
|
+
return {
|
|
168
|
+
canShowBeforeAfter: false,
|
|
169
|
+
emptyFieldKeys: [],
|
|
170
|
+
emptyFieldTooltips: [],
|
|
171
|
+
bundleLabel: "",
|
|
172
|
+
singleAllowedBundleLabel: null
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
if (block) {
|
|
176
|
+
const field = dom.findField(block.hostUuid, block.hostFieldName);
|
|
177
|
+
if (!field) {
|
|
178
|
+
return {
|
|
179
|
+
canShowBeforeAfter: false,
|
|
180
|
+
emptyFieldKeys: [],
|
|
181
|
+
emptyFieldTooltips: [],
|
|
182
|
+
bundleLabel: "",
|
|
183
|
+
singleAllowedBundleLabel: null
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
if (field) {
|
|
187
|
+
const fieldChildren = [...field.element.children];
|
|
188
|
+
const currentCount = state.getFieldBlockCount(field.key);
|
|
189
|
+
canShowBeforeAfter = determineCanAddChildren(
|
|
190
|
+
field,
|
|
191
|
+
fieldChildren,
|
|
192
|
+
[],
|
|
193
|
+
// Not moving any blocks, adding a new one
|
|
194
|
+
currentCount,
|
|
195
|
+
1,
|
|
196
|
+
// Adding 1 new block
|
|
197
|
+
[]
|
|
198
|
+
// Don't know which bundle will be added
|
|
199
|
+
);
|
|
200
|
+
const allowedBundles = field.allowedBundles.filter(
|
|
201
|
+
(bundle) => !isInternalBundle(bundle)
|
|
202
|
+
);
|
|
203
|
+
if (allowedBundles.length === 1) {
|
|
204
|
+
const bundle = allowedBundles[0];
|
|
205
|
+
if (bundle) {
|
|
206
|
+
singleAllowedBundleLabel = types.getBlockBundleDefinition(bundle)?.label || bundle;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
const bundleLabel = block ? types.getBlockBundleDefinition(block.itemBundle)?.label || block.itemBundle : "";
|
|
212
|
+
const emptyFieldKeys = [];
|
|
213
|
+
const emptyFieldTooltips2 = [];
|
|
214
|
+
if (block) {
|
|
215
|
+
const fieldConfigs = types.fieldConfig.forEntityTypeAndBundle(
|
|
216
|
+
block.entityType,
|
|
217
|
+
block.itemBundle
|
|
218
|
+
);
|
|
219
|
+
for (const fieldConfig of fieldConfigs) {
|
|
220
|
+
const key = getFieldKey(uuid, fieldConfig.name);
|
|
221
|
+
const count = state.getFieldBlockCount(key);
|
|
222
|
+
if (count === 0) {
|
|
223
|
+
emptyFieldKeys.push(key);
|
|
224
|
+
const fieldLabel = fieldConfig.label || fieldConfig.name;
|
|
225
|
+
const fieldElement = dom.findField(uuid, fieldConfig.name);
|
|
226
|
+
if (fieldElement) {
|
|
227
|
+
const allowedBundles = fieldElement.allowedBundles.filter(
|
|
228
|
+
(bundle) => !isInternalBundle(bundle)
|
|
229
|
+
);
|
|
230
|
+
if (allowedBundles.length === 1) {
|
|
231
|
+
const bundle = allowedBundles[0];
|
|
232
|
+
if (bundle) {
|
|
233
|
+
const singleBundleLabel = types.getBlockBundleDefinition(bundle)?.label || bundle;
|
|
234
|
+
const tooltip = $t(
|
|
235
|
+
"addButtonBundleInsideField",
|
|
236
|
+
'Add "@bundle" inside @parentBundle \xBB @fieldLabel'
|
|
237
|
+
).replace("@bundle", singleBundleLabel).replace("@parentBundle", bundleLabel).replace("@fieldLabel", fieldLabel);
|
|
238
|
+
emptyFieldTooltips2.push(tooltip);
|
|
239
|
+
} else {
|
|
240
|
+
emptyFieldTooltips2.push(
|
|
241
|
+
$t(
|
|
242
|
+
"addButtonInsideField",
|
|
243
|
+
"Add inside @parentBundle \xBB @fieldLabel..."
|
|
244
|
+
).replace("@parentBundle", bundleLabel).replace("@fieldLabel", fieldLabel)
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
} else {
|
|
248
|
+
emptyFieldTooltips2.push(
|
|
249
|
+
$t(
|
|
250
|
+
"addButtonInsideField",
|
|
251
|
+
"Add inside @parentBundle \xBB @fieldLabel..."
|
|
252
|
+
).replace("@parentBundle", bundleLabel).replace("@fieldLabel", fieldLabel)
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
} else {
|
|
256
|
+
emptyFieldTooltips2.push(
|
|
257
|
+
$t(
|
|
258
|
+
"addButtonInsideField",
|
|
259
|
+
"Add inside @parentBundle \xBB @fieldLabel..."
|
|
260
|
+
).replace("@parentBundle", bundleLabel).replace("@fieldLabel", fieldLabel)
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
cached = {
|
|
267
|
+
canShowBeforeAfter,
|
|
268
|
+
emptyFieldKeys,
|
|
269
|
+
emptyFieldTooltips: emptyFieldTooltips2,
|
|
270
|
+
bundleLabel,
|
|
271
|
+
singleAllowedBundleLabel
|
|
272
|
+
};
|
|
273
|
+
blockStateCache.set(uuid, cached);
|
|
274
|
+
}
|
|
275
|
+
return cached;
|
|
276
|
+
}
|
|
277
|
+
onBlokkliEvent("state:reloaded", () => {
|
|
278
|
+
orientationCache.clear();
|
|
279
|
+
blockStateCache.clear();
|
|
280
|
+
});
|
|
281
|
+
function getCircleAtPoint(x, y) {
|
|
282
|
+
if (ui.artboardScale.value <= 0.4) {
|
|
283
|
+
return -1;
|
|
284
|
+
}
|
|
285
|
+
const effectiveScale = Math.max(ui.artboardScale.value, 0.5);
|
|
286
|
+
const radius = BUTTON_RADIUS / effectiveScale;
|
|
287
|
+
for (let i = 0; i < MAX_CIRCLES; i++) {
|
|
288
|
+
if (circleVisible[i] > 0) {
|
|
289
|
+
const cx = circlePositions[i * 2];
|
|
290
|
+
const cy = circlePositions[i * 2 + 1];
|
|
291
|
+
const dx = x - cx;
|
|
292
|
+
const dy = y - cy;
|
|
293
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
294
|
+
if (distance <= radius) {
|
|
295
|
+
return i;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return -1;
|
|
300
|
+
}
|
|
301
|
+
if (gl && programInfo && bufferInfo) {
|
|
302
|
+
defineRenderer("add-buttons", {
|
|
303
|
+
zIndex: 1e3,
|
|
304
|
+
enabled: () => selection.uuids.value.length === 1,
|
|
305
|
+
cursor: () => hoveredCircle.value >= 0 ? "pointer" : null,
|
|
306
|
+
onClick: ({ mouseArtboard }) => {
|
|
307
|
+
if (selection.uuids.value.length !== 1) {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
const clickedCircle = getCircleAtPoint(mouseArtboard.x, mouseArtboard.y);
|
|
311
|
+
if (clickedCircle >= 0) {
|
|
312
|
+
const cx = circlePositions[clickedCircle * 2];
|
|
313
|
+
const cy = circlePositions[clickedCircle * 2 + 1];
|
|
314
|
+
if (clickedCircle === 0 || clickedCircle === 1) {
|
|
315
|
+
const position = clickedCircle === 0 ? "before" : "after";
|
|
316
|
+
emit("toggle", {
|
|
317
|
+
position,
|
|
318
|
+
coordinates: { x: cx, y: cy }
|
|
319
|
+
});
|
|
320
|
+
} else {
|
|
321
|
+
const fieldIndex = clickedCircle - 2;
|
|
322
|
+
emit("toggleField", {
|
|
323
|
+
index: fieldIndex,
|
|
324
|
+
coordinates: { x: cx, y: cy }
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
return false;
|
|
330
|
+
},
|
|
331
|
+
render: (ctx) => {
|
|
332
|
+
if (selection.isChangingOptions.value) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
circleVisible.fill(0);
|
|
336
|
+
if (ctx.selectedUuids.length !== 1) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
const uuid = ctx.selectedUuids[0];
|
|
340
|
+
if (!uuid) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const blockState = getBlockState(uuid);
|
|
344
|
+
if (blockState.canShowBeforeAfter) {
|
|
345
|
+
const blockRect = dom.getBlockRect(uuid);
|
|
346
|
+
if (!blockRect || blockRect.width === 0) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const orientation = getOrientationForUuid(uuid);
|
|
350
|
+
currentOrientation.value = orientation;
|
|
351
|
+
const BUTTON_SHIFT = 2 / ctx.artboardScale;
|
|
352
|
+
if (orientation === "horizontal") {
|
|
353
|
+
circlePositions[0] = blockRect.x - BUTTON_SHIFT;
|
|
354
|
+
circlePositions[1] = blockRect.y + blockRect.height / 2;
|
|
355
|
+
circleVisible[0] = 1;
|
|
356
|
+
circlePositions[2] = blockRect.x + blockRect.width + BUTTON_SHIFT;
|
|
357
|
+
circlePositions[3] = blockRect.y + blockRect.height / 2;
|
|
358
|
+
circleVisible[1] = 1;
|
|
359
|
+
} else {
|
|
360
|
+
circlePositions[0] = blockRect.x + blockRect.width / 2;
|
|
361
|
+
circlePositions[1] = blockRect.y - BUTTON_SHIFT;
|
|
362
|
+
circleVisible[0] = 1;
|
|
363
|
+
circlePositions[2] = blockRect.x + blockRect.width / 2;
|
|
364
|
+
circlePositions[3] = blockRect.y + blockRect.height + BUTTON_SHIFT;
|
|
365
|
+
circleVisible[1] = 1;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
currentUuid.value = uuid;
|
|
369
|
+
currentBundleLabel.value = blockState.bundleLabel;
|
|
370
|
+
currentSingleAllowedBundleLabel.value = blockState.singleAllowedBundleLabel;
|
|
371
|
+
if (blockState.emptyFieldKeys.length > 0) {
|
|
372
|
+
emptyFieldTooltips.value = blockState.emptyFieldTooltips;
|
|
373
|
+
for (let i = 0; i < blockState.emptyFieldKeys.length && i < 8; i++) {
|
|
374
|
+
const fieldKey = blockState.emptyFieldKeys[i];
|
|
375
|
+
if (!fieldKey) {
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
const fieldRect = dom.getFieldRect(fieldKey);
|
|
379
|
+
if (!fieldRect) {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
const circleIndex = i + 2;
|
|
383
|
+
circlePositions[circleIndex * 2] = fieldRect.x + fieldRect.width / 2;
|
|
384
|
+
circlePositions[circleIndex * 2 + 1] = fieldRect.y + fieldRect.height / 2;
|
|
385
|
+
circleVisible[circleIndex] = 1;
|
|
386
|
+
}
|
|
387
|
+
} else {
|
|
388
|
+
emptyFieldTooltips.value = [];
|
|
389
|
+
}
|
|
390
|
+
hoveredCircle.value = getCircleAtPoint(
|
|
391
|
+
ctx.mouseArtboard.x,
|
|
392
|
+
ctx.mouseArtboard.y
|
|
393
|
+
);
|
|
394
|
+
gl.useProgram(programInfo.program);
|
|
395
|
+
setUniforms(programInfo, {
|
|
396
|
+
u_circle_positions: circlePositions,
|
|
397
|
+
u_circle_visible: circleVisible,
|
|
398
|
+
u_color: color.value,
|
|
399
|
+
u_color_hover: colorHover.value,
|
|
400
|
+
u_color_field: colorField.value,
|
|
401
|
+
u_color_field_hover: colorFieldHover.value,
|
|
402
|
+
u_hovered_circle: hoveredCircle.value,
|
|
403
|
+
u_radius: BUTTON_RADIUS
|
|
404
|
+
});
|
|
405
|
+
animation.setSharedUniforms(gl, programInfo);
|
|
406
|
+
setBuffersAndAttributes(gl, programInfo, bufferInfo);
|
|
407
|
+
drawBufferInfo(gl, bufferInfo, gl.TRIANGLES);
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
</script>
|
|
412
|
+
|
|
413
|
+
<script>
|
|
414
|
+
export default {
|
|
415
|
+
name: "AddButtonsRenderer"
|
|
416
|
+
};
|
|
417
|
+
</script>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
2
|
+
toggle: (data: {
|
|
3
|
+
position: "before" | "after";
|
|
4
|
+
coordinates: {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
};
|
|
8
|
+
}) => any;
|
|
9
|
+
toggleField: (data: {
|
|
10
|
+
index: number;
|
|
11
|
+
coordinates: {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
};
|
|
15
|
+
}) => any;
|
|
16
|
+
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
17
|
+
onToggle?: ((data: {
|
|
18
|
+
position: "before" | "after";
|
|
19
|
+
coordinates: {
|
|
20
|
+
x: number;
|
|
21
|
+
y: number;
|
|
22
|
+
};
|
|
23
|
+
}) => any) | undefined;
|
|
24
|
+
onToggleField?: ((data: {
|
|
25
|
+
index: number;
|
|
26
|
+
coordinates: {
|
|
27
|
+
x: number;
|
|
28
|
+
y: number;
|
|
29
|
+
};
|
|
30
|
+
}) => any) | undefined;
|
|
31
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
32
|
+
export default _default;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
precision highp float;
|
|
2
|
+
|
|
3
|
+
// [x, y] position.
|
|
4
|
+
attribute vec2 a_position;
|
|
5
|
+
// The [x,y,width, height] of the quad the vertex belongs to.
|
|
6
|
+
attribute vec4 a_quad;
|
|
7
|
+
attribute float a_rect_id;
|
|
8
|
+
|
|
9
|
+
// The global scaling applied to all quads.
|
|
10
|
+
uniform float u_scale;
|
|
11
|
+
uniform float u_dpi;
|
|
12
|
+
// The amount of pixels to offset on the x axis.
|
|
13
|
+
uniform float u_offset_x;
|
|
14
|
+
// The amount of pixels to offset on the y axis.
|
|
15
|
+
uniform float u_offset_y;
|
|
16
|
+
uniform vec2 u_resolution;
|
|
17
|
+
|
|
18
|
+
// Circle positions (10 vec2s = 20 floats)
|
|
19
|
+
uniform vec2 u_circle_positions[10];
|
|
20
|
+
// Circle visibility (10 floats)
|
|
21
|
+
uniform float u_circle_visible[10];
|
|
22
|
+
// Hovered circle index (-1 for none)
|
|
23
|
+
uniform float u_hovered_circle;
|
|
24
|
+
// Button radius in pixels
|
|
25
|
+
uniform float u_radius;
|
|
26
|
+
|
|
27
|
+
// The transformed quad for the fragment shader.
|
|
28
|
+
varying vec4 v_quad;
|
|
29
|
+
varying vec2 v_circle_center;
|
|
30
|
+
varying float v_visible;
|
|
31
|
+
varying float v_is_hovered;
|
|
32
|
+
varying float v_scale_fade;
|
|
33
|
+
varying float v_rect_id;
|
|
34
|
+
|
|
35
|
+
void main() {
|
|
36
|
+
int rectId = int(a_rect_id);
|
|
37
|
+
|
|
38
|
+
// Get circle position and visibility for this rect
|
|
39
|
+
vec2 circlePos = u_circle_positions[rectId];
|
|
40
|
+
v_visible = u_circle_visible[rectId];
|
|
41
|
+
v_is_hovered = float(rectId) == u_hovered_circle ? 1.0 : 0.0;
|
|
42
|
+
v_rect_id = a_rect_id;
|
|
43
|
+
|
|
44
|
+
// Calculate fade factor based on scale (fade from 1.0 at 0.5 to 0.0 at 0.4)
|
|
45
|
+
v_scale_fade = 1.0;
|
|
46
|
+
if (u_scale < 0.5) {
|
|
47
|
+
// Interpolate from 1.0 (at scale 0.5) to 0.0 (at scale 0.4)
|
|
48
|
+
v_scale_fade = (u_scale - 0.4) / (0.5 - 0.4);
|
|
49
|
+
v_scale_fade = clamp(v_scale_fade, 0.0, 1.0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Border width in pixels (must match fragment shader)
|
|
53
|
+
float borderWidth = 4.0;
|
|
54
|
+
|
|
55
|
+
// Circle radius in artboard space - apply inverse scaling to keep constant size
|
|
56
|
+
// Then multiply by fade factor
|
|
57
|
+
// Add border width to the radius so the border renders outside
|
|
58
|
+
float radius = (u_radius + borderWidth) / u_scale * v_scale_fade;
|
|
59
|
+
|
|
60
|
+
// Calculate quad bounds centered on circle position
|
|
61
|
+
float left = circlePos.x - radius;
|
|
62
|
+
float top = circlePos.y - radius;
|
|
63
|
+
float width = radius * 2.0;
|
|
64
|
+
float height = radius * 2.0;
|
|
65
|
+
|
|
66
|
+
// Determine which corner of the quad this vertex represents
|
|
67
|
+
// Normalize position within the dummy quad (0.0 to 1.0)
|
|
68
|
+
vec2 quadCorner = vec2(
|
|
69
|
+
(a_position.x - a_quad.x) / a_quad.z,
|
|
70
|
+
(a_position.y - a_quad.y) / a_quad.w
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// Calculate actual vertex position in artboard space
|
|
74
|
+
vec2 vertexPos = vec2(
|
|
75
|
+
left + quadCorner.x * width,
|
|
76
|
+
top + quadCorner.y * height
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
// Apply global scale and offsets
|
|
80
|
+
vec2 offsetPosition = vertexPos * u_scale;
|
|
81
|
+
offsetPosition.x += u_offset_x;
|
|
82
|
+
offsetPosition.y += u_offset_y;
|
|
83
|
+
|
|
84
|
+
// Normalize position for rendering
|
|
85
|
+
vec2 normalizedPosition = offsetPosition / u_resolution;
|
|
86
|
+
|
|
87
|
+
// Transform to screen space (-1 to 1)
|
|
88
|
+
vec2 screenSpacePosition = normalizedPosition * 2.0 - vec2(1.0, 1.0);
|
|
89
|
+
screenSpacePosition.y = -screenSpacePosition.y;
|
|
90
|
+
|
|
91
|
+
// Output final position in clip space
|
|
92
|
+
gl_Position = vec4(screenSpacePosition, 0.0, 1.0) * u_dpi;
|
|
93
|
+
|
|
94
|
+
// Calculate transformed quad for fragment shader
|
|
95
|
+
v_quad = vec4(
|
|
96
|
+
(left * u_scale + u_offset_x) * u_dpi,
|
|
97
|
+
(u_resolution.y - top * u_scale - height * u_scale - u_offset_y) * u_dpi,
|
|
98
|
+
width * u_scale * u_dpi,
|
|
99
|
+
height * u_scale * u_dpi
|
|
100
|
+
);
|
|
101
|
+
v_circle_center = vec2(v_quad.x + v_quad.z / 2.0, v_quad.y + v_quad.w / 2.0);
|
|
102
|
+
}
|