Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/web/app/components/FooterPageSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ const snsLinkList: LinkList[] = [
},
]
const internalLinkList: LinkList[] = [
{
href: '/events',
text: 'related_events.title',
},
{
href: '/privacy',
text: 'privacy.title',
Expand Down
5 changes: 5 additions & 0 deletions apps/web/app/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -281,5 +281,10 @@
},
"sharemap": {
"title": "Share URL"
},
"related_events": {
"title": "Related Events",
"register": "Register for the event",
"close": "The event has ended"
}
}
5 changes: 5 additions & 0 deletions apps/web/app/lang/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -299,5 +299,10 @@
},
"sharemap": {
"title": "シェアURL"
},
"related_events": {
"title": "関連イベント",
"register": "イベントに参加する",
"close": "イベントは終了しました"
}
}
187 changes: 187 additions & 0 deletions apps/web/app/pages/events.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
<script setup lang="ts">
import { useFetch, useHead } from '#imports'
import { useLocaleCurrent } from '~/composables/useLocaleCurrent'
import type { RelatedEventInfo } from '@vuejs-jp/model'
import { conferenceTitle, linkUrl, ogRelatedEventDescription } from '~/utils/constants'
import { generalOg, twitterOg } from '~/utils/og.constants'

type RelatedEvents = Record<'eventsInfo', RelatedEventInfo>

const { data, error } = await useFetch('/api/events')
if (error.value) {
console.error(error.value)
}
const { eventsInfo } = data.value as RelatedEvents

const { path: localePath } = useLocaleCurrent()

const isClose = (startedAt: string) =>
new Date() > new Date(new Date(startedAt).getFullYear(), new Date(startedAt).getMonth(), new Date(startedAt).getDate())

useHead({
titleTemplate: (titleChunk) => `関連イベント | ${conferenceTitle}`,
meta: [
...generalOg({
title: `関連イベント | ${conferenceTitle}`,
description: ogRelatedEventDescription,
url: `${linkUrl}events`,
}),
...twitterOg({
title: `関連イベント | ${conferenceTitle}`,
description: ogRelatedEventDescription,
url: `${linkUrl}events`,
}),
],
})
</script>

<template>
<VFPageHeading>{{ $t('related_events.title') }}</VFPageHeading>
<div class="related-events">
<ul class="related-events-body">
<li v-for="(event, index) in eventsInfo.list" :key="index">
<VFRelatedEventFrame
:src="event.bannerUrl"
:alt="event.title"
:register-url="event.registerUrl"
:register-action-text="isClose(event.startedAt) ? $t('related_events.close') : $t('related_events.register')"
:disabled="isClose(event.startedAt)"
>
<template #title>
{{ event.title }}
</template>
<template #description>
{{ event.description }}
</template>
</VFRelatedEventFrame>
</li>
</ul>
<div class="back">
<VFLinkButton
class="back-action"
background-color="white"
color="vue-blue"
target=""
:href="`${localePath}/`"
>
{{ $t('back_to_top') }}
</VFLinkButton>
</div>
</div>
</template>

<style scoped>
@import url('../assets/base.css');
@import url('../assets/media.css');

