mirror of
https://github.com/DavidHDev/vue-bits.git
synced 2026-03-07 06:29:30 -07:00
1 line
3.0 KiB
JSON
1 line
3.0 KiB
JSON
{"name":"CircularText","title":"CircularText","description":"Layouts characters around a circle with optional rotation animation.","type":"registry:component","add":"when-added","files":[{"type":"registry:component","role":"file","content":"<script setup lang=\"ts\">\nimport { animate, Motion, MotionValue, useMotionValue } from 'motion-v';\nimport { computed, onMounted, watch } from 'vue';\n\ninterface CircularTextProps {\n text: string;\n spinDuration?: number;\n onHover?: 'slowDown' | 'speedUp' | 'pause' | 'goBonkers';\n className?: string;\n}\n\nconst props = withDefaults(defineProps<CircularTextProps>(), {\n spinDuration: 20,\n onHover: 'speedUp',\n className: ''\n});\n\nconst letters = computed(() => Array.from(props.text));\nconst rotation: MotionValue<number> = useMotionValue(0);\n\nlet currentAnimation: ReturnType<typeof animate> | null = null;\n\nconst startRotation = (duration: number) => {\n currentAnimation?.stop();\n const start = rotation.get();\n\n currentAnimation = animate(rotation, start + 360, {\n duration,\n ease: 'linear',\n repeat: Infinity\n });\n};\n\nonMounted(() => {\n startRotation(props.spinDuration);\n});\n\nwatch(\n () => [props.spinDuration, props.text],\n () => {\n startRotation(props.spinDuration);\n }\n);\n\nconst handleHoverStart = () => {\n if (!props.onHover) return;\n\n switch (props.onHover) {\n case 'slowDown':\n startRotation(props.spinDuration * 2);\n break;\n case 'speedUp':\n startRotation(props.spinDuration / 4);\n break;\n case 'pause':\n currentAnimation?.stop();\n break;\n case 'goBonkers':\n startRotation(props.spinDuration / 20);\n break;\n }\n};\n\nconst handleHoverEnd = () => {\n startRotation(props.spinDuration);\n};\n\nconst getLetterTransform = (index: number) => {\n const rotationDeg = (360 / letters.value.length) * index;\n const factor = Math.PI / letters.value.length;\n const x = factor * index;\n const y = factor * index;\n return `rotateZ(${rotationDeg}deg) translate3d(${x}px, ${y}px, 0)`;\n};\n</script>\n\n<template>\n <Motion\n tag=\"div\"\n :class=\"[\n 'm-0 mx-auto rounded-full w-[200px] h-[200px] relative font-black text-white text-center cursor-pointer origin-center',\n className\n ]\"\n :style=\"{\n rotate: rotation\n }\"\n :initial=\"{\n rotate: 0\n }\"\n @mouseenter=\"handleHoverStart\"\n @mouseleave=\"handleHoverEnd\"\n >\n <span\n v-for=\"(letter, i) in letters\"\n :key=\"i\"\n class=\"inline-block absolute inset-0 text-2xl transition-all duration-500 ease-[cubic-bezier(0,0,0,1)]\"\n :style=\"{\n transform: getLetterTransform(i),\n WebkitTransform: getLetterTransform(i)\n }\"\n >\n {{ letter }}\n </span>\n </Motion>\n</template>\n","path":"CircularText/CircularText.vue","_imports_":[],"registryDependencies":[],"dependencies":[],"devDependencies":[]}],"registryDependencies":[],"dependencies":[{"ecosystem":"js","name":"motion-v","version":"^1.10.2"}],"devDependencies":[],"categories":["TextAnimations"]} |