1
1
<template >
2
2
<TabbedLayout >
3
3
<template #preview >
4
- <div class =" relative overflow-y-auto no-scrollbar demo-container" >
4
+ <div class =" relative overflow-y-auto no-scrollbar demo-container" ref = " scrollContainerRef " >
5
5
<GlassSurface
6
6
:key =" key"
7
7
:width =" 360"
22
22
/>
23
23
24
24
<div class =" absolute flex flex-col items-center gap-6 top-0 left-0 right-0" >
25
- <div
26
- class =" absolute translate-y-1/2 top-12 text-4xl font-bold text-[#27FF64] z-0 whitespace-nowrap text-center"
27
- >
25
+ <div class =" absolute translate-y-1/2 top-12 text-4xl font-bold text-[#333] z-0 whitespace-nowrap text-center" >
28
26
Try scrolling.
29
27
</div >
30
28
31
- <!-- Top Spacer -->
32
29
<div class =" h-60 w-full" />
33
30
34
- <!-- Image Blocks -->
35
- <div v-for =" (item, index) in imageBlocks" :key =" index" class =" relative" >
31
+ <div v-for =" (item, index) in imageBlocks" :key =" index" class =" relative py-4" >
36
32
<img :src =" item.src" class =" w-128 rounded-2xl object-cover grayscale-100" />
37
33
<div
38
- class =" absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 font-extrabold text-center leading-[100%] text-[3rem] min-w-72"
34
+ class =" absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 font-extrabold text-center leading-[100%] text-[3rem] min-w-72 mix-blend-overlay text-white "
39
35
>
40
36
{{ item.text }}
41
37
</div >
42
38
</div >
43
39
44
- <!-- Bottom Spacer -->
45
40
<div class =" h-60 w-full" />
46
41
</div >
47
42
</div >
75
70
</template >
76
71
77
72
<script setup lang="ts">
78
- import { ref , watch } from ' vue' ;
73
+ import { ref , watch , onMounted , onUnmounted , useTemplateRef } from ' vue' ;
74
+ import Lenis from ' lenis' ;
79
75
import TabbedLayout from ' ../../components/common/TabbedLayout.vue' ;
80
76
import PropTable from ' ../../components/common/PropTable.vue' ;
81
77
import CliInstallation from ' ../../components/code/CliInstallation.vue' ;
@@ -88,6 +84,10 @@ import { useForceRerender } from '@/composables/useForceRerender';
88
84
89
85
const { rerenderKey : key, forceRerender } = useForceRerender ();
90
86
87
+ const scrollContainerRef = useTemplateRef <HTMLElement >(' scrollContainerRef' );
88
+ let lenis: Lenis | null = null ;
89
+ let rafId: number | null = null ;
90
+
91
91
const borderRadius = ref (50 );
92
92
const backgroundOpacity = ref (0.1 );
93
93
const saturation = ref (1 );
@@ -118,6 +118,49 @@ watch(
118
118
}
119
119
);
120
120
121
+ const initLenis = () => {
122
+ if (! scrollContainerRef .value ) return ;
123
+
124
+ lenis = new Lenis ({
125
+ wrapper: scrollContainerRef .value ,
126
+ content: scrollContainerRef .value .firstElementChild as HTMLElement ,
127
+ duration: 1.2 ,
128
+ easing : (t : number ) => Math .min (1 , 1.001 - Math .pow (2 , - 10 * t )),
129
+ orientation: ' vertical' ,
130
+ gestureOrientation: ' vertical' ,
131
+ smoothWheel: true ,
132
+ wheelMultiplier: 1 ,
133
+ touchMultiplier: 2 ,
134
+ infinite: false
135
+ });
136
+
137
+ const raf = (time : number ) => {
138
+ lenis ?.raf (time );
139
+ rafId = requestAnimationFrame (raf );
140
+ };
141
+
142
+ rafId = requestAnimationFrame (raf );
143
+ };
144
+
145
+ const destroyLenis = () => {
146
+ if (rafId ) {
147
+ cancelAnimationFrame (rafId );
148
+ rafId = null ;
149
+ }
150
+ if (lenis ) {
151
+ lenis .destroy ();
152
+ lenis = null ;
153
+ }
154
+ };
155
+
156
+ onMounted (() => {
157
+ initLenis ();
158
+ });
159
+
160
+ onUnmounted (() => {
161
+ destroyLenis ();
162
+ });
163
+
121
164
const imageBlocks = [
122
165
{
123
166
src: ' https://images.unsplash.com/photo-1500673587002-1d2548cfba1b?q=80&w=1740&auto=format&fit=crop' ,
0 commit comments