Files
imen_pishghaman/app/components/layout/Cursor.vue
T
S. EsmaeiliandClaude Opus 4.6 e31ef5a21f feat: migrate landing from Next.js to Nuxt 4 (Vue 3)
Full 1:1 migration preserving all visuals, animations and behavior:
- Nuxt 4 + Vue 3 (script setup, TypeScript strict) with SSG output
- Tailwind CSS v4 with @tailwindcss/vite
- Ant Design Vue 4 (dark theme, RTL, Persian locale) for design system
- Pinia for state management (ui + contact stores)
- motion-v (framer-motion port) for all animations
- lucide-vue-next for icons
- SEO improvements: og:image, canonical fix, real 404 page, JSON-LD services
- JS bundle reduced from 302KB to 239KB gzip
- Docker/nginx deployment preserved (out/ -> nginx)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-10-06 16:28:05 +03:30

53 lines
1.6 KiB
Vue

<script setup lang="ts">
import { motion, useMotionValue, useSpring } from "motion-v";
const x = useMotionValue(-100);
const y = useMotionValue(-100);
const sx = useSpring(x, { stiffness: 550, damping: 45, mass: 0.4 });
const sy = useSpring(y, { stiffness: 550, damping: 45, mass: 0.4 });
const hover = ref(false);
const visible = ref(false);
const move = (e: MouseEvent) => {
x.set(e.clientX);
y.set(e.clientY);
visible.value = true;
};
const over = (e: MouseEvent) => {
const t = e.target as HTMLElement | null;
hover.value = !!t?.closest?.(
"a, button, input, textarea, select, label, [data-hover]",
);
};
onMounted(() => {
window.addEventListener("mousemove", move, { passive: true });
window.addEventListener("mouseover", over, { passive: true });
});
onBeforeUnmount(() => {
window.removeEventListener("mousemove", move);
window.removeEventListener("mouseover", over);
});
</script>
<template>
<div class="pointer-events-none fixed inset-0 z-[120] hidden [@media(pointer:fine)]:block">
<motion.div :style="{ x: sx, y: sy }" class="absolute -left-4 -top-4 size-8">
<motion.div
:animate="{
scale: hover ? 1.9 : 1,
opacity: visible ? 1 : 0,
rotate: hover ? 45 : 0,
}"
:transition="{ type: 'spring', stiffness: 320, damping: 24 }"
class="size-8 rounded-md border-2 border-accent/80"
/>
<div
:class="`absolute inset-0 m-auto size-1 rounded-full bg-accent transition-opacity duration-300 ${
visible ? 'opacity-100' : 'opacity-0'
}`"
/>
</motion.div>
</div>
</template>