srcdev-nuxt-components 5.0.2 → 6.0.0

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.
Files changed (75) hide show
  1. package/README.md +1 -9
  2. package/nuxt.config.ts +5 -2
  3. package/package.json +11 -12
  4. package/assets/styles/extends-layer/srcdev-components/display-prompt-core/index.css +0 -70
  5. package/assets/styles/extends-layer/srcdev-components/index.css +0 -2
  6. package/assets/styles/extends-layer/srcdev-components/themes/_error.css +0 -15
  7. package/assets/styles/extends-layer/srcdev-components/themes/_info.css +0 -15
  8. package/assets/styles/extends-layer/srcdev-components/themes/_success.css +0 -15
  9. package/assets/styles/extends-layer/srcdev-components/themes/_warning.css +0 -15
  10. package/assets/styles/extends-layer/srcdev-components/themes/index.css +0 -4
  11. package/assets/styles/main.css +0 -2
  12. package/assets/styles/setup/_head.css +0 -5
  13. package/assets/styles/setup/a11y/_utils.css +0 -20
  14. package/assets/styles/setup/a11y/_variables.css +0 -10
  15. package/assets/styles/setup/a11y/index.css +0 -2
  16. package/assets/styles/setup/index.css +0 -5
  17. package/assets/styles/setup/typography/index.css +0 -2
  18. package/assets/styles/setup/typography/utility-classes/_generic-font-classes.css +0 -192
  19. package/assets/styles/setup/typography/utility-classes/_generic-font-variation-settings.css +0 -29
  20. package/assets/styles/setup/typography/utility-classes/_generic-font-weights.css +0 -41
  21. package/assets/styles/setup/typography/utility-classes/index.css +0 -3
  22. package/assets/styles/setup/typography/vars/_reponsive-font-sizes.css +0 -10
  23. package/assets/styles/setup/typography/vars/index.css +0 -1
  24. package/assets/styles/setup/utility-classes/_margin-helpers.css +0 -334
  25. package/assets/styles/setup/utility-classes/_padding-helpers.css +0 -308
  26. package/assets/styles/setup/utility-classes/_page.css +0 -50
  27. package/assets/styles/setup/utility-classes/index.css +0 -3
  28. package/assets/styles/setup/variables/colors/_blue.css +0 -15
  29. package/assets/styles/setup/variables/colors/_gray.css +0 -16
  30. package/assets/styles/setup/variables/colors/_green.css +0 -15
  31. package/assets/styles/setup/variables/colors/_orange.css +0 -15
  32. package/assets/styles/setup/variables/colors/_red.css +0 -15
  33. package/assets/styles/setup/variables/colors/_yellow.css +0 -15
  34. package/assets/styles/setup/variables/colors/index.css +0 -6
  35. package/assets/styles/setup/variables/index.css +0 -1
  36. package/components/accordian/AccordianCore.vue +0 -46
  37. package/components/animated-svg-text/AnimatedSvgText.vue +0 -87
  38. package/components/canvas-switcher/CanvasSwitcher.vue +0 -77
  39. package/components/carousel-basic/CarouselBasic.vue +0 -291
  40. package/components/carousel-basic/CarouselFlip.vue +0 -461
  41. package/components/carousel-basic/CarouselInfinite.vue +0 -325
  42. package/components/clip-element/ClipElement.vue +0 -73
  43. package/components/clipped-panels/ClippedPanel.vue +0 -73
  44. package/components/container-glow/ContainerGlowCore.vue +0 -211
  45. package/components/content-grid/ContentGrid.vue +0 -85
  46. package/components/deep-expanding-menu/DeepExpandingMenu.vue +0 -214
  47. package/components/deep-expanding-menu/DeepExpandingMenuOld.vue +0 -218
  48. package/components/display-banner/DisplayBanner.vue +0 -63
  49. package/components/display-details/DisplayDetailsCore.vue +0 -301
  50. package/components/display-dialog/DisplayDialogCore.vue +0 -255
  51. package/components/display-dialog/variants/DisplayDialogConfirm.vue +0 -45
  52. package/components/display-dialog/variants/DisplayDialogScrollableContent.vue +0 -49
  53. package/components/display-grid/DisplayGridCore.vue +0 -22
  54. package/components/display-prompt/DisplayPromptCore.vue +0 -187
  55. package/components/display-prompt/variants/DisplayPromptError.vue +0 -53
  56. package/components/expanding-panel/ExpandingPanel.vue +0 -124
  57. package/components/image-galleries/SliderGallery.vue +0 -784
  58. package/components/layout-grids/LayoutGridA.vue +0 -103
  59. package/components/layout-grids/LayoutGridB.vue +0 -132
  60. package/components/layout-row/LayoutRow.vue +0 -165
  61. package/components/masonry-grid/MasonryGrid.vue +0 -62
  62. package/components/masonry-grid-ordered/MasonryGridOrdered.vue +0 -158
  63. package/components/masonry-grid-sorted/MasonryGridSorted.vue +0 -115
  64. package/components/pop-over/PopOver.vue +0 -88
  65. package/components/responsive-header/NavigationItems.vue +0 -169
  66. package/components/responsive-header/ResponsiveHeader.vue +0 -686
  67. package/components/rotating-carousel/RotatingCarouselImage.vue +0 -200
  68. package/components/skip-links/SkipLinks.vue +0 -92
  69. package/components/tabs/TabsCore.vue +0 -277
  70. package/composables/useDialogControls.ts +0 -44
  71. package/composables/useStyleClassPassthrough.ts +0 -35
  72. package/composables/useTabs.ts +0 -201
  73. package/types/gallery-data.ts +0 -13
  74. package/types/responsiveHeader.ts +0 -38
  75. package/types/types.carousel-basic.ts +0 -19