.related-events {
margin: 0;
padding: 0 1.5%;
background-image: linear-gradient(#fff, #ebf0f5);
position: relative;
z-index: 0;
overflow: hidden;

@media (--tablet) {
padding: 0 6%;
}

&:before {
content: "";
position: absolute;
display: block;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('/form-bg.png');
background-size: auto;
background-repeat: repeat;
background-position: bottom left;
opacity: 0.8;
mix-blend-mode: overlay;
z-index: -1;
}
}

.related-events-body {
margin: 0 auto;
padding: 60px 0 120px;
width: 100%;
max-width: 960px;
display: flex;
flex-wrap: wrap;
justify-content: center;

@media (--tablet) {
padding: 20px 0 60px;
max-width: 100%
}

li {
width: calc((100% - 4%) / 2);

@media (--tablet) {
width: 100%;
}

&:nth-child(even) {
margin-left: 4%;

@media (--tablet) {
margin-left: 0;
}
}

@media (--tablet) {
&:nth-child(n + 2) {
margin-top: 20px;
}
}

&:nth-child(n + 3) {
margin-top: 4%;

@media (--tablet) {
margin-top: 20px;
}
}
}

a {
border-radius: 12px;
overflow: hidden;
display: block;
}
}

.back {
margin: 40px auto 120px;
width: 100%;
max-width: 260px;
}
.back-action {
--height-button: 66px;

height: var(--height-button);
border-radius: var(--height-button);
}

@media (--tablet) {
.back-action {
--height-button: 58px;
}
}

@media (--mobile) {
.back {
width: 100%;
padding: 0 23.5px;
margin-top: 30px;
margin-bottom: 60px;
}
.back-action {
--height-button: 58px;
}
}
</style>
16 changes: 16 additions & 0 deletions apps/web/app/server/api/events.get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import db from '../db'
import { defineEventHandler } from 'h3'
import type { RelatedEvent, RelatedEventInfo } from '@vuejs-jp/model'

export default defineEventHandler(async (event) => {
const response = await db.event.getList()
const eventData = response.default as RelatedEvent[]

const eventsInfo: RelatedEventInfo = {
type: 'related-event',
title: 'related-event',
list: eventData,
}

return { eventsInfo }
})
8 changes: 8 additions & 0 deletions apps/web/app/server/db/event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class Event {
async getList() {
const events = await import('~/utils/data/events.json')
return events
}
}

export default new Event()
4 changes: 3 additions & 1 deletion apps/web/app/server/db/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import event from './event'
import speaker from './speaker'
import sponsor from './sponsor'
import timetable from './timetable'

export default {
event,
speaker,
sponsor,
timetable
timetable,
}
3 changes: 1 addition & 2 deletions apps/web/app/server/db/speaker.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
class Speaker {
async getList() {
// TODO: supabaseからデータを取得する
const speakers = await import('~/utils/data/speakers.json')
return speakers
}
}

export default new Speaker()
export default new Speaker()
1 change: 0 additions & 1 deletion apps/web/app/server/db/sponsor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

class Sponsor {
async getList() {
// TODO: supabaseからデータを取得する
const sponsors = await import('~/utils/data/sponsors.json')
return sponsors
}
Expand Down
2 changes: 2 additions & 0 deletions apps/web/app/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export const ogNamecardDescription = 'さんのネームカードです。'

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

export const ogRelatedEventDescription = 'Vue Fes Japan 2024 の関連イベントです。'

export const linkUrl = 'https://vuefes.jp/2024/'

export const vuefesTwitterID = '@vuefes'
Expand Down
23 changes: 23 additions & 0 deletions apps/web/app/utils/data/events.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[
{
"title": "Vue Fes Japan × TSKaigi 合同イベント「次世代フロントエンドツールチェイン」",
"description": "Vue.js カンファレンス「Vue Fes Japan」と TypeScript カンファレンス「TSKaigi」が奇跡の合体!2024/10/19(土)開催予定の Vue Fes Japan 2024、2024/11/16(土)開催予定の TSKaigi Kansai 2024 に向けて、フロントエンド勢必見のイベントを緊急開催します!",
"startedAt": "2024/10/02",
"bannerUrl": "https://media.connpass.com/thumbs/f0/bb/f0bb7d40ab7393c91d6f3b9db5c0a1de.png",
"registerUrl": "https://vuejs-meetup.connpass.com/event/330325/"
},
{
"title": "Vue Fes Japan 2024 Pre LT Party",
"description": "まもなく開催される Vue Fes Japan 2024 に向け、Vue Fes Japan 2024 のゴールドスポンサーであるオプティムとeveryの共同開催で前夜祭(非公式)を開催します!Vue を中心に知識と交流の輪を広げましょう。",
"startedAt": "2024/10/17",
"bannerUrl": "https://media.connpass.com/thumbs/2b/28/2b280631579ea12bfb32af0237a54cbf.png",
"registerUrl": "https://optim.connpass.com/event/330716/"
},
{
"title": "Vue Fes Japan 2024 After Night",
"description": "Vue Fes Japan 2024 のアフターイベントを、スポンサー企業 4 社 (株式会社スタディスト、弁護士ドットコム株式会社、株式会社コドモン、株式会社エブリー) で共同開催します。",
"startedAt": "2024/10/30",
"bannerUrl": "https://media.connpass.com/thumbs/52/f1/52f1267c106785d9fda25602c966b02a.png",
"registerUrl": "https://studist.connpass.com/event/327702/"
}
]
5 changes: 5 additions & 0 deletions apps/web/netlify.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
to = "/2024/sharemap/index.html"
status = 200

[[redirects]]
from = "/2024/events"
to = "/2024/events/index.html"
status = 200

[[redirects]]
from = "/2024/jobboard"
to = "/2024/jobboard/index.html"
Expand Down
1 change: 1 addition & 0 deletions apps/web/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ export default defineNuxtConfig({
},
},
routeRules: {
'/events/': { prerender: true },
'/jobboard/': { prerender: true },
'/namecard/': { prerender: true },
'/sharemap/': { prerender: true },
Expand Down
1 change: 1 addition & 0 deletions packages/model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export * from './lib/job'
export * from './lib/namecard'
export * from './lib/path'
export * from './lib/peatix'
export * from './lib/related-event'
export * from './lib/speaker'
export * from './lib/sponsor'
export * from './lib/staff'
Expand Down
14 changes: 14 additions & 0 deletions packages/model/lib/related-event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export interface RelatedEvent {
title: string
description: string
startedAt: string
bannerUrl: string
registerUrl: string
disabled?: boolean
}

export interface RelatedEventInfo {
type: 'related-event'
title: 'related-event'
list: RelatedEvent[]
}
Loading
Loading