EventCard.vue 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. <template>
  2. <article class="event-card">
  3. <button
  4. type="button"
  5. class="event-header"
  6. :aria-expanded="isOpen"
  7. @click="isOpen = !isOpen"
  8. >
  9. <img
  10. v-if="event.cover_url"
  11. :src="event.cover_url"
  12. :alt="event.title"
  13. class="event-thumb"
  14. loading="lazy"
  15. >
  16. <div v-else class="event-thumb event-thumb--empty">
  17. <i class="mdi mdi-calendar-star text-violet-normal" style="font-size: 1.5rem;"/>
  18. </div>
  19. <div class="min-w-0 flex-1 text-left">
  20. <span class="event-badge">
  21. <i :class="`mdi ${typeIcon}`" style="font-size: 0.875rem;"/>
  22. {{ eventTypeLabel(event.type) }}
  23. </span>
  24. <h3 class="text-subtitle-1 font-semibold text-text mt-2 mb-1 truncate">
  25. {{ event.title }}
  26. </h3>
  27. <p v-if="dateTimeLabel" class="text-body-2 text-text-2">
  28. {{ dateTimeLabel }}
  29. </p>
  30. </div>
  31. <span
  32. class="material-icons text-violet-normal shrink-0 transition-transform duration-300"
  33. :class="{ 'rotate-180': isOpen }"
  34. >
  35. expand_more
  36. </span>
  37. </button>
  38. <div class="event-body" :class="isOpen ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]'">
  39. <div class="overflow-hidden">
  40. <div class="px-6 pb-6 pt-1">
  41. <p
  42. v-for="(paragraph, index) in paragraphs"
  43. :key="index"
  44. lang="pt-BR"
  45. class="text-body-2 text-text-2 text-justify hyphens-auto event-text"
  46. :class="{ 'mt-3': index > 0 }"
  47. >
  48. {{ paragraph }}
  49. </p>
  50. <img
  51. v-if="event.cover_url"
  52. :src="event.cover_url"
  53. :alt="event.title"
  54. class="event-cover"
  55. :class="{ 'mt-5': paragraphs.length }"
  56. loading="lazy"
  57. >
  58. <EventCarousel
  59. v-if="photos.length"
  60. :photos="photos"
  61. class="mt-4"
  62. />
  63. </div>
  64. </div>
  65. </div>
  66. </article>
  67. </template>
  68. <script setup lang="ts">
  69. import type { CompanyEvent } from '~/composables/useEvents'
  70. const { event } = defineProps<{ event: CompanyEvent }>()
  71. const isOpen = ref(true)
  72. const typeIcon = computed(() => (event.type === 'esporte' ? 'mdi-soccer' : 'mdi-palette-outline'))
  73. const dateTimeLabel = computed(() => formatEventDateTime(event))
  74. const photos = computed(() => (event.media ?? []).filter((photo) => !!photo.url))
  75. const paragraphs = computed(() =>
  76. (event.description ?? '')
  77. .split(/\r?\n/)
  78. .map((line) => line.trim())
  79. .filter(Boolean)
  80. )
  81. </script>
  82. <style scoped>
  83. .event-card {
  84. background-color: #ffffff;
  85. border-radius: 1rem;
  86. box-shadow: 0 2px 12px rgba(102, 29, 117, 0.07);
  87. transition: box-shadow 0.2s;
  88. overflow: hidden;
  89. height: 100%;
  90. }
  91. .event-card:hover {
  92. box-shadow: 0 6px 24px rgba(102, 29, 117, 0.13);
  93. }
  94. .event-header {
  95. display: flex;
  96. align-items: center;
  97. gap: 1rem;
  98. width: 100%;
  99. padding: 1.25rem 1.5rem;
  100. cursor: pointer;
  101. text-align: left;
  102. }
  103. .event-thumb {
  104. width: 72px;
  105. height: 72px;
  106. border-radius: 0.75rem;
  107. object-fit: cover;
  108. flex-shrink: 0;
  109. }
  110. .event-thumb--empty {
  111. display: inline-flex;
  112. align-items: center;
  113. justify-content: center;
  114. background-color: #f0e8f1;
  115. }
  116. .event-badge {
  117. display: inline-flex;
  118. align-items: center;
  119. gap: 0.25rem;
  120. background-color: #f0e8f1;
  121. color: #661d75;
  122. font-family: "Nunito", sans-serif;
  123. font-size: 0.6875rem;
  124. font-weight: 600;
  125. letter-spacing: 0.5px;
  126. text-transform: uppercase;
  127. padding: 0.125rem 0.5rem;
  128. border-radius: 9999px;
  129. }
  130. .event-body {
  131. display: grid;
  132. transition: grid-template-rows 0.35s ease;
  133. }
  134. .event-text {
  135. line-height: 1.7;
  136. }
  137. .event-cover {
  138. width: 100%;
  139. height: 240px;
  140. object-fit: cover;
  141. border-radius: 0.75rem;
  142. display: block;
  143. }
  144. @media (min-width: 1024px) {
  145. .event-cover {
  146. height: 280px;
  147. }
  148. }
  149. </style>