Files
gremiumhub/landing/app/components/landing/AnimatedBackground.vue

102 lines
3.1 KiB
Vue

<template>
<div class="absolute inset-0 overflow-hidden pointer-events-none" :class="variant">
<!-- Animated gradient orbs -->
<div
v-for="(orb, index) in orbs"
:key="index"
class="absolute rounded-full blur-3xl animate-float"
:class="orb.color"
:style="{
width: orb.size,
height: orb.size,
top: orb.top,
left: orb.left,
right: orb.right,
bottom: orb.bottom,
animationDelay: `${index * 2}s`,
animationDuration: `${6 + index * 2}s`
}"
/>
<!-- Grid pattern -->
<div v-if="showGrid" class="absolute inset-0 dots-pattern opacity-20" />
<!-- Animated lines (for tech feel) -->
<svg v-if="showLines" class="absolute inset-0 w-full h-full opacity-10" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="lineGradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" class="[stop-color:var(--color-primary-500)]" stop-opacity="0" />
<stop offset="50%" class="[stop-color:var(--color-primary-500)]" stop-opacity="1" />
<stop offset="100%" class="[stop-color:var(--color-primary-500)]" stop-opacity="0" />
</linearGradient>
</defs>
<!-- Horizontal animated lines -->
<g v-for="i in 3" :key="`h-${i}`">
<line
x1="0"
:y1="`${20 + i * 25}%`"
x2="100%"
:y2="`${20 + i * 25}%`"
stroke="url(#lineGradient)"
stroke-width="1"
class="animate-pulse-soft"
:style="{ animationDelay: `${i * 0.5}s` }"
/>
</g>
</svg>
<!-- Floating particles -->
<div v-if="showParticles" class="absolute inset-0">
<div
v-for="i in 12"
:key="`particle-${i}`"
class="absolute w-1 h-1 rounded-full bg-primary-400/30 animate-float"
:style="{
top: `${Math.random() * 100}%`,
left: `${Math.random() * 100}%`,
animationDelay: `${Math.random() * 5}s`,
animationDuration: `${4 + Math.random() * 4}s`
}"
/>
</div>
</div>
</template>
<script setup lang="ts">
interface Props {
variant?: 'hero' | 'section' | 'cta'
showGrid?: boolean
showLines?: boolean
showParticles?: boolean
}
const props = withDefaults(defineProps<Props>(), {
variant: 'section',
showGrid: true,
showLines: false,
showParticles: false
})
const orbs = computed(() => {
switch (props.variant) {
case 'hero':
return [
{ size: '400px', top: '-100px', left: '-100px', color: 'bg-primary-500/20' },
{ size: '300px', top: '200px', right: '-50px', color: 'bg-success-500/15' },
{ size: '250px', bottom: '-50px', left: '30%', color: 'bg-primary-400/15' }
]
case 'cta':
return [
{ size: '300px', top: '-50px', right: '-100px', color: 'bg-white/10' },
{ size: '200px', bottom: '-50px', left: '-50px', color: 'bg-white/5' }
]
default:
return [
{ size: '200px', top: '10%', left: '-50px', color: 'bg-primary-500/10' },
{ size: '150px', bottom: '20%', right: '-30px', color: 'bg-success-500/10' }
]
}
})
</script>