|
| 1 | +<style lang="scss" scoped> |
| 2 | +.text-container { |
| 3 | + --slice-0: inset(50% 50% 50% 50%); |
| 4 | + --slice-1: inset(15% 0 65% 0); |
| 5 | + --slice-2: inset(30% 0 50% 0); |
| 6 | + --slice-3: inset(50% 0 35% 0); |
| 7 | + --slice-4: inset(60% 0 20% 0); |
| 8 | + --slice-5: inset(80% 0 10% 0); |
| 9 | +
|
| 10 | + --slice-shadow-1: -1px -1px 0 #F8F005, 1px 1px 0 #00E6F6; |
| 11 | + --slice-shadow-2: -2px -2px 0 #F8F005, 2px 2px 0 #00E6F6; |
| 12 | +
|
| 13 | + .text { |
| 14 | +
|
| 15 | + &>.text-before, |
| 16 | + &>.text-after { |
| 17 | + --uno: pa top-0 right-0 bottom-0 left-0; |
| 18 | + text-shadow: var(--slice-shadow-1); |
| 19 | + clip-path: var(--slice-0); |
| 20 | + } |
| 21 | +
|
| 22 | + &>.text-after { |
| 23 | + --uno: blur-2; |
| 24 | + } |
| 25 | +
|
| 26 | + &.animate-glitch { |
| 27 | +
|
| 28 | + &>.text-before, |
| 29 | + &>.text-after { |
| 30 | + animation: glitch .3s infinite steps(1, end); |
| 31 | + } |
| 32 | + } |
| 33 | + } |
| 34 | +} |
| 35 | +
|
| 36 | +@keyframes glitch { |
| 37 | + 0% { |
| 38 | + clip-path: var(--slice-1); |
| 39 | + transform: translate(0, -5px); |
| 40 | + } |
| 41 | +
|
| 42 | + 20% { |
| 43 | + clip-path: var(--slice-5); |
| 44 | + transform: translate(10px, -5px); |
| 45 | + } |
| 46 | +
|
| 47 | + 40% { |
| 48 | + clip-path: var(--slice-2); |
| 49 | + transform: translate(0, 0); |
| 50 | + } |
| 51 | +
|
| 52 | + 60% { |
| 53 | + clip-path: var(--slice-5); |
| 54 | + transform: translate(-10px, 5px); |
| 55 | + text-shadow: var(--slice-shadow-2); |
| 56 | + } |
| 57 | +
|
| 58 | + 80% { |
| 59 | + clip-path: var(--slice-3); |
| 60 | + transform: translate(3px, 0); |
| 61 | + } |
| 62 | +
|
| 63 | + 100% { |
| 64 | + clip-path: var(--slice-4); |
| 65 | + transform: translate(10px, 0); |
| 66 | + text-shadow: var(--slice-shadow-2); |
| 67 | + } |
| 68 | +} |
| 69 | +</style> |
| 70 | + |
| 71 | +<template> |
| 72 | + <div class="text-container" pr text-8> |
| 73 | + <div |
| 74 | + pr class="text" |
| 75 | + :class="isPlaying ? 'animate-glitch animate-flash animate-duration-300 animate-count-infinite' : ''" |
| 76 | + > |
| 77 | + <slot :class="props.contentClass" /> |
| 78 | + <div class="text-before" :class="props.contentClass"> |
| 79 | + <slot /> |
| 80 | + </div> |
| 81 | + <div class="text-after" :class="props.contentClass"> |
| 82 | + <slot /> |
| 83 | + </div> |
| 84 | + </div> |
| 85 | + <slot name="background" :is-playing /> |
| 86 | + </div> |
| 87 | +</template> |
| 88 | + |
| 89 | +<script lang="ts" setup> |
| 90 | +const props = withDefaults(defineProps<{ |
| 91 | + contentClass?: string |
| 92 | +}>(), { |
| 93 | +
|
| 94 | +}) |
| 95 | +
|
| 96 | +const isPlaying = ref(false) |
| 97 | +
|
| 98 | +onMounted(() => { |
| 99 | + playAnimate() |
| 100 | +}) |
| 101 | +
|
| 102 | +async function playAnimate() { |
| 103 | + isPlaying.value = true |
| 104 | +
|
| 105 | + const playTime = _random(200, 1200) |
| 106 | +
|
| 107 | + await new Promise((resolve) => { |
| 108 | + setTimeout(() => { |
| 109 | + isPlaying.value = false |
| 110 | + resolve(null) |
| 111 | + }, playTime) |
| 112 | + }) |
| 113 | +
|
| 114 | + const interval = _random(2000, 5000) |
| 115 | + setTimeout(() => { |
| 116 | + playAnimate() |
| 117 | + }, interval) |
| 118 | +} |
| 119 | +</script> |
0 commit comments