ReviewsSection.vue 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. <template>
  2. <section v-if="reviews.length > 0" class="py-24 bg-background relative overflow-hidden">
  3. <!-- Background Decor -->
  4. <div class="absolute top-0 left-1/2 -translate-x-1/2 w-full max-w-7xl h-full pointer-events-none">
  5. <div class="absolute top-24 left-0 w-64 h-64 bg-primary/5 rounded-full blur-3xl" />
  6. <div class="absolute bottom-24 right-0 w-64 h-64 bg-primary/5 rounded-full blur-3xl" />
  7. </div>
  8. <div class="container mx-auto px-4 relative z-10">
  9. <div class="text-center mb-16">
  10. <h2 class="font-display text-4xl font-bold mb-4 bg-clip-text text-transparent bg-gradient-to-r from-foreground to-foreground/60">
  11. {{ t('home.reviews.title') }}
  12. </h2>
  13. <p class="text-muted-foreground max-w-2xl mx-auto">
  14. {{ t('home.reviews.subtitle') }}
  15. </p>
  16. </div>
  17. <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
  18. <div
  19. v-for="(review, idx) in reviews"
  20. :key="idx"
  21. v-motion
  22. :initial="{ opacity: 0, y: 20 }"
  23. :enter="{ opacity: 1, y: 0, transition: { delay: idx * 100 } }"
  24. class="bg-card/40 backdrop-blur-xl border border-border/50 p-8 rounded-3xl hover:border-primary/30 transition-all group"
  25. >
  26. <div class="flex gap-0.5 mb-6">
  27. <Star
  28. v-for="i in 5"
  29. :key="i"
  30. class="w-4 h-4"
  31. :class="i <= review.rating ? 'text-yellow-500 fill-yellow-500' : 'text-muted-foreground/20'"
  32. />
  33. </div>
  34. <p class="text-foreground/80 leading-relaxed mb-8 italic">
  35. "{{ review.review_text }}"
  36. </p>
  37. <div class="flex items-center gap-3">
  38. <div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center text-primary font-bold text-sm">
  39. {{ review.first_name[0] }}
  40. </div>
  41. <div>
  42. <p class="font-bold text-sm">{{ review.first_name }}</p>
  43. <p class="text-[10px] text-muted-foreground uppercase tracking-widest">{{ t('home.reviews.verifiedCustomer') }}</p>
  44. </div>
  45. </div>
  46. </div>
  47. </div>
  48. </div>
  49. </section>
  50. </template>
  51. <script setup lang="ts">
  52. import { ref, onMounted } from 'vue';
  53. import { useI18n } from 'vue-i18n';
  54. import { Star } from 'lucide-vue-next';
  55. import { getPublicReviews } from '@/lib/api';
  56. const { t } = useI18n();
  57. const reviews = ref<any[]>([]);
  58. onMounted(async () => {
  59. try {
  60. reviews.value = await getPublicReviews();
  61. } catch (e) {
  62. console.error('Failed to load reviews:', e);
  63. }
  64. });
  65. </script>