Skip to content

Commit 41b53f1

Browse files
committed
feat: events page
1 parent 4b5881b commit 41b53f1

File tree

18 files changed

+463
-5
lines changed

18 files changed

+463
-5
lines changed

apps/web/app/components/FooterPageSection.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ const snsLinkList: LinkList[] = [
3737
},
3838
]
3939
const internalLinkList: LinkList[] = [
40+
{
41+
href: '/events',
42+
text: 'related_events.title',
43+
},
4044
{
4145
href: '/privacy',
4246
text: 'privacy.title',

apps/web/app/lang/en.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,5 +281,10 @@
281281
},
282282
"sharemap": {
283283
"title": "Share URL"
284+
},
285+
"related_events": {
286+
"title": "Related Events",
287+
"register": "Register for the event",
288+
"close": "The event has ended"
284289
}
285290
}

apps/web/app/lang/ja.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,5 +299,10 @@
299299
},
300300
"sharemap": {
301301
"title": "シェアURL"
302+
},
303+
"related_events": {
304+
"title": "関連イベント",
305+
"register": "イベントに参加する",
306+
"close": "イベントは終了しました"
302307
}
303308
}

apps/web/app/pages/events.vue

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
<script setup lang="ts">
2+
import { useFetch, useHead } from '#imports'
3+
import { useLocaleCurrent } from '~/composables/useLocaleCurrent'
4+
import type { RelatedEventInfo } from '@vuejs-jp/model'
5+
import { conferenceTitle, linkUrl, ogRelatedEventDescription } from '~/utils/constants'
6+
import { generalOg, twitterOg } from '~/utils/og.constants'
7+
8+
type RelatedEvents = Record<'eventsInfo', RelatedEventInfo>
9+
10+
const { data, error } = await useFetch('/api/events')
11+
if (error.value) {
12+
console.error(error.value)
13+
}
14+
const { eventsInfo } = data.value as RelatedEvents
15+
16+
const { path: localePath } = useLocaleCurrent()
17+
18+
const isClose = (startedAt: string) =>
19+
new Date() > new Date(new Date(startedAt).getFullYear(), new Date(startedAt).getMonth(), new Date(startedAt).getDate())
20+
21+
useHead({
22+
titleTemplate: (titleChunk) => `関連イベント | ${conferenceTitle}`,
23+
meta: [
24+
...generalOg({
25+
title: `関連イベント | ${conferenceTitle}`,
26+
description: ogRelatedEventDescription,
27+
url: `${linkUrl}events`,
28+
}),
29+
...twitterOg({
30+
title: `関連イベント | ${conferenceTitle}`,
31+
description: ogRelatedEventDescription,
32+
url: `${linkUrl}events`,
33+
}),
34+
],
35+
})
36+
</script>
37+
38+
<template>
39+
<VFPageHeading>{{ $t('related_events.title') }}</VFPageHeading>
40+
<div class="related-events">
41+
<ul class="related-events-body">
42+
<li v-for="(event, index) in eventsInfo.list" :key="index">
43+
<VFRelatedEventFrame
44+
:src="event.bannerUrl"
45+
:alt="event.title"
46+
:register-url="event.registerUrl"
47+
:register-action-text="isClose(event.startedAt) ? $t('related_events.close') : $t('related_events.register')"
48+
:disabled="isClose(event.startedAt)"
49+
>
50+
<template #title>
51+
{{ event.title }}
52+
</template>
53+
<template #description>
54+
{{ event.description }}
55+
</template>
56+
</VFRelatedEventFrame>
57+
</li>
58+
</ul>
59+
<div class="back">
60+
<VFLinkButton
61+
class="back-action"
62+
background-color="white"
63+
color="vue-blue"
64+
target=""
65+
:href="`${localePath}/`"
66+
>
67+
{{ $t('back_to_top') }}
68+
</VFLinkButton>
69+
</div>
70+
</div>
71+
</template>
72+
73+
<style scoped>
74+
@import url('../assets/base.css');
75+
@import url('../assets/media.css');
76+
77+
.related-events {
78+
margin: 0;
79+
padding: 0 1.5%;
80+
background-image: linear-gradient(#fff, #ebf0f5);
81+
position: relative;
82+
z-index: 0;
83+
overflow: hidden;
84+
85+
@media (--tablet) {
86+
padding: 0 6%;
87+
}
88+
89+
&:before {
90+
content: "";
91+
position: absolute;
92+
display: block;
93+
bottom: 0;
94+
left: 0;
95+
width: 100%;
96+
height: 100%;
97+
background-image: url('/form-bg.png');
98+
background-size: auto;
99+
background-repeat: repeat;
100+
background-position: bottom left;
101+
opacity: 0.8;
102+
mix-blend-mode: overlay;
103+
z-index: -1;
104+
}
105+
}
106+
107+
.related-events-body {
108+
margin: 0 auto;
109+
padding: 60px 0 120px;
110+
width: 100%;
111+
max-width: 960px;
112+
display: flex;
113+
flex-wrap: wrap;
114+
justify-content: center;
115+
116+
@media (--tablet) {
117+
padding: 20px 0 60px;
118+
max-width: 100%
119+
}
120+
121+
li {
122+
width: calc((100% - 4%) / 2);
123+
124+
@media (--tablet) {
125+
width: 100%;
126+
}
127+
128+
&:nth-child(even) {
129+
margin-left: 4%;
130+
131+
@media (--tablet) {
132+
margin-left: 0;
133+
}
134+
}
135+
136+
@media (--tablet) {
137+
&:nth-child(n + 2) {
138+
margin-top: 20px;
139+
}
140+
}
141+
142+
&:nth-child(n + 3) {
143+
margin-top: 4%;
144+
145+
@media (--tablet) {
146+
margin-top: 20px;
147+
}
148+
}
149+
}
150+
151+
a {
152+
border-radius: 12px;
153+
overflow: hidden;
154+
display: block;
155+
}
156+
}
157+
158+
.back {
159+
margin: 40px auto 120px;
160+
width: 100%;
161+
max-width: 260px;
162+
}
163+
.back-action {
164+
--height-button: 66px;
165+
166+
height: var(--height-button);
167+
border-radius: var(--height-button);
168+
}
169+
170+
@media (--tablet) {
171+
.back-action {
172+
--height-button: 58px;
173+
}
174+
}
175+
176+
@media (--mobile) {
177+
.back {
178+
width: 100%;
179+
padding: 0 23.5px;
180+
margin-top: 30px;
181+
margin-bottom: 60px;
182+
}
183+
.back-action {
184+
--height-button: 58px;
185+
}
186+
}
187+
</style>

apps/web/app/server/api/events.get.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import db from '../db'
2+
import { defineEventHandler } from 'h3'
3+
import type { RelatedEvent, RelatedEventInfo } from '@vuejs-jp/model'
4+
5+
export default defineEventHandler(async (event) => {
6+
const response = await db.event.getList()
7+
const eventData = response.default as RelatedEvent[]
8+
9+
const eventsInfo: RelatedEventInfo = {
10+
type: 'related-event',
11+
title: 'related-event',
12+
list: eventData,
13+
}
14+
15+
return { eventsInfo }
16+
})

apps/web/app/server/db/event.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
class Event {
2+
async getList() {
3+
const events = await import('~/utils/data/events.json')
4+
return events
5+
}
6+
}
7+
8+
export default new Event()

apps/web/app/server/db/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
import event from './event'
12
import speaker from './speaker'
23
import sponsor from './sponsor'
34
import timetable from './timetable'
45

56
export default {
7+
event,
68
speaker,
79
sponsor,
8-
timetable
10+
timetable,
911
}

apps/web/app/server/db/speaker.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
class Speaker {
22
async getList() {
3-
// TODO: supabaseからデータを取得する
43
const speakers = await import('~/utils/data/speakers.json')
54
return speakers
65
}
76
}
87

9-
export default new Speaker()
8+
export default new Speaker()

apps/web/app/server/db/sponsor.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11

22
class Sponsor {
33
async getList() {
4-
// TODO: supabaseからデータを取得する
54
const sponsors = await import('~/utils/data/sponsors.json')
65
return sponsors
76
}

apps/web/app/utils/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ export const ogNamecardDescription = 'さんのネームカードです。'
2424

2525
export const ogJobboardDescription = 'Vue Fes Japan 2024 のジョブボードです。'
2626

27+
export const ogRelatedEventDescription = 'Vue Fes Japan 2024 の関連イベントです。'
28+
2729
export const linkUrl = 'https://vuefes.jp/2024/'
2830

2931
export const vuefesTwitterID = '@vuefes'

0 commit comments

Comments
 (0)