Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -1,20 +1,37 @@
<script setup lang="ts">
import type { Sponsor } from '#shared/types/sponsor'
import { useI18n } from 'vue-i18n'

const { sponsor } = defineProps<{
sponsor: Sponsor
export interface ContentCardItem {
id: string
title: {
zh: string
en: string
}
intro: {
zh: string
en: string
}
link: string
image: string
reward_type?: string
reward_data?: number
}

const { item } = defineProps<{
item: ContentCardItem
}>()

const { locale, t } = useI18n()
const activeLocale = computed(() => locale.value === 'zh' ? 'zh' : 'en')

const needsExpand = computed(() => item.intro[activeLocale.value]?.length > 200)

const needsExpand = computed(() => sponsor.intro[locale.value]?.length > 200)
const hasRibbon = computed(() => sponsor.reward_type !== 'Null' && sponsor.reward_data > 0)
const hasRibbon = computed(() => item.reward_type !== 'Null' && item.reward_data && item.reward_data > 0)
const ribbonColorClass = computed(() =>
sponsor.reward_type === '連續贊助' ? 'bg-amber-400' : 'bg-teal-500',
item.reward_type === '連續贊助' ? 'bg-amber-400' : 'bg-teal-500',
)
const ribbonTypeKey = computed(() =>
sponsor.reward_type === '連續贊助' ? 'consecutive' : 'cumulative',
item.reward_type === '連續贊助' ? 'consecutive' : 'cumulative',
)
</script>

Expand All @@ -26,19 +43,19 @@ const ribbonTypeKey = computed(() =>
:class="ribbonColorClass"
>
<span class="block">{{ t(`ribbon.${ribbonTypeKey}`) }}</span>
<span class="block">{{ t('ribbon.years', { n: sponsor.reward_data }) }}</span>
<span class="block">{{ t('ribbon.years', { n: item.reward_data }) }}</span>
</span>
<NuxtLink
class="p-4 rounded-xl bg-white flex shrink-0 w-full aspect-[3/2] items-center justify-center md:w-60 md:aspect-[3/2]"
external
rel="noreferrer"
target="_blank"
:to="sponsor.link"
:to="item.link"
>
<NuxtImg
:alt="sponsor.name[locale]"
:alt="item.title[locale]"
class="h-full w-full object-contain"
:src="sponsor.image"
:src="item.image"
/>
</NuxtLink>

Expand All @@ -49,31 +66,31 @@ const ribbonTypeKey = computed(() =>
external
rel="noreferrer"
target="_blank"
:to="sponsor.link"
:to="item.link"
>
{{ sponsor.name[locale] }}
{{ item.title[locale] }}
</NuxtLink>
</h3>

<template v-if="needsExpand">
<input
:id="`expand-${sponsor.id}`"
:id="`expand-${item.id}`"
class="peer sr-only"
type="checkbox"
>
<MDC
class="text-sm text-primary-700 leading-7 mt-3 text-left line-clamp-5 prose peer-checked:line-clamp-none"
:value="sponsor.intro[locale]"
:value="item.intro[locale]"
/>
<label
class="text-xs text-primary-500 mt-1 block cursor-pointer hover:underline peer-checked:hidden"
:for="`expand-${sponsor.id}`"
:for="`expand-${item.id}`"
>
{{ t('read_more') }}
</label>
<label
class="text-xs text-primary-500 mt-1 hidden cursor-pointer hover:underline peer-checked:block"
:for="`expand-${sponsor.id}`"
:for="`expand-${item.id}`"
>
{{ t('show_less') }}
</label>
Expand All @@ -82,7 +99,7 @@ const ribbonTypeKey = computed(() =>
<MDC
v-else
class="text-sm text-primary-700 leading-7 mt-3 text-left prose"
:value="sponsor.intro[locale]"
:value="item.intro[locale]"
/>
</div>
</article>
Expand Down
43 changes: 43 additions & 0 deletions app/pages/fringe.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<script setup lang="ts">
import type { Fringe } from '#shared/types/fringe'
import { useI18n } from 'vue-i18n'
import CpContentCard from '~/components/shared/CpContentCard.vue'

const { t } = useI18n()

const { data: fringes } = await useFetch<Fringe[]>('/api/fringe')
Comment thread
Link1515 marked this conversation as resolved.
const noFringe = computed(() => !fringes.value || fringes.value.length === 0)
</script>

<template>
<main class="mx-auto my-8 max-w-[80vw] w-[1200px]">
<section v-if="noFringe">
<p class="text-primary-500 text-center">
{{ t('noFringe') }}
</p>
</section>
<section
v-else
class="gap-4 grid"
>
<CpContentCard
v-for="fringe in fringes"
:key="fringe.id"
:item="{
id: `fringe-${fringe.id}`,
title: fringe.title,
intro: fringe.intro,
link: fringe.link,
image: fringe.logo,
}"
/>
</section>
</main>
</template>

<i18n lang="yaml">
zh:
noFringe: "周邊活動目前尚未公布。"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

這個文字我等等去大籌上問問,可能會需要像是:「如果有你有活動,可以到....申請」

en:
noFringe: "Fringe events have not been announced yet."
</i18n>
14 changes: 12 additions & 2 deletions app/pages/sponsor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import type { Sponsor } from '#shared/types/sponsor'
import { useI18n } from 'vue-i18n'
import { SPONSOR_LEVELS } from '#shared/types/sponsor'
import SponsorCard from '~/components/feature/CpSponsorCard.vue'
import CpContentCard from '~/components/shared/CpContentCard.vue'

const { t } = useI18n()
const localePath = useLocalePath()
Expand Down Expand Up @@ -80,7 +80,17 @@ useSeoMeta({
v-for="sponsor in sponsors"
:key="sponsor.id"
>
<SponsorCard :sponsor="sponsor" />
<CpContentCard
:item="{
id: `sponsor-${sponsor.id}`,
title: sponsor.name,
intro: sponsor.intro,
link: sponsor.link,
image: sponsor.image,
reward_type: sponsor.reward_type,
reward_data: sponsor.reward_data,
}"
/>
</div>
</div>
</div>
Expand Down
16 changes: 16 additions & 0 deletions server/api/fringe.get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { transformGoogleDriveImageUrl } from '../utils/images'
import { fetchSheet } from '../utils/sheets'

export default defineEventHandler(async () => {
const fringeRows = await fetchSheet('fringe')

const fringes = import.meta.dev ? fringeRows : fringeRows.filter(({ publish }) => publish)

return fringes.map(({ id, title_zh, title_en, intro_zh, intro_en, link, logo }) => ({
id,
title: { zh: title_zh, en: title_en },
intro: { zh: intro_zh, en: intro_en },
link,
logo: transformGoogleDriveImageUrl(logo),
}))
})
14 changes: 2 additions & 12 deletions server/api/sponsor.get.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
import { transformGoogleDriveImageUrl } from '../utils/images'
import { fetchSheet } from '../utils/sheets'

function transformImageUrl(source: string) {
if (source.startsWith('https://drive.google.com/file/d/')) {
const id = source.split('/')[5]
const url = `https://drive.google.com/thumbnail?id=${id}`

return url
}

return source
}

export default defineEventHandler(async () => {
const sheets = await fetchSheet('sponsor-list')

Expand All @@ -22,6 +12,6 @@ export default defineEventHandler(async () => {
...attr,
name: { zh: name_zh, en: name_en },
intro: { zh: intro_zh, en: intro_en },
image: transformImageUrl(image),
image: transformGoogleDriveImageUrl(image),
}))
})
9 changes: 9 additions & 0 deletions server/utils/images/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function transformGoogleDriveImageUrl(source: string) {
if (source.startsWith('https://drive.google.com/file/d/')) {
const id = source.split('/')[5]

return `https://drive.google.com/thumbnail?id=${id}`
}

return source
}
30 changes: 30 additions & 0 deletions shared/types/fringe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { z } from 'zod'

export const FringeRowSchema = z.object({
id: z.string(),
title_zh: z.string(),
title_en: z.string(),
intro_zh: z.string(),
intro_en: z.string(),
link: z.string(),
contact: z.string(),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

或許可以想想怎麼把 contact 的資訊呈現出來

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

想確認一下 contact 欄位是什麼意思呢? 是聯絡人嗎?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

對的喔

contact_email: z.string(),
logo: z.string(),
publish: z.string().transform((val) => val.trim().toLowerCase() === 'true'),
})
export type FringeRow = z.infer<typeof FringeRowSchema>

export const FringeSchema = z.object({
id: z.string(),
title: z.object({
zh: z.string(),
en: z.string(),
}),
intro: z.object({
zh: z.string(),
en: z.string(),
}),
link: z.string(),
logo: z.string(),
})
export type Fringe = z.infer<typeof FringeSchema>
5 changes: 4 additions & 1 deletion shared/types/sheets.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import type * as z from 'zod'
import { FringeRowSchema } from './fringe'
import { SponsorListRowSchema } from './sponsor'
import { SponsorshipAddOnSchema, SponsorshipTierSchema } from './sponsorship'
import { StaffRowSchema } from './staff'

export type SheetID = typeof SHEET_IDS[number]

export const SHEET_IDS = Object.freeze(['sponsorship-tiers', 'sponsorship-add-ons-zh', 'sponsorship-add-ons-en', 'sponsor-list', 'staff'] as const)
export const SHEET_IDS = Object.freeze(['sponsorship-tiers', 'sponsorship-add-ons-zh', 'sponsorship-add-ons-en', 'sponsor-list', 'staff', 'fringe'] as const)
Comment thread
Link1515 marked this conversation as resolved.
export const SHEET_NAMES = Object.freeze({
'sponsorship-tiers': '贊助方案',
'sponsorship-add-ons-zh': '贊助方案加價購(中文)',
'sponsorship-add-ons-en': '贊助方案加價購(英文)',
'sponsor-list': '贊助列表',
'staff': '工作夥伴',
'fringe': '周邊資訊',
} satisfies Record<SheetID, string>)
export const SHEET_SCHEMAS = Object.freeze({
'sponsorship-tiers': SponsorshipTierSchema,
'sponsorship-add-ons-zh': SponsorshipAddOnSchema,
'sponsorship-add-ons-en': SponsorshipAddOnSchema,
'sponsor-list': SponsorListRowSchema,
'staff': StaffRowSchema,
'fringe': FringeRowSchema,
} satisfies Record<SheetID, z.Schema>)