diff --git a/src/app/api/summary/route.ts b/src/app/api/summary/route.ts index fa838c43..17c030af 100644 --- a/src/app/api/summary/route.ts +++ b/src/app/api/summary/route.ts @@ -1,5 +1,5 @@ -import { OpenAI } from "langchain" import { AnalyzeDocumentChain, loadSummarizationChain } from "langchain/chains" +import { OpenAI } from "langchain/llms/openai" import { PromptTemplate } from "langchain/prompts" import removeMarkdown from "remove-markdown" diff --git a/src/pages_b/404.tsx b/src/pages_b/404.tsx deleted file mode 100644 index b1766644..00000000 --- a/src/pages_b/404.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { useState } from "react" - -import { SiteLayout } from "~/components/site/SiteLayout" -import { SitePage } from "~/components/site/SitePage" -import { SITE_URL } from "~/lib/env" - -export default function Custom404() { - const [siteId, setSiteId] = useState("") - - try { - fetch(`/api/host2handle?host=${window.location.host}`) - .then((res) => res.json()) - .then((tenant) => { - if (tenant.subdomain) { - setSiteId(tenant.subdomain) - } - }) - } catch (error) {} - - return ( - - - - ) -} diff --git a/src/pages_b/_app.tsx b/src/pages_b/_app.tsx deleted file mode 100644 index 4456131d..00000000 --- a/src/pages_b/_app.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import "aplayer-react/dist/index.css" -import { appWithTranslation } from "next-i18next" -import NextNProgress from "nextjs-progressbar" -import { Toaster } from "react-hot-toast" -import { AppPropsWithLayout } from "types/next" -import { WagmiConfig, createClient } from "wagmi" - -import { - ConnectKitProvider, - getDefaultClientConfig, -} from "@crossbell/connect-kit" -import { - NotificationModal, - NotificationModalColorScheme, -} from "@crossbell/notification" -import { Hydrate, QueryClient } from "@tanstack/react-query" -import { PersistQueryClientProvider } from "@tanstack/react-query-persist-client" - -import "~/css/main.css" -// eslint-disable-next-line import/no-unresolved -import { useDarkMode } from "~/hooks/useDarkMode" -import { useMobileLayout } from "~/hooks/useMobileLayout" -import { APP_NAME } from "~/lib/env" -import { toGateway } from "~/lib/ipfs-parser" -import { createIDBPersister } from "~/lib/persister.client" -import { urlComposer } from "~/lib/url-composer" - -const wagmiClient = createClient(getDefaultClientConfig({ appName: APP_NAME })) - -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - cacheTime: 1000 * 60 * 60 * 24, // 24 hours - }, - }, -}) - -const persister = createIDBPersister() - -const colorScheme: NotificationModalColorScheme = { - text: `rgb(var(--tw-colors-i-zinc-800))`, - textSecondary: `rgb(var(--tw-colors-i-gray-600))`, - background: `rgb(var(--tw-colors-i-white))`, - border: `var(--border-color)`, -} - -function MyApp({ Component, pageProps }: AppPropsWithLayout) { - const getLayout = Component.getLayout ?? ((page) => page) - - useDarkMode() - useMobileLayout() - - return ( - - { - const queryIsReadyForPersistance = - query.state.status === "success" - if (queryIsReadyForPersistance) { - return !((query.state?.data as any)?.pages?.length > 1) - } else { - return false - } - }, - }, - }} - > - - - {/* */} - - {getLayout()} - - - - - - - ) -} - -// Only uncomment this method if you have blocking data requirements for -// every single page in your application. This disables the ability to -// perform automatic static optimization, causing every page in your app to -// be server-side rendered. -// -// MyApp.getInitialProps = async (appContext) => { -// // calls page's `getInitialProps` and fills `appProps.pageProps` -// const appProps = await App.getInitialProps(appContext); -// -// return { ...appProps } -// } - -export default appWithTranslation(MyApp) diff --git a/src/pages_b/_site/[site]/[page].tsx b/src/pages_b/_site/[site]/[page].tsx deleted file mode 100644 index bc5ec2cf..00000000 --- a/src/pages_b/_site/[site]/[page].tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { GetServerSideProps } from "next" -import { ReactElement } from "react" - -import { QueryClient } from "@tanstack/react-query" - -import { SiteLayout } from "~/components/site/SiteLayout" -import { getServerSideProps as getLayoutServerSideProps } from "~/components/site/SiteLayout.server" -import { SitePage } from "~/components/site/SitePage" -import { serverSidePropsHandler } from "~/lib/server-side-props" -import { useGetPage } from "~/queries/page" -import { useGetSite } from "~/queries/site" - -export const getServerSideProps: GetServerSideProps = serverSidePropsHandler( - async (ctx) => { - const queryClient = new QueryClient() - const domainOrSubdomain = ctx.params!.site as string - const pageSlug = ctx.params!.page as string - - const { props: layoutProps } = await getLayoutServerSideProps( - ctx, - queryClient, - { - useStat: true, - }, - ) - - return { - props: { - ...layoutProps, - domainOrSubdomain, - pageSlug, - }, - } - }, -) - -function SitePagePage({ - domainOrSubdomain, - pageSlug, -}: { - domainOrSubdomain: string - pageSlug: string -}) { - const site = useGetSite(domainOrSubdomain) - const page = useGetPage({ - characterId: site.data?.characterId, - slug: pageSlug, - useStat: true, - }) - - return ( - - ) -} - -SitePagePage.getLayout = (page: ReactElement) => { - return ( - - {page} - - ) -} - -export default SitePagePage diff --git a/src/pages_b/_site/[site]/archives.tsx b/src/pages_b/_site/[site]/archives.tsx deleted file mode 100644 index 087e8258..00000000 --- a/src/pages_b/_site/[site]/archives.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { GetServerSideProps } from "next" -import type { ReactElement } from "react" - -import { QueryClient } from "@tanstack/react-query" - -import { SiteArchives } from "~/components/site/SiteArchives" -import { SiteLayout } from "~/components/site/SiteLayout" -import { getServerSideProps as getLayoutServerSideProps } from "~/components/site/SiteLayout.server" -import { serverSidePropsHandler } from "~/lib/server-side-props" -import { PageVisibilityEnum } from "~/lib/types" -import { useGetPagesBySiteLite } from "~/queries/page" -import { useGetSite } from "~/queries/site" - -export const getServerSideProps: GetServerSideProps = serverSidePropsHandler( - async (ctx) => { - const queryClient = new QueryClient() - const domainOrSubdomain = ctx.params!.site as string - const { props: layoutProps } = await getLayoutServerSideProps( - ctx, - queryClient, - { - limit: 100, - }, - ) - - return { - props: { - ...layoutProps, - domainOrSubdomain, - }, - } - }, -) - -function SiteArchivesPage({ - domainOrSubdomain, -}: { - domainOrSubdomain: string -}) { - const site = useGetSite(domainOrSubdomain) - const posts = useGetPagesBySiteLite({ - characterId: site.data?.characterId, - limit: 100, - type: "post", - visibility: PageVisibilityEnum.Published, - }) - - return ( - - ) -} - -SiteArchivesPage.getLayout = (page: ReactElement) => { - return ( - - {page} - - ) -} - -export default SiteArchivesPage diff --git a/src/pages_b/_site/[site]/feed/comments.tsx b/src/pages_b/_site/[site]/feed/comments.tsx deleted file mode 100644 index e8371c66..00000000 --- a/src/pages_b/_site/[site]/feed/comments.tsx +++ /dev/null @@ -1,83 +0,0 @@ -// @ts-ignore -import jsonfeedToRSS from "jsonfeed-to-rss" -import { GetServerSideProps } from "next" - -import { QueryClient } from "@tanstack/react-query" - -import { getSiteLink } from "~/lib/helpers" -import { setHeader } from "~/lib/json-feed" -import { renderPageContent } from "~/markdown" -import { fetchGetComments, fetchGetSite } from "~/queries/site.server" - -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const queryClient = new QueryClient() - setHeader(ctx) - const domainOrSubdomain = ctx.params!.site as string - - const site = await fetchGetSite(domainOrSubdomain, queryClient) - const comments = await fetchGetComments( - { - characterId: site?.characterId, - }, - queryClient, - ) - - const link = getSiteLink({ - subdomain: site?.handle || "", - }) - - const data = { - version: "https://jsonfeed.org/version/1", - title: "Comments on " + site?.metadata?.content?.name, - description: site?.metadata?.content?.bio, - icon: site?.metadata?.content?.avatars?.[0], - home_page_url: link, - feed_url: `${link}/feed/notifications`, - items: comments?.list?.map((comment) => { - const type = comment.toNote?.metadata?.content?.tags?.[0] - let toTitle - if (type === "post" || type === "page") { - toTitle = comment.toNote?.metadata?.content?.title - } else { - if ((comment.toNote?.metadata?.content?.content?.length || 0) > 30) { - toTitle = - comment.toNote?.metadata?.content?.content?.slice(0, 30) + "..." - } else { - toTitle = comment.toNote?.metadata?.content?.content - } - } - const name = - comment?.character?.metadata?.content?.name || - `@${comment?.character?.handle}` - - return { - id: comment.characterId + "-" + comment.noteId, - title: `${name}: ${comment.metadata?.content?.content}`, - content_html: `${name} commented on ${type} ${toTitle}: ${ - renderPageContent(comment.metadata?.content?.content || "") - .contentHTML - }`, - url: `${link}/${ - comment.toNote?.metadata?.content?.attributes?.find( - (attribute: any) => attribute.trait_type === "xlog_slug", - )?.value || comment.toNote?.characterId + "-" + comment.toNote?.noteId - }`, - date_published: comment.createdAt, - date_modified: comment.updatedAt, - } - }), - } - - ctx.res.write( - ctx.query.format === "xml" ? jsonfeedToRSS(data) : JSON.stringify(data), - ) - ctx.res.end() - - return { - props: {}, - } -} - -const SiteFeed: React.FC = () => null - -export default SiteFeed diff --git a/src/pages_b/_site/[site]/feed/index.tsx b/src/pages_b/_site/[site]/feed/index.tsx deleted file mode 100644 index 6e39838b..00000000 --- a/src/pages_b/_site/[site]/feed/index.tsx +++ /dev/null @@ -1,25 +0,0 @@ -// @ts-ignore -import jsonfeedToRSS from "jsonfeed-to-rss" -import { GetServerSideProps } from "next" - -import { getJsonFeed, setHeader } from "~/lib/json-feed" - -export const getServerSideProps: GetServerSideProps = async (ctx) => { - setHeader(ctx) - const domainOrSubdomain = ctx.params!.site as string - - const data = await getJsonFeed(domainOrSubdomain, "/feed") - - ctx.res.write( - ctx.query.format === "xml" ? jsonfeedToRSS(data) : JSON.stringify(data), - ) - ctx.res.end() - - return { - props: {}, - } -} - -const SiteFeed: React.FC = () => null - -export default SiteFeed diff --git a/src/pages_b/_site/[site]/index.tsx b/src/pages_b/_site/[site]/index.tsx deleted file mode 100644 index 0d56f358..00000000 --- a/src/pages_b/_site/[site]/index.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { GetServerSideProps } from "next" -import type { ReactElement } from "react" - -import { QueryClient } from "@tanstack/react-query" - -import { SiteHome } from "~/components/site/SiteHome" -import { SiteLayout } from "~/components/site/SiteLayout" -import { getServerSideProps as getLayoutServerSideProps } from "~/components/site/SiteLayout.server" -import { PageVisibilityEnum } from "~/lib/types" -import { useGetPagesBySiteLite } from "~/queries/page" -import { useGetSite } from "~/queries/site" - -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const queryClient = new QueryClient() - const domainOrSubdomain = ctx.params!.site as string - const { props: layoutProps } = await getLayoutServerSideProps( - ctx, - queryClient, - { - useStat: true, - }, - ) - - return { - props: { - ...layoutProps, - domainOrSubdomain, - }, - } -} - -function SiteIndexPage({ domainOrSubdomain }: { domainOrSubdomain: string }) { - const site = useGetSite(domainOrSubdomain) - const posts = useGetPagesBySiteLite({ - characterId: site.data?.characterId, - type: "post", - visibility: PageVisibilityEnum.Published, - useStat: true, - }) - - return ( - - ) -} - -SiteIndexPage.getLayout = (page: ReactElement) => { - return ( - - {page} - - ) -} - -export default SiteIndexPage diff --git a/src/pages_b/_site/[site]/manifest.json.tsx b/src/pages_b/_site/[site]/manifest.json.tsx deleted file mode 100644 index cf3f59eb..00000000 --- a/src/pages_b/_site/[site]/manifest.json.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { GetServerSideProps } from "next" - -import { QueryClient } from "@tanstack/react-query" - -import { fetchGetSite } from "~/queries/site.server" - -export const getServerSideProps: GetServerSideProps = async (ctx) => { - ctx.res.setHeader("Content-Type", "application/json") - - const queryClient = new QueryClient() - const domainOrSubdomain = ctx.params!.site as string - const site = await fetchGetSite(domainOrSubdomain, queryClient) - - ctx.res.write( - JSON.stringify({ - name: site?.metadata?.content?.name, - short_name: site?.metadata?.content?.name, - description: site?.metadata?.content?.bio, - icons: [ - { - src: site?.metadata?.content?.avatars?.[0] || "assets/logo.png", - type: "image/png", - sizes: "any", - }, - ], - theme_color: "#ffffff", - background_color: "#ffffff", - start_url: "/", - display: "standalone", - orientation: "portrait", - }), - ) - ctx.res.end() - - return { - props: {}, - } -} - -const ManifestJson: React.FC = () => null - -export default ManifestJson diff --git a/src/pages_b/_site/[site]/nft.tsx b/src/pages_b/_site/[site]/nft.tsx deleted file mode 100644 index d2b66c3b..00000000 --- a/src/pages_b/_site/[site]/nft.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { GetServerSideProps } from "next" -import { useTranslation } from "next-i18next" -import Script from "next/script" -import { ReactElement, useEffect, useState } from "react" -import type { Asset } from "unidata.js" - -import { QueryClient } from "@tanstack/react-query" - -import { SiteLayout } from "~/components/site/SiteLayout" -import { getServerSideProps as getLayoutServerSideProps } from "~/components/site/SiteLayout.server" -import { UniLink } from "~/components/ui/UniLink" -import { UniMedia } from "~/components/ui/UniMedia" -import { useGetNFTs, useGetSite } from "~/queries/site" - -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const queryClient = new QueryClient() - const domainOrSubdomain = ctx.params!.site as string - const { props: layoutProps } = await getLayoutServerSideProps( - ctx, - queryClient, - { - skipPages: true, - }, - ) - - return { - props: { - ...layoutProps, - domainOrSubdomain, - }, - } -} - -function SiteNFTPage({ domainOrSubdomain }: { domainOrSubdomain: string }) { - const site = useGetSite(domainOrSubdomain) - const { t } = useTranslation(["common", "site"]) - - const nftsOrigin = useGetNFTs(site.data?.owner) - - const [nfts, setNfts] = useState([]) - useEffect(() => { - if (nftsOrigin?.data?.list && !nfts.length) { - setNfts(nftsOrigin.data.list) - } - }, [nftsOrigin.data, nfts]) - - return ( - <> - -

