You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
90 lines
1.8 KiB
90 lines
1.8 KiB
3 months ago
|
<template>
|
||
|
<span
|
||
|
v-if="!props.highlightText"
|
||
|
:class="cn('inline-block px-1 pb-1 highlight-all', props.class)"
|
||
|
>
|
||
|
{{ props.text }}
|
||
|
</span>
|
||
|
<span v-else>
|
||
|
{{ beforeText }}
|
||
|
<div :class="cn('inline-block highlight-all', props.class)">
|
||
|
{{ props.highlightText }}
|
||
|
</div>
|
||
|
{{ afterText }}
|
||
|
</span>
|
||
|
</template>
|
||
|
|
||
|
<script setup lang="ts">
|
||
|
import { computed, type HTMLAttributes } from 'vue'
|
||
|
import { cn } from '@/lib/utils'
|
||
|
|
||
|
interface Props {
|
||
|
delay?: number
|
||
|
duration?: number
|
||
|
class?: HTMLAttributes['class']
|
||
|
textEndColor?: string
|
||
|
highlightText?: string
|
||
|
text: string
|
||
|
}
|
||
|
|
||
|
const props = withDefaults(defineProps<Props>(), {
|
||
|
delay: 0,
|
||
|
duration: 2000,
|
||
|
endColor: 'inherit',
|
||
|
})
|
||
|
|
||
|
const delayMs = computed(() => `${props.delay}ms`)
|
||
|
const durationMs = computed(() => `${props.duration}ms`)
|
||
|
|
||
|
const beforeText = computed(() => {
|
||
|
if (!props.highlightText || !props.text) return ''
|
||
|
|
||
|
const index = props.text.indexOf(props.highlightText)
|
||
|
if (index === -1) return props.text
|
||
|
|
||
|
return props.text.substring(0, index)
|
||
|
})
|
||
|
|
||
|
const afterText = computed(() => {
|
||
|
if (!props.highlightText || !props.text) return ''
|
||
|
|
||
|
const index = props.text.indexOf(props.highlightText)
|
||
|
if (index === -1) return ''
|
||
|
|
||
|
return props.text.substring(index + props.highlightText.length)
|
||
|
})
|
||
|
</script>
|
||
|
|
||
|
<style scoped>
|
||
|
@keyframes background-expand {
|
||
|
0% {
|
||
|
background-size: 0% 100%;
|
||
|
}
|
||
|
100% {
|
||
|
background-size: 100% 100%;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@keyframes text-color-change {
|
||
|
0% {
|
||
|
color: inherit;
|
||
|
}
|
||
|
100% {
|
||
|
color: v-bind(textEndColor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
span {
|
||
|
background-size: 0% 100%;
|
||
|
background-repeat: no-repeat;
|
||
|
background-position: left center;
|
||
|
}
|
||
|
|
||
|
.highlight-all,
|
||
|
.highlight-text {
|
||
|
animation:
|
||
|
background-expand v-bind(durationMs) ease-in-out v-bind(delayMs) forwards,
|
||
|
text-color-change v-bind(durationMs) ease-in-out v-bind(delayMs) forwards;
|
||
|
}
|
||
|
</style>
|