From 0edd71fb709cfc1ff6806b63aa06d811beed381a Mon Sep 17 00:00:00 2001 From: jiyuujin Date: Fri, 12 Jul 2024 17:09:07 +0900 Subject: [PATCH] update detail page (speaker, sponsor) --- apps/web/app/composables/useSponsor.ts | 16 + apps/web/app/composables/useSupabase.ts | 8 +- apps/web/app/pages/sessions/[id]/index.vue | 264 ++++++++++++++ apps/web/app/pages/sponsors/[id]/index.vue | 325 ++++++++++++++++++ apps/web/app/utils/constants.ts | 4 + apps/web/nuxt.config.ts | 20 ++ packages/model/lib/sponsor.ts | 7 +- packages/ui/components/sponsor/Tag.stories.ts | 36 ++ packages/ui/components/sponsor/Tag.vue | 29 ++ 9 files changed, 705 insertions(+), 4 deletions(-) create mode 100644 apps/web/app/composables/useSponsor.ts create mode 100644 apps/web/app/pages/sessions/[id]/index.vue create mode 100644 apps/web/app/pages/sponsors/[id]/index.vue create mode 100644 packages/ui/components/sponsor/Tag.stories.ts create mode 100644 packages/ui/components/sponsor/Tag.vue diff --git a/apps/web/app/composables/useSponsor.ts b/apps/web/app/composables/useSponsor.ts new file mode 100644 index 00000000..7742ff1f --- /dev/null +++ b/apps/web/app/composables/useSponsor.ts @@ -0,0 +1,16 @@ +import type { SponsorType, OptionSponsorType } from '@vuejs-jp/model' +import { match } from 'ts-pattern' + +export function useSponsor() { + function color(tag: SponsorType | OptionSponsorType) { + return match(tag) + .with('platinum', () => '#93AF5E') + .with('gold', () => '#FFC408') + .with('silver', () => '#ADBFD4') + .with('bronze', () => '#F17C67') + .with('option', 'option-separate', 'name-card', 'special-naming-rights', 'after-party', 'simultaneous-interpretation', 'special-lunch', 'media', 'tool', () => '#546F89') + .exhaustive() + } + + return { color } +} diff --git a/apps/web/app/composables/useSupabase.ts b/apps/web/app/composables/useSupabase.ts index 57f9e6af..e78165ea 100644 --- a/apps/web/app/composables/useSupabase.ts +++ b/apps/web/app/composables/useSupabase.ts @@ -6,7 +6,13 @@ import type { FormSpeaker, FormSponsor, FormAttendee, FormStaff } from '~/types/ export function useSupabase() { const client = useSupabaseClient() - async function fetchData(table: Table) { + async function fetchData(table: Table, options?: { id?: string; detailPageId?: string }) { + if (options?.id) { + return await client.from(table).select().eq('id', options.id) + } + if (options?.detailPageId) { + return await client.from(table).select().eq('detail_page_id', options.detailPageId) + } return await client.from(table).select() } diff --git a/apps/web/app/pages/sessions/[id]/index.vue b/apps/web/app/pages/sessions/[id]/index.vue new file mode 100644 index 00000000..5f870443 --- /dev/null +++ b/apps/web/app/pages/sessions/[id]/index.vue @@ -0,0 +1,264 @@ + + + + + diff --git a/apps/web/app/pages/sponsors/[id]/index.vue b/apps/web/app/pages/sponsors/[id]/index.vue new file mode 100644 index 00000000..2c54b6dd --- /dev/null +++ b/apps/web/app/pages/sponsors/[id]/index.vue @@ -0,0 +1,325 @@ + + + + + diff --git a/apps/web/app/utils/constants.ts b/apps/web/app/utils/constants.ts index e8256e22..1e32b917 100644 --- a/apps/web/app/utils/constants.ts +++ b/apps/web/app/utils/constants.ts @@ -8,6 +8,10 @@ export const ogCoCDescription = export const ogPrivacyDescription = 'Vue Fes Japan 2024 のプライバシーポリシーです。' +export const ogSpeakerDescription = 'Vue Fes Japan 2024 のスピーカー、セッション情報です。' + +export const ogSponsorDescription = 'Vue Fes Japan 2024 のスポンサー情報です。' + export const ogJobboardDescription = 'Vue Fes Japan 2024 のジョブボードです。' export const linkUrl = 'https://vuefes.jp/2024/' diff --git a/apps/web/nuxt.config.ts b/apps/web/nuxt.config.ts index 331c9933..e25c7737 100644 --- a/apps/web/nuxt.config.ts +++ b/apps/web/nuxt.config.ts @@ -1,3 +1,4 @@ +import { createClient } from '@supabase/supabase-js' import svgLoader from 'vite-svg-loader' import { conferenceTitle } from './app/utils/constants' import { generalOg, twitterOg } from './app/utils/og.constants' @@ -87,6 +88,7 @@ export default defineNuxtConfig({ nitro: { prerender: { crawlLinks: true, + failOnError: false, routes: ['/'], ignore: ['/api'], }, @@ -105,6 +107,20 @@ export default defineNuxtConfig({ const supabaseKey = process.env.SUPABASE_KEY const serviceKey = process.env.SERVICE_KEY if (!supabaseUrl || !supabaseKey || serviceKey) return + + const client = createClient(supabaseUrl, supabaseKey, {}) + const { data: speakers, error: error1 } = await client.from('speakers').select() + const { data: sponsors, error: error2 } = await client.from('sponsors').select() + if (error1 || error2) return + + const speakerRoutes = speakers?.map((d) => `/sessions/${d.detail_page_id}`) + const speakerEnRoutes = speakers?.map((d) => `/en/sessions/${d.detail_page_id}`) + const sponsorRoutes = sponsors?.map((d) => `/sponsors/${d.detail_page_id}`) + const sponsorEnRoutes = sponsors?.map((d) => `/en/sponsors/${d.detail_page_id}`) + nitroConfig.prerender?.routes?.push(...(speakerRoutes || [])) + nitroConfig.prerender?.routes?.push(...(speakerEnRoutes || [])) + nitroConfig.prerender?.routes?.push(...(sponsorRoutes || [])) + nitroConfig.prerender?.routes?.push(...(sponsorEnRoutes || [])) }, 'prerender:routes': (context) => { for (const path of [...context.routes]) { @@ -125,6 +141,10 @@ export default defineNuxtConfig({ 'postcss-custom-media': {}, }, }, + routeRules: { + '/sessions/': { prerender: true }, + '/sponsors/': { prerender: true }, + }, runtimeConfig: { public: { gtagId: process.env.NUXT_GTAG_ID, diff --git a/packages/model/lib/sponsor.ts b/packages/model/lib/sponsor.ts index b060f9c1..b83bbc55 100644 --- a/packages/model/lib/sponsor.ts +++ b/packages/model/lib/sponsor.ts @@ -1,4 +1,4 @@ -type SponsorType = 'platinum' | 'gold' | 'silver' | 'bronze' | 'option' | 'option-separate' +export type SponsorType = 'platinum' | 'gold' | 'silver' | 'bronze' | 'option' | 'option-separate' export type SponsorCategory = | 'platinumSponsors' @@ -14,7 +14,8 @@ export type SponsorCategory = | 'toolSponsors' -type Tag = 'name-card' +export type OptionSponsorType = + | 'name-card' | 'special-naming-rights' | 'after-party' | 'simultaneous-interpretation' @@ -30,7 +31,7 @@ export type Sponsor = { description_en: string speaker_id?: string image_url: string - tag: Array + tag: Array link_url: string is_open: boolean display_order?: number diff --git a/packages/ui/components/sponsor/Tag.stories.ts b/packages/ui/components/sponsor/Tag.stories.ts new file mode 100644 index 00000000..5c4fd957 --- /dev/null +++ b/packages/ui/components/sponsor/Tag.stories.ts @@ -0,0 +1,36 @@ +import { StoryFn } from '@storybook/vue3' +import Tag from './Tag.vue' + +export default { + title: 'sponsor/Tag', + component: Tag, + args: { + background: '#93AF5E', + label: 'プラチナ', + }, + argTypes: { + background: { + description: 'The background property', + control: { + type: 'text', + }, + }, + label: { + description: 'The label property', + control: { + type: 'text', + }, + }, + }, +} + +const Template: StoryFn = (args, { argTypes }) => ({ + props: Object.keys(argTypes), + components: { Tag }, + setup() { + return { args } + }, + template: '', +}) + +export const Default = Template.bind({}) diff --git a/packages/ui/components/sponsor/Tag.vue b/packages/ui/components/sponsor/Tag.vue new file mode 100644 index 00000000..d19f9b20 --- /dev/null +++ b/packages/ui/components/sponsor/Tag.vue @@ -0,0 +1,29 @@ + + + + +