diff --git a/apps/web/app/components/FooterPageSection.vue b/apps/web/app/components/FooterPageSection.vue index bead1e55..c8c35e6c 100644 --- a/apps/web/app/components/FooterPageSection.vue +++ b/apps/web/app/components/FooterPageSection.vue @@ -37,6 +37,10 @@ const snsLinkList: LinkList[] = [ }, ] const internalLinkList: LinkList[] = [ + { + href: '/events', + text: 'related_events.title', + }, { href: '/privacy', text: 'privacy.title', diff --git a/apps/web/app/lang/en.json b/apps/web/app/lang/en.json index 436d8780..3fd3785b 100644 --- a/apps/web/app/lang/en.json +++ b/apps/web/app/lang/en.json @@ -281,5 +281,10 @@ }, "sharemap": { "title": "Share URL" + }, + "related_events": { + "title": "Related Events", + "register": "Register for the event", + "close": "The event has ended" } } diff --git a/apps/web/app/lang/ja.json b/apps/web/app/lang/ja.json index 81664aeb..b35c5e1d 100644 --- a/apps/web/app/lang/ja.json +++ b/apps/web/app/lang/ja.json @@ -299,5 +299,10 @@ }, "sharemap": { "title": "シェアURL" + }, + "related_events": { + "title": "関連イベント", + "register": "イベントに参加する", + "close": "イベントは終了しました" } } diff --git a/apps/web/app/pages/events.vue b/apps/web/app/pages/events.vue new file mode 100644 index 00000000..75999ef7 --- /dev/null +++ b/apps/web/app/pages/events.vue @@ -0,0 +1,187 @@ + + + + + diff --git a/apps/web/app/server/api/events.get.ts b/apps/web/app/server/api/events.get.ts new file mode 100644 index 00000000..89be2974 --- /dev/null +++ b/apps/web/app/server/api/events.get.ts @@ -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 } +}) diff --git a/apps/web/app/server/db/event.ts b/apps/web/app/server/db/event.ts new file mode 100644 index 00000000..c7f79500 --- /dev/null +++ b/apps/web/app/server/db/event.ts @@ -0,0 +1,8 @@ +class Event { + async getList() { + const events = await import('~/utils/data/events.json') + return events + } +} + +export default new Event() diff --git a/apps/web/app/server/db/index.ts b/apps/web/app/server/db/index.ts index fcbceedf..fb72fddf 100644 --- a/apps/web/app/server/db/index.ts +++ b/apps/web/app/server/db/index.ts @@ -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, } diff --git a/apps/web/app/server/db/speaker.ts b/apps/web/app/server/db/speaker.ts index 858b92e5..d17ee0ac 100644 --- a/apps/web/app/server/db/speaker.ts +++ b/apps/web/app/server/db/speaker.ts @@ -1,9 +1,8 @@ class Speaker { async getList() { - // TODO: supabaseからデータを取得する const speakers = await import('~/utils/data/speakers.json') return speakers } } -export default new Speaker() \ No newline at end of file +export default new Speaker() diff --git a/apps/web/app/server/db/sponsor.ts b/apps/web/app/server/db/sponsor.ts index 872a35bb..e6641e70 100644 --- a/apps/web/app/server/db/sponsor.ts +++ b/apps/web/app/server/db/sponsor.ts @@ -1,7 +1,6 @@ class Sponsor { async getList() { - // TODO: supabaseからデータを取得する const sponsors = await import('~/utils/data/sponsors.json') return sponsors } diff --git a/apps/web/app/utils/constants.ts b/apps/web/app/utils/constants.ts index 30c38286..47a96399 100644 --- a/apps/web/app/utils/constants.ts +++ b/apps/web/app/utils/constants.ts @@ -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' diff --git a/apps/web/app/utils/data/events.json b/apps/web/app/utils/data/events.json new file mode 100644 index 00000000..22e05b87 --- /dev/null +++ b/apps/web/app/utils/data/events.json @@ -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/" + } +] \ No newline at end of file diff --git a/apps/web/netlify.toml b/apps/web/netlify.toml index 532c35be..e5b444e6 100644 --- a/apps/web/netlify.toml +++ b/apps/web/netlify.toml @@ -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" diff --git a/apps/web/nuxt.config.ts b/apps/web/nuxt.config.ts index e1eecc8d..0a7c714e 100644 --- a/apps/web/nuxt.config.ts +++ b/apps/web/nuxt.config.ts @@ -162,6 +162,7 @@ export default defineNuxtConfig({ }, }, routeRules: { + '/events/': { prerender: true }, '/jobboard/': { prerender: true }, '/namecard/': { prerender: true }, '/sharemap/': { prerender: true }, diff --git a/packages/model/index.ts b/packages/model/index.ts index 675f6967..36b741a0 100644 --- a/packages/model/index.ts +++ b/packages/model/index.ts @@ -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' diff --git a/packages/model/lib/related-event.ts b/packages/model/lib/related-event.ts new file mode 100644 index 00000000..76d677ee --- /dev/null +++ b/packages/model/lib/related-event.ts @@ -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[] +} diff --git a/packages/ui/components/event/RelatedEventFrame.stories.ts b/packages/ui/components/event/RelatedEventFrame.stories.ts new file mode 100644 index 00000000..4b91378d --- /dev/null +++ b/packages/ui/components/event/RelatedEventFrame.stories.ts @@ -0,0 +1,64 @@ +import { StoryFn } from '@storybook/vue3' +import RelatedEventFrame from './RelatedEventFrame.vue' + +export default { + title: 'event/RelatedEventFrame', + component: RelatedEventFrame, + args: { + src: 'https://media.connpass.com/thumbs/f0/bb/f0bb7d40ab7393c91d6f3b9db5c0a1de.png', + alt: 'Vue Fes Japan × TSKaigi 合同イベント「次世代フロントエンドツールチェイン」', + registerUrl: 'https://vuejs-meetup.connpass.com/event/330325/', + registerActionText: '参加する', + }, + argTypes: { + src: { + description: 'The src property', + control: { + type: 'text', + }, + }, + alt: { + description: 'The alt property', + control: { + type: 'text', + }, + }, + registerUrl: { + description: 'The registerUrl property', + control: { + type: 'text', + }, + }, + registerActionText: { + description: 'The registerActionText property', + control: { + type: 'text', + }, + }, + description: { + description: 'The description property', + control: { + type: 'text', + }, + }, + }, +} + +const Template: StoryFn = (args, { argTypes }) => ({ + props: Object.keys(argTypes), + components: { RelatedEventFrame }, + setup() { + return { args } + }, + template: ` + + + `, +}) + +export const Default = Template.bind({}) + +export const Disabled = Template.bind({}) +Disabled.args = { + disabled: true, +} diff --git a/packages/ui/components/event/RelatedEventFrame.vue b/packages/ui/components/event/RelatedEventFrame.vue new file mode 100644 index 00000000..1742acbe --- /dev/null +++ b/packages/ui/components/event/RelatedEventFrame.vue @@ -0,0 +1,114 @@ + + + + + diff --git a/packages/ui/components/link/LinkButton.vue b/packages/ui/components/link/LinkButton.vue index a1abd7b6..c1626fc0 100644 --- a/packages/ui/components/link/LinkButton.vue +++ b/packages/ui/components/link/LinkButton.vue @@ -33,6 +33,15 @@ const hoverOut = () => { hover.value = false } const style = computed(() => { + if (props.is === 'a' && props.disabled) { + return { + color: '#35495e', + pointerEvents: 'none', + opacity: 0.6, + boxShadow: 'none', + backgroundColor: '#C9DAEA', + } + } if (hover.value) { return { fontWeight: fontWeight('heading/200'), @@ -67,7 +76,7 @@ const iconColor = computed(() => { :is="is ?? 'a'" :href :target - :disabled + :disabled="is === 'button' ? props.disabled : undefined" :style class="link-button" @mouseover="hoverIn"