diff --git a/.github/workflows/firebase-deploy.yml b/.github/workflows/firebase-deploy.yml index bf284520..02823886 100644 --- a/.github/workflows/firebase-deploy.yml +++ b/.github/workflows/firebase-deploy.yml @@ -49,6 +49,7 @@ jobs: NOTION_DATABASE_CONFIG: ${{ secrets.NOTION_DATABASE_CONFIG }} NOTION_DATABASE_NEWS: ${{ secrets.NOTION_DATABASE_NEWS }} NOTION_DATABASE_MEETLINKS: ${{ secrets.NOTION_DATABASE_MEETLINKS }} + NOTION_DATABASE_ADVERTISEMENTS: ${{ secrets.NOTION_DATABASE_ADVERTISEMENTS }} - name: Deploy to Firebase Hosting run: | diff --git a/.github/workflows/firebase-preview.yml b/.github/workflows/firebase-preview.yml index 53f97ed4..ffb138b7 100644 --- a/.github/workflows/firebase-preview.yml +++ b/.github/workflows/firebase-preview.yml @@ -31,6 +31,7 @@ jobs: NOTION_DATABASE_CONFIG: ${{ secrets.NOTION_DATABASE_CONFIG }} NOTION_DATABASE_NEWS: ${{ secrets.NOTION_DATABASE_NEWS }} NOTION_DATABASE_MEETLINKS: ${{ secrets.NOTION_DATABASE_MEETLINKS }} + NOTION_DATABASE_ADVERTISEMENTS: ${{ secrets.NOTION_DATABASE_ADVERTISEMENTS }} - uses: FirebaseExtended/action-hosting-deploy@v0 with: diff --git a/assets/whatsThis.min.svg b/assets/whatsThis.min.svg new file mode 100644 index 00000000..6a8a2281 --- /dev/null +++ b/assets/whatsThis.min.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/components/AdvertisementGrid.vue b/components/AdvertisementGrid.vue new file mode 100644 index 00000000..0c3fee89 --- /dev/null +++ b/components/AdvertisementGrid.vue @@ -0,0 +1,158 @@ + + + + + diff --git a/components/AdvertisementGridItemModal.vue b/components/AdvertisementGridItemModal.vue new file mode 100644 index 00000000..c1debb7e --- /dev/null +++ b/components/AdvertisementGridItemModal.vue @@ -0,0 +1,159 @@ + + + + + diff --git a/nuxt.config.ts b/nuxt.config.ts index 545ee13c..2cac6fdf 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -141,6 +141,7 @@ const config: NuxtConfig = { configDatabaseId: process.env.NOTION_DATABASE_CONFIG, newsDatabaseId: process.env.NOTION_DATABASE_NEWS, meetLinksDatabaseId: process.env.NOTION_DATABASE_MEETLINKS, + advertisementsDatabaseId: process.env.NOTION_DATABASE_ADVERTISEMENTS, }, styleResources: { diff --git a/pages/about.vue b/pages/about.vue index b191089c..e031130a 100644 --- a/pages/about.vue +++ b/pages/about.vue @@ -1,9 +1,9 @@ + + + ログアウト @@ -154,6 +163,7 @@ export default Vue.extend({ diff --git a/patches/@chakra-ui+nuxt+0.3.1.patch b/patches/@chakra-ui+nuxt+0.3.1.patch index aef1592a..2bf08585 100644 --- a/patches/@chakra-ui+nuxt+0.3.1.patch +++ b/patches/@chakra-ui+nuxt+0.3.1.patch @@ -1,5 +1,5 @@ diff --git a/node_modules/@chakra-ui/nuxt/lib/plugin.js b/node_modules/@chakra-ui/nuxt/lib/plugin.js -index afe037f..35f8e3a 100644 +index afe037f..a5b8897 100644 --- a/node_modules/@chakra-ui/nuxt/lib/plugin.js +++ b/node_modules/@chakra-ui/nuxt/lib/plugin.js @@ -3,6 +3,12 @@ import { createClientDirective } from '@chakra-ui/vue/src/directives' @@ -15,3 +15,14 @@ index afe037f..35f8e3a 100644 Vue.prototype.$chakra = { theme, icons: <%= JSON.stringify(options.icons, null, 2) %> +@@ -17,5 +23,9 @@ if (process.client) { + + // VScrollLock + const VScrollLock = require('v-scroll-lock').default +- Vue.use(VScrollLock) ++ Vue.use(VScrollLock, { ++ bodyScrollOptions: { ++ reserveScrollBarGap: true, ++ } ++ }) + } diff --git a/utils/notion.ts b/utils/notion.ts index a4885213..2d165993 100644 --- a/utils/notion.ts +++ b/utils/notion.ts @@ -1,6 +1,12 @@ const NOTION_API_BASEURL = 'https://notion-api.splitbee.io/v1' const IGNORE = true as const +export interface NotionMediaItem { + name: string + url: string + rawUrl: string +} + export function fetchNotionData(type: string, id: string) { return fetch(`${NOTION_API_BASEURL}/${type}/${id}`, { method: 'GET', @@ -74,6 +80,47 @@ export function isValidNewsItem(target: any): target is NewsItem { ) } +export interface AdvertisementItem extends NotionDatabaseItem { + slug: string + title?: string + author: string + description?: string + thumbnail?: NotionMediaItem[] + link?: string + category?: string[] + isHidden?: boolean +} + +export function isValidAdvertisementItem( + target: any +): target is AdvertisementItem { + return ( + _isValidNotionDatabaseItem(target) && + isNotEmptyString(target.slug) && + ('title' in target ? isNotEmptyString(target.title) : IGNORE) && + isNotEmptyString(target.author) && + ('description' in target ? isNotEmptyString(target.description) : IGNORE) && + ('thumbnail' in target + ? Array.isArray(target.thumbnail) && + target.thumbnail.every((v: any) => isNotionMediaItem(v)) + : IGNORE) && + ('link' in target ? isNotEmptyString(target.link) : IGNORE) && + ('category' in target + ? Array.isArray(target.category) && + target.category.every((v: any) => isNotEmptyString(v)) + : IGNORE) && + ('isHidden' in target ? typeof target.isHidden === 'boolean' : IGNORE) + ) +} + function isNotEmptyString(target: any): target is string { return typeof target === 'string' && target !== '' } + +function isNotionMediaItem(target: any): target is NotionMediaItem { + return ( + isNotEmptyString(target.name) && + isNotEmptyString(target.url) && + isNotEmptyString(target.rawUrl) + ) +}