Files
vue-bits/public/r/ShinyText.json
2026-02-02 11:38:18 +05:30

1 line
4.3 KiB
JSON

{"name":"ShinyText","title":"ShinyText","description":"Metallic sheen sweeps across text producing a reflective highlight.","type":"registry:component","add":"when-added","files":[{"type":"registry:component","role":"file","content":"<script setup lang=\"ts\">\nimport { Motion, useAnimationFrame, useMotionValue, useTransform } from 'motion-v';\nimport { computed, ref, watch } from 'vue';\n\ninterface ShinyTextProps {\n text: string;\n disabled?: boolean;\n speed?: number;\n className?: string;\n color?: string;\n shineColor?: string;\n spread?: number;\n yoyo?: boolean;\n pauseOnHover?: boolean;\n direction?: 'left' | 'right';\n delay?: number;\n}\n\nconst props = withDefaults(defineProps<ShinyTextProps>(), {\n disabled: false,\n speed: 2,\n className: '',\n color: '#b5b5b5',\n shineColor: '#ffffff',\n spread: 120,\n yoyo: false,\n pauseOnHover: false,\n direction: 'left',\n delay: 0\n});\n\nconst isPaused = ref(false);\nconst progress = useMotionValue(0);\nconst elapsedRef = ref(0);\nconst lastTimeRef = ref<number | null>(null);\nconst directionRef = ref(props.direction === 'left' ? 1 : -1);\n\nconst animationDuration = computed(() => props.speed * 1000);\nconst delayDuration = computed(() => props.delay * 1000);\n\nuseAnimationFrame(time => {\n if (props.disabled || isPaused.value) {\n lastTimeRef.value = null;\n return;\n }\n\n if (lastTimeRef.value === null) {\n lastTimeRef.value = time;\n return;\n }\n\n const deltaTime = time - lastTimeRef.value;\n lastTimeRef.value = time;\n\n elapsedRef.value += deltaTime;\n\n // Animation goes from 0 to 100\n if (props.yoyo) {\n const cycleDuration = animationDuration.value + delayDuration.value;\n const fullCycle = cycleDuration * 2;\n const cycleTime = elapsedRef.value % fullCycle;\n\n if (cycleTime < animationDuration.value) {\n // Forward animation: 0 -> 100\n const p = (cycleTime / animationDuration.value) * 100;\n progress.set(directionRef.value === 1 ? p : 100 - p);\n } else if (cycleTime < cycleDuration) {\n // Delay at end\n progress.set(directionRef.value === 1 ? 100 : 0);\n } else if (cycleTime < cycleDuration + animationDuration.value) {\n // Reverse animation: 100 -> 0\n const reverseTime = cycleTime - cycleDuration;\n const p = 100 - (reverseTime / animationDuration.value) * 100;\n progress.set(directionRef.value === 1 ? p : 100 - p);\n } else {\n // Delay at start\n progress.set(directionRef.value === 1 ? 0 : 100);\n }\n } else {\n const cycleDuration = animationDuration.value + delayDuration.value;\n const cycleTime = elapsedRef.value % cycleDuration;\n\n if (cycleTime < animationDuration.value) {\n // Animation phase: 0 -> 100\n const p = (cycleTime / animationDuration.value) * 100;\n progress.set(directionRef.value === 1 ? p : 100 - p);\n } else {\n // Delay phase - hold at end (shine off-screen)\n progress.set(directionRef.value === 1 ? 100 : 0);\n }\n }\n});\n\nwatch(\n () => props.direction,\n () => {\n directionRef.value = props.direction === 'left' ? 1 : -1;\n elapsedRef.value = 0;\n progress.set(0);\n },\n {\n immediate: true\n }\n);\n\nconst backgroundPosition = useTransform(progress, p => `${150 - p * 2}% center`);\n\nconst handleMouseEnter = () => {\n if (props.pauseOnHover) isPaused.value = true;\n};\n\nconst handleMouseLeave = () => {\n if (props.pauseOnHover) isPaused.value = false;\n};\n\nconst gradientStyle = computed(() => ({\n backgroundImage: `linear-gradient(${props.spread}deg, ${props.color} 0%, ${props.color} 35%, ${props.shineColor} 50%, ${props.color} 65%, ${props.color} 100%)`,\n backgroundSize: '200% auto',\n WebkitBackgroundClip: 'text',\n backgroundClip: 'text',\n WebkitTextFillColor: 'transparent'\n}));\n</script>\n\n<template>\n <Motion\n tag=\"span\"\n :class=\"['inline-block', className]\"\n :style=\"{ ...gradientStyle, backgroundPosition }\"\n @mouseenter=\"handleMouseEnter\"\n @mouseleave=\"handleMouseLeave\"\n >\n {{ text }}\n </Motion>\n</template>\n","path":"ShinyText/ShinyText.vue","_imports_":[],"registryDependencies":[],"dependencies":[],"devDependencies":[]}],"registryDependencies":[],"dependencies":[{"ecosystem":"js","name":"motion-v","version":"^1.10.2"}],"devDependencies":[],"categories":["TextAnimations"]}