@@ -1,325 +0,0 @@
1
- <template>
2
- <section class="carousel-infinite" :class="[elementClasses]" ref="carouselWrapperRef" role="region" aria-label="Image carousel">
3
- <!-- Screen reader announcement for current item -->
4
- <div aria-live="polite" aria-atomic="true" class="sr-only">Item {{ currentVisibleIndex + 1 }} of {{ itemCount }}</div>
5
-
6
- <LayoutRow tag="div" variant="full-width" :style-class-passthrough="['mbe-20']">
7
- <div tabindex="0" class="item-container" :class="{ 'allow-overflow': allowCarouselOverflow }" ref="carouselContainerRef" role="group" aria-label="Carousel items">
8
- <div v-for="(item, index) in carouselDataIds" :key="index" class="item" ref="carouselItems" :aria-current="currentVisibleIndex === index ? 'true' : 'false'">
9
- <slot :name="item"></slot>
10
- </div>
11
- </div>
12
- </LayoutRow>
13
-
14
- <LayoutRow tag="div" variant="full-width" :style-class-passthrough="['mbe-20']">
15
- <div tabindex="0" class="controls-container" ref="controlsContainerRef">
16
- <div class="markers-container">
17
- <ul class="markers-list">
18
- <li v-for="index in itemCount" :key="index" class="markers-item">
19
- <button
20
- @click.prevent="jumpToFrame(index - 1)"
21
- class="btn-marker"
22
- :class="[{ active: currentVisibleIndex === index - 1 }]"
23
- :aria-label="`Jump to item ${Math.floor(index + 1)}`"
24
- ></button>
25
- </li>
26
- </ul>
27
- </div>
28
- <div class="buttons-container">
29
- <button type="button" @click.prevent="actionPrevious()" class="btn-action" aria-label="Go to previous item">
30
- <Icon name="ic:outline-keyboard-arrow-left" class="arrows-icon" />
31
- </button>
32
- <button type="button" @click.prevent="actionNext()" class="btn-action" aria-label="Go to next item">
33
- <Icon name="ic:outline-keyboard-arrow-right" class="arrows-icon" />
34
- </button>
35
- </div>
36
- </div>
37
- </LayoutRow>
38
- </section>
39
- </template>
40
-
41
- <script setup lang="ts">
42
- import { useEventListener, useResizeObserver, useSwipe } from '@vueuse/core';
43
-
44
- const props = defineProps({
45
- carouselDataIds: {
46
- type: Array as PropType<string[]>,
47
- default: () => [],
48
- },
49
- styleClassPassthrough: {
50
- type: Array as PropType<string[]>,
51
- default: () => [],
52
- },
53
- transitionSpeed: {
54
- type: Number,
55
- default: 200,
56
- },
57
- allowCarouselOverflow: {
58
- type: Boolean,
59
- default: false,
60
- },
61
- returnToStart: {
62
- type: Boolean,
63
- default: false,
64
- },
65
- });
66
-
67
- const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
68
-
69
- const carouselWrapperRef = ref<HTMLDivElement | null>(null);
70
- const carouselContainerRef = ref<HTMLDivElement | null>(null);
71
- const carouselItemsRef = useTemplateRef<HTMLDivElement[]>('carouselItems');
72
- const controlsContainerRef = ref<HTMLDivElement | null>(null);
73
- const carouselInitComplete = ref(false);
74
-
75
- const currentIndex = ref(0);
76
- const itemCount = ref(props.carouselDataIds.length);
77
- const transitionSpeedStr = props.transitionSpeed + 'ms';
78
-
79
- const itemWidth = ref(0);
80
- const itemWidthOffsetStr = computed(() => {
81
- return `-${itemWidth.value}px`;
82
- });
83
-
84
- const currentVisibleIndex = ref(0);
85
-
86
- const carouselContainerRefLeftPosition = computed(() => {
87
- return carouselContainerRef.value ? carouselContainerRef.value.getBoundingClientRect().left : 0;
88
- });
89
- const fullScreenOffsset = computed(() => {
90
- return `-${Math.floor(carouselContainerRefLeftPosition.value)}px`;
91
- });
92
- console.log('INIT: carouselContainerRefLeftPosition:', carouselContainerRefLeftPosition.value, 'fullScreenOffsset:', fullScreenOffsset.value);
93
-
94
- const updateItemOrder = (index: number, order: number, zIndex: number = 2) => {
95
- if (carouselItemsRef?.value && carouselItemsRef.value[index]) {
96
- carouselItemsRef.value[index].style.order = order.toString();
97
- carouselItemsRef.value[index].style.zIndex = zIndex.toString();
98
- }
99
- };
100
-
101
- const reorderItems = (direction: 'next' | 'previous' | 'jump' = 'jump') => {
102
- console.log(`Reordering items in direction: ${direction}`);
103
- if (!carouselItemsRef?.value || !carouselInitComplete.value) return;
104
-
105
- // Capture positions before reordering
106
- const beforeRects = carouselItemsRef.value.map((item) => item.getBoundingClientRect());
107
-
108
- // Apply new order and z-index based on direction
109
- let order = 1;
110
-
111
- // For items from currentVisibleIndex to end
112
- for (let i = currentVisibleIndex.value; i < itemCount.value; i++) {
113
- let zIndex = 2; // default normal z-index
114
-
115
- if (i === currentVisibleIndex.value) {
116
- // The item becoming visible
117
- if (direction === 'previous') {
118
- // When going previous, the item moving to first position should go behind
119
- zIndex = 1;
120
- } else {
121
- // Normal case - visible item gets highest z-index
122
- zIndex = 3;
123
- }
124
- }
125
-
126
- updateItemOrder(i, order++, zIndex);
127
- }
128
-
129
- // For items from 0 to currentVisibleIndex
130
- for (let i = 0; i < currentVisibleIndex.value; i++) {
131
- // Items that wrap around get lower z-index to slide behind
132
- const zIndex = 1;
133
- updateItemOrder(i, order++, zIndex);
134
- }
135
- };
136
-
137
- const actionPrevious = () => {
138
- if (!carouselInitComplete.value || !carouselItemsRef?.value) return;
139
-
140
- if (props.returnToStart && currentVisibleIndex.value === 0) {
141
- currentVisibleIndex.value = itemCount.value - 1;
142
- } else {
143
- currentVisibleIndex.value = currentVisibleIndex.value === 0 ? itemCount.value - 1 : currentVisibleIndex.value - 1;
144
- }
145
-
146
- reorderItems('previous');
147
- currentIndex.value = currentVisibleIndex.value;
148
- };
149
-
150
- const actionNext = () => {
151
- if (!carouselInitComplete.value || !carouselItemsRef?.value) return;
152
-
153
- if (props.returnToStart && currentVisibleIndex.value === itemCount.value - 1) {
154
- currentVisibleIndex.value = 0;
155
- } else {
156
- currentVisibleIndex.value = currentVisibleIndex.value === itemCount.value - 1 ? 0 : currentVisibleIndex.value + 1;
157
- }
158
-
159
- reorderItems('next');
160
- currentIndex.value = currentVisibleIndex.value;
161
- };
162
-
163
- const jumpToFrame = (index: number) => {
164
- if (index >= 0 && index < itemCount.value) {
165
- currentVisibleIndex.value = index;
166
- reorderItems('jump');
167
- currentIndex.value = currentVisibleIndex.value;
168
- }
169
- };
170
-
171
- const checkAndMoveLastItem = () => {
172
- if (props.allowCarouselOverflow) {
173
- const itemsFit = Math.floor(carouselContainerRefLeftPosition.value / itemWidth.value + 1);
174
- jumpToFrame(itemCount.value - 1);
175
- }
176
- };
177
-
178
- const initialSetup = () => {
179
- if (carouselItemsRef?.value && carouselItemsRef.value.length > 0 && carouselItemsRef.value[0]) {
180
- itemWidth.value = carouselItemsRef.value[0].offsetWidth;
181
-
182
- // Set initial order and z-index for all items
183
- carouselItemsRef.value.forEach((item, index) => {
184
- item.style.order = String(index + 1);
185
- // First item gets higher z-index, others get normal z-index
186
- item.style.zIndex = index === 0 ? '3' : '2';
187
- });
188
- }
189
-
190
- carouselInitComplete.value = true;
191
- checkAndMoveLastItem();
192
- };
193
-
194
- const { direction } = useSwipe(carouselContainerRef, {
195
- passive: false,
196
- onSwipeEnd() {
197
- if (direction.value === 'left') {
198
- actionNext();
199
- } else if (direction.value === 'right') {
200
- actionPrevious();
201
- }
202
- },
203
- });
204
-
205
- useEventListener(carouselContainerRef, 'keydown', (event: KeyboardEvent) => {
206
- if (event.key === 'ArrowLeft') {
207
- actionPrevious();
208
- } else if (event.key === 'ArrowRight') {
209
- actionNext();
210
- }
211
- });
212
-
213
- useEventListener(controlsContainerRef, 'keydown', (event: KeyboardEvent) => {
214
- if (event.key === 'ArrowLeft') {
215
- actionPrevious();
216
- } else if (event.key === 'ArrowRight') {
217
- actionNext();
218
- }
219
- });
220
-
221
- useResizeObserver(carouselWrapperRef, async () => {
222
- initialSetup();
223
- });
224
-
225
- onMounted(() => {
226
- initialSetup();
227
- console.log('onMounted: carouselContainerRefLeftPosition:', carouselContainerRefLeftPosition.value, 'fullScreenOffsset:', fullScreenOffsset.value);
228
- });
229
- </script>
230
-
231
- <style lang="css">
232
- .carousel-infinite {
233
- --_carousel-item-track-gap: 10px;
234
-
235
- display: grid;
236
- grid-template-columns: 1fr;
237
- gap: 10px;
238
-
239
- .sr-only {
240
- position: absolute;
241
- width: 1px;
242
- height: 1px;
243
- padding: 0;
244
- margin: -1px;
245
- overflow: hidden;
246
- clip: rect(0, 0, 0, 0);
247
- white-space: nowrap;
248
- border: 0;
249
- }
250
-
251
- .item-container {
252
- display: flex;
253
- gap: var(--_carousel-item-track-gap);
254
- overflow-x: hidden;
255
- position: relative;
256
-
257
- &.allow-overflow {
258
- overflow-x: initial;
259
-
260
- .item {
261
- translate: calc(v-bind(itemWidthOffsetStr) - var(--_carousel-item-track-gap)) 0;
262
- }
263
- }
264
-
265
- .item {
266
- display: flex;
267
- flex: 0 0 100%;
268
- max-inline-size: 800px;
269
- position: relative;
270
- }
271
- }
272
-
273
- .controls-container {
274
- display: flex;
275
- align-items: center;
276
- justify-content: flex-end;
277
-
278
- .markers-container {
279
- .markers-list {
280
- display: flex;
281
- flex-direction: row;
282
- gap: 10px;
283
- list-style-type: none;
284
- margin: unset;
285
- padding: unset;
286
-
287
- .markers-item {
288
- .btn-marker {
289
- border: none;
290
- outline: none;
291
- box-shadow: none;
292
- cursor: pointer;
293
- transition: background-color v-bind(transitionSpeedStr) linear;
294
-
295
- &.active {
296
- background-color: red;
297
- }
298
- }
299
- }
300
- }
301
- }
302
-
303
- .buttons-container {
304
- display: flex;
305
- align-items: center;
306
- justify-content: end;
307
- gap: 20px;
308
-
309
- .btn-action {
310
- display: flex;
311
- align-items: center;
312
- justify-content: center;
313
-
314
- cursor: pointer;
315
- height: fit-content;
316
-
317
- .arrows-icon {
318
- width: 24px;
319
- height: 24px;
320
- }
321
- }
322
- }
323
- }
324
- }
325
- </style>
@@ -1,73 +0,0 @@
1
- <template>
2
- <div class="clip-element-wrapper" ref="container" :class="elementClasses">
3
- <div class="clipped-element" :style="`--_clip-path: inset(${clipOffset}px 0 0 0)`" ref="clipElement">
4
- <slot name="default"></slot>
5
- </div>
6
- </div>
7
- </template>
8
-
9
- <script lang="ts" setup>
10
-
11
- const props = defineProps({
12
- maxClip: {
13
- type: Number,
14
- default: 100,
15
- },
16
- styleClassPassthrough: {
17
- type: Array as PropType<string[]>,
18
- default: () => [],
19
- },
20
- });
21
-
22
- const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
23
-
24
-
25
- const container = ref(null);
26
- const clipElement = ref<HTMLDivElement | null>(null);
27
- const clipOffset = ref(0);
28
-
29
- const updateClip = () => {
30
-
31
- if (clipElement.value) {
32
-
33
- const topPosition = Math.floor(clipElement.value.getBoundingClientRect().top);
34
-
35
- if (topPosition < props.maxClip && topPosition > 0) {
36
- clipOffset.value = props.maxClip - topPosition;
37
- }
38
- else if (topPosition < 0) {
39
- clipOffset.value = props.maxClip + Math.abs(topPosition);
40
- }
41
- else if (topPosition > props.maxClip) {
42
- clipOffset.value = 0;
43
- }
44
- }
45
- };
46
-
47
- onMounted(() => {
48
-
49
- if (import.meta.client) {
50
- updateClip(); // Initial check
51
- window.addEventListener('scroll', updateClip, { passive: true });
52
- }
53
-
54
- });
55
-
56
- onBeforeUnmount(() => {
57
- window.removeEventListener('scroll', updateClip);
58
- });
59
-
60
-
61
- </script>
62
-
63
- <style lang="css">
64
- .clip-element-wrapper {
65
- position: relative;
66
- overflow: hidden;
67
- }
68
- .clipped-element {
69
- width: 100%;
70
- clip-path: var(--_clip-path);
71
- display: block;
72
- }
73
- </style>
@@ -1,73 +0,0 @@
1
- <template>
2
- <component :is="tag" class="clipped-panel" :class="[variant, elementClasses]">
3
- <slot name="default"></slot>
4
- </component>
5
- </template>
6
-
7
- <script lang="ts">
8
- const TAGS_ALLOWED = <string[]>['div', 'p', 'span', 'section', 'article', 'aside', 'header', 'footer', 'main', 'nav', 'ul', 'ol'];
9
- </script>
10
-
11
- <script setup lang="ts">
12
- const props = defineProps({
13
- tag: {
14
- type: String,
15
- default: 'div',
16
- validator(value: string) {
17
- return TAGS_ALLOWED.includes(value);
18
- },
19
- },
20
- variant: {
21
- type: String,
22
- default: 'square',
23
- validator(value: string) {
24
- return ['circle-cutout', 'rectangle', 'square'].includes(value);
25
- },
26
- },
27
- styleClassPassthrough: {
28
- type: Array as PropType<string[]>,
29
- default: () => [],
30
- },
31
- });
32
-
33
- const { elementClasses, resetElementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
34
-
35
- watch(
36
- () => props.styleClassPassthrough,
37
- () => {
38
- resetElementClasses(props.styleClassPassthrough);
39
- }
40
- );
41
- </script>
42
-
43
- <style lang="css">
44
- .clipped-panel {
45
- --_foreground-color: light-dark(hsl(0, 29%, 3%), hsl(0, 0%, 92%));
46
-
47
- /* Component styles */
48
-
49
- background-color: red;
50
- /* color: var(--_foreground-color); */
51
- outline: 1px solid var(--_foreground-color);
52
- /* box-shadow: 5px 5px 5px 5px white; */
53
-
54
- aspect-ratio: 1;
55
-
56
- &.rectangle {
57
-
58
- --_max-x-position: 300px;
59
- --_curve-radius: 10px;
60
-
61
- clip-path: path('M 10, 50 L 140, 50 A 10, 10, 0, 0, 0 150, 40 L 150, 10 A 10, 10, 0, 0, 1 160, 0 L 290, 0 A 10, 10, 0, 0, 1 300, 10 L 300, 190 A 10, 10, 0, 0, 1 290, 200 L 10, 200 A 10, 10, 0, 0, 1 0, 190 L 0, 60 A 10, 10, 0, 0, 1 10, 50 Z');
62
- width: 300px;
63
- }
64
- &.square {
65
- /* clip-path: path('M 10, 50 L 90, 50 A 10, 10, 0, 0, 0 100, 40 L 100, 10 L 110, 0 L 190, 0 L 200, 10 L 200, 190 L 190, 200 L 10, 200 L 0, 190 L 0, 60 L 10, 50 Z'); */
66
- clip-path: path('M 10, 50 L 90, 50 A 10, 10, 0, 0, 0 100, 40 L 100, 10 A 10, 10, 0, 0, 1 110, 0 L 190, 0 A 10, 10, 0, 0, 1 200, 10 L 200, 190 A 10, 10, 0, 0, 1 190, 200 L 10, 200 A 10, 10, 0, 0, 1 0, 190 L 0, 60 A 10, 10, 0, 0, 1 10, 50 Z');
67
- width: 200px;
68
- }
69
- &.circle-cutout {
70
- clip-path: path('M Z');
71
- }
72
- }
73
- </style>
@@ -1,211 +0,0 @@
1
- <template>
2
- <div class="container-glow-wrapper" :class="elementClasses" ref="containerGlowWrapper">
3
- <component :is="tag" v-for="(item, key) in itemCount" :key="key" class="container-glow-core" ref="containerGlowItem">
4
- <div class="glows"></div>
5
- <slot :name="`container-glow-${key}`"></slot>
6
- </component>
7
- </div>
8
- </template>
9
-
10
- <script setup lang="ts">
11
- interface Config {
12
- proximity: number;
13
- spread: number;
14
- blur: number;
15
- gap: number;
16
- vertical: boolean;
17
- opacity: number;
18
- }
19
-
20
- const props = defineProps({
21
- itemCount: {
22
- type: Number,
23
- required: true,
24
- },
25
- tag: {
26
- type: String as PropType<string>,
27
- default: 'div',
28
- },
29
- styleClassPassthrough: {
30
- type: Array as PropType<string[]>,
31
- default: () => [],
32
- },
33
- config: {
34
- type: Object as PropType<Config>,
35
- default: () => ({
36
- proximity: 40,
37
- spread: 80,
38
- blur: 20,
39
- gap: 32,
40
- vertical: false,
41
- opacity: 0.15,
42
- }),
43
- },
44
- });
45
-
46
- const { elementClasses } = useStyleClassPassthrough(props.styleClassPassthrough);
47
-
48
- const controller = new AbortController();
49
-
50
- const containerGlowWrapper = ref<HTMLElement>();
51
- const containerGlowItem = ref<HTMLElement[]>([]);
52
-
53
- const updateStyles = (event: PointerEvent) => {
54
- // get the angle based on the center point of the card and pointer position
55
- for (const cardElem of containerGlowItem.value) {
56
- // Check the card against the proximity and then start updating
57
- const cardBounds = cardElem.getBoundingClientRect();
58
- // Get distance between pointer and outerbounds of card
59
- if (
60
- event?.x > cardBounds.left - props.config.proximity &&
61
- event?.x < cardBounds.left + cardBounds.width + props.config.proximity &&
62
- event?.y > cardBounds.top - props.config.proximity &&
63
- event?.y < cardBounds.top + cardBounds.height + props.config.proximity
64
- ) {
65
- // If within proximity set the active opacity
66
- cardElem.style.setProperty('--opacity-active', String(1));
67
- } else {
68
- cardElem.style.setProperty('--opacity-active', String(props.config.opacity));
69
- }
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('--start', String(angle + 90));
74
- }
75
- };
76
-
77
- const applyStyles = () => {
78
- containerGlowWrapper.value?.style.setProperty('--gap', String(props.config.gap));
79
- containerGlowWrapper.value?.style.setProperty('--blur', String(props.config.blur));
80
- containerGlowWrapper.value?.style.setProperty('--spread', String(props.config.spread));
81
- containerGlowWrapper.value?.style.setProperty('--direction', props.config.vertical ? 'column' : 'row');
82
- };
83
-
84
- // document.body.addEventListener('pointermove', updateStyles);
85
-
86
- onMounted(() => {
87
- applyStyles();
88
- if (containerGlowWrapper.value) {
89
- document.body.addEventListener('pointermove', updateStyles, {
90
- signal: controller.signal,
91
- });
92
- }
93
- });
94
-
95
- onBeforeUnmount(() => {
96
- return controller.abort();
97
- });
98
- </script>
99
-
100
- <style lang="css">
101
- .container-glow-wrapper {
102
- @property --start {
103
- syntax: '<number>';
104
- inherits: true;
105
- initial-value: 0;
106
- }
107
-
108
- display: flex;
109
- gap: 3.2rem;
110
-
111
- .container-glow-core {
112
- & *,
113
- & *:after,
114
- & *:before {
115
- box-sizing: border-box;
116
- }
117
-
118
- --gradient: conic-gradient(
119
- from 180deg at 50% 70%,
120
- hsla(0, 0%, 98%, 1) 0deg,
121
- #eec32d 72.0000010728836deg,
122
- #ec4b4b 144.0000021457672deg,
123
- #709ab9 216.00000858306885deg,
124
- #4dffbf 288.0000042915344deg,
125
- hsla(0, 0%, 98%, 1) 1turn
126
- );
127
- --opacity-active: 0.15;
128
- --start: 0;
129
-
130
- position: relative;
131
-
132
- height: 100%;
133
- background: light-dark(white, hsl(246 44% 7%));
134
- padding: 2rem;
135
- aspect-ratio: 330 / 400;
136
- border-radius: 12px;
137
- min-width: 280px;
138
- max-width: 280px;
139
- display: flex;
140
- flex-direction: column;
141
- gap: 0.25rem;
142
-
143
- &:is(:hover, :focus-visible) {
144
- z-index: 2;
145
- }
146
-
147
- &::before,
148
- &::after {
149
- content: '';
150
- position: absolute;
151
- inset: 0;
152
- }
153
-
154
- &::before {
155
- pointer-events: none;
156
-
157
- border: 2px solid transparent;
158
- border-radius: 12px;
159
- background: hsl(280 10% 50% / 1);
160
- background-attachment: fixed;
161
- border-radius: 12px;
162
- mask: linear-gradient(#0000, #0000),
163
- conic-gradient(from calc(((var(--start) + (var(--spread) * 0.25)) - (var(--spread) * 1.5)) * 1deg), hsl(0 0% 100% / 0.15) 0deg, white, hsl(0 0% 100% / 0.15) calc(var(--spread) * 2.5deg));
164
- mask-clip: padding-box, border-box;
165
- mask-composite: intersect;
166
- opacity: var(--opacity-active);
167
- transition: opacity 1s;
168
- }
169
-
170
- &::after {
171
- pointer-events: none;
172
-
173
- background: var(--gradient);
174
- background-attachment: fixed;
175
- border-radius: 12px;
176
- opacity: var(--opacity-active, 0);
177
- transition: opacity 1s;
178
- --alpha: 0;
179
- border: 2px solid transparent;
180
- mask: linear-gradient(#0000, #0000), conic-gradient(from calc(((var(--start) + (var(--spread) * 0.25)) - (var(--spread) * 0.5)) * 1deg), #0000 0deg, #fff, #0000 calc(var(--spread) * 0.5deg));
181
- filter: brightness(1.5);
182
- mask-clip: padding-box, border-box;
183
- mask-composite: intersect;
184
- }
185
-
186
- .glows {
187
- pointer-events: none;
188
- position: absolute;
189
- inset: 0;
190
- filter: blur(calc(var(--blur) * 1px));
191
-
192
- &::after,
193
- &::before {
194
- --alpha: 0;
195
- content: '';
196
- background: var(--gradient);
197
- background-attachment: fixed;
198
- position: absolute;
199
- inset: -5px;
200
- border: 10px solid transparent;
201
- border-radius: 12px;
202
- mask: linear-gradient(#0000, #0000), conic-gradient(from calc((var(--start) - (var(--spread) * 0.5)) * 1deg), #000 0deg, #fff, #0000 calc(var(--spread) * 1deg));
203
- mask-composite: intersect;
204
- mask-clip: padding-box, border-box;
205
- opacity: var(--opacity-active);
206
- transition: opacity 1s;
207
- }
208
- }
209
- }
210
- }
211
- </style>