HeroSection.vue 4.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. <template>
  2. <section class="relative min-h-[70vh] sm:min-h-[85vh] flex items-center justify-center overflow-hidden bg-white">
  3. <div class="absolute inset-0 grid-pattern opacity-50" />
  4. <div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[800px] h-[800px] bg-gradient-glow rounded-full blur-3xl" />
  5. <div class="container mx-auto px-4 pt-20 sm:pt-24 lg:pt-0 lg:mt-8">
  6. <div class="grid lg:grid-cols-2 gap-12 items-center">
  7. <!-- Text -->
  8. <div class="text-center lg:text-left animate-slide-up">
  9. <div class="inline-flex items-center justify-center px-4 py-1.5 mb-6 rounded-full bg-primary/10 border border-primary/20">
  10. <span class="text-xs text-primary font-bold tracking-widest">{{ t("hero.badge") }}</span>
  11. </div>
  12. <h1 class="font-display text-4xl sm:text-5xl lg:text-6xl font-extrabold leading-[1.1] mb-4 sm:mb-6 tracking-tight">
  13. {{ t("hero.title") }}
  14. <span class="block text-primary">{{ t("hero.titleGradient") }}</span>
  15. </h1>
  16. <p class="text-base sm:text-lg text-foreground/70 max-w-xl mx-auto lg:mx-0 mb-6 sm:mb-8 leading-relaxed font-medium">
  17. {{ t("hero.description") }}
  18. </p>
  19. <div class="flex flex-col sm:flex-row gap-4 justify-center lg:justify-start">
  20. <Button variant="hero" size="xl" class="group" as="a" href="#upload">
  21. <Upload class="w-5 h-5" />
  22. {{ t("hero.uploadButton") }}
  23. <ArrowRight class="w-5 h-5 group-hover:translate-x-1 transition-transform" />
  24. </Button>
  25. <Button variant="heroOutline" size="xl" as="a" href="#process">
  26. {{ t("hero.pricingButton") }}
  27. </Button>
  28. </div>
  29. <!-- Stats -->
  30. <div class="grid grid-cols-3 gap-6 mt-8 sm:mt-10 pt-6 border-t border-black/[0.05]">
  31. <div class="space-y-1">
  32. <div class="font-display text-xl sm:text-2xl font-bold text-primary">{{ t("hero.stats.precisionValue") }}</div>
  33. <div class="text-[10px] uppercase tracking-widest font-bold text-foreground/40">{{ t("hero.stats.precision") }}</div>
  34. </div>
  35. <div class="space-y-1">
  36. <div class="font-display text-xl sm:text-2xl font-bold text-primary">{{ t("hero.stats.materialsValue") }}</div>
  37. <div class="text-[10px] uppercase tracking-widest font-bold text-foreground/40">{{ t("hero.stats.materials") }}</div>
  38. </div>
  39. <div class="space-y-1">
  40. <div class="font-display text-xl sm:text-2xl font-bold text-primary">{{ t("hero.stats.shippingValue") }}</div>
  41. <div class="text-[10px] uppercase tracking-widest font-bold text-foreground/40">{{ t("hero.stats.shipping") }}</div>
  42. </div>
  43. </div>
  44. </div>
  45. <!-- Image (Desktop Only) -->
  46. <div v-if="isDesktop" class="relative animate-float block">
  47. <div class="relative z-10 p-1.5 bg-white/50 backdrop-blur-sm rounded-[2.5rem] shadow-[0_32px_64px_rgba(0,0,0,0.08)] border border-black/[0.03]">
  48. <img
  49. src="/src/assets/hero-premium.png"
  50. alt="High Precision 3D Printing"
  51. class="w-full h-auto rounded-[2rem] aspect-[4/3] object-cover"
  52. loading="lazy"
  53. />
  54. </div>
  55. <div class="absolute -top-6 -right-6 w-32 h-32 border border-primary/20 rounded-[2rem] animate-pulse" />
  56. <div class="absolute -bottom-10 -left-10 w-40 h-40 bg-primary/5 rounded-full blur-3xl" />
  57. </div>
  58. </div>
  59. </div>
  60. </section>
  61. </template>
  62. <script setup lang="ts">
  63. import { ref, onMounted, onUnmounted } from "vue";
  64. import { useI18n } from "vue-i18n";
  65. import { ArrowRight, Upload } from "lucide-vue-next";
  66. import Button from "./ui/button.vue";
  67. const { t } = useI18n();
  68. const isDesktop = ref(false);
  69. const checkIsDesktop = () => {
  70. isDesktop.value = window.innerWidth >= 1024;
  71. };
  72. onMounted(() => {
  73. checkIsDesktop();
  74. window.addEventListener('resize', checkIsDesktop);
  75. });
  76. onUnmounted(() => {
  77. window.removeEventListener('resize', checkIsDesktop);
  78. });
  79. </script>