|
5 | 5 | > |
6 | 6 | <section |
7 | 7 | id="landing-base" |
8 | | - class="flex flex-col bg-theme-background-2 z-max text-white items-center justify-between min-h-screen w-full overflow-x-hidden" |
| 8 | + class="relative flex flex-col z-max text-white items-center justify-between min-h-screen w-full overflow-x-hidden" |
9 | 9 | > |
| 10 | + <div class="absolute inset-0 overflow-hidden pointer-events-none z-0"> |
| 11 | + <div |
| 12 | + v-for="col in bookColumns" |
| 13 | + :key="col.id" |
| 14 | + :class="col.responsiveClass" |
| 15 | + class="absolute top-0 flex-col justife- gap-3" |
| 16 | + :style="col.style" |
| 17 | + > |
| 18 | + <div |
| 19 | + v-for="(block, bi) in col.blocks" |
| 20 | + :key="bi" |
| 21 | + class="flex flex-col gap-1.5" |
| 22 | + :style="block.style" |
| 23 | + > |
| 24 | + <div |
| 25 | + v-for="(line, li) in block.lines" |
| 26 | + :key="li" |
| 27 | + class="rounded-full bg-white opacity-20" |
| 28 | + :style="{ width: line.width, height: line.height }" |
| 29 | + /> |
| 30 | + </div> |
| 31 | + </div> |
| 32 | + </div> |
10 | 33 | <div |
11 | 34 | v-if="isLoaded" |
12 | | - class="flex-1 bg-theme-background-2 container mx-auto flex px-5 py-24 flex-col justify-center items-center z-50" |
| 35 | + class="relative flex-1 container mx-auto flex px-5 py-24 flex-col justify-center items-center z-10" |
13 | 36 | > |
14 | 37 | <div |
15 | 38 | v-if="!isNecessaryLogin" |
|
139 | 162 | tryOnUnmounted(() => { |
140 | 163 | plugin.emit('call-landing-unmounted') |
141 | 164 | }) |
| 165 | +
|
| 166 | + const rand = (min: number, max: number) => |
| 167 | + Math.random() * (max - min) + min |
| 168 | +
|
| 169 | + interface BookBlock { |
| 170 | + lines: { width: string; height: string }[] |
| 171 | + style: string |
| 172 | + } |
| 173 | +
|
| 174 | + interface BookColumn { |
| 175 | + id: number |
| 176 | + blocks: BookBlock[] |
| 177 | + style: string |
| 178 | + responsiveClass: string |
| 179 | + } |
| 180 | +
|
| 181 | + const NUM_COLUMNS = 9 |
| 182 | +
|
| 183 | + const bookColumns = Array.from({ length: NUM_COLUMNS }, (_, i): BookColumn => { |
| 184 | + const leftPct = (i / NUM_COLUMNS) * 100 + rand(-2, 2) |
| 185 | + const duration = rand(18, 32) |
| 186 | + const delay = rand(-duration, 0) |
| 187 | + const maxOpacity = rand(0.07, 0.16) |
| 188 | +
|
| 189 | + const blocks: BookBlock[] = Array.from({ length: rand(5, 15) | 0 }, () => { |
| 190 | + const lineCount = (rand(2, 7) | 0) |
| 191 | + const blockDelay = rand(0, 8) |
| 192 | + const blockFadeDuration = rand(3, 6) |
| 193 | +
|
| 194 | + return { |
| 195 | + lines: Array.from({ length: lineCount }, (_, li) => { |
| 196 | + const isLast = li === lineCount - 1 |
| 197 | + return { |
| 198 | + width: isLast ? `${rand(40, 75)}%` : `${rand(85, 100)}%`, |
| 199 | + height: '2px', |
| 200 | + } |
| 201 | + }), |
| 202 | + style: [ |
| 203 | + `animation: bookFadeInOut ${blockFadeDuration}s ${blockDelay}s ease-in-out infinite alternate`, |
| 204 | + `--max-op: ${maxOpacity}`, |
| 205 | + ].join(';'), |
| 206 | + } |
| 207 | + }) |
| 208 | +
|
| 209 | + // mobile: 3 cols, sm: 5 cols, lg: all 9 |
| 210 | + const responsiveClass = |
| 211 | + i < 3 ? 'flex' : i < 5 ? 'hidden sm:flex' : 'hidden lg:flex' |
| 212 | +
|
| 213 | + return { |
| 214 | + id: i, |
| 215 | + blocks, |
| 216 | + responsiveClass, |
| 217 | + style: [ |
| 218 | + `left: ${leftPct}%`, |
| 219 | + `width: ${rand(60, 110)}px`, |
| 220 | + `animation: bookDrift ${duration}s ${delay}s linear infinite`, |
| 221 | + ].join(';'), |
| 222 | + } |
| 223 | + }) |
142 | 224 | </script> |
| 225 | + |
| 226 | +<style scoped> |
| 227 | +@keyframes bookDrift { |
| 228 | + from { |
| 229 | + transform: translateY(110vh) rotate(-1.5deg); |
| 230 | + } |
| 231 | + to { |
| 232 | + transform: translateY(-20vh) rotate(1.5deg); |
| 233 | + } |
| 234 | +} |
| 235 | +
|
| 236 | +@keyframes bookFadeInOut { |
| 237 | + from { |
| 238 | + opacity: 0; |
| 239 | + } |
| 240 | + to { |
| 241 | + opacity: var(--max-op, 0.12); |
| 242 | + } |
| 243 | +} |
| 244 | +</style> |
0 commit comments