@blokkli/editor 2.0.0-alpha.16 → 2.0.0-alpha.18
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 +640 -137
- package/dist/modules/drupal/graphql/base/fragment.blokkliProps.graphql +1 -1
- package/dist/modules/drupal/graphql/base/fragment.paragraphsFieldItem.graphql +3 -1
- package/dist/modules/drupal/graphql/base/query.pbConfig.graphql +1 -10
- package/dist/modules/drupal/graphql/features/comments.graphql +11 -8
- package/dist/modules/drupal/graphql/mutations/set_paragraph_schedule.graphql +15 -0
- package/dist/modules/drupal/index.mjs +33 -0
- package/dist/modules/drupal/runtime/adapter/index.js +12 -4
- package/dist/runtime/adapter/index.d.ts +21 -0
- package/dist/runtime/blokkliPlugins/ContextMenu/Menu/index.vue +3 -0
- package/dist/runtime/blokkliPlugins/ItemAction/index.vue +23 -15
- package/dist/runtime/blokkliPlugins/ItemAction/index.vue.d.ts +20 -44
- package/dist/runtime/blokkliPlugins/TourItem/index.vue +10 -5
- package/dist/runtime/components/Blocks/FromLibrary/index.vue +4 -2
- package/dist/runtime/components/BlokkliEditable.vue +32 -14
- package/dist/runtime/components/BlokkliField.vue +3 -0
- package/dist/runtime/components/BlokkliField.vue.d.ts +3 -3
- package/dist/runtime/components/BlokkliItem.vue +1 -1
- package/dist/runtime/components/BlokkliItem.vue.d.ts +4 -2
- package/dist/runtime/components/BlokkliProvider.vue +41 -28
- package/dist/runtime/components/BlokkliProvider.vue.d.ts +2 -1
- package/dist/runtime/components/Edit/Actions/index.vue +36 -20
- package/dist/runtime/components/Edit/AnimationCanvas/index.vue +436 -25
- package/dist/runtime/components/Edit/ArtboardTooltip/index.vue +83 -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/Dialog/index.vue +6 -4
- package/dist/runtime/components/Edit/DraggableList.vue +15 -7
- package/dist/runtime/components/Edit/DraggableList.vue.d.ts +5 -5
- 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 +101 -31
- package/dist/runtime/components/Edit/EditProvider.vue.d.ts +3 -0
- package/dist/runtime/components/Edit/Features/AddList/index.vue +9 -11
- package/dist/runtime/components/Edit/Features/Analyze/Overlay/index.vue +28 -26
- package/dist/runtime/components/Edit/Features/Analyze/Renderer.vue +1 -1
- package/dist/runtime/components/Edit/Features/Analyze/Results/ResultsItemNodesTarget.vue +15 -11
- package/dist/runtime/components/Edit/Features/Anchors/Renderer.vue +19 -102
- package/dist/runtime/components/Edit/Features/Artboard/Renderer.vue +3 -0
- package/dist/runtime/components/Edit/Features/BlockAddList/index.vue +29 -53
- package/dist/runtime/components/Edit/Features/BlockScheduler/Dialog/ScheduleSection.vue +154 -0
- package/dist/runtime/components/Edit/Features/BlockScheduler/Dialog/ScheduleSection.vue.d.ts +27 -0
- package/dist/runtime/components/Edit/Features/BlockScheduler/Dialog/index.vue +222 -0
- package/dist/runtime/components/Edit/Features/{Selection/AddButtons/AddButtonsField.vue.d.ts → BlockScheduler/Dialog/index.vue.d.ts} +6 -9
- package/dist/runtime/components/Edit/Features/BlockScheduler/index.vue +96 -0
- package/dist/runtime/components/Edit/Features/Clipboard/index.vue +15 -16
- package/dist/runtime/components/Edit/Features/CommandPalette/Palette/Item/index.vue +51 -0
- package/dist/runtime/components/Edit/Features/CommandPalette/Palette/{Group → Item}/index.vue.d.ts +9 -13
- package/dist/runtime/components/Edit/Features/CommandPalette/Palette/index.vue +46 -66
- 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/{Publish/Dialog/ScheduleDate.vue.d.ts → Comments/CommentInput/index.vue.d.ts} +2 -2
- 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 +21 -9
- package/dist/runtime/components/Edit/Features/Conversions/index.vue +4 -7
- 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 +7 -165
- package/dist/runtime/components/Edit/Features/Delete/index.vue +1 -1
- package/dist/runtime/components/Edit/Features/DraggingOverlay/DragItems/index.vue +14 -6
- package/dist/runtime/components/Edit/Features/DraggingOverlay/DropTargets/index.vue +55 -48
- package/dist/runtime/components/Edit/Features/DraggingOverlay/index.vue +30 -18
- package/dist/runtime/components/Edit/Features/Duplicate/index.vue +6 -8
- package/dist/runtime/components/Edit/Features/Edit/index.vue +16 -22
- package/dist/runtime/components/Edit/Features/EditForm/index.vue +7 -6
- package/dist/runtime/components/Edit/Features/EditableField/Overlay/Frame/index.vue +69 -4
- package/dist/runtime/components/Edit/Features/EditableField/Overlay/Frame/index.vue.d.ts +2 -2
- package/dist/runtime/components/Edit/Features/EditableField/Overlay/Plaintext/index.vue +13 -9
- package/dist/runtime/components/Edit/Features/EditableField/Overlay/index.vue +45 -87
- package/dist/runtime/components/Edit/Features/EditableField/Overlay/index.vue.d.ts +2 -2
- package/dist/runtime/components/Edit/Features/EditableField/index.vue +41 -43
- package/dist/runtime/components/Edit/Features/Fragments/Dialog/index.vue +11 -9
- package/dist/runtime/components/Edit/Features/Fragments/index.vue +3 -3
- 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 +261 -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/Hover/index.vue.d.ts +2 -0
- package/dist/runtime/components/Edit/Features/Library/EditReusable/index.vue +5 -7
- package/dist/runtime/components/Edit/Features/Library/LibraryDialog/index.vue +19 -27
- package/dist/runtime/components/Edit/Features/Library/ReusableDialog/index.vue +32 -28
- package/dist/runtime/components/Edit/Features/Library/index.vue +28 -23
- package/dist/runtime/components/Edit/Features/MediaLibrary/Library/index.vue +6 -3
- package/dist/runtime/components/Edit/Features/MediaLibrary/index.vue +15 -12
- package/dist/runtime/components/Edit/Features/MultiSelect/Overlay/index.vue +36 -29
- 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 +8 -6
- package/dist/runtime/components/Edit/Features/Options/index.vue +6 -6
- 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/Publish/Dialog/index.vue +68 -15
- package/dist/runtime/components/Edit/Features/Search/Overlay/Results/Page/index.vue +15 -15
- package/dist/runtime/components/Edit/Features/Search/index.vue +4 -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 +7 -5
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/fragment.glsl +106 -0
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/Renderer/index.vue +440 -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 +53 -125
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/index.vue.d.ts +2 -2
- package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue +88 -29
- package/dist/runtime/components/Edit/Features/Selection/Overlay/index.vue.d.ts +5 -3
- package/dist/runtime/components/Edit/Features/Selection/Overlay/vertex.glsl +11 -2
- package/dist/runtime/components/Edit/Features/Selection/OverlayFallback/index.vue +2 -2
- package/dist/runtime/components/Edit/Features/Selection/index.vue +66 -39
- package/dist/runtime/components/Edit/Features/Structure/List/Field/index.vue +2 -2
- package/dist/runtime/components/Edit/Features/Structure/List/Item/index.vue +13 -6
- package/dist/runtime/components/Edit/Features/Tour/Overlay/index.vue +3 -0
- package/dist/runtime/components/Edit/Features/Transform/index.vue +2 -27
- package/dist/runtime/components/Edit/Features/Translations/Banner/index.vue +17 -11
- package/dist/runtime/components/Edit/Features/Translations/index.vue +20 -23
- package/dist/runtime/components/Edit/Features/Validations/SidebarItem/index.vue +5 -5
- package/dist/runtime/components/Edit/Features/index.vue +17 -7
- 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/Form/Toggle/index.vue +4 -3
- package/dist/runtime/components/Edit/Form/Toggle/index.vue.d.ts +12 -2
- package/dist/runtime/components/Edit/Indicators/index.vue +1 -1
- package/dist/runtime/components/Edit/InfoBox/index.vue +6 -2
- package/dist/runtime/components/Edit/InfoBox/index.vue.d.ts +12 -2
- package/dist/runtime/components/Edit/Konami/Game/index.vue +5 -5
- package/dist/runtime/components/Edit/{Features/Publish/Dialog/ScheduleDate.vue → ScheduleDate/index.vue} +6 -58
- package/dist/runtime/components/Edit/ScheduleDate/index.vue.d.ts +23 -0
- package/dist/runtime/components/Edit/ShortcutIndicator/index.vue +3 -0
- package/dist/runtime/components/Edit/Transition/Height.vue +95 -0
- package/dist/runtime/components/Edit/Transition/Height.vue.d.ts +36 -0
- package/dist/runtime/components/Edit/index.d.ts +7 -3
- package/dist/runtime/components/Edit/index.js +12 -4
- package/dist/runtime/composables/defineBlokkli.js +4 -2
- package/dist/runtime/css/output.css +1 -1
- package/dist/runtime/helpers/animationProvider.d.ts +35 -1
- package/dist/runtime/helpers/animationProvider.js +179 -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/useStateBasedCache.d.ts +4 -0
- package/dist/runtime/helpers/composables/useStateBasedCache.js +13 -0
- package/dist/runtime/helpers/composables/useStickyToolbar.d.ts +4 -1
- package/dist/runtime/helpers/composables/useStickyToolbar.js +53 -35
- package/dist/runtime/helpers/definitionProvider.d.ts +1 -1
- package/dist/runtime/helpers/dom/index.d.ts +1 -0
- package/dist/runtime/helpers/domProvider.d.ts +54 -14
- package/dist/runtime/helpers/domProvider.js +168 -134
- package/dist/runtime/helpers/index.d.ts +1 -8
- package/dist/runtime/helpers/index.js +1 -84
- package/dist/runtime/helpers/providers/blocks.d.ts +10 -0
- package/dist/runtime/helpers/providers/blocks.js +91 -0
- package/dist/runtime/helpers/providers/directive.d.ts +24 -0
- package/dist/runtime/helpers/providers/directive.js +205 -0
- package/dist/runtime/helpers/providers/element.d.ts +6 -0
- package/dist/runtime/helpers/providers/element.js +35 -0
- package/dist/runtime/helpers/providers/fields.d.ts +8 -0
- package/dist/runtime/helpers/providers/fields.js +47 -0
- package/dist/runtime/helpers/selectionProvider.d.ts +11 -11
- package/dist/runtime/helpers/selectionProvider.js +38 -45
- package/dist/runtime/helpers/stateProvider.d.ts +7 -2
- package/dist/runtime/helpers/stateProvider.js +83 -14
- 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/themeProvider.d.ts +2 -1
- package/dist/runtime/helpers/themeProvider.js +24 -14
- package/dist/runtime/helpers/typesProvider.js +10 -26
- package/dist/runtime/helpers/uiProvider.d.ts +11 -3
- package/dist/runtime/helpers/uiProvider.js +45 -17
- package/dist/runtime/icons/calendar.svg +1 -0
- package/dist/runtime/icons/clock.svg +1 -0
- package/dist/runtime/icons/comment_add.svg +1 -5
- package/dist/runtime/icons/delete.svg +1 -8
- package/dist/runtime/icons/duplicate.svg +1 -12
- package/dist/runtime/icons/edit.svg +1 -8
- package/dist/runtime/icons/reusable.svg +1 -5
- package/dist/runtime/plugins/blokkliDirectives.js +96 -0
- package/dist/runtime/types/index.d.ts +66 -35
- package/package.json +1 -1
- package/dist/runtime/components/Edit/DragInteractions/index.vue +0 -401
- package/dist/runtime/components/Edit/Features/CommandPalette/Palette/Group/index.vue +0 -63
- package/dist/runtime/components/Edit/Features/Selection/AddButtons/AddButtonsField.vue +0 -54
- package/dist/runtime/plugins/blokkliEditable.js +0 -31
- /package/dist/runtime/components/Edit/{DragInteractions → Features/BlockScheduler}/index.vue.d.ts +0 -0
- /package/dist/runtime/plugins/{blokkliEditable.d.ts → blokkliDirectives.d.ts} +0 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
precision highp float;
|
|
2
|
+
|
|
3
|
+
varying vec4 v_quad;
|
|
4
|
+
varying vec2 v_circle_center;
|
|
5
|
+
varying float v_visible;
|
|
6
|
+
varying float v_is_hovered;
|
|
7
|
+
varying float v_scale_fade;
|
|
8
|
+
varying float v_rect_id;
|
|
9
|
+
|
|
10
|
+
uniform float u_dpi;
|
|
11
|
+
uniform vec3 u_color;
|
|
12
|
+
uniform vec3 u_color_hover;
|
|
13
|
+
uniform vec3 u_color_field;
|
|
14
|
+
uniform vec3 u_color_field_hover;
|
|
15
|
+
|
|
16
|
+
void main() {
|
|
17
|
+
// Early exit if not visible or fully faded out
|
|
18
|
+
if (v_visible < 0.5 || v_scale_fade < 0.01) {
|
|
19
|
+
discard;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Calculate distance from pixel to circle center
|
|
23
|
+
vec2 pixelPos = gl_FragCoord.xy;
|
|
24
|
+
float dist = distance(pixelPos, v_circle_center);
|
|
25
|
+
|
|
26
|
+
// Circle radius (includes border)
|
|
27
|
+
float radius = v_quad.z / 2.0;
|
|
28
|
+
|
|
29
|
+
// Border width in pixels (must match vertex shader) - scaled by DPI
|
|
30
|
+
float borderWidth = 4.0 * u_dpi;
|
|
31
|
+
|
|
32
|
+
// Inner circle radius (without border)
|
|
33
|
+
float innerRadius = radius - borderWidth;
|
|
34
|
+
|
|
35
|
+
// Anti-aliased circle
|
|
36
|
+
float edgeSoftness = 1.0 * u_dpi;
|
|
37
|
+
float alpha = 1.0 - smoothstep(radius - edgeSoftness, radius, dist);
|
|
38
|
+
|
|
39
|
+
if (alpha < 0.01) {
|
|
40
|
+
discard;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Calculate position relative to circle center
|
|
44
|
+
vec2 offset = pixelPos - v_circle_center;
|
|
45
|
+
|
|
46
|
+
// Plus dimensions relative to inner circle radius
|
|
47
|
+
// Reduce thickness at low DPI (zoomed out)
|
|
48
|
+
float plusThicknessBase = u_dpi <= 0.5 ? 1.25 : 1.5;
|
|
49
|
+
float plusThickness = plusThicknessBase * u_dpi;
|
|
50
|
+
float plusLength = innerRadius * 0.5; // 50% of inner radius
|
|
51
|
+
float plusSoftness = 0.25 * u_dpi;
|
|
52
|
+
|
|
53
|
+
// Calculate soft plus factor (0 = not plus, 1 = fully plus)
|
|
54
|
+
float horizontalDist = max(abs(offset.y) - plusThickness, 0.0);
|
|
55
|
+
float verticalDist = max(abs(offset.x) - plusThickness, 0.0);
|
|
56
|
+
|
|
57
|
+
float horizontalBarFactor = 0.0;
|
|
58
|
+
if (abs(offset.x) < plusLength) {
|
|
59
|
+
horizontalBarFactor = 1.0 - smoothstep(0.0, plusSoftness, horizontalDist);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
float verticalBarFactor = 0.0;
|
|
63
|
+
if (abs(offset.y) < plusLength) {
|
|
64
|
+
verticalBarFactor = 1.0 - smoothstep(0.0, plusSoftness, verticalDist);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
float plusFactor = max(horizontalBarFactor, verticalBarFactor);
|
|
68
|
+
|
|
69
|
+
// Check if pixel is in the border area (outside the inner circle)
|
|
70
|
+
bool isBorder = dist >= innerRadius && dist <= radius;
|
|
71
|
+
|
|
72
|
+
// Determine base fill color
|
|
73
|
+
vec3 fillColor;
|
|
74
|
+
bool isFieldButton = v_rect_id >= 2.0;
|
|
75
|
+
if (isFieldButton) {
|
|
76
|
+
fillColor = v_is_hovered > 0.5 ? u_color_field_hover : u_color_field;
|
|
77
|
+
} else {
|
|
78
|
+
fillColor = v_is_hovered > 0.5 ? u_color_hover : u_color;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Determine final color
|
|
82
|
+
vec3 finalColor;
|
|
83
|
+
if (isBorder) {
|
|
84
|
+
// Soft border transition - blend from fill color to white over 0.5px
|
|
85
|
+
float transitionRange = 0.5 * u_dpi;
|
|
86
|
+
float borderStart = innerRadius;
|
|
87
|
+
float borderEnd = innerRadius + transitionRange;
|
|
88
|
+
|
|
89
|
+
// Calculate blend factor (0 = fill color, 1 = white)
|
|
90
|
+
float blendFactor = smoothstep(borderStart, borderEnd, dist);
|
|
91
|
+
|
|
92
|
+
// Blend between fill color and white
|
|
93
|
+
finalColor = mix(fillColor, vec3(1.0, 1.0, 1.0), blendFactor);
|
|
94
|
+
} else {
|
|
95
|
+
// Circle background
|
|
96
|
+
finalColor = fillColor;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Apply soft plus on top
|
|
100
|
+
if (plusFactor > 0.0) {
|
|
101
|
+
finalColor = mix(finalColor, vec3(1.0, 1.0, 1.0), plusFactor);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Apply scale fade to alpha
|
|
105
|
+
gl_FragColor = vec4(finalColor, alpha);
|
|
106
|
+
}
|
|
@@ -0,0 +1,440 @@
|
|
|
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
|
+
import { itemEntityType } from "#blokkli-build/config";
|
|
34
|
+
const {
|
|
35
|
+
animation,
|
|
36
|
+
theme,
|
|
37
|
+
dom,
|
|
38
|
+
selection,
|
|
39
|
+
state,
|
|
40
|
+
types,
|
|
41
|
+
ui,
|
|
42
|
+
$t,
|
|
43
|
+
blocks,
|
|
44
|
+
fields
|
|
45
|
+
} = useBlokkli();
|
|
46
|
+
const emptyFieldTooltips = ref([]);
|
|
47
|
+
const currentUuid = ref("");
|
|
48
|
+
const currentBundleLabel = ref("");
|
|
49
|
+
const currentSingleAllowedBundleLabel = ref(null);
|
|
50
|
+
const tooltipData = computed(() => {
|
|
51
|
+
if (hoveredCircle.value < 0) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
const index = hoveredCircle.value;
|
|
55
|
+
const artboardX = circlePositions[index * 2];
|
|
56
|
+
const artboardY = circlePositions[index * 2 + 1];
|
|
57
|
+
if (artboardX === void 0 || artboardY === void 0) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
const scale = ui.artboardScale.value;
|
|
61
|
+
const offset = ui.artboardOffset.value;
|
|
62
|
+
const screenX = artboardX * scale + offset.x;
|
|
63
|
+
const screenY = artboardY * scale + offset.y;
|
|
64
|
+
let transform;
|
|
65
|
+
let position;
|
|
66
|
+
let text;
|
|
67
|
+
let isField = false;
|
|
68
|
+
if (index === 0 || index === 1) {
|
|
69
|
+
const orientation = currentOrientation.value;
|
|
70
|
+
if (currentSingleAllowedBundleLabel.value) {
|
|
71
|
+
if (index === 0) {
|
|
72
|
+
text = $t("addButtonBundleBefore", 'Add "@bundle" before').replace(
|
|
73
|
+
"@bundle",
|
|
74
|
+
currentSingleAllowedBundleLabel.value
|
|
75
|
+
);
|
|
76
|
+
} else {
|
|
77
|
+
text = $t("addButtonBundleAfter", 'Add "@bundle" after').replace(
|
|
78
|
+
"@bundle",
|
|
79
|
+
currentSingleAllowedBundleLabel.value
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
if (index === 0) {
|
|
84
|
+
text = $t("addButtonBeforeBundle", "Add before...");
|
|
85
|
+
} else {
|
|
86
|
+
text = $t("addButtonAfterBundle", "Add after...");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (orientation === "horizontal") {
|
|
90
|
+
if (index === 0) {
|
|
91
|
+
transform = `translate(${TOOLTIP_MARGIN}px, -50%)`;
|
|
92
|
+
position = "right";
|
|
93
|
+
} else {
|
|
94
|
+
transform = `translate(calc(-100% - ${TOOLTIP_MARGIN}px), -50%)`;
|
|
95
|
+
position = "left";
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
if (index === 0) {
|
|
99
|
+
transform = `translate(-50%, ${TOOLTIP_MARGIN}px)`;
|
|
100
|
+
position = "bottom";
|
|
101
|
+
} else {
|
|
102
|
+
transform = `translate(-50%, calc(-100% - ${TOOLTIP_MARGIN}px))`;
|
|
103
|
+
position = "top";
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
transform = `translate(-50%, calc(-100% - ${TOOLTIP_MARGIN}px))`;
|
|
108
|
+
position = "top";
|
|
109
|
+
isField = true;
|
|
110
|
+
const fieldIndex = index - 2;
|
|
111
|
+
text = emptyFieldTooltips.value[fieldIndex] || "Add to field";
|
|
112
|
+
}
|
|
113
|
+
return { x: screenX, y: screenY, transform, position, text, isField };
|
|
114
|
+
});
|
|
115
|
+
const emit = defineEmits(["toggle", "toggleField"]);
|
|
116
|
+
const gl = animation.gl();
|
|
117
|
+
const programInfo = gl ? animation.registerProgram("add-buttons", gl, [vs, fs]) : null;
|
|
118
|
+
const MAX_CIRCLES = 10;
|
|
119
|
+
const BUTTON_RADIUS = 12;
|
|
120
|
+
const TOOLTIP_MARGIN = 20;
|
|
121
|
+
let bufferInfo = null;
|
|
122
|
+
if (gl) {
|
|
123
|
+
class CircleBufferCollector extends RectangleBufferCollector {
|
|
124
|
+
}
|
|
125
|
+
const collector = new CircleBufferCollector(gl);
|
|
126
|
+
for (let i = 0; i < MAX_CIRCLES; i++) {
|
|
127
|
+
collector.addRectangle(
|
|
128
|
+
{
|
|
129
|
+
id: `circle-${i}`,
|
|
130
|
+
x: 0,
|
|
131
|
+
y: 0,
|
|
132
|
+
width: 40,
|
|
133
|
+
height: 40
|
|
134
|
+
},
|
|
135
|
+
i
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
bufferInfo = collector.createBufferInfo();
|
|
139
|
+
}
|
|
140
|
+
const circlePositions = new Float32Array(MAX_CIRCLES * 2);
|
|
141
|
+
const circleVisible = new Float32Array(MAX_CIRCLES);
|
|
142
|
+
const hoveredCircle = ref(-1);
|
|
143
|
+
const color = computed(() => {
|
|
144
|
+
return toShaderColor(theme.accent.value[600]);
|
|
145
|
+
});
|
|
146
|
+
const colorHover = computed(() => {
|
|
147
|
+
return toShaderColor(theme.accent.value[500]);
|
|
148
|
+
});
|
|
149
|
+
const colorField = computed(() => {
|
|
150
|
+
return toShaderColor(theme.accent.value[400]);
|
|
151
|
+
});
|
|
152
|
+
const colorFieldHover = computed(() => {
|
|
153
|
+
return toShaderColor(theme.accent.value[300]);
|
|
154
|
+
});
|
|
155
|
+
const orientationCache = /* @__PURE__ */ new Map();
|
|
156
|
+
const currentOrientation = ref("horizontal");
|
|
157
|
+
const blockStateCache = /* @__PURE__ */ new Map();
|
|
158
|
+
function getOrientationForUuid(uuid) {
|
|
159
|
+
let cached = orientationCache.get(uuid);
|
|
160
|
+
if (!cached) {
|
|
161
|
+
const item = blocks.getBlock(uuid);
|
|
162
|
+
if (item) {
|
|
163
|
+
const field = fields.find(item.host.uuid, item.host.fieldName);
|
|
164
|
+
if (field) {
|
|
165
|
+
cached = getChildrenOrientation(field.element);
|
|
166
|
+
orientationCache.set(uuid, cached);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return cached || "horizontal";
|
|
171
|
+
}
|
|
172
|
+
function getBlockState(uuid) {
|
|
173
|
+
let cached = blockStateCache.get(uuid);
|
|
174
|
+
if (!cached) {
|
|
175
|
+
let canShowBeforeAfter = false;
|
|
176
|
+
let singleAllowedBundleLabel = null;
|
|
177
|
+
const block = blocks.getBlock(uuid);
|
|
178
|
+
if (!block) {
|
|
179
|
+
return {
|
|
180
|
+
canShowBeforeAfter: false,
|
|
181
|
+
emptyFieldKeys: [],
|
|
182
|
+
emptyFieldTooltips: [],
|
|
183
|
+
bundleLabel: "",
|
|
184
|
+
singleAllowedBundleLabel: null
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
if (block) {
|
|
188
|
+
const field = fields.find(block.host.uuid, block.host.fieldName);
|
|
189
|
+
if (!field) {
|
|
190
|
+
return {
|
|
191
|
+
canShowBeforeAfter: false,
|
|
192
|
+
emptyFieldKeys: [],
|
|
193
|
+
emptyFieldTooltips: [],
|
|
194
|
+
bundleLabel: "",
|
|
195
|
+
singleAllowedBundleLabel: null
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (field) {
|
|
199
|
+
const fieldChildren = [...field.element.children];
|
|
200
|
+
const currentCount = state.getFieldBlockCount(field.key);
|
|
201
|
+
canShowBeforeAfter = determineCanAddChildren(
|
|
202
|
+
field,
|
|
203
|
+
fieldChildren,
|
|
204
|
+
[],
|
|
205
|
+
// Not moving any blocks, adding a new one
|
|
206
|
+
currentCount,
|
|
207
|
+
1,
|
|
208
|
+
// Adding 1 new block
|
|
209
|
+
[]
|
|
210
|
+
// Don't know which bundle will be added
|
|
211
|
+
);
|
|
212
|
+
const allowedBundles = field.allowedBundles.filter(
|
|
213
|
+
(bundle) => !isInternalBundle(bundle)
|
|
214
|
+
);
|
|
215
|
+
if (allowedBundles.length === 1) {
|
|
216
|
+
const bundle = allowedBundles[0];
|
|
217
|
+
if (bundle) {
|
|
218
|
+
singleAllowedBundleLabel = types.getBlockBundleDefinition(bundle)?.label || bundle;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const bundleLabel = block ? types.getBlockBundleDefinition(block.bundle)?.label || block.bundle : "";
|
|
224
|
+
const emptyFieldKeys = [];
|
|
225
|
+
const emptyFieldTooltips2 = [];
|
|
226
|
+
if (block) {
|
|
227
|
+
const fieldConfigs = types.fieldConfig.forEntityTypeAndBundle(
|
|
228
|
+
itemEntityType,
|
|
229
|
+
block.bundle
|
|
230
|
+
);
|
|
231
|
+
for (const fieldConfig of fieldConfigs) {
|
|
232
|
+
const key = getFieldKey(uuid, fieldConfig.name);
|
|
233
|
+
const count = state.getFieldBlockCount(key);
|
|
234
|
+
if (count === 0) {
|
|
235
|
+
emptyFieldKeys.push(key);
|
|
236
|
+
const fieldLabel = fieldConfig.label || fieldConfig.name;
|
|
237
|
+
const fieldElement = fields.find(uuid, fieldConfig.name);
|
|
238
|
+
if (fieldElement) {
|
|
239
|
+
const allowedBundles = fieldElement.allowedBundles.filter(
|
|
240
|
+
(bundle) => !isInternalBundle(bundle)
|
|
241
|
+
);
|
|
242
|
+
if (allowedBundles.length === 1) {
|
|
243
|
+
const bundle = allowedBundles[0];
|
|
244
|
+
if (bundle) {
|
|
245
|
+
const singleBundleLabel = types.getBlockBundleDefinition(bundle)?.label || bundle;
|
|
246
|
+
const tooltip = $t(
|
|
247
|
+
"addButtonBundleInsideField",
|
|
248
|
+
'Add "@bundle" inside @parentBundle \xBB @fieldLabel'
|
|
249
|
+
).replace("@bundle", singleBundleLabel).replace("@parentBundle", bundleLabel).replace("@fieldLabel", fieldLabel);
|
|
250
|
+
emptyFieldTooltips2.push(tooltip);
|
|
251
|
+
} else {
|
|
252
|
+
emptyFieldTooltips2.push(
|
|
253
|
+
$t(
|
|
254
|
+
"addButtonInsideField",
|
|
255
|
+
"Add inside @parentBundle \xBB @fieldLabel..."
|
|
256
|
+
).replace("@parentBundle", bundleLabel).replace("@fieldLabel", fieldLabel)
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
} else {
|
|
260
|
+
emptyFieldTooltips2.push(
|
|
261
|
+
$t(
|
|
262
|
+
"addButtonInsideField",
|
|
263
|
+
"Add inside @parentBundle \xBB @fieldLabel..."
|
|
264
|
+
).replace("@parentBundle", bundleLabel).replace("@fieldLabel", fieldLabel)
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
emptyFieldTooltips2.push(
|
|
269
|
+
$t(
|
|
270
|
+
"addButtonInsideField",
|
|
271
|
+
"Add inside @parentBundle \xBB @fieldLabel..."
|
|
272
|
+
).replace("@parentBundle", bundleLabel).replace("@fieldLabel", fieldLabel)
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
cached = {
|
|
279
|
+
canShowBeforeAfter,
|
|
280
|
+
emptyFieldKeys,
|
|
281
|
+
emptyFieldTooltips: emptyFieldTooltips2,
|
|
282
|
+
bundleLabel,
|
|
283
|
+
singleAllowedBundleLabel
|
|
284
|
+
};
|
|
285
|
+
blockStateCache.set(uuid, cached);
|
|
286
|
+
}
|
|
287
|
+
return cached;
|
|
288
|
+
}
|
|
289
|
+
onBlokkliEvent("state:reloaded", () => {
|
|
290
|
+
orientationCache.clear();
|
|
291
|
+
blockStateCache.clear();
|
|
292
|
+
});
|
|
293
|
+
function getCircleAtPoint(x, y) {
|
|
294
|
+
if (ui.artboardScale.value <= 0.4) {
|
|
295
|
+
return -1;
|
|
296
|
+
}
|
|
297
|
+
const effectiveScale = Math.max(ui.artboardScale.value, 0.5);
|
|
298
|
+
const radius = BUTTON_RADIUS / effectiveScale;
|
|
299
|
+
for (let i = 0; i < MAX_CIRCLES; i++) {
|
|
300
|
+
if (circleVisible[i] > 0) {
|
|
301
|
+
const cx = circlePositions[i * 2];
|
|
302
|
+
const cy = circlePositions[i * 2 + 1];
|
|
303
|
+
const dx = x - cx;
|
|
304
|
+
const dy = y - cy;
|
|
305
|
+
const distance = Math.sqrt(dx * dx + dy * dy);
|
|
306
|
+
if (distance <= radius) {
|
|
307
|
+
return i;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return -1;
|
|
312
|
+
}
|
|
313
|
+
if (gl && programInfo && bufferInfo) {
|
|
314
|
+
defineRenderer("add-buttons", {
|
|
315
|
+
zIndex: 1e3,
|
|
316
|
+
enabled: () => {
|
|
317
|
+
if (selection.uuids.value.length !== 1) {
|
|
318
|
+
return false;
|
|
319
|
+
}
|
|
320
|
+
if (ui.openTooltip.value && ui.openTooltip.value !== "add-buttons") {
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
if (ui.hasTransformOverlayOpen.value) {
|
|
324
|
+
return false;
|
|
325
|
+
}
|
|
326
|
+
return true;
|
|
327
|
+
},
|
|
328
|
+
cursor: () => hoveredCircle.value >= 0 ? "pointer" : null,
|
|
329
|
+
onClick: ({ mouseArtboard }) => {
|
|
330
|
+
if (selection.uuids.value.length !== 1) {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
const clickedCircle = getCircleAtPoint(mouseArtboard.x, mouseArtboard.y);
|
|
334
|
+
if (clickedCircle >= 0) {
|
|
335
|
+
const cx = circlePositions[clickedCircle * 2];
|
|
336
|
+
const cy = circlePositions[clickedCircle * 2 + 1];
|
|
337
|
+
if (clickedCircle === 0 || clickedCircle === 1) {
|
|
338
|
+
const position = clickedCircle === 0 ? "before" : "after";
|
|
339
|
+
emit("toggle", {
|
|
340
|
+
position,
|
|
341
|
+
coordinates: { x: cx, y: cy }
|
|
342
|
+
});
|
|
343
|
+
} else {
|
|
344
|
+
const fieldIndex = clickedCircle - 2;
|
|
345
|
+
emit("toggleField", {
|
|
346
|
+
index: fieldIndex,
|
|
347
|
+
coordinates: { x: cx, y: cy }
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
return false;
|
|
353
|
+
},
|
|
354
|
+
render: (ctx) => {
|
|
355
|
+
if (selection.isChangingOptions.value) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
circleVisible.fill(0);
|
|
359
|
+
if (ctx.selectedUuids.length !== 1) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
const uuid = ctx.selectedUuids[0];
|
|
363
|
+
if (!uuid) {
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const blockState = getBlockState(uuid);
|
|
367
|
+
if (blockState.canShowBeforeAfter) {
|
|
368
|
+
const blockRect = dom.getBlockRect(uuid);
|
|
369
|
+
if (!blockRect || blockRect.width === 0) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const orientation = getOrientationForUuid(uuid);
|
|
373
|
+
currentOrientation.value = orientation;
|
|
374
|
+
const BUTTON_SHIFT = 2 / ctx.artboardScale;
|
|
375
|
+
if (orientation === "horizontal") {
|
|
376
|
+
circlePositions[0] = blockRect.x - BUTTON_SHIFT;
|
|
377
|
+
circlePositions[1] = blockRect.y + blockRect.height / 2;
|
|
378
|
+
circleVisible[0] = 1;
|
|
379
|
+
circlePositions[2] = blockRect.x + blockRect.width + BUTTON_SHIFT;
|
|
380
|
+
circlePositions[3] = blockRect.y + blockRect.height / 2;
|
|
381
|
+
circleVisible[1] = 1;
|
|
382
|
+
} else {
|
|
383
|
+
circlePositions[0] = blockRect.x + blockRect.width / 2;
|
|
384
|
+
circlePositions[1] = blockRect.y - BUTTON_SHIFT;
|
|
385
|
+
circleVisible[0] = 1;
|
|
386
|
+
circlePositions[2] = blockRect.x + blockRect.width / 2;
|
|
387
|
+
circlePositions[3] = blockRect.y + blockRect.height + BUTTON_SHIFT;
|
|
388
|
+
circleVisible[1] = 1;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
currentUuid.value = uuid;
|
|
392
|
+
currentBundleLabel.value = blockState.bundleLabel;
|
|
393
|
+
currentSingleAllowedBundleLabel.value = blockState.singleAllowedBundleLabel;
|
|
394
|
+
if (blockState.emptyFieldKeys.length > 0) {
|
|
395
|
+
emptyFieldTooltips.value = blockState.emptyFieldTooltips;
|
|
396
|
+
for (let i = 0; i < blockState.emptyFieldKeys.length && i < 8; i++) {
|
|
397
|
+
const fieldKey = blockState.emptyFieldKeys[i];
|
|
398
|
+
if (!fieldKey) {
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
const fieldRect = dom.getFieldRect(fieldKey);
|
|
402
|
+
if (!fieldRect) {
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
const circleIndex = i + 2;
|
|
406
|
+
circlePositions[circleIndex * 2] = fieldRect.x + fieldRect.width / 2;
|
|
407
|
+
circlePositions[circleIndex * 2 + 1] = fieldRect.y + fieldRect.height / 2;
|
|
408
|
+
circleVisible[circleIndex] = 1;
|
|
409
|
+
}
|
|
410
|
+
} else {
|
|
411
|
+
emptyFieldTooltips.value = [];
|
|
412
|
+
}
|
|
413
|
+
hoveredCircle.value = getCircleAtPoint(
|
|
414
|
+
ctx.mouseArtboard.x,
|
|
415
|
+
ctx.mouseArtboard.y
|
|
416
|
+
);
|
|
417
|
+
gl.useProgram(programInfo.program);
|
|
418
|
+
setUniforms(programInfo, {
|
|
419
|
+
u_circle_positions: circlePositions,
|
|
420
|
+
u_circle_visible: circleVisible,
|
|
421
|
+
u_color: color.value,
|
|
422
|
+
u_color_hover: colorHover.value,
|
|
423
|
+
u_color_field: colorField.value,
|
|
424
|
+
u_color_field_hover: colorFieldHover.value,
|
|
425
|
+
u_hovered_circle: hoveredCircle.value,
|
|
426
|
+
u_radius: BUTTON_RADIUS
|
|
427
|
+
});
|
|
428
|
+
animation.setSharedUniforms(gl, programInfo);
|
|
429
|
+
setBuffersAndAttributes(gl, programInfo, bufferInfo);
|
|
430
|
+
drawBufferInfo(gl, bufferInfo, gl.TRIANGLES);
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
</script>
|
|
435
|
+
|
|
436
|
+
<script>
|
|
437
|
+
export default {
|
|
438
|
+
name: "AddButtonsRenderer"
|
|
439
|
+
};
|
|
440
|
+
</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
|
+
}
|