srcdev-nuxt-components 6.1.21 → 6.1.23
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/app/components/accordian/AccordianCore.vue +1 -1
- package/app/components/animated-svg-text/AnimatedSvgText.vue +5 -5
- package/app/components/carousel-basic/CarouselBasic.vue +1 -1
- package/app/components/carousel-basic/CarouselFlip.vue +154 -133
- package/app/components/carousel-basic/CarouselInfinite.vue +120 -89
- package/app/components/clip-element/ClipElement.vue +18 -28
- package/app/components/clipped-panels/ClippedPanel.vue +1 -1
- package/app/components/container-glow/ContainerGlowCore.vue +62 -39
- package/app/components/deep-expanding-menu/DeepExpandingMenu.vue +1 -1
- package/app/components/deep-expanding-menu/DeepExpandingMenuOld.vue +1 -1
- package/app/components/display-banner/DisplayBanner.vue +1 -1
- package/app/components/display-card/DisplayCard.vue +1 -1
- package/app/components/display-details/DisplayDetailsCore.vue +1 -1
- package/app/components/display-dialog/DisplayDialogCore.vue +1 -1
- package/app/components/display-dialog/variants/DisplayDialogConfirm.vue +2 -2
- package/app/components/display-dialog/variants/DisplayDialogScrollableContent.vue +2 -2
- package/app/components/display-grid/DisplayGridCore.vue +4 -4
- package/app/components/display-prompt/DisplayPromptCore.vue +1 -1
- package/app/components/display-prompt/variants/DisplayPromptError.vue +1 -1
- package/app/components/display-toast/DisplayToast.vue +1 -1
- package/app/components/expanding-panel/ExpandingPanel.vue +1 -1
- package/app/components/glowing-border/GlowingBorder.vue +1 -1
- package/app/components/image-galleries/SliderGallery.vue +104 -103
- package/app/components/layout-grids/LayoutGridA.vue +5 -5
- package/app/components/layout-grids/LayoutGridB.vue +10 -10
- package/app/components/layout-row/LayoutRow.vue +1 -1
- package/app/components/magnetic-navigation/MagneticNavigation.vue +1 -1
- package/app/components/masonry-grid/MasonryGrid.vue +12 -8
- package/app/components/masonry-grid-ordered/MasonryGridOrdered.vue +1 -1
- package/app/components/masonry-grid-sorted/MasonryGridSorted.vue +26 -21
- package/app/components/parallax/SectionParallax.vue +1 -1
- package/app/components/pop-over/PopOver.vue +4 -4
- package/app/components/responsive-header/NavigationItems.vue +1 -1
- package/app/components/responsive-header/ResponsiveHeader.vue +1 -1
- package/app/components/rotating-carousel/RotatingCarouselImage.vue +1 -1
- package/app/components/tabs/TabsCore.vue +41 -20
- package/app/components/typography/HeaderBlock.vue +40 -0
- package/app/composables/useStyleClassPassthrough.ts +19 -22
- package/package.json +1 -1
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<section
|
|
2
|
+
<section
|
|
3
|
+
class="carousel-infinite"
|
|
4
|
+
:class="[elementClasses]"
|
|
5
|
+
ref="carouselWrapperRef"
|
|
6
|
+
role="region"
|
|
7
|
+
aria-label="Image carousel"
|
|
8
|
+
>
|
|
3
9
|
<!-- Screen reader announcement for current item -->
|
|
4
|
-
<div aria-live="polite" aria-atomic="true" class="sr-only">
|
|
10
|
+
<div aria-live="polite" aria-atomic="true" class="sr-only">
|
|
11
|
+
Item {{ currentVisibleIndex + 1 }} of {{ itemCount }}
|
|
12
|
+
</div>
|
|
5
13
|
|
|
6
14
|
<LayoutRow tag="div" variant="full-width" :style-class-passthrough="['mbe-20']">
|
|
7
|
-
<div
|
|
8
|
-
|
|
15
|
+
<div
|
|
16
|
+
tabindex="0"
|
|
17
|
+
class="item-container"
|
|
18
|
+
:class="{ 'allow-overflow': allowCarouselOverflow }"
|
|
19
|
+
ref="carouselContainerRef"
|
|
20
|
+
role="group"
|
|
21
|
+
aria-label="Carousel items"
|
|
22
|
+
>
|
|
23
|
+
<div
|
|
24
|
+
v-for="(item, index) in carouselDataIds"
|
|
25
|
+
:key="index"
|
|
26
|
+
class="item"
|
|
27
|
+
ref="carouselItems"
|
|
28
|
+
:aria-current="currentVisibleIndex === index ? 'true' : 'false'"
|
|
29
|
+
>
|
|
9
30
|
<slot :name="item"></slot>
|
|
10
31
|
</div>
|
|
11
32
|
</div>
|
|
@@ -39,7 +60,7 @@
|
|
|
39
60
|
</template>
|
|
40
61
|
|
|
41
62
|
<script setup lang="ts">
|
|
42
|
-
import { useEventListener, useResizeObserver, useSwipe } from
|
|
63
|
+
import { useEventListener, useResizeObserver, useSwipe } from "@vueuse/core"
|
|
43
64
|
|
|
44
65
|
const props = defineProps({
|
|
45
66
|
carouselDataIds: {
|
|
@@ -47,7 +68,7 @@ const props = defineProps({
|
|
|
47
68
|
default: () => [],
|
|
48
69
|
},
|
|
49
70
|
styleClassPassthrough: {
|
|
50
|
-
type: Array as PropType<string[]>,
|
|
71
|
+
type: [String, Array] as PropType<string | string[]>,
|
|
51
72
|
default: () => [],
|
|
52
73
|
},
|
|
53
74
|
transitionSpeed: {
|
|
@@ -62,170 +83,180 @@ const props = defineProps({
|
|
|
62
83
|
type: Boolean,
|
|
63
84
|
default: false,
|
|
64
85
|
},
|
|
65
|
-
})
|
|
86
|
+
})
|
|
66
87
|
|
|
67
|
-
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
88
|
+
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
68
89
|
|
|
69
|
-
const carouselWrapperRef = ref<HTMLDivElement | null>(null)
|
|
70
|
-
const carouselContainerRef = ref<HTMLDivElement | null>(null)
|
|
71
|
-
const carouselItemsRef = useTemplateRef<HTMLDivElement[]>(
|
|
72
|
-
const controlsContainerRef = ref<HTMLDivElement | null>(null)
|
|
73
|
-
const carouselInitComplete = ref(false)
|
|
90
|
+
const carouselWrapperRef = ref<HTMLDivElement | null>(null)
|
|
91
|
+
const carouselContainerRef = ref<HTMLDivElement | null>(null)
|
|
92
|
+
const carouselItemsRef = useTemplateRef<HTMLDivElement[]>("carouselItems")
|
|
93
|
+
const controlsContainerRef = ref<HTMLDivElement | null>(null)
|
|
94
|
+
const carouselInitComplete = ref(false)
|
|
74
95
|
|
|
75
|
-
const currentIndex = ref(0)
|
|
76
|
-
const itemCount = ref(props.carouselDataIds.length)
|
|
77
|
-
const transitionSpeedStr = props.transitionSpeed +
|
|
96
|
+
const currentIndex = ref(0)
|
|
97
|
+
const itemCount = ref(props.carouselDataIds.length)
|
|
98
|
+
const transitionSpeedStr = props.transitionSpeed + "ms"
|
|
78
99
|
|
|
79
|
-
const itemWidth = ref(0)
|
|
100
|
+
const itemWidth = ref(0)
|
|
80
101
|
const itemWidthOffsetStr = computed(() => {
|
|
81
|
-
return `-${itemWidth.value}px
|
|
82
|
-
})
|
|
102
|
+
return `-${itemWidth.value}px`
|
|
103
|
+
})
|
|
83
104
|
|
|
84
|
-
const currentVisibleIndex = ref(0)
|
|
105
|
+
const currentVisibleIndex = ref(0)
|
|
85
106
|
|
|
86
107
|
const carouselContainerRefLeftPosition = computed(() => {
|
|
87
|
-
return carouselContainerRef.value ? carouselContainerRef.value.getBoundingClientRect().left : 0
|
|
88
|
-
})
|
|
108
|
+
return carouselContainerRef.value ? carouselContainerRef.value.getBoundingClientRect().left : 0
|
|
109
|
+
})
|
|
89
110
|
const fullScreenOffsset = computed(() => {
|
|
90
|
-
return `-${Math.floor(carouselContainerRefLeftPosition.value)}px
|
|
91
|
-
})
|
|
92
|
-
console.log(
|
|
111
|
+
return `-${Math.floor(carouselContainerRefLeftPosition.value)}px`
|
|
112
|
+
})
|
|
113
|
+
console.log(
|
|
114
|
+
"INIT: carouselContainerRefLeftPosition:",
|
|
115
|
+
carouselContainerRefLeftPosition.value,
|
|
116
|
+
"fullScreenOffsset:",
|
|
117
|
+
fullScreenOffsset.value
|
|
118
|
+
)
|
|
93
119
|
|
|
94
120
|
const updateItemOrder = (index: number, order: number, zIndex: number = 2) => {
|
|
95
121
|
if (carouselItemsRef?.value && carouselItemsRef.value[index]) {
|
|
96
|
-
carouselItemsRef.value[index].style.order = order.toString()
|
|
97
|
-
carouselItemsRef.value[index].style.zIndex = zIndex.toString()
|
|
122
|
+
carouselItemsRef.value[index].style.order = order.toString()
|
|
123
|
+
carouselItemsRef.value[index].style.zIndex = zIndex.toString()
|
|
98
124
|
}
|
|
99
|
-
}
|
|
125
|
+
}
|
|
100
126
|
|
|
101
|
-
const reorderItems = (direction:
|
|
102
|
-
console.log(`Reordering items in direction: ${direction}`)
|
|
103
|
-
if (!carouselItemsRef?.value || !carouselInitComplete.value) return
|
|
127
|
+
const reorderItems = (direction: "next" | "previous" | "jump" = "jump") => {
|
|
128
|
+
console.log(`Reordering items in direction: ${direction}`)
|
|
129
|
+
if (!carouselItemsRef?.value || !carouselInitComplete.value) return
|
|
104
130
|
|
|
105
131
|
// Capture positions before reordering
|
|
106
|
-
const beforeRects = carouselItemsRef.value.map((item) => item.getBoundingClientRect())
|
|
132
|
+
const beforeRects = carouselItemsRef.value.map((item) => item.getBoundingClientRect())
|
|
107
133
|
|
|
108
134
|
// Apply new order and z-index based on direction
|
|
109
|
-
let order = 1
|
|
135
|
+
let order = 1
|
|
110
136
|
|
|
111
137
|
// For items from currentVisibleIndex to end
|
|
112
138
|
for (let i = currentVisibleIndex.value; i < itemCount.value; i++) {
|
|
113
|
-
let zIndex = 2
|
|
139
|
+
let zIndex = 2 // default normal z-index
|
|
114
140
|
|
|
115
141
|
if (i === currentVisibleIndex.value) {
|
|
116
142
|
// The item becoming visible
|
|
117
|
-
if (direction ===
|
|
143
|
+
if (direction === "previous") {
|
|
118
144
|
// When going previous, the item moving to first position should go behind
|
|
119
|
-
zIndex = 1
|
|
145
|
+
zIndex = 1
|
|
120
146
|
} else {
|
|
121
147
|
// Normal case - visible item gets highest z-index
|
|
122
|
-
zIndex = 3
|
|
148
|
+
zIndex = 3
|
|
123
149
|
}
|
|
124
150
|
}
|
|
125
151
|
|
|
126
|
-
updateItemOrder(i, order++, zIndex)
|
|
152
|
+
updateItemOrder(i, order++, zIndex)
|
|
127
153
|
}
|
|
128
154
|
|
|
129
155
|
// For items from 0 to currentVisibleIndex
|
|
130
156
|
for (let i = 0; i < currentVisibleIndex.value; i++) {
|
|
131
157
|
// Items that wrap around get lower z-index to slide behind
|
|
132
|
-
const zIndex = 1
|
|
133
|
-
updateItemOrder(i, order++, zIndex)
|
|
158
|
+
const zIndex = 1
|
|
159
|
+
updateItemOrder(i, order++, zIndex)
|
|
134
160
|
}
|
|
135
|
-
}
|
|
161
|
+
}
|
|
136
162
|
|
|
137
163
|
const actionPrevious = () => {
|
|
138
|
-
if (!carouselInitComplete.value || !carouselItemsRef?.value) return
|
|
164
|
+
if (!carouselInitComplete.value || !carouselItemsRef?.value) return
|
|
139
165
|
|
|
140
166
|
if (props.returnToStart && currentVisibleIndex.value === 0) {
|
|
141
|
-
currentVisibleIndex.value = itemCount.value - 1
|
|
167
|
+
currentVisibleIndex.value = itemCount.value - 1
|
|
142
168
|
} else {
|
|
143
|
-
currentVisibleIndex.value = currentVisibleIndex.value === 0 ? itemCount.value - 1 : currentVisibleIndex.value - 1
|
|
169
|
+
currentVisibleIndex.value = currentVisibleIndex.value === 0 ? itemCount.value - 1 : currentVisibleIndex.value - 1
|
|
144
170
|
}
|
|
145
171
|
|
|
146
|
-
reorderItems(
|
|
147
|
-
currentIndex.value = currentVisibleIndex.value
|
|
148
|
-
}
|
|
172
|
+
reorderItems("previous")
|
|
173
|
+
currentIndex.value = currentVisibleIndex.value
|
|
174
|
+
}
|
|
149
175
|
|
|
150
176
|
const actionNext = () => {
|
|
151
|
-
if (!carouselInitComplete.value || !carouselItemsRef?.value) return
|
|
177
|
+
if (!carouselInitComplete.value || !carouselItemsRef?.value) return
|
|
152
178
|
|
|
153
179
|
if (props.returnToStart && currentVisibleIndex.value === itemCount.value - 1) {
|
|
154
|
-
currentVisibleIndex.value = 0
|
|
180
|
+
currentVisibleIndex.value = 0
|
|
155
181
|
} else {
|
|
156
|
-
currentVisibleIndex.value = currentVisibleIndex.value === itemCount.value - 1 ? 0 : currentVisibleIndex.value + 1
|
|
182
|
+
currentVisibleIndex.value = currentVisibleIndex.value === itemCount.value - 1 ? 0 : currentVisibleIndex.value + 1
|
|
157
183
|
}
|
|
158
184
|
|
|
159
|
-
reorderItems(
|
|
160
|
-
currentIndex.value = currentVisibleIndex.value
|
|
161
|
-
}
|
|
185
|
+
reorderItems("next")
|
|
186
|
+
currentIndex.value = currentVisibleIndex.value
|
|
187
|
+
}
|
|
162
188
|
|
|
163
189
|
const jumpToFrame = (index: number) => {
|
|
164
190
|
if (index >= 0 && index < itemCount.value) {
|
|
165
|
-
currentVisibleIndex.value = index
|
|
166
|
-
reorderItems(
|
|
167
|
-
currentIndex.value = currentVisibleIndex.value
|
|
191
|
+
currentVisibleIndex.value = index
|
|
192
|
+
reorderItems("jump")
|
|
193
|
+
currentIndex.value = currentVisibleIndex.value
|
|
168
194
|
}
|
|
169
|
-
}
|
|
195
|
+
}
|
|
170
196
|
|
|
171
197
|
const checkAndMoveLastItem = () => {
|
|
172
198
|
if (props.allowCarouselOverflow) {
|
|
173
|
-
const itemsFit = Math.floor(carouselContainerRefLeftPosition.value / itemWidth.value + 1)
|
|
174
|
-
jumpToFrame(itemCount.value - 1)
|
|
199
|
+
const itemsFit = Math.floor(carouselContainerRefLeftPosition.value / itemWidth.value + 1)
|
|
200
|
+
jumpToFrame(itemCount.value - 1)
|
|
175
201
|
}
|
|
176
|
-
}
|
|
202
|
+
}
|
|
177
203
|
|
|
178
204
|
const initialSetup = () => {
|
|
179
205
|
if (carouselItemsRef?.value && carouselItemsRef.value.length > 0 && carouselItemsRef.value[0]) {
|
|
180
|
-
itemWidth.value = carouselItemsRef.value[0].offsetWidth
|
|
206
|
+
itemWidth.value = carouselItemsRef.value[0].offsetWidth
|
|
181
207
|
|
|
182
208
|
// Set initial order and z-index for all items
|
|
183
209
|
carouselItemsRef.value.forEach((item, index) => {
|
|
184
|
-
item.style.order = String(index + 1)
|
|
210
|
+
item.style.order = String(index + 1)
|
|
185
211
|
// First item gets higher z-index, others get normal z-index
|
|
186
|
-
item.style.zIndex = index === 0 ?
|
|
187
|
-
})
|
|
212
|
+
item.style.zIndex = index === 0 ? "3" : "2"
|
|
213
|
+
})
|
|
188
214
|
}
|
|
189
215
|
|
|
190
|
-
carouselInitComplete.value = true
|
|
191
|
-
checkAndMoveLastItem()
|
|
192
|
-
}
|
|
216
|
+
carouselInitComplete.value = true
|
|
217
|
+
checkAndMoveLastItem()
|
|
218
|
+
}
|
|
193
219
|
|
|
194
220
|
const { direction } = useSwipe(carouselContainerRef, {
|
|
195
221
|
passive: false,
|
|
196
222
|
onSwipeEnd() {
|
|
197
|
-
if (direction.value ===
|
|
198
|
-
actionNext()
|
|
199
|
-
} else if (direction.value ===
|
|
200
|
-
actionPrevious()
|
|
223
|
+
if (direction.value === "left") {
|
|
224
|
+
actionNext()
|
|
225
|
+
} else if (direction.value === "right") {
|
|
226
|
+
actionPrevious()
|
|
201
227
|
}
|
|
202
228
|
},
|
|
203
|
-
})
|
|
229
|
+
})
|
|
204
230
|
|
|
205
|
-
useEventListener(carouselContainerRef,
|
|
206
|
-
if (event.key ===
|
|
207
|
-
actionPrevious()
|
|
208
|
-
} else if (event.key ===
|
|
209
|
-
actionNext()
|
|
231
|
+
useEventListener(carouselContainerRef, "keydown", (event: KeyboardEvent) => {
|
|
232
|
+
if (event.key === "ArrowLeft") {
|
|
233
|
+
actionPrevious()
|
|
234
|
+
} else if (event.key === "ArrowRight") {
|
|
235
|
+
actionNext()
|
|
210
236
|
}
|
|
211
|
-
})
|
|
237
|
+
})
|
|
212
238
|
|
|
213
|
-
useEventListener(controlsContainerRef,
|
|
214
|
-
if (event.key ===
|
|
215
|
-
actionPrevious()
|
|
216
|
-
} else if (event.key ===
|
|
217
|
-
actionNext()
|
|
239
|
+
useEventListener(controlsContainerRef, "keydown", (event: KeyboardEvent) => {
|
|
240
|
+
if (event.key === "ArrowLeft") {
|
|
241
|
+
actionPrevious()
|
|
242
|
+
} else if (event.key === "ArrowRight") {
|
|
243
|
+
actionNext()
|
|
218
244
|
}
|
|
219
|
-
})
|
|
245
|
+
})
|
|
220
246
|
|
|
221
247
|
useResizeObserver(carouselWrapperRef, async () => {
|
|
222
|
-
initialSetup()
|
|
223
|
-
})
|
|
248
|
+
initialSetup()
|
|
249
|
+
})
|
|
224
250
|
|
|
225
251
|
onMounted(() => {
|
|
226
|
-
initialSetup()
|
|
227
|
-
console.log(
|
|
228
|
-
|
|
252
|
+
initialSetup()
|
|
253
|
+
console.log(
|
|
254
|
+
"onMounted: carouselContainerRefLeftPosition:",
|
|
255
|
+
carouselContainerRefLeftPosition.value,
|
|
256
|
+
"fullScreenOffsset:",
|
|
257
|
+
fullScreenOffsset.value
|
|
258
|
+
)
|
|
259
|
+
})
|
|
229
260
|
</script>
|
|
230
261
|
|
|
231
262
|
<style lang="css">
|
|
@@ -7,57 +7,47 @@
|
|
|
7
7
|
</template>
|
|
8
8
|
|
|
9
9
|
<script lang="ts" setup>
|
|
10
|
-
|
|
11
10
|
const props = defineProps({
|
|
12
11
|
maxClip: {
|
|
13
12
|
type: Number,
|
|
14
13
|
default: 100,
|
|
15
14
|
},
|
|
16
15
|
styleClassPassthrough: {
|
|
17
|
-
type: Array as PropType<string[]>,
|
|
16
|
+
type: [String, Array] as PropType<string | string[]>,
|
|
18
17
|
default: () => [],
|
|
19
18
|
},
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
|
|
19
|
+
})
|
|
23
20
|
|
|
21
|
+
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
24
22
|
|
|
25
|
-
const container = ref(null)
|
|
26
|
-
const clipElement = ref<HTMLDivElement | null>(null)
|
|
27
|
-
const clipOffset = ref(0)
|
|
23
|
+
const container = ref(null)
|
|
24
|
+
const clipElement = ref<HTMLDivElement | null>(null)
|
|
25
|
+
const clipOffset = ref(0)
|
|
28
26
|
|
|
29
27
|
const updateClip = () => {
|
|
30
|
-
|
|
31
28
|
if (clipElement.value) {
|
|
32
|
-
|
|
33
|
-
const topPosition = Math.floor(clipElement.value.getBoundingClientRect().top);
|
|
29
|
+
const topPosition = Math.floor(clipElement.value.getBoundingClientRect().top)
|
|
34
30
|
|
|
35
31
|
if (topPosition < props.maxClip && topPosition > 0) {
|
|
36
|
-
clipOffset.value = props.maxClip - topPosition
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
else if (topPosition > props.maxClip) {
|
|
42
|
-
clipOffset.value = 0;
|
|
32
|
+
clipOffset.value = props.maxClip - topPosition
|
|
33
|
+
} else if (topPosition < 0) {
|
|
34
|
+
clipOffset.value = props.maxClip + Math.abs(topPosition)
|
|
35
|
+
} else if (topPosition > props.maxClip) {
|
|
36
|
+
clipOffset.value = 0
|
|
43
37
|
}
|
|
44
38
|
}
|
|
45
|
-
}
|
|
39
|
+
}
|
|
46
40
|
|
|
47
41
|
onMounted(() => {
|
|
48
|
-
|
|
49
42
|
if (import.meta.client) {
|
|
50
|
-
updateClip()
|
|
51
|
-
window.addEventListener(
|
|
43
|
+
updateClip() // Initial check
|
|
44
|
+
window.addEventListener("scroll", updateClip, { passive: true })
|
|
52
45
|
}
|
|
53
|
-
|
|
54
|
-
});
|
|
46
|
+
})
|
|
55
47
|
|
|
56
48
|
onBeforeUnmount(() => {
|
|
57
|
-
window.removeEventListener(
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
|
|
49
|
+
window.removeEventListener("scroll", updateClip)
|
|
50
|
+
})
|
|
61
51
|
</script>
|
|
62
52
|
|
|
63
53
|
<style lang="css">
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="container-glow-wrapper" :class="elementClasses" ref="containerGlowWrapper">
|
|
3
|
-
<component
|
|
3
|
+
<component
|
|
4
|
+
:is="tag"
|
|
5
|
+
v-for="(item, key) in itemCount"
|
|
6
|
+
:key="key"
|
|
7
|
+
class="container-glow-core"
|
|
8
|
+
ref="containerGlowItem"
|
|
9
|
+
>
|
|
4
10
|
<div class="glows"></div>
|
|
5
11
|
<slot :name="`container-glow-${key}`"></slot>
|
|
6
12
|
</component>
|
|
@@ -9,12 +15,12 @@
|
|
|
9
15
|
|
|
10
16
|
<script setup lang="ts">
|
|
11
17
|
interface Config {
|
|
12
|
-
proximity: number
|
|
13
|
-
spread: number
|
|
14
|
-
blur: number
|
|
15
|
-
gap: number
|
|
16
|
-
vertical: boolean
|
|
17
|
-
opacity: number
|
|
18
|
+
proximity: number
|
|
19
|
+
spread: number
|
|
20
|
+
blur: number
|
|
21
|
+
gap: number
|
|
22
|
+
vertical: boolean
|
|
23
|
+
opacity: number
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
const props = defineProps({
|
|
@@ -24,10 +30,10 @@ const props = defineProps({
|
|
|
24
30
|
},
|
|
25
31
|
tag: {
|
|
26
32
|
type: String as PropType<string>,
|
|
27
|
-
default:
|
|
33
|
+
default: "div",
|
|
28
34
|
},
|
|
29
35
|
styleClassPassthrough: {
|
|
30
|
-
type: Array as PropType<string[]>,
|
|
36
|
+
type: [String, Array] as PropType<string | string[]>,
|
|
31
37
|
default: () => [],
|
|
32
38
|
},
|
|
33
39
|
config: {
|
|
@@ -41,20 +47,20 @@ const props = defineProps({
|
|
|
41
47
|
opacity: 0.15,
|
|
42
48
|
}),
|
|
43
49
|
},
|
|
44
|
-
})
|
|
50
|
+
})
|
|
45
51
|
|
|
46
|
-
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
52
|
+
const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough)
|
|
47
53
|
|
|
48
|
-
const controller = new AbortController()
|
|
54
|
+
const controller = new AbortController()
|
|
49
55
|
|
|
50
|
-
const containerGlowWrapper = ref<HTMLElement>()
|
|
51
|
-
const containerGlowItem = ref<HTMLElement[]>([])
|
|
56
|
+
const containerGlowWrapper = ref<HTMLElement>()
|
|
57
|
+
const containerGlowItem = ref<HTMLElement[]>([])
|
|
52
58
|
|
|
53
59
|
const updateStyles = (event: PointerEvent) => {
|
|
54
60
|
// get the angle based on the center point of the card and pointer position
|
|
55
61
|
for (const cardElem of containerGlowItem.value) {
|
|
56
62
|
// Check the card against the proximity and then start updating
|
|
57
|
-
const cardBounds = cardElem.getBoundingClientRect()
|
|
63
|
+
const cardBounds = cardElem.getBoundingClientRect()
|
|
58
64
|
// Get distance between pointer and outerbounds of card
|
|
59
65
|
if (
|
|
60
66
|
event?.x > cardBounds.left - props.config.proximity &&
|
|
@@ -63,44 +69,44 @@ const updateStyles = (event: PointerEvent) => {
|
|
|
63
69
|
event?.y < cardBounds.top + cardBounds.height + props.config.proximity
|
|
64
70
|
) {
|
|
65
71
|
// If within proximity set the active opacity
|
|
66
|
-
cardElem.style.setProperty(
|
|
72
|
+
cardElem.style.setProperty("--opacity-active", String(1))
|
|
67
73
|
} else {
|
|
68
|
-
cardElem.style.setProperty(
|
|
74
|
+
cardElem.style.setProperty("--opacity-active", String(props.config.opacity))
|
|
69
75
|
}
|
|
70
|
-
const cardCentre = [cardBounds.left + cardBounds.width * 0.5, cardBounds.top + cardBounds.height * 0.5]
|
|
71
|
-
let angle = (Math.atan2(event?.y - cardCentre[1], event?.x - cardCentre[0]) * 180) / Math.PI
|
|
72
|
-
angle = angle < 0 ? angle + 360 : angle
|
|
73
|
-
cardElem.style.setProperty(
|
|
76
|
+
const cardCentre = [cardBounds.left + cardBounds.width * 0.5, cardBounds.top + cardBounds.height * 0.5]
|
|
77
|
+
let angle = (Math.atan2(event?.y - cardCentre[1], event?.x - cardCentre[0]) * 180) / Math.PI
|
|
78
|
+
angle = angle < 0 ? angle + 360 : angle
|
|
79
|
+
cardElem.style.setProperty("--start", String(angle + 90))
|
|
74
80
|
}
|
|
75
|
-
}
|
|
81
|
+
}
|
|
76
82
|
|
|
77
83
|
const applyStyles = () => {
|
|
78
|
-
containerGlowWrapper.value?.style.setProperty(
|
|
79
|
-
containerGlowWrapper.value?.style.setProperty(
|
|
80
|
-
containerGlowWrapper.value?.style.setProperty(
|
|
81
|
-
containerGlowWrapper.value?.style.setProperty(
|
|
82
|
-
}
|
|
84
|
+
containerGlowWrapper.value?.style.setProperty("--gap", String(props.config.gap))
|
|
85
|
+
containerGlowWrapper.value?.style.setProperty("--blur", String(props.config.blur))
|
|
86
|
+
containerGlowWrapper.value?.style.setProperty("--spread", String(props.config.spread))
|
|
87
|
+
containerGlowWrapper.value?.style.setProperty("--direction", props.config.vertical ? "column" : "row")
|
|
88
|
+
}
|
|
83
89
|
|
|
84
90
|
// document.body.addEventListener('pointermove', updateStyles);
|
|
85
91
|
|
|
86
92
|
onMounted(() => {
|
|
87
|
-
applyStyles()
|
|
93
|
+
applyStyles()
|
|
88
94
|
if (containerGlowWrapper.value) {
|
|
89
|
-
document.body.addEventListener(
|
|
95
|
+
document.body.addEventListener("pointermove", updateStyles, {
|
|
90
96
|
signal: controller.signal,
|
|
91
|
-
})
|
|
97
|
+
})
|
|
92
98
|
}
|
|
93
|
-
})
|
|
99
|
+
})
|
|
94
100
|
|
|
95
101
|
onBeforeUnmount(() => {
|
|
96
|
-
return controller.abort()
|
|
97
|
-
})
|
|
102
|
+
return controller.abort()
|
|
103
|
+
})
|
|
98
104
|
</script>
|
|
99
105
|
|
|
100
106
|
<style lang="css">
|
|
101
107
|
.container-glow-wrapper {
|
|
102
108
|
@property --start {
|
|
103
|
-
syntax:
|
|
109
|
+
syntax: "<number>";
|
|
104
110
|
inherits: true;
|
|
105
111
|
initial-value: 0;
|
|
106
112
|
}
|
|
@@ -146,7 +152,7 @@ onBeforeUnmount(() => {
|
|
|
146
152
|
|
|
147
153
|
&::before,
|
|
148
154
|
&::after {
|
|
149
|
-
content:
|
|
155
|
+
content: "";
|
|
150
156
|
position: absolute;
|
|
151
157
|
inset: 0;
|
|
152
158
|
}
|
|
@@ -160,7 +166,12 @@ onBeforeUnmount(() => {
|
|
|
160
166
|
background-attachment: fixed;
|
|
161
167
|
border-radius: 12px;
|
|
162
168
|
mask: linear-gradient(#0000, #0000),
|
|
163
|
-
conic-gradient(
|
|
169
|
+
conic-gradient(
|
|
170
|
+
from calc(((var(--start) + (var(--spread) * 0.25)) - (var(--spread) * 1.5)) * 1deg),
|
|
171
|
+
hsl(0 0% 100% / 0.15) 0deg,
|
|
172
|
+
white,
|
|
173
|
+
hsl(0 0% 100% / 0.15) calc(var(--spread) * 2.5deg)
|
|
174
|
+
);
|
|
164
175
|
mask-clip: padding-box, border-box;
|
|
165
176
|
mask-composite: intersect;
|
|
166
177
|
opacity: var(--opacity-active);
|
|
@@ -177,7 +188,13 @@ onBeforeUnmount(() => {
|
|
|
177
188
|
transition: opacity 1s;
|
|
178
189
|
--alpha: 0;
|
|
179
190
|
border: 2px solid transparent;
|
|
180
|
-
mask: linear-gradient(#0000, #0000),
|
|
191
|
+
mask: linear-gradient(#0000, #0000),
|
|
192
|
+
conic-gradient(
|
|
193
|
+
from calc(((var(--start) + (var(--spread) * 0.25)) - (var(--spread) * 0.5)) * 1deg),
|
|
194
|
+
#0000 0deg,
|
|
195
|
+
#fff,
|
|
196
|
+
#0000 calc(var(--spread) * 0.5deg)
|
|
197
|
+
);
|
|
181
198
|
filter: brightness(1.5);
|
|
182
199
|
mask-clip: padding-box, border-box;
|
|
183
200
|
mask-composite: intersect;
|
|
@@ -192,14 +209,20 @@ onBeforeUnmount(() => {
|
|
|
192
209
|
&::after,
|
|
193
210
|
&::before {
|
|
194
211
|
--alpha: 0;
|
|
195
|
-
content:
|
|
212
|
+
content: "";
|
|
196
213
|
background: var(--gradient);
|
|
197
214
|
background-attachment: fixed;
|
|
198
215
|
position: absolute;
|
|
199
216
|
inset: -5px;
|
|
200
217
|
border: 10px solid transparent;
|
|
201
218
|
border-radius: 12px;
|
|
202
|
-
mask: linear-gradient(#0000, #0000),
|
|
219
|
+
mask: linear-gradient(#0000, #0000),
|
|
220
|
+
conic-gradient(
|
|
221
|
+
from calc((var(--start) - (var(--spread) * 0.5)) * 1deg),
|
|
222
|
+
#000 0deg,
|
|
223
|
+
#fff,
|
|
224
|
+
#0000 calc(var(--spread) * 1deg)
|
|
225
|
+
);
|
|
203
226
|
mask-composite: intersect;
|
|
204
227
|
mask-clip: padding-box, border-box;
|
|
205
228
|
opacity: var(--opacity-active);
|