From 484e88013e29da332fa134392897b80c1d06c114 Mon Sep 17 00:00:00 2001 From: aggre Date: Fri, 5 Apr 2024 10:56:33 +0900 Subject: [PATCH] supports PageContentHomeBeforeContent slots --- preview/config.ts | 6 ++ preview/src/theme/Default.astro | 13 ++++ src/db/redis.ts | 30 ++++---- src/index.ts | 120 ++++++++++++++++++++------------ src/types.ts | 8 +++ 5 files changed, 117 insertions(+), 60 deletions(-) diff --git a/preview/config.ts b/preview/config.ts index 28d102278..215ed098d 100644 --- a/preview/config.ts +++ b/preview/config.ts @@ -80,6 +80,12 @@ export default () => memberships: [payloads[0], payloads[1], payloads[2]], // You can post only if you have either Tier-1, Tier-2, or Tier-3. }, }, + slots: { + 'page:content:home:before-content': { + title: 'News', + items: 5, + }, + }, }, { id: 'default-3', diff --git a/preview/src/theme/Default.astro b/preview/src/theme/Default.astro index e6f154209..b098edebf 100644 --- a/preview/src/theme/Default.astro +++ b/preview/src/theme/Default.astro @@ -1,5 +1,13 @@ --- +import { ClubsSlotName, type ClubsPropsPages } from '@devprotocol/clubs-core' import '@devprotocol/clubs-core/styles' + +type Props = ClubsPropsPages +const { clubs } = Astro.props + +const SlotsPageContentHomeBeforeContent = clubs.slots.filter( + (slot) => slot.slot === ClubsSlotName.PageContentHomeBeforeContent, +) --- @@ -11,6 +19,11 @@ import '@devprotocol/clubs-core/styles'
+ { + SlotsPageContentHomeBeforeContent.map((Slot) => ( + + )) + }
diff --git a/src/db/redis.ts b/src/db/redis.ts index 309a6de7b..768f62f99 100644 --- a/src/db/redis.ts +++ b/src/db/redis.ts @@ -15,23 +15,25 @@ import { import { reduceBy } from 'ramda' import { uuidToQuery } from '../fixtures/search' -const defaultClient = createClient({ - url: import.meta.env.REDIS_URL, - username: import.meta.env.REDIS_USERNAME ?? '', - password: import.meta.env.REDIS_PASSWORD ?? '', - socket: { - keepAlive: 1, - reconnectStrategy: 1, - }, -}) - -export type RedisDefaultClient = typeof defaultClient +const defaultClient = () => + createClient({ + url: import.meta.env.REDIS_URL, + username: import.meta.env.REDIS_USERNAME ?? '', + password: import.meta.env.REDIS_PASSWORD ?? '', + socket: { + keepAlive: 1, + reconnectStrategy: 1, + }, + }) + +export type RedisDefaultClient = ReturnType export const getDefaultClient = async () => { - if (defaultClient.isOpen === false) { - await defaultClient.connect() + const client = defaultClient() + if (client.isOpen === false) { + await client.connect() } - return defaultClient + return client } export const getAllPosts = async ({ diff --git a/src/index.ts b/src/index.ts index e2ebb600c..54e7ab4d5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,13 +12,14 @@ import { type ClubsApiPath, SinglePath, type Membership, + ClubsSlotName, } from '@devprotocol/clubs-core' import { addCommentHandler, deleteCommentHandler, fetchCommentsHandler, } from './apiHandler/comment' -import { maskFactory } from './fixtures/masking' +import { mask, maskFactory } from './fixtures/masking' import { addReactionHandler } from './apiHandler/reactions' import { addPostHandler, @@ -27,7 +28,11 @@ import { } from './apiHandler/posts' import { v5 as uuidv5 } from 'uuid' import { verifyMessage } from 'ethers' -import { whenDefinedAll, type UndefinedOr } from '@devprotocol/util-ts' +import { + isNotError, + whenDefinedAll, + type UndefinedOr, +} from '@devprotocol/util-ts' import Screenshot1 from './assets/images/posts-1.jpg' import Screenshot2 from './assets/images/posts-2.jpg' import Screenshot3 from './assets/images/posts-3.jpg' @@ -459,52 +464,75 @@ export const getApiPaths = (async ( export const getSlots = (async (options, __, { paths, factory }) => { const [path1, path2, path3] = paths + const feeds = + (options.find(({ key }) => key === 'feeds') + ?.value as readonly OptionsDatabase[]) ?? [] - if (factory === 'admin' && path1 === 'posts' && path2 === undefined) { - const addSlotsValue = { - slot: 'admin:aside:after-built-in-buttons', - component: NavigationLink, - props: { - navigation: { - display: 'Create a new feed', - path: '/admin/posts/new', - }, - }, - } - - return [addSlotsValue] - } - - if (factory === 'admin' && path1 === 'posts' && path2 === 'edit' && path3) { - const feeds = - (options.find(({ key }) => key === 'feeds') - ?.value as readonly OptionsDatabase[]) ?? [] - const feed = feeds.find((feed) => feed.id === path3) - - const label = feed?.title - ? `Add '${feed.title}' to the menu` - : `Add 'Posts' to the menu` - const display = feed?.title ? feed.title : 'Posts' - const path = feed?.slug ? `/${feed.slug}` : '/posts' - - const addSlotsValue = { - slot: 'admin:aside:after-built-in-buttons', - component: CreateNavigationLink, - props: { - createNavigation: { - label, - link: { - display, - path, + return [ + ...(factory === 'page' // == The public feed page with PageContentHomeBeforeContent slot + ? ( + await Promise.all( + feeds + .filter( + (feed) => + feed.slots?.[ClubsSlotName.PageContentHomeBeforeContent] !== + undefined, + ) + .map(async (feed) => { + const posts = await getAllPosts('documents:redis', { + key: feed.database.key, + }) + return [ + { + slot: ClubsSlotName.PageContentHomeBeforeContent, + component: Readme, // @@@TODO: This should be replaced in another component + props: { + posts: isNotError(posts) ? posts.map(mask) : [], + feedId: feed.id, + }, + }, + ] + }), + ) + ).flat() + : []), + ...(factory === 'admin' && path1 === 'posts' && path2 === undefined // == The feeds list page + ? [ + { + slot: 'admin:aside:after-built-in-buttons', + component: NavigationLink, + props: { + navigation: { + display: 'Create a new feed', + path: '/admin/posts/new', + }, + }, }, - }, - }, - } - - return [addSlotsValue] - } - - return [] + ] + : []), + ...((feed) => + feed && + factory === 'admin' && + path1 === 'posts' && + path2 === 'edit' && + path3 // == The feed edit page + ? [ + { + slot: 'admin:aside:after-built-in-buttons', + component: CreateNavigationLink, + props: { + createNavigation: { + label: `Add '${feed.title ?? 'Posts'}' to the menu`, + link: { + display: feed.title ?? 'Posts', + path: `/${feed.slug ?? 'posts'}`, + }, + }, + }, + }, + ] + : [])(feeds.find((feed) => feed.id === path3)), + ] }) satisfies ClubsFunctionGetSlots export default { diff --git a/src/types.ts b/src/types.ts index 37a846403..3497be703 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2,6 +2,7 @@ import type { ClubsGeneralUnit, Membership as MembershipCore, } from '@devprotocol/clubs-core' +import { ClubsSlotName } from '@devprotocol/clubs-core' export type Option = { readonly key: 'posts' @@ -46,6 +47,7 @@ export type Comment = CommentPrimitives & { readonly updated_at: Date } +const { PageContentHomeBeforeContent } = ClubsSlotName export type OptionsDatabase = { readonly id: string readonly slug?: string @@ -55,6 +57,12 @@ export type OptionsDatabase = { readonly memberships: readonly [] | readonly Uint8Array[] } } + readonly slots?: { + readonly [PageContentHomeBeforeContent]?: { + readonly title: string + readonly items: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 + } + } readonly database: | { readonly type: 'encoded:redis'