Skip to content

Commit 484f4ef

Browse files
authored
feat: add related events page (#907)
* feat: add related events page * feat: add page settings * feat: add event data * feat: related events page style * feat: add alt text
1 parent cd7f0b0 commit 484f4ef

File tree

11 files changed

+232
-4
lines changed

11 files changed

+232
-4
lines changed

app/components/footer/VFFooter.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ const isEventFeatureEnabled = __FEATURE_EVENT__;
8787

8888
<ul class="other-links">
8989
<li :class="{ hidden: !isEventFeatureEnabled }">
90-
<NuxtLink :to="localePath('/event')">{{
91-
t("events")
90+
<NuxtLink :to="localePath('/related-events')">{{
91+
t("relatedEvents.sectionTitle")
9292
}}</NuxtLink>
9393
</li>
9494
<li>

app/layouts/default.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ const WIDE_ROUTE_NAMES: RoutesNamesList[] = [
9999
"sponsors",
100100
"sponsors-sponsorId",
101101
"event",
102+
"related-events",
102103
];
103104
104105
const isWidenContent = computed(() =>

app/pages/related-events/index.vue

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
<script setup lang="ts">
2+
import {
3+
RELATED_EVENTS as enRelatedEvents,
4+
} from "../../../i18n/en/related-events";
5+
6+
import {
7+
RELATED_EVENTS as jaRelatedEvents,
8+
} from "../../../i18n/ja/related-events";
9+
10+
import {
11+
VFSection,
12+
VFButton,
13+
} from "#components";
14+
15+
import {
16+
computed,
17+
defineOgImage,
18+
useI18n,
19+
useRuntimeConfig,
20+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
21+
useHead,
22+
useSeoMeta,
23+
} from "#imports";
24+
25+
const runtimeConfig = useRuntimeConfig();
26+
const { t, locale } = useI18n();
27+
28+
const relatedEvents = computed(() => locale.value === "en" ? enRelatedEvents : jaRelatedEvents);
29+
30+
const dateOption = computed(() => locale.value === "en"
31+
? {
32+
year: "numeric" as const,
33+
month: "long" as const,
34+
day: "numeric" as const,
35+
weekday: "short" as const,
36+
}
37+
: {
38+
year: "numeric" as const,
39+
month: "short" as const,
40+
day: "numeric" as const,
41+
weekday: "short" as const,
42+
});
43+
44+
defineOgImage({
45+
component: "root",
46+
url: `${runtimeConfig.public.siteUrl}images/og/related-events.png`,
47+
});
48+
49+
useSeoMeta({
50+
title: t("relatedEvents.sectionTitle"),
51+
ogTitle: t("relatedEvents.sectionTitle"),
52+
});
53+
</script>
54+
55+
<template>
56+
<div id="pages-related-events">
57+
<h1>{{ $t('relatedEvents.title') }}</h1>
58+
</div>
59+
60+
<VFSection :title="t('relatedEvents.sectionTitle')" class="vf-section discussion-event">
61+
<ul class="event-card">
62+
<li v-for="event in relatedEvents" :key="event.id" class="event-card-item">
63+
<img :src="event.coverUrl" :alt="event.coverAlt" width="400" height="164" class="event-card-image">
64+
<div class="event-card-content">
65+
<div>
66+
<h2 class="event-card-title">
67+
{{ event.title }}
68+
</h2>
69+
<time :datetime="event.date" class="event-card-date">
70+
{{ new Date(event.date).toLocaleDateString(locale, dateOption) }}
71+
</time>
72+
<template v-for="(paragraph, index) in event.description?.split('\n')" :key="index">
73+
<p>
74+
{{ paragraph }}
75+
</p>
76+
</template>
77+
</div>
78+
<VFButton :link="event.linkUrl" external outlined>
79+
{{ t("relatedEvents.linkText") }}
80+
</VFButton>
81+
</div>
82+
</li>
83+
</ul>
84+
</VFSection>
85+
</template>
86+
87+
<style scoped>
88+
@import "~/assets/styles/custom-media-query.css";
89+
90+
#pages-related-events {
91+
display: grid;
92+
row-gap: 1.5rem;
93+
94+
@media (--mobile) {
95+
row-gap: 1rem;
96+
}
97+
98+
h1 {
99+
font-family: "ClashDisplay-Semibold";
100+
font-size: 3rem;
101+
padding: 7rem 0 8rem;
102+
margin: 0;
103+
line-height: 1;
104+
105+
@media (--mobile) {
106+
padding: 2rem 0.75rem 3rem;
107+
}
108+
}
109+
}
110+
111+
.event-card {
112+
display: grid;
113+
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
114+
gap: 32px;
115+
}
116+
117+
.event-card-image {
118+
width: 100%;
119+
height: auto;
120+
}
121+
122+
.event-card-item {
123+
display: flex;
124+
flex-direction: column;
125+
border: 1px solid var(--color-divider);
126+
border-radius: 10px;
127+
overflow: hidden;
128+
background: var(--color-white);
129+
}
130+
131+
.event-card-content {
132+
display: flex;
133+
flex-direction: column;
134+
align-items: center;
135+
justify-content: space-between;
136+
flex-grow: 1;
137+
gap: 32px;
138+
padding: 24px;
139+
140+
@media (--mobile) {
141+
gap: 24px;
142+
padding: 16px;
143+
}
144+
}
145+
146+
.event-card-title {
147+
margin: 0 0 8px;
148+
149+
@media (--mobile) {
150+
margin: 0 0 6px;
151+
}
152+
}
153+
154+
.event-card-date {
155+
display: block;
156+
margin-bottom: 24px;
157+
font-size: 0.8125rem;
158+
line-height: 1.5;
159+
text-align: end;
160+
161+
@media (--mobile) {
162+
margin-bottom: 16px;
163+
font-size: 0.75rem;
164+
}
165+
}
166+
</style>

i18n/en/index.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,11 +274,15 @@ snsIconImageAlt:
274274
youtube: "YouTube icon"
275275
github: "GitHub icon"
276276
note: "note icon"
277-
events: "Related Events"
278277
privacyPolicy: "Privacy Policy"
279278
coc: "Code of Conduct"
280279
transactions: "Notation based on the Act on Specified Commercial Transactions"
281280
backTop: "Back to Top"
282281
validation:
283282
required: "The input of {target} is required."
284283
email: "The Email Address is not in the correct format."
284+
285+
relatedEvents:
286+
title: "Related Events"
287+
sectionTitle: "Related Events"
288+
linkText: "View Event Page"

i18n/en/related-events.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { RelatedEvents } from "../related-events";
2+
3+
export const RELATED_EVENTS: RelatedEvents[] = [
4+
{
5+
id: "related-events_2",
6+
title: "Frontend Conference Hokkaido 2025 After-Party: Vue.js Hands-on by Vue Fes Japan",
7+
coverUrl: "/images/related-events/vuejs-hands-on.png",
8+
coverAlt: "Thumbnail image: [Sapporo] Vue.js Hands-on by Vue Fes Japan",
9+
date: "2025-09-07",
10+
description: "This is an offline hands-on event hosted by Vue Fes Japan.\nHeld the day after Frontend Conference Hokkaido as an \"after-party\" sub-event, it aims to keep the excitement alive while offering participants a chance to deepen their learning and connections through a hands-on format focused on Vue.js.\nWhether you’re just starting to learn Vue.js or already using it, everyone is welcome!",
11+
linkUrl: "https://vuejs-meetup.connpass.com/event/365538/",
12+
},
13+
{
14+
id: "related-events_1",
15+
title: "Frontend Conference Tokyo × Vue Fes Japan Collaboration Event: Frontline Frontend for the Field",
16+
coverUrl: "/images/related-events/frontline-frontend-for-the-field.png",
17+
coverAlt: "Thumbnail image: [Tokyo] Frontline Frontend for the Field - Frontend Conference Tokyo × Vue Fes Japan Collaboration Event",
18+
date: "2025-08-25",
19+
description: "\"Frontend Conference Tokyo\" and \"Vue Fes Japan\" Join Forces in a Miracle Collaboration!\nIn anticipation of Frontend Conference Tokyo 2025 (scheduled for Sunday, September 21, 2025) and Vue Fes Japan 2025 (scheduled for Saturday, October 25, 2025), we’re holding a special must-attend event for all frontend enthusiasts!\nThe theme for this event is: \"Frontline Frontend for the Field\"!",
20+
linkUrl: "https://vuejs-meetup.connpass.com/event/363753/",
21+
},
22+
];

i18n/ja/index.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,11 +273,15 @@ snsIconImageAlt:
273273
youtube: "YouTubeアイコン"
274274
github: "GitHubアイコン"
275275
note: "noteアイコン"
276-
events: "関連イベント"
277276
privacyPolicy: "プライバシーポリシー"
278277
coc: "行動規範"
279278
transactions: "特定商取引法に基づく表示"
280279
backTop: "トップに戻る"
281280
validation:
282281
required: "{target}の入力は必須です。"
283282
email: "メールアドレスが正しい形式ではありません。"
283+
284+
relatedEvents:
285+
title: "Related Events"
286+
sectionTitle: "関連イベント"
287+
linkText: "イベントページを見る"

i18n/ja/related-events.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { RelatedEvents } from "../related-events";
2+
3+
export const RELATED_EVENTS: RelatedEvents[] = [
4+
{
5+
id: "related-events_2",
6+
title: "フロントエンドカンファレンス北海道2025 後日祭「Vue.js ハンズオン by Vue Fes Japan」",
7+
coverUrl: "/images/related-events/vuejs-hands-on.png",
8+
coverAlt: "サムネイル画像:【札幌開催】Vue.js ハンズオン by Vue Fes Japan",
9+
date: "2025-09-07",
10+
description: "Vue Fes Japan が開催するオフラインでのハンズオンイベントです。\nこのイベントは、フロントエンドカンファレンス北海道の“後日祭”として、カンファレンス翌日に開催されるサブイベントです。 イベントの熱量が冷めやらぬうちに、Vue.js にフォーカスしたハンズオン形式で、さらに学びと交流を深めることを目的としています。\nVue.js をこれから学びたい人も、すでに使っている人も、どなたでも歓迎です。",
11+
linkUrl: "https://vuejs-meetup.connpass.com/event/365538/",
12+
},
13+
{
14+
id: "related-events_1",
15+
title: "フロントエンドカンファレンス東京 x Vue Fes Japan コラボイベント「現場のためのフロントエンド最前線」",
16+
coverUrl: "/images/related-events/frontline-frontend-for-the-field.png",
17+
coverAlt: "サムネイル画像:【東京開催】現場のためのフロントエンド最前線フロントエンドカンファレンス東京 x Vue Fes Japan コラボイベント",
18+
date: "2025-08-25",
19+
description: "「フロントエンドカンファレンス東京」と「Vue Fes Japan」が奇跡の合体!\n2025/9/21(日)開催予定のフロントエンドカンファレンス東京2025、2025/10/25(土)開催予定のVue Fes Japan 2025 に向けて、フロントエンド勢必見のイベントを緊急開催します!\n本イベントのテーマは「現場のためのフロントエンド最前線」です!",
20+
linkUrl: "https://vuejs-meetup.connpass.com/event/363753/",
21+
},
22+
];

i18n/related-events.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export interface RelatedEvents {
2+
id: string;
3+
title: string;
4+
coverUrl: string;
5+
coverAlt: string;
6+
date: string;
7+
description: string;
8+
linkUrl: string;
9+
}
860 KB
Loading
273 KB
Loading

0 commit comments

Comments
 (0)