NFT {t("Showcase")}

-
- {nftsOrigin.isLoading ? ( -
{t("Loading")}...
- ) : ( -
- {nfts - .filter((nft) => nft.items?.[0]?.address) - .map((nft: Asset) => ( - - -
- {nft.name} -
-
- ))} -
- )} -
- - ) -} - -SiteNFTPage.getLayout = (page: ReactElement) => { - return {page} -} - -export default SiteNFTPage diff --git a/src/pages_b/_site/[site]/preview/[page].tsx b/src/pages_b/_site/[site]/preview/[page].tsx deleted file mode 100644 index 6c9f191b..00000000 --- a/src/pages_b/_site/[site]/preview/[page].tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { GetServerSideProps } from "next" -import { useRouter } from "next/router" -import type { ReactElement } from "react" - -import { QueryClient } from "@tanstack/react-query" - -import { SiteLayout } from "~/components/site/SiteLayout" -import { getServerSideProps as getLayoutServerSideProps } from "~/components/site/SiteLayout.server" -import { SitePage } from "~/components/site/SitePage" -import { useUserRole } from "~/hooks/useUserRole" -import { getSiteLink } from "~/lib/helpers" -import { serverSidePropsHandler } from "~/lib/server-side-props" -import { useGetPage } from "~/queries/page" -import { useGetSite } from "~/queries/site" - -export const getServerSideProps: GetServerSideProps = serverSidePropsHandler( - async (ctx) => { - const queryClient = new QueryClient() - const domainOrSubdomain = ctx.params!.site as string - - const { props: layoutProps } = await getLayoutServerSideProps( - ctx, - queryClient, - { - preview: true, - }, - ) - - return { - props: { - ...layoutProps, - domainOrSubdomain, - }, - } - }, -) - -function SitePagePage() { - const router = useRouter() - const domainOrSubdomain = router.query.site as string - const pageSlug = router.query.page as string - const userRole = useUserRole(domainOrSubdomain) - - const site = useGetSite(domainOrSubdomain) - - const page = useGetPage({ - characterId: site.data?.characterId, - slug: pageSlug, - handle: domainOrSubdomain, - }) - - if (userRole.isSuccess && !userRole.data && page.isSuccess) { - router.push( - getSiteLink({ - subdomain: domainOrSubdomain, - }), - ) - } - - return ( - - ) -} - -SitePagePage.getLayout = (page: ReactElement) => { - return {page} -} - -export default SitePagePage diff --git a/src/pages_b/_site/[site]/robots.txt.tsx b/src/pages_b/_site/[site]/robots.txt.tsx deleted file mode 100644 index e71b848a..00000000 --- a/src/pages_b/_site/[site]/robots.txt.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { GetServerSideProps } from "next" - -export const getServerSideProps: GetServerSideProps = async (ctx) => { - ctx.res.setHeader("Content-Type", "text/plain") - ctx.res.setHeader("Access-Control-Allow-Methods", "GET") - ctx.res.setHeader("Access-Control-Allow-Origin", "*") - - ctx.res.write(`User-agent: * -Disallow: /dashboard/ -Disallow: /preview/ - -Sitemap: https://${ctx.req.headers.host}/sitemap.xml`) - ctx.res.end() - - return { - props: {}, - } -} - -const RobotsTxt: React.FC = () => null - -export default RobotsTxt diff --git a/src/pages_b/_site/[site]/search.tsx b/src/pages_b/_site/[site]/search.tsx deleted file mode 100644 index 1cb4d148..00000000 --- a/src/pages_b/_site/[site]/search.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { GetServerSideProps } from "next" -import { useTranslation } from "next-i18next" -import { useRouter } from "next/router" -import type { ReactElement } from "react" - -import { QueryClient } from "@tanstack/react-query" - -import { SearchInput } from "~/components/common/SearchInput" -import { SiteLayout } from "~/components/site/SiteLayout" -import { getServerSideProps as getLayoutServerSideProps } from "~/components/site/SiteLayout.server" -import { SiteSearch } from "~/components/site/SiteSearch" -import { useGetSearchPagesBySite } from "~/queries/page" -import { useGetSite } from "~/queries/site" - -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const queryClient = new QueryClient() - const domainOrSubdomain = ctx.params!.site as string - const { props: layoutProps } = await getLayoutServerSideProps( - ctx, - queryClient, - { - skipPages: true, - }, - ) - - return { - props: { - ...layoutProps, - domainOrSubdomain, - }, - } -} - -function SiteSearchPage({ domainOrSubdomain }: { domainOrSubdomain: string }) { - const site = useGetSite(domainOrSubdomain) - const router = useRouter() - const keyword = router.query.q as string - const { t } = useTranslation(["common"]) - - const posts = useGetSearchPagesBySite({ - characterId: site.data?.characterId, - keyword, - }) - - return ( - <> -
- -
-

- {posts.data?.pages?.[0].count || "0"} {t("results")} -

- {posts.isLoading ? ( - <>{t("Loading")}... - ) : ( - - )} - - ) -} - -SiteSearchPage.getLayout = (page: ReactElement) => { - return ( - - {page} - - ) -} - -export default SiteSearchPage diff --git a/src/pages_b/_site/[site]/sitemap.xml.tsx b/src/pages_b/_site/[site]/sitemap.xml.tsx deleted file mode 100644 index f8a31073..00000000 --- a/src/pages_b/_site/[site]/sitemap.xml.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import dayjs from "dayjs" -import { GetServerSideProps } from "next" - -import { QueryClient } from "@tanstack/react-query" - -import { getSiteLink } from "~/lib/helpers" -import { PageVisibilityEnum } from "~/lib/types" -import { fetchGetPagesBySite } from "~/queries/page.server" -import { fetchGetSite } from "~/queries/site.server" - -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const queryClient = new QueryClient() - ctx.res.setHeader("Content-Type", "text/xml") - ctx.res.setHeader("Access-Control-Allow-Methods", "GET") - ctx.res.setHeader("Access-Control-Allow-Origin", "*") - const domainOrSubdomain = ctx.params!.site as string - - const site = await fetchGetSite(domainOrSubdomain, queryClient) - const pages = await fetchGetPagesBySite( - { - characterId: site?.characterId, - type: "post", - visibility: PageVisibilityEnum.Published, - limit: 1000, - }, - queryClient, - ) - - const link = getSiteLink({ - domain: site?.metadata?.content?.custom_domain, - subdomain: site?.handle || "", - }) - ctx.res.write(` - -${pages.list?.map( - (page: any) => ` - ${link}/${page.slug || page.id} - ${dayjs(page.date_updated).format("YYYY-MM-DD")} - `, -).join(` -`)} -`) - ctx.res.end() - - return { - props: {}, - } -} - -const SiteFeed: React.FC = () => null - -export default SiteFeed diff --git a/src/pages_b/_site/[site]/tag/[tag].tsx b/src/pages_b/_site/[site]/tag/[tag].tsx deleted file mode 100644 index 52409b90..00000000 --- a/src/pages_b/_site/[site]/tag/[tag].tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { GetServerSideProps } from "next" -import type { ReactElement } from "react" - -import { QueryClient } from "@tanstack/react-query" - -import { SiteArchives } from "~/components/site/SiteArchives" -import { SiteLayout } from "~/components/site/SiteLayout" -import { getServerSideProps as getLayoutServerSideProps } from "~/components/site/SiteLayout.server" -import { serverSidePropsHandler } from "~/lib/server-side-props" -import { PageVisibilityEnum } from "~/lib/types" -import { useGetPagesBySiteLite } from "~/queries/page" -import { useGetSite } from "~/queries/site" - -export const getServerSideProps: GetServerSideProps = serverSidePropsHandler( - async (ctx) => { - const queryClient = new QueryClient() - const domainOrSubdomain = ctx.params!.site as string - const tag = ctx.params!.tag as string - - const { props: layoutProps } = await getLayoutServerSideProps( - ctx, - queryClient, - { - limit: 100, - }, - ) - - return { - props: { - ...layoutProps, - domainOrSubdomain, - tag, - }, - } - }, -) - -function SiteTagPage({ - domainOrSubdomain, - tag, -}: { - domainOrSubdomain: string - tag: string -}) { - const site = useGetSite(domainOrSubdomain) - const posts = useGetPagesBySiteLite({ - characterId: site.data?.characterId, - limit: 100, - type: "post", - visibility: PageVisibilityEnum.Published, - tags: [tag], - }) - - return ( - - ) -} - -SiteTagPage.getLayout = (page: ReactElement) => { - return {page} -} - -export default SiteTagPage diff --git a/src/pages_b/activities.tsx b/src/pages_b/activities.tsx deleted file mode 100644 index 315aa02f..00000000 --- a/src/pages_b/activities.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { GetServerSideProps } from "next" -import { serverSideTranslations } from "next-i18next/serverSideTranslations" -import { ReactElement, useState } from "react" - -import { useAccountState, useConnectModal } from "@crossbell/connect-kit" -import { QueryClient, dehydrate } from "@tanstack/react-query" - -import { MainFeed } from "~/components/home/HomeFeed" -import { MainSidebar } from "~/components/home/HomeSidebar" -import { MainLayout } from "~/components/main/MainLayout" -import { Tabs } from "~/components/ui/Tabs" -import { languageDetector } from "~/lib/language-detector" -import type { FeedType } from "~/models/home.model" -import { prefetchGetFeed, prefetchGetShowcase } from "~/queries/home.server" - -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const queryClient = new QueryClient() - await prefetchGetShowcase(queryClient) - await prefetchGetFeed( - { - type: "latest", - }, - queryClient, - ) - - return { - props: { - ...(await serverSideTranslations(languageDetector(ctx), [ - "common", - "index", - "dashboard", - ])), - dehydratedState: JSON.parse(JSON.stringify(dehydrate(queryClient))), - }, - } -} - -function Activities() { - const currentCharacterId = useAccountState( - (s) => s.computed.account?.characterId, - ) - const connectModal = useConnectModal() - - const [feedType, setFeedType] = useState("latest") - const tabs = [ - { - text: "Latest", - onClick: () => setFeedType("latest"), - active: feedType === "latest", - }, - { - text: "Hottest", - onClick: () => setFeedType("hot"), - active: feedType === "hot", - }, - { - text: "Following", - onClick: () => { - if (!currentCharacterId) { - connectModal.show() - } else { - setFeedType("following") - } - }, - active: feedType === "following", - }, - ] - - return ( -
-
-
- - -
- -
-
- ) -} - -Activities.getLayout = (page: ReactElement) => { - return {page} -} - -export default Activities diff --git a/src/pages_b/dashboard/[subdomain]/achievements.tsx b/src/pages_b/dashboard/[subdomain]/achievements.tsx deleted file mode 100644 index 09192d86..00000000 --- a/src/pages_b/dashboard/[subdomain]/achievements.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import { GetServerSideProps } from "next" -import { useRouter } from "next/router" -import type { ReactElement } from "react" - -import { AchievementItem } from "~/components/common/AchievementItem" -import { DashboardMain } from "~/components/dashboard/DashboardMain" -import { serverSidePropsHandler } from "~/lib/server-side-props" -import { useGetAchievements, useGetSite } from "~/queries/site" - -export const getServerSideProps: GetServerSideProps = serverSidePropsHandler( - async (ctx) => { - const { props: layoutProps } = await getLayoutServerSideProps(ctx) - - return { - props: { - ...layoutProps, - }, - } - }, -) - -export default function AchievementsPage() { - const router = useRouter() - const subdomain = router.query.subdomain as string - const site = useGetSite(subdomain) - - const achievement = useGetAchievements(site.data?.characterId) - - return ( - -
- <> - {achievement.data?.list?.map((series) => { - let length = series.groups?.length - if (!length) { - return null - } - return ( -
-
- {series.info.title} -
-
- {series.groups?.map((group) => ( - - ))} -
-
- ) - })} - -
-
- ) -} - -AchievementsPage.getLayout = (page: ReactElement) => { - return {page} -} diff --git a/src/pages_b/dashboard/[subdomain]/comments.tsx b/src/pages_b/dashboard/[subdomain]/comments.tsx deleted file mode 100644 index 27592a46..00000000 --- a/src/pages_b/dashboard/[subdomain]/comments.tsx +++ /dev/null @@ -1,154 +0,0 @@ -import { GetServerSideProps } from "next" -import { Trans, useTranslation } from "next-i18next" -import { useRouter } from "next/router" -import type { ReactElement } from "react" -import { Virtuoso } from "react-virtuoso" - -import { CommentItem } from "~/components/common/CommentItem" -import { DashboardLayout } from "~/components/dashboard/DashboardLayout" -import { getServerSideProps as getLayoutServerSideProps } from "~/components/dashboard/DashboardLayout.server" -import { DashboardMain } from "~/components/dashboard/DashboardMain" -import { UniLink } from "~/components/ui/UniLink" -import { getSiteLink } from "~/lib/helpers" -import { serverSidePropsHandler } from "~/lib/server-side-props" -import { useGetCommentsBySite, useGetSite } from "~/queries/site" - -export const getServerSideProps: GetServerSideProps = serverSidePropsHandler( - async (ctx) => { - const { props: layoutProps } = await getLayoutServerSideProps(ctx) - - return { - props: { - ...layoutProps, - }, - } - }, -) - -export default function CommentsPage() { - const router = useRouter() - const subdomain = router.query.subdomain as string - const { t } = useTranslation(["dashboard", "common"]) - - const site = useGetSite(subdomain) - - const comments = useGetCommentsBySite({ - characterId: site.data?.characterId, - }) - - const feedUrl = - getSiteLink({ - subdomain: subdomain, - }) + "/feed/comments" - - return ( - -
-
-

- {t( - "You can subscribe to comments through an RSS reader to receive timely reminders.", - )} -

-

- {t("Subscription address:")}{" "} - - {feedUrl} - -

-
-
-
- - comments.hasNextPage && comments.fetchNextPage() - } - components={{ - Footer: comments.isLoading ? Loader : undefined, - }} - itemContent={(_, p) => - p?.list?.map((comment, idx) => { - const type = comment.toNote?.metadata?.content?.tags?.[0] - let toTitle - if (type === "post" || type === "page") { - toTitle = comment.toNote?.metadata?.content?.title - } else { - if ( - (comment.toNote?.metadata?.content?.content?.length || - 0) > 30 - ) { - toTitle = - comment.toNote?.metadata?.content?.content?.slice( - 0, - 30, - ) + "..." - } else { - toTitle = comment.toNote?.metadata?.content?.content - } - } - const name = - comment?.character?.metadata?.content?.name || - `@${comment?.character?.handle}` - - return ( -
-
- {name}{" "} - - . - - ), - }} - ns="dashboard" - /> - : -
- -
- ) - }) - } - >
-
-
-
-
- ) -} - -CommentsPage.getLayout = (page: ReactElement) => { - return {page} -} - -const Loader = () => { - const { t } = useTranslation("common") - return ( -
- {t("Loading")}... -
- ) -} diff --git a/src/pages_b/dashboard/[subdomain]/editor.tsx b/src/pages_b/dashboard/[subdomain]/editor.tsx deleted file mode 100644 index 6db444fa..00000000 --- a/src/pages_b/dashboard/[subdomain]/editor.tsx +++ /dev/null @@ -1,880 +0,0 @@ -import { useDebounceEffect } from "ahooks" -import type { Root } from "mdast" -import { nanoid } from "nanoid" -import { GetServerSideProps } from "next" -import { useTranslation } from "next-i18next" -import { useRouter } from "next/router" -import NodeID3 from "node-id3" -import { - ChangeEvent, - FC, - memo, - useCallback, - useEffect, - useMemo, - useRef, - useState, -} from "react" -import type { ReactElement } from "react" -import toast from "react-hot-toast" -import { shallow } from "zustand/shallow" - -import type { EditorView } from "@codemirror/view" -import { useQueryClient } from "@tanstack/react-query" - -import { PageContent } from "~/components/common/PageContent" -import { DashboardLayout } from "~/components/dashboard/DashboardLayout" -import { getServerSideProps as getLayoutServerSideProps } from "~/components/dashboard/DashboardLayout.server" -import { DashboardMain } from "~/components/dashboard/DashboardMain" -import { OptionsButton } from "~/components/dashboard/OptionsButton" -import { PublishButton } from "~/components/dashboard/PublishButton" -import { Button } from "~/components/ui/Button" -import { CodeMirrorEditor } from "~/components/ui/CodeMirror" -import { EditorToolbar } from "~/components/ui/EditorToolbar" -import { Input } from "~/components/ui/Input" -import { Modal } from "~/components/ui/Modal" -import { TagInput } from "~/components/ui/TagInput" -import { UniLink } from "~/components/ui/UniLink" -import { toolbars } from "~/editor" -import { useDate } from "~/hooks/useDate" -import { - Values, - initialEditorState, - useEditorState, -} from "~/hooks/useEdtiorState" -import { useGetState } from "~/hooks/useGetState" -import { useIsMobileLayout } from "~/hooks/useMobileLayout" -import { useSyncOnce } from "~/hooks/useSyncOnce" -import { useUploadFile } from "~/hooks/useUploadFile" -import { showConfetti } from "~/lib/confetti" -import { getDefaultSlug } from "~/lib/default-slug" -import { CSB_SCAN } from "~/lib/env" -import { getSiteLink, getTwitterShareUrl } from "~/lib/helpers" -import { getPageVisibility } from "~/lib/page-helpers" -import { serverSidePropsHandler } from "~/lib/server-side-props" -import { delStorage, setStorage } from "~/lib/storage" -import { PageVisibilityEnum } from "~/lib/types" -import { cn, pick } from "~/lib/utils" -import { Rendered, renderPageContent } from "~/markdown" -import { checkPageSlug } from "~/models/page.model" -import { - useCreateOrUpdatePage, - useGetPage, - useGetPagesBySiteLite, -} from "~/queries/page" -import { useGetSite } from "~/queries/site" - -export const getServerSideProps: GetServerSideProps = serverSidePropsHandler( - async (ctx) => { - const { props: layoutProps } = await getLayoutServerSideProps(ctx) - - return { - props: { - ...layoutProps, - }, - } - }, -) - -const getInputDatetimeValue = (date: Date | string, dayjs: any) => { - const str = dayjs(date).format() - return str.substring(0, ((str.indexOf("T") | 0) + 6) | 0) -} - -export default function SubdomainEditor() { - const router = useRouter() - const queryClient = useQueryClient() - const { t } = useTranslation("dashboard") - - let pageId = router.query.id as string | undefined - const subdomain = router.query.subdomain as string - const isPost = router.query.type === "post" - - const site = useGetSite(subdomain) - - const [draftKey, setDraftKey] = useState("") - useEffect(() => { - if (subdomain) { - let key - if (!pageId) { - const randomId = nanoid() - key = `draft-${site.data?.characterId}-local-${randomId}` - setDraftKey(key) - queryClient.invalidateQueries([ - "getPagesBySite", - site.data?.characterId, - ]) - router.replace( - `/dashboard/${subdomain}/editor?id=local-${randomId}&type=${router.query.type}`, - ) - } else { - key = `draft-${site.data?.characterId}-${pageId}` - } - setDraftKey(key) - setDefaultSlug( - key - .replace(`draft-${site.data?.characterId}-local-`, "") - .replace(`draft-${site.data?.characterId}-`, ""), - ) - } - }, [subdomain, pageId, queryClient, router, site.data?.characterId]) - - const page = useGetPage({ - characterId: site.data?.characterId, - noteId: pageId && /\d+/.test(pageId) ? +pageId : undefined, - slug: pageId || draftKey.replace(`draft-${site.data?.characterId}-`, ""), - handle: subdomain, - }) - - const { data: posts = { pages: [] } } = useGetPagesBySiteLite({ - characterId: site.data?.characterId, - limit: 100, - type: "post", - visibility: PageVisibilityEnum.Published, - }) - - const userTags = useMemo(() => { - const result = new Set() - - if (posts?.pages?.length) { - for (const page of posts.pages) { - for (const post of page.list) { - post.metadata?.content?.tags?.forEach((tag) => { - if (tag !== "post" && tag !== "page") { - result.add(tag) - } - }) - } - } - } - return Array.from(result) - }, [posts.pages]) - - const [visibility, setVisibility] = useState() - - useEffect(() => { - if (page.isSuccess) { - setVisibility(getPageVisibility(page.data || undefined)) - } - }, [page.isSuccess, page.data]) - - const uploadFile = useUploadFile() - - // reset editor state when page changes - useSyncOnce(() => { - useEditorState.setState(initialEditorState) - }) - - const values = useEditorState() - - const [initialContent, setInitialContent] = useState("") - const [defaultSlug, setDefaultSlug] = useState("") - - const getValues = useGetState(values) - const getDraftKey = useGetState(draftKey) - - const updateValue = useCallback( - (key: K, value: Values[K]) => { - if (visibility !== PageVisibilityEnum.Draft) { - setVisibility(PageVisibilityEnum.Modified) - } - - const values = getValues() - const draftKey = getDraftKey() - if (key === "title") { - setDefaultSlug( - getDefaultSlug( - value as string, - draftKey.replace(`draft-${site.data?.characterId}-`, ""), - ), - ) - } - if (key === "slug" && !/^[a-zA-Z0-9\-_]*$/.test(value as string)) { - toast.error( - t( - "Slug can only contain letters, numbers, hyphens, and underscores.", - ), - ) - return - } - const newValues = { ...values, [key]: value } - if (draftKey) { - setStorage(draftKey, { - date: +new Date(), - values: newValues, - isPost: isPost, - }) - queryClient.invalidateQueries([ - "getPagesBySite", - site.data?.characterId, - ]) - } - useEditorState.setState(newValues) - }, - [isPost, queryClient, subdomain, visibility], - ) - - const createOrUpdatePage = useCreateOrUpdatePage() - - const isMobileLayout = useIsMobileLayout() - const [isRendering, setIsRendering] = useState(false) - - const savePage = async (published: boolean) => { - const check = await checkPageSlug({ - slug: values.slug || defaultSlug, - characterId: site.data?.characterId, - noteId: page?.data?.noteId, - }) - if (check) { - toast.error(check) - } else { - const uniqueTags = Array.from(new Set(values.tags.split(","))).join(",") - createOrUpdatePage.mutate({ - ...values, - tags: uniqueTags, - slug: values.slug || defaultSlug, - siteId: subdomain, - ...(visibility === PageVisibilityEnum.Draft - ? {} - : { pageId: `${page?.data?.characterId}-${page?.data?.noteId}` }), - isPost: isPost, - published, - externalUrl: - (values.slug || defaultSlug) && - `${getSiteLink({ - subdomain, - domain: site.data?.metadata?.content?.custom_domain, - })}/${encodeURIComponent(values.slug || defaultSlug)}`, - applications: page.data?.metadata?.content?.sources, - characterId: site.data?.characterId, - }) - } - } - - const [isCheersOpen, setIsCheersOpen] = useState(false) - - useEffect(() => { - if (createOrUpdatePage.isSuccess) { - if (createOrUpdatePage.data?.code === 0) { - if (draftKey) { - delStorage(draftKey) - queryClient.invalidateQueries([ - "getPagesBySite", - site.data?.characterId, - ]) - queryClient.invalidateQueries([ - "getPage", - draftKey.replace(`draft-${site.data?.characterId}-`, ""), - ]) - } else { - queryClient.invalidateQueries(["getPage", pageId]) - } - - if (createOrUpdatePage.data.data) { - router.replace( - `/dashboard/${subdomain}/editor?id=${site.data?.characterId}-${createOrUpdatePage.data.data}&type=${router.query.type}`, - ) - } - - setIsCheersOpen(true) - showConfetti() - } else { - toast.error("Error: " + createOrUpdatePage.data?.message) - } - } - }, [createOrUpdatePage.isSuccess]) - - useEffect(() => { - if (!page.data || !draftKey) return - setInitialContent(page.data.metadata?.content?.content || "") - useEditorState.setState({ - title: page.data.metadata?.content?.title || "", - publishedAt: page.data.metadata?.content?.date_published, - published: !!page.data.noteId, - excerpt: page.data.metadata?.content?.summary || "", - slug: page.data.metadata?.content?.slug || "", - tags: - page.data.metadata?.content?.tags - ?.filter((tag) => tag !== "post" && tag !== "page") - ?.join(", ") || "", - content: page.data.metadata?.content?.content || "", - }) - setDefaultSlug( - getDefaultSlug( - page.data.metadata?.content?.title || "", - draftKey.replace(`draft-${site.data?.characterId}-`, ""), - ), - ) - }, [page.data, subdomain, draftKey, site.data?.characterId]) - - const [currentScrollArea, setCurrentScrollArea] = useState("") - const [view, setView] = useState() - const [tree, setTree] = useState() - - // preview - - const [parsedContent, setParsedContent] = useState() - - useDebounceEffect( - () => { - const result = renderPageContent(values.content) - setTree(result.tree) - setParsedContent(result) - }, - [values.content], - { - wait: 500, - }, - ) - - const previewRef = useRef(null) - - // editor - const onCreateEditor = useCallback( - (view: EditorView) => { - setView?.(view) - }, - [setView], - ) - - const onChange = useCallback( - (value: string) => { - updateValue("content", value) - }, - [updateValue], - ) - - const handleDropFile = useCallback( - async (file: File) => { - const toastId = toast.loading("Uploading...") - try { - if ( - !file.type.startsWith("image/") && - !file.type.startsWith("audio/") - ) { - throw new Error("You can only upload images and audios") - } - - const { key } = await uploadFile(file) - toast.success("Uploaded!", { - id: toastId, - }) - if (file.type.startsWith("image/")) { - view?.dispatch( - view.state.replaceSelection( - `\n![${file.name.replace(/\.\w+$/, "")}](${key})\n`, - ), - ) - } else if (file.type.startsWith("audio/")) { - const fileArrayBuffer = await file.arrayBuffer() - const fileBuffer = Buffer.from(fileArrayBuffer) - const tags = NodeID3.read(fileBuffer) - const name = tags.title ?? file.name - const artist = tags.artist - const cover = await (async () => { - const image = tags.image - if (!image || typeof image === "string") return image - - const toastId = toast.loading("Uploading cover...") - const { key } = await uploadFile( - new Blob([image.imageBuffer], { type: image.type.name }), - ) - toast.success("Uploaded cover!", { - id: toastId, - }) - return key - })() - view?.dispatch( - view.state.replaceSelection( - `\n