HomeNextEvents.vue 3.54 KB
Newer Older
Emmanuel Salomon's avatar
Emmanuel Salomon committed
1
<template>
2
  <section id="agenda" class="container py-12">
3
    <div class="border-b-2 container flex items-end mb-3 pb-2 pl-1">
4
      <JuneCalendar class="w-12 mr-3 fill-current dark:text-gray-100" />
Emmanuel Salomon's avatar
Emmanuel Salomon committed
5
      <a
6
        :href="`${$config.forum_url}/calendar`"
7
        target="_blank"
8
9
10
11
12
13
14
15
16
17
        class="
          group
          bg-clip-text bg-gradient-to-r
          font-extrabold
          from-purple-800
          hover:underline
          text-4xl text-transparent
          to-blue-600
          uppercase
        "
18
        rel="noopener noreferrer"
Emmanuel Salomon's avatar
Emmanuel Salomon committed
19
      >
20
21
22
23
24
        Agenda
        <fa
          icon="external-link-alt"
          class="w-3 ml-1.5 text-gray-500 opacity-0 group-hover:opacity-75"
        />
Emmanuel Salomon's avatar
Emmanuel Salomon committed
25
26
      </a>
    </div>
Emmanuel Salomon's avatar
Emmanuel Salomon committed
27

28
29
30
31
32
33
34
35
36
37
    <aside v-if="!loading" class="lg:flex">
      <div
        v-for="(column, num) in columns"
        :key="num"
        class="flex-1"
        :class="num === 1 && 'lg:ml-4'"
      >
        <a
          v-for="(event, index) in column"
          :key="index"
38
          :href="`${$config.forum_url}/t/${event.slug}/${event.id}`"
39
          target="_blank"
40
41
42
43
44
45
46
47
48
          class="
            block
            hover:bg-hover-light
            dark-hover:text-gray-800
            p-2
            mt-1
            rounded-lg
            transition-colors
          "
49
          rel="noopener noreferrer"
50
51
52
53
54
        >
          <div class="event-date text-sm text-gray-500">
            {{ prettyDate(event.event.start) }}
            <div v-for="(tag, i) in event.tag" :key="i">{{ tag }}</div>
          </div>
55
          <div v-html="emojify(event.title)" />
56
57
58
59
60
61
62
63
        </a>
      </div>
    </aside>

    <div v-else class="h-80 flex items-center">
      <span class="loading-state h-12 w-12 scale-150 transform mx-auto" />
    </div>
  </section>
Emmanuel Salomon's avatar
Emmanuel Salomon committed
64
65
66
</template>

<script>
67
import JuneCalendar from '~/static/img/june-calendar.svg?inline'
Emmanuel Salomon's avatar
Emmanuel Salomon committed
68
import { fetchNextEvents } from '~/libs/api-forum'
69
import { performEmojiUnescape } from '~/libs/emoji'
Emmanuel Salomon's avatar
Emmanuel Salomon committed
70
71
72

export default {
  name: 'HomeNextEvents',
73
74
75
  components: {
    JuneCalendar,
  },
Emmanuel Salomon's avatar
Emmanuel Salomon committed
76
77
78
79
  data() {
    return {
      events: [],
      loading: false,
Emmanuel Salomon's avatar
Emmanuel Salomon committed
80
      cols: 2,
Emmanuel Salomon's avatar
Emmanuel Salomon committed
81
82
    }
  },
Emmanuel Salomon's avatar
Emmanuel Salomon committed
83
84
85
86
87
88
89
90
91
92
  computed: {
    columns() {
      const columns = []
      const mid = Math.ceil(this.events.length / this.cols)
      for (let col = 0; col < this.cols; col++) {
        columns.push(this.events.slice(col * mid, col * mid + mid))
      }
      return columns
    },
  },
Emmanuel Salomon's avatar
Emmanuel Salomon committed
93
94
  async mounted() {
    this.loading = true
Emmanuel Salomon's avatar
Emmanuel Salomon committed
95
    this.events = await fetchNextEvents(`?start=${this.formatDateForParams()}`)
Emmanuel Salomon's avatar
Emmanuel Salomon committed
96
97
    this.loading = false
  },
Emmanuel Salomon's avatar
Emmanuel Salomon committed
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

  methods: {
    formatDateForParams(date = new Date()) {
      const offset = date.getTimezoneOffset()
      date = new Date(date.getTime() - offset * 60 * 1000)
      return date.toISOString().split('T')[0]
    },
    prettyDate(date) {
      const formatter = new Intl.DateTimeFormat(
        this.$i18n.locale,
        this.$i18n.dateTimeFormats[this.$i18n.locale].full
      )
      return formatter
        .formatToParts(Date.parse(date))
        .map(({ type, value }) => {
          switch (type) {
            case 'literal':
              return value === ', ' ? ' à ' : value === ':' ? 'h' : value
            default:
              return value
          }
        })
        .reduce((string, part) => string + part)
    },
122
123
124
125
126
127
128
    emojify(text) {
      return performEmojiUnescape(text, {
        emojiSet: 'images/emoji/twitter',
        emojiCDNUrl: 'https://forum.monnaie-libre.fr',
        getURL: (url) => url,
      })
    },
Emmanuel Salomon's avatar
Emmanuel Salomon committed
129
  },
Emmanuel Salomon's avatar
Emmanuel Salomon committed
130
131
}
</script>
Emmanuel Salomon's avatar
Emmanuel Salomon committed
132
133
134
135
136
137

<style lang="postcss" scoped>
.event-date:first-letter {
  text-transform: uppercase;
}
</style>