From e53aa3ea021eda27e34d32089318afd4713b8577 Mon Sep 17 00:00:00 2001 From: DIYgod Date: Wed, 29 Jun 2022 17:47:41 +0100 Subject: [PATCH] feat: crossbell renovation - site home page --- src/components/site/SiteFooter.tsx | 8 ++ src/components/site/SiteHeader.tsx | 82 +--------------- src/components/site/SiteHome.tsx | 11 ++- src/components/site/SiteLayout.tsx | 34 +++---- src/lib/unidata.ts | 5 +- src/models/page.model.ts | 144 +++++++++++++---------------- src/models/site.model.ts | 69 ++++++-------- src/pages/_site/[site]/index.tsx | 44 ++++----- src/router/site.ts | 17 ++-- 9 files changed, 148 insertions(+), 266 deletions(-) diff --git a/src/components/site/SiteFooter.tsx b/src/components/site/SiteFooter.tsx index 260f74ac..4b300838 100644 --- a/src/components/site/SiteFooter.tsx +++ b/src/components/site/SiteFooter.tsx @@ -1,5 +1,6 @@ import { APP_NAME, OUR_DOMAIN } from "~/lib/env" import { UniLink } from "../ui/UniLink" +import { IS_PROD } from "~/lib/constants" export const SiteFooter: React.FC<{ site: { name: string } }> = ({ site }) => { return ( @@ -16,6 +17,13 @@ export const SiteFooter: React.FC<{ site: { name: string } }> = ({ site }) => { className="hover:text-indigo-500" > {APP_NAME} + {" "} + ยท {" "} + + Dashboard diff --git a/src/components/site/SiteHeader.tsx b/src/components/site/SiteHeader.tsx index b59635e4..c1de9061 100644 --- a/src/components/site/SiteHeader.tsx +++ b/src/components/site/SiteHeader.tsx @@ -11,6 +11,7 @@ import { DashboardIcon } from "../icons/DashboardIcon" import { Avatar } from "../ui/Avatar" import { Button } from "../ui/Button" import { UniLink } from "../ui/UniLink" +import { Profile } from "unidata.js" export type HeaderLinkType = { icon?: React.ReactNode @@ -43,7 +44,7 @@ export const SiteHeader: React.FC<{ icon: string | null | undefined navigation?: HeaderLinkType[] subscribed?: boolean - viewer: Viewer | null + viewer?: Profile | null }> = ({ siteName, description, icon, navigation, subscribed, viewer }) => { const setSubscribeModalOpened = useStore( (store) => store.setSubscribeModalOpened, @@ -59,20 +60,6 @@ export const SiteHeader: React.FC<{ ...(navigation || []), ] - const dropdownLinks: HeaderLinkType[] = [ - { - icon: , - label: "Writer dashboard", - url: `${IS_PROD ? "https" : "http"}://${OUR_DOMAIN}/dashboard`, - }, - { - label: "Sign out", - onClick() { - logout() - }, - }, - ] - return (
@@ -90,36 +77,6 @@ export const SiteHeader: React.FC<{ {description && (
{description}
)} -
- -
@@ -129,41 +86,6 @@ export const SiteHeader: React.FC<{ return })} - {viewer ? ( -
- -
-
- {dropdownLinks.map((link, i) => { - return ( - - {link.label} - - ) - })} -
-
-
- ) : ( - - )}
diff --git a/src/components/site/SiteHome.tsx b/src/components/site/SiteHome.tsx index 8743f649..4570fa6a 100644 --- a/src/components/site/SiteHome.tsx +++ b/src/components/site/SiteHome.tsx @@ -2,9 +2,10 @@ import Link from "next/link" import { formatDate } from "~/lib/date" import { Paginated, type PostOnSiteHome } from "~/lib/types" import { EmptyState } from "../ui/EmptyState" +import { Notes } from "unidata.js" export const SiteHome: React.FC<{ - posts?: Paginated + posts?: Notes }> = ({ posts }) => { if (!posts) return null @@ -13,14 +14,14 @@ export const SiteHome: React.FC<{ {posts.total === 0 && } {posts.total > 0 && (
- {posts.nodes.map((post) => { - const excerpt = post.excerpt || post.autoExcerpt + {posts.list.map((post) => { + const excerpt = post.summary?.content return ( - +

{post.title}

- {formatDate(post.publishedAt)} + {formatDate(post.date_published)}
{excerpt} diff --git a/src/components/site/SiteLayout.tsx b/src/components/site/SiteLayout.tsx index abd48829..218786cc 100644 --- a/src/components/site/SiteLayout.tsx +++ b/src/components/site/SiteLayout.tsx @@ -8,16 +8,11 @@ import { SiteFooter } from "./SiteFooter" import { SiteHeader } from "./SiteHeader" import { useRouter } from "next/router" import { useStore } from "~/lib/store" +import { Profile } from "unidata.js" export type SiteLayoutProps = { - site: { - id: string - name: string - description?: string | null - icon?: string | null - navigation?: SiteNavigationItem[] | null - } - viewer: Viewer | null + site: Profile + viewer?: Profile | null subscription?: { email?: boolean } | null children: React.ReactNode title?: string | null @@ -47,29 +42,22 @@ export const SiteLayout: React.FC = ({ <>
{children}
- - {site.id && ( - - )} + ) } diff --git a/src/lib/unidata.ts b/src/lib/unidata.ts index c3339136..34ec1f1a 100644 --- a/src/lib/unidata.ts +++ b/src/lib/unidata.ts @@ -1,8 +1,5 @@ import Unidata from "unidata.js" -let unidata: Unidata | null = null; -if (typeof window !== "undefined") { - unidata = new Unidata() -} +let unidata = new Unidata() export default unidata diff --git a/src/models/page.model.ts b/src/models/page.model.ts index 4bf8b970..8b8eea43 100644 --- a/src/models/page.model.ts +++ b/src/models/page.model.ts @@ -66,35 +66,28 @@ export async function createOrUpdatePage( isPost?: boolean }, ) { - if (unidata) { - return await unidata.notes.set({ - source: 'Crossbell Note', - identity: input.siteId, - platform: 'Crossbell', - action: input.pageId ? 'update' : 'add', - }, { - ...(input.pageId && { id: input.pageId }), - ...(input.title && { title: input.title }), - ...(input.content && { - body: { - content: input.content, - mime_type: 'text/markdown', - }}), - ...(input.publishedAt && { date_published: input.published ? input.publishedAt : new Date('9999-01-01').toISOString() }), - ...(input.excerpt && { - summary: { - content: input.excerpt, - mime_type: 'text/markdown', - } - }), - tags: [input.isPost ? "post" : "page"], - }) - } else { - return { - code: 1, - message: 'Unidata is not found', - } - } + return await unidata.notes.set({ + source: 'Crossbell Note', + identity: input.siteId, + platform: 'Crossbell', + action: input.pageId ? 'update' : 'add', + }, { + ...(input.pageId && { id: input.pageId }), + ...(input.title && { title: input.title }), + ...(input.content && { + body: { + content: input.content, + mime_type: 'text/markdown', + }}), + ...(input.publishedAt && { date_published: input.published ? input.publishedAt : new Date('9999-01-01').toISOString() }), + ...(input.excerpt && { + summary: { + content: input.excerpt, + mime_type: 'text/markdown', + } + }), + tags: [input.isPost ? "post" : "page"], + }) } export async function scheduleEmailForPost( @@ -147,63 +140,58 @@ export async function getPagesBySite( const visibility = input.visibility || PageVisibilityEnum.All - let pages: Notes | null = null - if (unidata) { - pages = await unidata.notes.get({ - source: 'Crossbell Note', - identity: input.site, - platform: 'Crossbell', - limit: input.take || 100, - }); + let pages = await unidata.notes.get({ + source: 'Crossbell Note', + identity: input.site, + platform: 'Crossbell', + limit: input.take || 1000, + }); - if (pages?.list) { - switch (visibility) { - case PageVisibilityEnum.Published: - pages.list = pages.list.filter(page => +new Date(page.date_published) <= +new Date()) - break - case PageVisibilityEnum.Draft: - pages.list = pages.list.filter(page => page.date_published === new Date('9999-01-01').toISOString()) - break - case PageVisibilityEnum.Scheduled: - pages.list = pages.list.filter(page => +new Date(page.date_published) > +new Date() && page.date_published !== new Date('9999-01-01').toISOString()) - break - } - pages.list = pages.list.filter(page => page.tags?.includes(input.type)) - pages.total = pages.list.length - - pages.list = await Promise.all(pages?.list.map(async (page) => { - if (page.body?.content && page.body?.mime_type === 'text/markdown' && input.render) { - const rendered = await renderPageContent(page.body.content) - page.body = { - content: rendered.contentHTML, + if (pages?.list) { + switch (visibility) { + case PageVisibilityEnum.Published: + pages.list = pages.list.filter(page => +new Date(page.date_published) <= +new Date()) + break + case PageVisibilityEnum.Draft: + pages.list = pages.list.filter(page => page.date_published === new Date('9999-01-01').toISOString()) + break + case PageVisibilityEnum.Scheduled: + pages.list = pages.list.filter(page => +new Date(page.date_published) > +new Date() && page.date_published !== new Date('9999-01-01').toISOString()) + break + } + pages.list = pages.list.filter(page => page.tags?.includes(input.type)) + pages.total = pages.list.length + + pages.list = await Promise.all(pages?.list.map(async (page) => { + if (page.body?.content && page.body?.mime_type === 'text/markdown' && input.render) { + const rendered = await renderPageContent(page.body.content) + page.body = { + content: rendered.contentHTML, + mime_type: 'text/html' + } + if (!page.summary) { + page.summary = { + content: rendered.excerpt, mime_type: 'text/html' } - if (!page.summary) { - page.summary = { - content: rendered.excerpt, - mime_type: 'text/html' - } - } } - return page - })) - } - - return pages + } + return page + })) } + + return pages } export async function deletePage({ site, id }: { site: string, id: string }) { - if (unidata) { - await unidata.notes.set({ - source: 'Crossbell Note', - identity: site, - platform: 'Crossbell', - action: 'remove', - }, { - id, - }) - } + return await unidata.notes.set({ + source: 'Crossbell Note', + identity: site, + platform: 'Crossbell', + action: 'remove', + }, { + id, + }) } export async function getPage( diff --git a/src/models/site.model.ts b/src/models/site.model.ts index f77cf895..b9ca979f 100644 --- a/src/models/site.model.ts +++ b/src/models/site.model.ts @@ -40,39 +40,31 @@ export const checkSubdomain = async ({ } export const getUserSites = async (address: string) => { - if (unidata) { - const profiles = await unidata.profiles.get({ - source: 'Crossbell Profile', - identity: address, - platform: 'Ethereum', - }); + const profiles = await unidata.profiles.get({ + source: 'Crossbell Profile', + identity: address, + platform: 'Ethereum', + }); - const sites = profiles.list?.sort((a, b) => +new Date(b.date_updated || 0) - +new Date(a.date_updated || 0)) + const sites = profiles.list?.sort((a, b) => +new Date(b.date_updated || 0) - +new Date(a.date_updated || 0)) - if (!sites || !sites.length) return null + if (!sites || !sites.length) return null - return sites - } else { - return null - } + return sites } export const getSite = async (input: string) => { - if (unidata) { - const profiles = await unidata.profiles.get({ - source: 'Crossbell Profile', - identity: input, - platform: 'Crossbell', - }); + const profiles = await unidata.profiles.get({ + source: 'Crossbell Profile', + identity: input, + platform: 'Crossbell', + }); - const site = profiles.list?.sort((a, b) => +new Date(b.date_updated || 0) - +new Date(a.date_updated || 0))?.[0] + const site = profiles.list?.sort((a, b) => +new Date(b.date_updated || 0) - +new Date(a.date_updated || 0))?.[0] - if (!site) return null + if (!site) return null - return site - } else { - return null - } + return site } export const getSubscription = async (data: { @@ -103,24 +95,17 @@ export async function updateSite( navigation?: SiteNavigationItem[] // TODO }, ) { - if (unidata) { - return await unidata.profiles.set({ - source: 'Crossbell Profile', - identity: payload.site, - platform: 'Crossbell', - action: 'update', - }, { - ...(payload.name && { name: payload.name }), - ...(payload.description && { bio: payload.description }), - ...(payload.icon && { avatars: [payload.icon] }), - ...(payload.subdomain && { username: payload.subdomain }), - }) - } else { - return { - code: 1, - message: 'Unidata is not found', - } - } + return await unidata.profiles.set({ + source: 'Crossbell Profile', + identity: payload.site, + platform: 'Crossbell', + action: 'update', + }, { + ...(payload.name && { name: payload.name }), + ...(payload.description && { bio: payload.description }), + ...(payload.icon && { avatars: [payload.icon] }), + ...(payload.subdomain && { username: payload.subdomain }), + }) } export async function createSite( diff --git a/src/pages/_site/[site]/index.tsx b/src/pages/_site/[site]/index.tsx index 697411a7..ef378aba 100644 --- a/src/pages/_site/[site]/index.tsx +++ b/src/pages/_site/[site]/index.tsx @@ -1,35 +1,39 @@ import { GetServerSideProps } from "next" import { SiteHome } from "~/components/site/SiteHome" import { SiteLayout } from "~/components/site/SiteLayout" -import { getAuthUser } from "~/lib/auth.server" import { trpc } from "~/lib/trpc" import { createSSGHelpers } from "@trpc/react/ssg" import { appRouter } from "~/router" import { getTRPCContext } from "~/lib/trpc.server" import { Viewer } from "~/lib/types" import { getViewer } from "~/lib/viewer" +import { useAccount } from 'wagmi' +import { useEffect, useState } from 'react' +import { getUserSites, getSite } from "~/models/site.model" +import { getPagesBySite } from "~/models/page.model" +import { Profile, Notes } from "unidata.js" +import { PageVisibilityEnum } from "~/lib/types" export const getServerSideProps: GetServerSideProps = async (ctx) => { - const user = await getAuthUser(ctx.req) const domainOrSubdomain = ctx.params!.site as string - const viewer = getViewer(user) const trpcContext = await getTRPCContext(ctx) const ssg = createSSGHelpers({ router: appRouter, ctx: trpcContext }) - await Promise.all([ - ssg.fetchQuery("site", { site: domainOrSubdomain }), - ssg.fetchQuery("site.pages", { + const [site, posts] = await Promise.all([ + getSite(domainOrSubdomain), + getPagesBySite({ site: domainOrSubdomain, take: 1000, - includeExcerpt: true, + type: "post", + visibility: PageVisibilityEnum.Published, }), - ssg.fetchQuery("site.subscription", { site: domainOrSubdomain }), ]) return { props: { - viewer, + site, + posts, domainOrSubdomain, trpcState: ssg.dehydrate(), }, @@ -37,27 +41,15 @@ export const getServerSideProps: GetServerSideProps = async (ctx) => { } function SiteIndexPage({ - viewer, - domainOrSubdomain, + site, + posts, }: { - viewer: Viewer | null + site: Profile, + posts: Notes, domainOrSubdomain: string }) { - const { data: site } = trpc.useQuery( - ["site", { site: domainOrSubdomain }], - {}, - ) - const { data: subscription } = trpc.useQuery([ - "site.subscription", - { site: domainOrSubdomain }, - ]) - const { data: posts } = trpc.useQuery([ - "site.pages", - { site: domainOrSubdomain, take: 1000, includeExcerpt: true }, - ]) - return ( - + ) diff --git a/src/router/site.ts b/src/router/site.ts index afe2bebc..c5e6f849 100644 --- a/src/router/site.ts +++ b/src/router/site.ts @@ -54,23 +54,24 @@ export const siteRouter = createRouter() includeExcerpt: z.boolean().optional(), }), output: z.object({ - nodes: z.array( + list: z.array( z.object({ id: z.string(), title: z.string(), - contentHTML: z.string().optional(), - publishedAt: z.date().transform((v) => v.toISOString()), - published: z.boolean(), - slug: z.string(), - excerpt: z.string().nullable(), - autoExcerpt: z.string().optional(), + body: z.object({ + content: z.string(), + }), + date_published: z.date().transform((v) => v.toISOString()), + summary: z.object({ + content: z.string(), + }), }), ), total: z.number(), hasMore: z.boolean(), }), async resolve({ input, ctx }) { - const result = await getPagesBySite(ctx.gate, input) + const result = await getPagesBySite(input) return result }, })