scroll-slides 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -1,11 +1,367 @@
1
1
  # scroll-slides
2
2
 
3
- ## Install
3
+ English | [简体中文](./README_zh.md)
4
+
5
+ A smooth and customizable scroll-based slide animation component for Vue 3. Create engaging scroll experiences with dynamic scaling, translation, and occlusion effects.
6
+
7
+ ![npm version](https://img.shields.io/npm/v/scroll-slides.svg)
8
+ ![license](https://img.shields.io/npm/l/scroll-slides.svg)
9
+
10
+ ## ✨ Features
11
+
12
+ - 🎯 **Smooth Scroll Animations** - Transform items as they scroll with elegant scaling and translation effects
13
+ - 📱 **Direction Support** - Both vertical and horizontal scrolling modes
14
+ - 🎨 **Highly Customizable** - Fine-tune animation parameters to match your design
15
+ - 🔄 **Dynamic Item Management** - Add or remove items on the fly
16
+ - 📐 **Flexible Templates** - Use generic or per-item slot templates
17
+ - 🚀 **Performance Optimized** - Efficient event handling and DOM updates
18
+ - 💅 **TypeScript Support** - Full type definitions included
19
+ - 🎭 **Occlusion Effects** - Optional lower item clipping for depth perception
20
+
21
+ ## 📦 Installation
4
22
 
5
23
  ```bash
6
24
  npm install scroll-slides
25
+ ```
7
26
 
27
+ ```bash
8
28
  yarn add scroll-slides
29
+ ```
9
30
 
31
+ ```bash
10
32
  pnpm add scroll-slides
11
33
  ```
34
+
35
+ ## 🚀 Quick Start
36
+
37
+ ### Basic Usage
38
+
39
+ ```vue
40
+ <script setup>
41
+ import { ScrollSlide } from 'scroll-slides';
42
+ </script>
43
+
44
+ <template>
45
+ <ScrollSlide
46
+ direction="vertical"
47
+ :item-count="10"
48
+ style="height: 600px; overflow-y: auto;"
49
+ >
50
+ <template #item="{ index }">
51
+ <div class="slide-item">
52
+ Slide {{ index + 1 }}
53
+ </div>
54
+ </template>
55
+ </ScrollSlide>
56
+ </template>
57
+
58
+ <style scoped>
59
+ .slide-item {
60
+ width: 100%;
61
+ height: 100px;
62
+ display: flex;
63
+ align-items: center;
64
+ justify-content: center;
65
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
66
+ border-radius: 15px;
67
+ color: white;
68
+ margin-bottom: 10px;
69
+ }
70
+ </style>
71
+ ```
72
+
73
+ ### Horizontal Scrolling
74
+
75
+ ```vue
76
+ <template>
77
+ <ScrollSlide
78
+ direction="horizontal"
79
+ :item-count="15"
80
+ :scale-start-percent="0.95"
81
+ :translate-factor="50"
82
+ :spacer-enabled="true"
83
+ style="width: 100%; height: 200px; overflow-x: auto;"
84
+ >
85
+ <template #item="{ index }">
86
+ <div class="horizontal-item">
87
+ Item {{ index + 1 }}
88
+ </div>
89
+ </template>
90
+ </ScrollSlide>
91
+ </template>
92
+
93
+ <style scoped>
94
+ .horizontal-item {
95
+ width: 200px;
96
+ height: 120px;
97
+ margin-right: 15px;
98
+ background: #4CAF50;
99
+ border-radius: 10px;
100
+ display: flex;
101
+ justify-content: center;
102
+ align-items: center;
103
+ color: white;
104
+ }
105
+ </style>
106
+ ```
107
+
108
+ ### Independent Templates
109
+
110
+ You can define unique content for each item using indexed slots:
111
+
112
+ ```vue
113
+ <template>
114
+ <ScrollSlide direction="vertical" :item-count="3">
115
+ <template #item-0>
116
+ <div class="custom-item">🌸 First Item</div>
117
+ </template>
118
+
119
+ <template #item-1>
120
+ <div class="custom-item">🎨 Second Item</div>
121
+ </template>
122
+
123
+ <template #item-2>
124
+ <div class="custom-item">🚀 Third Item</div>
125
+ </template>
126
+ </ScrollSlide>
127
+ </template>
128
+ ```
129
+
130
+ ## 📖 API Reference
131
+
132
+ ### Props
133
+
134
+ | Prop | Type | Default | Description |
135
+ |------|------|---------|-------------|
136
+ | `direction` | `'vertical' \| 'horizontal'` | `'vertical'` | Scrolling direction |
137
+ | `itemCount` | `number` | `0` | Total number of items in the list |
138
+ | `scaleRatio` | `number` | `0.7` | Final scale of the item when it slides out (0-1) |
139
+ | `scaleStartPercent` | `number` | `0.8` | Threshold percentage for scaling to start (0-1) |
140
+ | `translateFactor` | `number` | `100` | Adjusts the displacement offset during slide-out |
141
+ | `spacerEnabled` | `boolean` | `false` | Adds a spacer at start to allow first item to scroll out |
142
+ | `occludeLowerItems` | `boolean` | `false` | Applies clip-path to prevent visual overlap |
143
+
144
+ ### Slots
145
+
146
+ #### Default Item Slot
147
+
148
+ Used when no specific item slot is defined:
149
+
150
+ ```vue
151
+ <template #item="{ index }">
152
+ <!-- Your content here -->
153
+ <!-- index: number - The zero-based index of the current item -->
154
+ </template>
155
+ ```
156
+
157
+ #### Indexed Item Slots
158
+
159
+ Define unique content for specific items:
160
+
161
+ ```vue
162
+ <template #item-0>
163
+ <!-- Content for first item -->
164
+ </template>
165
+
166
+ <template #item-1>
167
+ <!-- Content for second item -->
168
+ </template>
169
+ ```
170
+
171
+ **Note:** Indexed slots take priority over the generic `#item` slot.
172
+
173
+ #### Spacer Slot
174
+
175
+ Customize the spacer element (when `spacerEnabled` is `true`):
176
+
177
+ ```vue
178
+ <template #spacer="{ size }">
179
+ <!-- size: number - The calculated size of the spacer in pixels -->
180
+ <div>Custom Spacer Content</div>
181
+ </template>
182
+ ```
183
+
184
+ ## 🎨 Customization Examples
185
+
186
+ ### Subtle Animation
187
+
188
+ ```vue
189
+ <ScrollSlide
190
+ :scale-ratio="0.9"
191
+ :scale-start-percent="0.95"
192
+ :translate-factor="20"
193
+ :item-count="10"
194
+ >
195
+ <template #item="{ index }">
196
+ <!-- Your content -->
197
+ </template>
198
+ </ScrollSlide>
199
+ ```
200
+
201
+ ### Dramatic Effect
202
+
203
+ ```vue
204
+ <ScrollSlide
205
+ :scale-ratio="0.5"
206
+ :scale-start-percent="0.7"
207
+ :translate-factor="150"
208
+ :occlude-lower-items="true"
209
+ :item-count="10"
210
+ >
211
+ <template #item="{ index }">
212
+ <!-- Your content -->
213
+ </template>
214
+ </ScrollSlide>
215
+ ```
216
+
217
+ ### Horizontal Card Carousel
218
+
219
+ ```vue
220
+ <ScrollSlide
221
+ direction="horizontal"
222
+ :item-count="20"
223
+ :scale-ratio="0.85"
224
+ :scale-start-percent="0.9"
225
+ :translate-factor="30"
226
+ :spacer-enabled="true"
227
+ style="width: 100%; height: 250px; overflow-x: auto;"
228
+ >
229
+ <template #item="{ index }">
230
+ <div class="card">
231
+ Card {{ index + 1 }}
232
+ </div>
233
+ </template>
234
+ </ScrollSlide>
235
+ ```
236
+
237
+ ## 🔧 Advanced Usage
238
+
239
+ ### Dynamic Item Count
240
+
241
+ ```vue
242
+ <script setup>
243
+ import { ref } from 'vue';
244
+ import { ScrollSlide } from 'scroll-slides';
245
+
246
+ const items = ref([1, 2, 3, 4, 5]);
247
+
248
+ const addItem = () => {
249
+ items.value.push(items.value.length + 1);
250
+ };
251
+
252
+ const removeItem = () => {
253
+ items.value.pop();
254
+ };
255
+ </script>
256
+
257
+ <template>
258
+ <div>
259
+ <button @click="addItem">Add Item</button>
260
+ <button @click="removeItem">Remove Item</button>
261
+
262
+ <ScrollSlide :item-count="items.length">
263
+ <template #item="{ index }">
264
+ <div>Item {{ items[index] }}</div>
265
+ </template>
266
+ </ScrollSlide>
267
+ </div>
268
+ </template>
269
+ ```
270
+
271
+ ### Responsive Configuration
272
+
273
+ ```vue
274
+ <script setup>
275
+ import { ref, computed, onMounted, onUnmounted } from 'vue';
276
+ import { ScrollSlide } from 'scroll-slides';
277
+
278
+ const windowWidth = ref(window.innerWidth);
279
+
280
+ const direction = computed(() =>
281
+ windowWidth.value < 768 ? 'vertical' : 'horizontal'
282
+ );
283
+
284
+ const updateWidth = () => {
285
+ windowWidth.value = window.innerWidth;
286
+ };
287
+
288
+ onMounted(() => window.addEventListener('resize', updateWidth));
289
+ onUnmounted(() => window.removeEventListener('resize', updateWidth));
290
+ </script>
291
+
292
+ <template>
293
+ <ScrollSlide
294
+ :direction="direction"
295
+ :item-count="10"
296
+ :style="direction === 'vertical'
297
+ ? 'height: 500px; overflow-y: auto;'
298
+ : 'width: 100%; overflow-x: auto;'"
299
+ >
300
+ <template #item="{ index }">
301
+ <!-- Responsive content -->
302
+ </template>
303
+ </ScrollSlide>
304
+ </template>
305
+ ```
306
+
307
+ ## 💡 Tips & Best Practices
308
+
309
+ 1. **Container Styling**: Always set explicit dimensions and overflow properties on the ScrollSlide container:
310
+ ```vue
311
+ <ScrollSlide style="height: 600px; overflow-y: auto;">
312
+ ```
313
+
314
+ 2. **Item Spacing**: Add margins to your item content, not the slot wrapper:
315
+ ```css
316
+ .my-item {
317
+ margin-bottom: 10px; /* for vertical */
318
+ margin-right: 10px; /* for horizontal */
319
+ }
320
+ ```
321
+
322
+ 3. **Performance**: For large lists, consider using virtual scrolling techniques in combination with scroll-slides.
323
+
324
+ 4. **Z-Index**: Items are automatically z-indexed in reverse order (first item on top). Plan your designs accordingly.
325
+
326
+ 5. **Spacer Usage**: Enable `spacerEnabled` when you want the first item to be able to scroll to the center/top of the viewport.
327
+
328
+ ## 🛠️ Development
329
+
330
+ ```bash
331
+ # Clone the repository
332
+ git clone https://github.com/agoudbg/scroll-slides.git
333
+
334
+ # Install dependencies
335
+ pnpm install
336
+
337
+ # Run development server
338
+ pnpm dev
339
+
340
+ # Build library
341
+ pnpm build
342
+
343
+ # Build demo
344
+ pnpm build:demo
345
+ ```
346
+
347
+ ## 📄 License
348
+
349
+ MIT License - see [LICENSE](LICENSE) file for details
350
+
351
+ ## 🤝 Contributing
352
+
353
+ Contributions, issues, and feature requests are welcome! Feel free to check the [issues page](https://github.com/agoudbg/scroll-slides/issues).
354
+
355
+ ## 👤 Author
356
+
357
+ **agoudbg**
358
+ - GitHub: [@agoudbg](https://github.com/agoudbg)
359
+ - Email: agoudbg@gmail.com
360
+
361
+ ## 🌟 Show Your Support
362
+
363
+ Give a ⭐️ if this project helped you!
364
+
365
+ ---
366
+
367
+ Made with ❤️ using Vue 3 and TypeScript
@@ -1,17 +1,3 @@
1
- declare const spacerEnabled: import("vue").Ref<boolean, boolean>;
2
- declare const sliderRef: import("vue").Ref<HTMLElement | null, HTMLElement | null>;
3
- declare const itemStates: {
4
- [key: number]: {
5
- scale: number;
6
- translate: number;
7
- opacity: number;
8
- };
9
- };
10
- declare const isVertical: import("vue").ComputedRef<boolean>;
11
- declare const transformProperty: import("vue").ComputedRef<"translateY" | "translateX">;
12
- declare const itemIndices: import("vue").ComputedRef<number[]>;
13
- declare const spacerSize: import("vue").Ref<number, number>;
14
- declare const __VLS_ctx: InstanceType<__VLS_PickNotAny<typeof __VLS_self, new () => {}>>;
15
1
  declare var __VLS_1: {
16
2
  size: number;
17
3
  }, __VLS_4: `item-${number}`, __VLS_5: {
@@ -19,130 +5,138 @@ declare var __VLS_1: {
19
5
  }, __VLS_7: {
20
6
  index: number;
21
7
  };
22
- type __VLS_Slots = __VLS_PrettifyGlobal<__VLS_OmitStringIndex<typeof __VLS_ctx.$slots> & {
8
+ type __VLS_Slots = {} & {
23
9
  [K in NonNullable<typeof __VLS_4>]?: (props: typeof __VLS_5) => any;
24
10
  } & {
25
11
  spacer?: (props: typeof __VLS_1) => any;
26
12
  } & {
27
13
  item?: (props: typeof __VLS_7) => any;
28
- }>;
29
- declare const __VLS_self: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
14
+ };
15
+ declare const __VLS_component: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
16
+ /**
17
+ * Scrolling direction
18
+ * @default 'vertical'
19
+ * @values 'vertical', 'horizontal'
20
+ */
30
21
  direction: {
31
22
  type: StringConstructor;
32
23
  default: string;
33
24
  validator: (value: string) => boolean;
34
25
  };
26
+ /**
27
+ * Total number of items in the list
28
+ * @default 0
29
+ */
35
30
  itemCount: {
36
31
  type: NumberConstructor;
37
32
  default: number;
38
33
  };
34
+ /**
35
+ * Scaling ratio
36
+ * The final scale of the item when it slides out
37
+ * @default 0.7
38
+ */
39
39
  scaleRatio: {
40
40
  type: NumberConstructor;
41
41
  default: number;
42
42
  };
43
+ /**
44
+ * Threshold percentage for scaling to start
45
+ * Range 0-1, defines where in the viewport the scaling animation begins
46
+ * @default 0.8
47
+ */
43
48
  scaleStartPercent: {
44
49
  type: NumberConstructor;
45
50
  default: number;
46
51
  };
52
+ /**
53
+ * Translation factor
54
+ * Adjusts the displacement offset during the slide-out effect
55
+ * @default 100
56
+ */
47
57
  translateFactor: {
48
58
  type: NumberConstructor;
49
59
  default: number;
50
60
  };
61
+ /**
62
+ * Whether to enable the spacer element
63
+ * If true, adds a spacer at the start to allow the first item to scroll out of view
64
+ * @default false
65
+ */
51
66
  spacerEnabled: {
52
67
  type: BooleanConstructor;
53
68
  default: boolean;
54
69
  };
55
- }>, {
56
- spacerEnabled: typeof spacerEnabled;
57
- sliderRef: typeof sliderRef;
58
- itemStates: typeof itemStates;
59
- isVertical: typeof isVertical;
60
- transformProperty: typeof transformProperty;
61
- itemIndices: typeof itemIndices;
62
- spacerSize: typeof spacerSize;
63
- }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
64
- direction: {
65
- type: StringConstructor;
66
- default: string;
67
- validator: (value: string) => boolean;
68
- };
69
- itemCount: {
70
- type: NumberConstructor;
71
- default: number;
72
- };
73
- scaleRatio: {
74
- type: NumberConstructor;
75
- default: number;
76
- };
77
- scaleStartPercent: {
78
- type: NumberConstructor;
79
- default: number;
80
- };
81
- translateFactor: {
82
- type: NumberConstructor;
83
- default: number;
84
- };
85
- spacerEnabled: {
70
+ /**
71
+ * Whether to occlude lower items
72
+ * If true, applies a clip-path to prevent visual overlap between scaled items
73
+ * @default false
74
+ */
75
+ occludeLowerItems: {
86
76
  type: BooleanConstructor;
87
77
  default: boolean;
88
78
  };
89
- }>> & Readonly<{}>, {
90
- direction: string;
91
- itemCount: number;
92
- scaleRatio: number;
93
- scaleStartPercent: number;
94
- translateFactor: number;
95
- spacerEnabled: boolean;
96
- }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
97
- declare const __VLS_component: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
79
+ }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
80
+ /**
81
+ * Scrolling direction
82
+ * @default 'vertical'
83
+ * @values 'vertical', 'horizontal'
84
+ */
98
85
  direction: {
99
86
  type: StringConstructor;
100
87
  default: string;
101
88
  validator: (value: string) => boolean;
102
89
  };
90
+ /**
91
+ * Total number of items in the list
92
+ * @default 0
93
+ */
103
94
  itemCount: {
104
95
  type: NumberConstructor;
105
96
  default: number;
106
97
  };
98
+ /**
99
+ * Scaling ratio
100
+ * The final scale of the item when it slides out
101
+ * @default 0.7
102
+ */
107
103
  scaleRatio: {
108
104
  type: NumberConstructor;
109
105
  default: number;
110
106
  };
107
+ /**
108
+ * Threshold percentage for scaling to start
109
+ * Range 0-1, defines where in the viewport the scaling animation begins
110
+ * @default 0.8
111
+ */
111
112
  scaleStartPercent: {
112
113
  type: NumberConstructor;
113
114
  default: number;
114
115
  };
116
+ /**
117
+ * Translation factor
118
+ * Adjusts the displacement offset during the slide-out effect
119
+ * @default 100
120
+ */
115
121
  translateFactor: {
116
122
  type: NumberConstructor;
117
123
  default: number;
118
124
  };
125
+ /**
126
+ * Whether to enable the spacer element
127
+ * If true, adds a spacer at the start to allow the first item to scroll out of view
128
+ * @default false
129
+ */
119
130
  spacerEnabled: {
120
131
  type: BooleanConstructor;
121
132
  default: boolean;
122
133
  };
123
- }>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
124
- direction: {
125
- type: StringConstructor;
126
- default: string;
127
- validator: (value: string) => boolean;
128
- };
129
- itemCount: {
130
- type: NumberConstructor;
131
- default: number;
132
- };
133
- scaleRatio: {
134
- type: NumberConstructor;
135
- default: number;
136
- };
137
- scaleStartPercent: {
138
- type: NumberConstructor;
139
- default: number;
140
- };
141
- translateFactor: {
142
- type: NumberConstructor;
143
- default: number;
144
- };
145
- spacerEnabled: {
134
+ /**
135
+ * Whether to occlude lower items
136
+ * If true, applies a clip-path to prevent visual overlap between scaled items
137
+ * @default false
138
+ */
139
+ occludeLowerItems: {
146
140
  type: BooleanConstructor;
147
141
  default: boolean;
148
142
  };
@@ -153,6 +147,7 @@ declare const __VLS_component: import("vue").DefineComponent<import("vue").Extra
153
147
  scaleStartPercent: number;
154
148
  translateFactor: number;
155
149
  spacerEnabled: boolean;
150
+ occludeLowerItems: boolean;
156
151
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
157
152
  declare const _default: __VLS_WithSlots<typeof __VLS_component, __VLS_Slots>;
158
153
  export default _default;
@@ -1 +1 @@
1
- .slider[data-v-2ecb83b3]{position:relative;width:100%;height:100%;overflow-y:auto;overflow-x:hidden;box-sizing:border-box}.slider.horizontal[data-v-2ecb83b3]{display:flex;align-items:center;overflow-x:auto;overflow-y:hidden;white-space:nowrap}.slider-item[data-v-2ecb83b3]{position:relative}.slider-item .slider-slot[data-v-2ecb83b3]{position:relative;transition:transform .04s}.horizontal .slider-item[data-v-2ecb83b3]{display:inline-block;vertical-align:middle;transform-origin:center right}.slider-spacer[data-v-2ecb83b3]{width:100%;height:100%;pointer-events:none}
1
+ .slider[data-v-30dc45e5]{position:relative;width:100%;height:100%;overflow-y:auto;overflow-x:hidden;box-sizing:border-box}.slider.horizontal[data-v-30dc45e5]{display:flex;align-items:center;overflow-x:auto;overflow-y:hidden;white-space:nowrap}.slider-item[data-v-30dc45e5]{position:relative}.slider-item .slider-slot[data-v-30dc45e5]{position:relative;transition:transform .04s}.horizontal .slider-item[data-v-30dc45e5]{display:inline-block;vertical-align:middle;transform-origin:center right}.slider-spacer[data-v-30dc45e5]{width:100%;height:100%;pointer-events:none}
@@ -1,62 +1,115 @@
1
- import { defineComponent as U, toRefs as j, ref as _, reactive as q, computed as b, watch as L, onMounted as X, onUnmounted as Y, nextTick as D, createElementBlock as h, openBlock as y, normalizeClass as G, createCommentVNode as J, unref as K, normalizeStyle as P, renderSlot as R, Fragment as Q, renderList as Z, createElementVNode as ee } from "vue";
2
- const te = /* @__PURE__ */ U({
1
+ import { defineComponent as te, toRefs as ae, ref as $, reactive as le, computed as I, watch as W, onMounted as oe, nextTick as x, onUnmounted as se, createElementBlock as S, openBlock as P, normalizeClass as ne, createCommentVNode as re, unref as ce, normalizeStyle as L, renderSlot as b, Fragment as ie, renderList as ue, createElementVNode as ve } from "vue";
2
+ const de = /* @__PURE__ */ te({
3
3
  __name: "ScrollSlide",
4
4
  props: {
5
+ /**
6
+ * Scrolling direction
7
+ * @default 'vertical'
8
+ * @values 'vertical', 'horizontal'
9
+ */
5
10
  direction: {
6
11
  type: String,
7
12
  default: "vertical",
8
13
  // 'vertical' or 'horizontal'
9
- validator: (c) => ["vertical", "horizontal"].includes(c)
14
+ validator: (u) => ["vertical", "horizontal"].includes(u)
10
15
  },
16
+ /**
17
+ * Total number of items in the list
18
+ * @default 0
19
+ */
11
20
  itemCount: {
12
21
  type: Number,
13
22
  default: 0
14
23
  },
24
+ /**
25
+ * Scaling ratio
26
+ * The final scale of the item when it slides out
27
+ * @default 0.7
28
+ */
15
29
  scaleRatio: {
16
30
  type: Number,
17
31
  default: 0.7
18
32
  },
33
+ /**
34
+ * Threshold percentage for scaling to start
35
+ * Range 0-1, defines where in the viewport the scaling animation begins
36
+ * @default 0.8
37
+ */
19
38
  scaleStartPercent: {
20
39
  type: Number,
21
40
  default: 0.8
22
41
  },
42
+ /**
43
+ * Translation factor
44
+ * Adjusts the displacement offset during the slide-out effect
45
+ * @default 100
46
+ */
23
47
  translateFactor: {
24
48
  type: Number,
25
49
  default: 100
26
50
  },
51
+ /**
52
+ * Whether to enable the spacer element
53
+ * If true, adds a spacer at the start to allow the first item to scroll out of view
54
+ * @default false
55
+ */
27
56
  spacerEnabled: {
28
57
  type: Boolean,
29
58
  default: !1
59
+ },
60
+ /**
61
+ * Whether to occlude lower items
62
+ * If true, applies a clip-path to prevent visual overlap between scaled items
63
+ * @default false
64
+ */
65
+ occludeLowerItems: {
66
+ type: Boolean,
67
+ default: !1
30
68
  }
31
69
  },
32
- setup(c) {
33
- const n = c, {
34
- direction: m,
35
- itemCount: g,
36
- scaleRatio: S,
37
- scaleStartPercent: N,
38
- translateFactor: B,
39
- spacerEnabled: w
40
- } = j(n), a = _(null), d = _([]), r = q({}), o = b(() => n.direction === "vertical"), I = b(() => o.value ? "translateY" : "translateX"), F = (e, t) => Math.min(Math.max(e / t, 0), 1), x = (e) => e * e * (3 - 2 * e), z = b(() => Array.from({ length: n.itemCount }, (e, t) => t)), s = () => {
41
- A(), k();
42
- }, A = () => {
43
- if (!a.value) return;
44
- const e = a.value, t = e[o.value ? "clientHeight" : "clientWidth"];
45
- d.value.forEach((l, i) => {
46
- const v = l.getBoundingClientRect(), f = o.value ? v.top : v.left, M = e.getBoundingClientRect(), H = f - (o.value ? M.top : M.left), T = Math.min(
47
- Math.max(0, (t - H) / t),
70
+ setup(u) {
71
+ const l = u, {
72
+ direction: y,
73
+ itemCount: z,
74
+ scaleRatio: w,
75
+ scaleStartPercent: q,
76
+ translateFactor: U,
77
+ spacerEnabled: k,
78
+ occludeLowerItems: j
79
+ } = ae(l), o = $(null), g = $([]), r = le({});
80
+ let v = null;
81
+ const s = I(() => l.direction === "vertical"), X = I(() => s.value ? "translateY" : "translateX"), Y = (e, t) => Math.min(Math.max(e / t, 0), 1), D = (e) => e * e * (3 - 2 * e), E = I(() => Array.from({ length: l.itemCount }, (e, t) => t)), n = () => {
82
+ G(), B();
83
+ }, G = () => {
84
+ if (!o.value) return;
85
+ const e = o.value, t = e[s.value ? "clientHeight" : "clientWidth"], a = e[s.value ? "scrollTop" : "scrollLeft"];
86
+ let c = -1 / 0, f = 0;
87
+ g.value.forEach((i, m) => {
88
+ const N = i.getBoundingClientRect(), J = s.value ? N.top : N.left, F = e.getBoundingClientRect(), K = J - (s.value ? F.top : F.left), Q = Math.min(
89
+ Math.max(0, (t - K) / t),
48
90
  1
49
- ), V = F(1 - T - n.scaleStartPercent, 1 - n.scaleStartPercent), C = x(V), W = 1 + (n.scaleRatio - 1) * C, O = C * n.translateFactor;
50
- let p;
51
- const E = Math.min(Math.max(C || 0, 0), 1);
52
- E > 0.6 ? p = 0 : E < 0.4 ? p = 1 : p = (0.6 - E) / 0.2, r[i] = {
53
- scale: W,
54
- translate: O,
55
- opacity: p
91
+ ), Z = Y(1 - Q - l.scaleStartPercent, 1 - l.scaleStartPercent), C = D(Z), p = 1 + (l.scaleRatio - 1) * C, T = C * l.translateFactor;
92
+ let h;
93
+ const R = Math.min(Math.max(C || 0, 0), 1);
94
+ R > 0.6 ? h = 0 : R < 0.4 ? h = 1 : h = (0.6 - R) / 0.2;
95
+ let _;
96
+ const A = s.value ? i.offsetHeight : i.offsetWidth, H = (s.value ? i.offsetTop : i.offsetLeft) - a + A * (0.5 - T / 100 - p / 2), ee = H + A * p;
97
+ if (l.occludeLowerItems && m > 0 && f > 0.05) {
98
+ const O = c - H;
99
+ if (O > 0.5 && p > 0.01) {
100
+ const V = O / p;
101
+ s.value ? _ = `inset(${V}px 0 0 0)` : _ = `inset(0 0 0 ${V}px)`;
102
+ }
103
+ }
104
+ c = ee, f = h, r[m] = {
105
+ scale: p,
106
+ translate: T,
107
+ opacity: h,
108
+ clipPath: _
56
109
  };
57
110
  });
58
- }, $ = () => {
59
- a.value && (d.value = Array.from(a.value.querySelectorAll(".slider-item")), z.value.forEach((e) => {
111
+ }, M = () => {
112
+ o.value && (g.value = Array.from(o.value.querySelectorAll(".slider-item")), E.value.forEach((e) => {
60
113
  r[e] || (r[e] = {
61
114
  scale: 1,
62
115
  translate: 0,
@@ -64,84 +117,88 @@ const te = /* @__PURE__ */ U({
64
117
  });
65
118
  }), Object.keys(r).forEach((e) => {
66
119
  const t = Number(e);
67
- t >= n.itemCount && delete r[t];
68
- }), s());
120
+ t >= l.itemCount && delete r[t];
121
+ }), n());
69
122
  };
70
- L(() => n.itemCount, (e, t) => {
123
+ W(() => l.itemCount, (e, t) => {
71
124
  setTimeout(() => {
72
- $();
125
+ M();
73
126
  }, 0);
74
127
  }, { immediate: !1 });
75
- const u = _(0), k = () => {
76
- if (!a.value) return 0;
77
- const e = a.value[o.value ? "clientHeight" : "clientWidth"];
128
+ const d = $(0), B = () => {
129
+ if (!o.value) return 0;
130
+ const e = o.value[s.value ? "clientHeight" : "clientWidth"];
78
131
  let t = 0;
79
- if (d.value.length > 0) {
80
- const l = d.value[0];
81
- if (l) {
82
- const i = l.getBoundingClientRect();
83
- t = o.value ? i.height : i.width;
132
+ if (g.value.length > 0) {
133
+ const a = g.value[0];
134
+ if (a) {
135
+ const c = a.getBoundingClientRect();
136
+ t = s.value ? c.height : c.width;
84
137
  }
85
138
  }
86
- u.value = Math.max(0, e - t);
139
+ d.value = Math.max(0, e - t);
87
140
  };
88
- return k(), X(() => {
89
- a.value && (a.value.addEventListener("scroll", s), window.addEventListener("resize", s), a.value.addEventListener("touchmove", s, { passive: !0 }), $());
90
- }), Y(() => {
91
- a.value && (a.value.removeEventListener("scroll", s), a.value.removeEventListener("touchmove", s)), window.removeEventListener("resize", s);
92
- }), L([
93
- m,
94
- g,
95
- S,
96
- N,
97
- B,
98
- w
141
+ return B(), oe(() => {
142
+ if (!o.value) return;
143
+ const e = o.value;
144
+ v = new ResizeObserver(() => n()), v.observe(e), e.addEventListener("scroll", n), window.addEventListener("resize", n), e.addEventListener("touchmove", n, { passive: !0 }), M(), x(() => requestAnimationFrame(n));
145
+ }), se(() => {
146
+ v == null || v.disconnect(), v = null, o.value && (o.value.removeEventListener("scroll", n), o.value.removeEventListener("touchmove", n)), window.removeEventListener("resize", n);
147
+ }), W([
148
+ y,
149
+ z,
150
+ w,
151
+ q,
152
+ U,
153
+ k,
154
+ j
99
155
  ], () => {
100
- console.log("Props changed, reinitializing items"), D(() => {
101
- s();
156
+ console.log("Props changed, reinitializing items"), x(() => {
157
+ n();
102
158
  });
103
- }), (e, t) => (y(), h("div", {
104
- class: G(["slider", { horizontal: !o.value }]),
159
+ }), (e, t) => (P(), S("div", {
160
+ class: ne(["slider", { horizontal: !s.value }]),
105
161
  ref_key: "sliderRef",
106
- ref: a
162
+ ref: o
107
163
  }, [
108
- K(w) ? (y(), h("div", {
164
+ ce(k) ? (P(), S("div", {
109
165
  key: 0,
110
166
  class: "slider-spacer",
111
- style: P(o.value ? { height: `${u.value}px`, minHeight: `${u.value}px` } : { width: `${u.value}px`, minWidth: `${u.value}px`, display: "inline-block" })
167
+ style: L(s.value ? { height: `${d.value}px`, minHeight: `${d.value}px` } : { width: `${d.value}px`, minWidth: `${d.value}px`, display: "inline-block" })
112
168
  }, [
113
- R(e.$slots, "spacer", { size: u.value }, void 0, !0)
114
- ], 4)) : J("", !0),
115
- (y(!0), h(Q, null, Z(z.value, (l) => {
116
- var i, v, f;
117
- return y(), h("div", {
118
- key: l,
169
+ b(e.$slots, "spacer", { size: d.value }, void 0, !0)
170
+ ], 4)) : re("", !0),
171
+ (P(!0), S(ie, null, ue(E.value, (a) => {
172
+ var c, f, i, m;
173
+ return P(), S("div", {
174
+ key: a,
119
175
  class: "slider-item",
120
- style: P({
121
- zIndex: z.value.length - l
176
+ style: L({
177
+ zIndex: E.value.length - a
122
178
  })
123
179
  }, [
124
- ee("div", {
180
+ ve("div", {
125
181
  class: "slider-slot",
126
- style: P({
127
- transform: `${I.value}(${-((i = r[l]) == null ? void 0 : i.translate) || 0}%) scale(${((v = r[l]) == null ? void 0 : v.scale) || 1})`,
128
- opacity: (f = r[l]) == null ? void 0 : f.opacity
182
+ style: L({
183
+ transform: `${X.value}(${-((c = r[a]) == null ? void 0 : c.translate) || 0}%) scale(${((f = r[a]) == null ? void 0 : f.scale) || 1})`,
184
+ opacity: (i = r[a]) == null ? void 0 : i.opacity,
185
+ clipPath: (m = r[a]) == null ? void 0 : m.clipPath
129
186
  })
130
187
  }, [
131
- R(e.$slots, `item-${l}`, { index: l }, () => [
132
- R(e.$slots, "item", { index: l }, void 0, !0)
188
+ b(e.$slots, `item-${a}`, { index: a }, () => [
189
+ b(e.$slots, "item", { index: a }, void 0, !0)
133
190
  ], !0)
134
191
  ], 4)
135
192
  ], 4);
136
193
  }), 128))
137
194
  ], 2));
138
195
  }
139
- }), ae = (c, n) => {
140
- const m = c.__vccOpts || c;
141
- for (const [g, S] of n)
142
- m[g] = S;
143
- return m;
144
- }, ne = /* @__PURE__ */ ae(te, [["__scopeId", "data-v-2ecb83b3"]]);
196
+ }), fe = (u, l) => {
197
+ const y = u.__vccOpts || u;
198
+ for (const [z, w] of l)
199
+ y[z] = w;
200
+ return y;
201
+ }, ye = /* @__PURE__ */ fe(de, [["__scopeId", "data-v-30dc45e5"]]);
145
202
  export {
146
- ne as ScrollSlide
203
+ ye as ScrollSlide
147
204
  };
@@ -1 +1 @@
1
- (function(c,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(c=typeof globalThis<"u"?globalThis:c||self,e(c.ScrollSlide={},c.Vue))})(this,function(c,e){"use strict";const w=((m,o)=>{const p=m.__vccOpts||m;for(const[S,g]of o)p[S]=g;return p})(e.defineComponent({__name:"ScrollSlide",props:{direction:{type:String,default:"vertical",validator:m=>["vertical","horizontal"].includes(m)},itemCount:{type:Number,default:0},scaleRatio:{type:Number,default:.7},scaleStartPercent:{type:Number,default:.8},translateFactor:{type:Number,default:100},spacerEnabled:{type:Boolean,default:!1}},setup(m){const o=m,{direction:p,itemCount:S,scaleRatio:g,scaleStartPercent:B,translateFactor:R,spacerEnabled:k}=e.toRefs(o),l=e.ref(null),h=e.ref([]),r=e.reactive({}),i=e.computed(()=>o.direction==="vertical"),$=e.computed(()=>i.value?"translateY":"translateX"),M=(t,n)=>Math.min(Math.max(t/n,0),1),L=t=>t*t*(3-2*t),z=e.computed(()=>Array.from({length:o.itemCount},(t,n)=>n)),s=()=>{N(),C()},N=()=>{if(!l.value)return;const t=l.value,n=t[i.value?"clientHeight":"clientWidth"];h.value.forEach((a,d)=>{const f=a.getBoundingClientRect(),v=i.value?f.top:f.left,P=t.getBoundingClientRect(),I=v-(i.value?P.top:P.left),T=Math.min(Math.max(0,(n-I)/n),1),x=M(1-T-o.scaleStartPercent,1-o.scaleStartPercent),_=L(x),F=1+(o.scaleRatio-1)*_,V=_*o.translateFactor;let y;const E=Math.min(Math.max(_||0,0),1);E>.6?y=0:E<.4?y=1:y=(.6-E)/.2,r[d]={scale:F,translate:V,opacity:y}})},b=()=>{l.value&&(h.value=Array.from(l.value.querySelectorAll(".slider-item")),z.value.forEach(t=>{r[t]||(r[t]={scale:1,translate:0,opacity:1})}),Object.keys(r).forEach(t=>{const n=Number(t);n>=o.itemCount&&delete r[n]}),s())};e.watch(()=>o.itemCount,(t,n)=>{setTimeout(()=>{b()},0)},{immediate:!1});const u=e.ref(0),C=()=>{if(!l.value)return 0;const t=l.value[i.value?"clientHeight":"clientWidth"];let n=0;if(h.value.length>0){const a=h.value[0];if(a){const d=a.getBoundingClientRect();n=i.value?d.height:d.width}}u.value=Math.max(0,t-n)};return C(),e.onMounted(()=>{l.value&&(l.value.addEventListener("scroll",s),window.addEventListener("resize",s),l.value.addEventListener("touchmove",s,{passive:!0}),b())}),e.onUnmounted(()=>{l.value&&(l.value.removeEventListener("scroll",s),l.value.removeEventListener("touchmove",s)),window.removeEventListener("resize",s)}),e.watch([p,S,g,B,R,k],()=>{console.log("Props changed, reinitializing items"),e.nextTick(()=>{s()})}),(t,n)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["slider",{horizontal:!i.value}]),ref_key:"sliderRef",ref:l},[e.unref(k)?(e.openBlock(),e.createElementBlock("div",{key:0,class:"slider-spacer",style:e.normalizeStyle(i.value?{height:`${u.value}px`,minHeight:`${u.value}px`}:{width:`${u.value}px`,minWidth:`${u.value}px`,display:"inline-block"})},[e.renderSlot(t.$slots,"spacer",{size:u.value},void 0,!0)],4)):e.createCommentVNode("",!0),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(z.value,a=>{var d,f,v;return e.openBlock(),e.createElementBlock("div",{key:a,class:"slider-item",style:e.normalizeStyle({zIndex:z.value.length-a})},[e.createElementVNode("div",{class:"slider-slot",style:e.normalizeStyle({transform:`${$.value}(${-((d=r[a])==null?void 0:d.translate)||0}%) scale(${((f=r[a])==null?void 0:f.scale)||1})`,opacity:(v=r[a])==null?void 0:v.opacity})},[e.renderSlot(t.$slots,`item-${a}`,{index:a},()=>[e.renderSlot(t.$slots,"item",{index:a},void 0,!0)],!0)],4)],4)}),128))],2))}}),[["__scopeId","data-v-2ecb83b3"]]);c.ScrollSlide=w,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})});
1
+ (function(f,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],e):(f=typeof globalThis<"u"?globalThis:f||self,e(f.ScrollSlide={},f.Vue))})(this,(function(f,e){"use strict";const F=((u,n)=>{const g=u.__vccOpts||u;for(const[z,E]of n)g[z]=E;return g})(e.defineComponent({__name:"ScrollSlide",props:{direction:{type:String,default:"vertical",validator:u=>["vertical","horizontal"].includes(u)},itemCount:{type:Number,default:0},scaleRatio:{type:Number,default:.7},scaleStartPercent:{type:Number,default:.8},translateFactor:{type:Number,default:100},spacerEnabled:{type:Boolean,default:!1},occludeLowerItems:{type:Boolean,default:!1}},setup(u){const n=u,{direction:g,itemCount:z,scaleRatio:E,scaleStartPercent:O,translateFactor:V,spacerEnabled:B,occludeLowerItems:A}=e.toRefs(n),a=e.ref(null),P=e.ref([]),c=e.reactive({});let m=null;const s=e.computed(()=>n.direction==="vertical"),H=e.computed(()=>s.value?"translateY":"translateX"),W=(t,l)=>Math.min(Math.max(t/l,0),1),j=t=>t*t*(3-2*t),_=e.computed(()=>Array.from({length:n.itemCount},(t,l)=>l)),r=()=>{q(),R()},q=()=>{if(!a.value)return;const t=a.value,l=t[s.value?"clientHeight":"clientWidth"],o=t[s.value?"scrollTop":"scrollLeft"];let i=-1/0,h=0;P.value.forEach((d,v)=>{const $=d.getBoundingClientRect(),U=s.value?$.top:$.left,I=t.getBoundingClientRect(),X=U-(s.value?I.top:I.left),Y=Math.min(Math.max(0,(l-X)/l),1),D=W(1-Y-n.scaleStartPercent,1-n.scaleStartPercent),k=j(D),y=1+(n.scaleRatio-1)*k,L=k*n.translateFactor;let S;const w=Math.min(Math.max(k||0,0),1);w>.6?S=0:w<.4?S=1:S=(.6-w)/.2;let b;const M=s.value?d.offsetHeight:d.offsetWidth,T=(s.value?d.offsetTop:d.offsetLeft)-o+M*(.5-L/100-y/2),G=T+M*y;if(n.occludeLowerItems&&v>0&&h>.05){const N=i-T;if(N>.5&&y>.01){const x=N/y;s.value?b=`inset(${x}px 0 0 0)`:b=`inset(0 0 0 ${x}px)`}}i=G,h=S,c[v]={scale:y,translate:L,opacity:S,clipPath:b}})},C=()=>{a.value&&(P.value=Array.from(a.value.querySelectorAll(".slider-item")),_.value.forEach(t=>{c[t]||(c[t]={scale:1,translate:0,opacity:1})}),Object.keys(c).forEach(t=>{const l=Number(t);l>=n.itemCount&&delete c[l]}),r())};e.watch(()=>n.itemCount,(t,l)=>{setTimeout(()=>{C()},0)},{immediate:!1});const p=e.ref(0),R=()=>{if(!a.value)return 0;const t=a.value[s.value?"clientHeight":"clientWidth"];let l=0;if(P.value.length>0){const o=P.value[0];if(o){const i=o.getBoundingClientRect();l=s.value?i.height:i.width}}p.value=Math.max(0,t-l)};return R(),e.onMounted(()=>{if(!a.value)return;const t=a.value;m=new ResizeObserver(()=>r()),m.observe(t),t.addEventListener("scroll",r),window.addEventListener("resize",r),t.addEventListener("touchmove",r,{passive:!0}),C(),e.nextTick(()=>requestAnimationFrame(r))}),e.onUnmounted(()=>{m==null||m.disconnect(),m=null,a.value&&(a.value.removeEventListener("scroll",r),a.value.removeEventListener("touchmove",r)),window.removeEventListener("resize",r)}),e.watch([g,z,E,O,V,B,A],()=>{console.log("Props changed, reinitializing items"),e.nextTick(()=>{r()})}),(t,l)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["slider",{horizontal:!s.value}]),ref_key:"sliderRef",ref:a},[e.unref(B)?(e.openBlock(),e.createElementBlock("div",{key:0,class:"slider-spacer",style:e.normalizeStyle(s.value?{height:`${p.value}px`,minHeight:`${p.value}px`}:{width:`${p.value}px`,minWidth:`${p.value}px`,display:"inline-block"})},[e.renderSlot(t.$slots,"spacer",{size:p.value},void 0,!0)],4)):e.createCommentVNode("",!0),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(_.value,o=>{var i,h,d,v;return e.openBlock(),e.createElementBlock("div",{key:o,class:"slider-item",style:e.normalizeStyle({zIndex:_.value.length-o})},[e.createElementVNode("div",{class:"slider-slot",style:e.normalizeStyle({transform:`${H.value}(${-((i=c[o])==null?void 0:i.translate)||0}%) scale(${((h=c[o])==null?void 0:h.scale)||1})`,opacity:(d=c[o])==null?void 0:d.opacity,clipPath:(v=c[o])==null?void 0:v.clipPath})},[e.renderSlot(t.$slots,`item-${o}`,{index:o},()=>[e.renderSlot(t.$slots,"item",{index:o},void 0,!0)],!0)],4)],4)}),128))],2))}}),[["__scopeId","data-v-30dc45e5"]]);f.ScrollSlide=F,Object.defineProperty(f,Symbol.toStringTag,{value:"Module"})}));
package/package.json CHANGED
@@ -1,35 +1,42 @@
1
- {
2
- "name": "scroll-slides",
3
- "version": "0.2.0",
4
- "type": "module",
5
- "types": "./dist/index.d.ts",
6
- "files": [
7
- "dist"
8
- ],
9
- "main": "./dist/scroll-slides.umd.cjs",
10
- "module": "./dist/scroll-slides.js",
11
- "author": {
12
- "name": "agoudbg",
13
- "email": "agoudbg@gmail.com",
14
- "url": "https://github.com/agoudbg"
15
- },
16
- "homepage": "https://github.com/agoudbg/scroll-slides",
17
- "scripts": {
18
- "dev": "vite",
19
- "build": "vite build && vue-tsc --emitDeclarationOnly --project tsconfig.app.json",
20
- "build:demo": "vite build --config vite.demo.config.ts",
21
- "types": "vue-tsc --declaration --emitDeclarationOnly --project tsconfig.app.json",
22
- "preview": "vite preview"
23
- },
24
- "dependencies": {
25
- "vue": "^3.5.13"
26
- },
27
- "devDependencies": {
28
- "@types/node": "^22.14.0",
29
- "@vitejs/plugin-vue": "^5.2.1",
30
- "@vue/tsconfig": "^0.7.0",
31
- "typescript": "~5.7.2",
32
- "vite": "^6.2.0",
33
- "vue-tsc": "^2.2.4"
34
- }
1
+ {
2
+ "name": "scroll-slides",
3
+ "version": "0.3.0",
4
+ "type": "module",
5
+ "types": "./dist/index.d.ts",
6
+ "files": [
7
+ "dist"
8
+ ],
9
+ "main": "./dist/scroll-slides.umd.cjs",
10
+ "module": "./dist/scroll-slides.js",
11
+ "author": {
12
+ "name": "agoudbg",
13
+ "email": "agoudbg@gmail.com",
14
+ "url": "https://github.com/agoudbg"
15
+ },
16
+ "license": "MIT",
17
+ "homepage": "https://github.com/agoudbg/scroll-slides",
18
+ "scripts": {
19
+ "dev": "vite",
20
+ "build": "vite build && vue-tsc --emitDeclarationOnly --project tsconfig.app.json",
21
+ "build:demo": "vite build --config vite.demo.config.ts",
22
+ "types": "vue-tsc --declaration --emitDeclarationOnly --project tsconfig.app.json",
23
+ "preview": "vite preview"
24
+ },
25
+ "dependencies": {
26
+ "scroll-slides": "link:..\\..\\..\\AppData\\Local\\pnpm\\global\\5\\node_modules\\scroll-slides",
27
+ "vue": "^3.5.26"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^22.19.7",
31
+ "@vitejs/plugin-vue": "^5.2.4",
32
+ "@vue/tsconfig": "^0.7.0",
33
+ "typescript": "~5.7.3",
34
+ "vite": "^6.4.1",
35
+ "vue-tsc": "^2.2.12"
36
+ },
37
+ "pnpm": {
38
+ "overrides": {
39
+ "scroll-slides": "link:../../../AppData/Local/pnpm/global/5/node_modules/scroll-slides"
40
+ }
41
+ }
35
42
  }
package/dist/vite.svg DELETED
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>