Nothing to read yet…
Subscribe to publications and find their posts here!
-
+
See what posts people are reading!
diff --git a/app/(home-pages)/reader/ReaderLayout.tsx b/app/(home-pages)/reader/ReaderLayout.tsx
deleted file mode 100644
index c8be5af8..00000000
--- a/app/(home-pages)/reader/ReaderLayout.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-"use client";
-import { PageTitle } from "components/ActionBar/DesktopNavigation";
-import { DashboardLayout } from "components/PageLayouts/DashboardLayout";
-import { DashboardPageLayout } from "components/PageLayouts/DashboardPageLayout";
-import { ReaderUnreadSmall } from "components/Icons/ReaderSmall";
-import { GlobalContent } from "./GlobalContent";
-import { InboxContent } from "./InboxContent";
-import type { Cursor, Post } from "./getReaderFeed";
-
-export function ReaderLayout(props: {
- readerFeedPromise: Promise<{ posts: Post[]; nextCursor: Cursor | null }>;
- hotFeedPromise: Promise<{ posts: Post[] }>;
- defaultTab: "Inbox" | "Trending";
-}) {
- return (
-
} pageTitle="Reader" />}
- tabs={{
- Inbox: {
- content: (
-
-
-
- ),
- },
- Trending: {
- content: (
-
-
-
- ),
- },
- }}
- />
- );
-}
diff --git a/app/(home-pages)/reader/hot/page.tsx b/app/(home-pages)/reader/hot/page.tsx
index 3e0430b2..5a4e6d6c 100644
--- a/app/(home-pages)/reader/hot/page.tsx
+++ b/app/(home-pages)/reader/hot/page.tsx
@@ -1,7 +1,5 @@
-import { getHotFeed } from "../getHotFeed";
-import { GlobalContent } from "../GlobalContent";
+import { redirect } from "next/navigation";
-export default async function HotPage() {
- const feedPromise = getHotFeed();
- return
;
+export default function HotPage() {
+ redirect("/reader/trending");
}
diff --git a/app/(home-pages)/reader/layout.tsx b/app/(home-pages)/reader/layout.tsx
new file mode 100644
index 00000000..7f299d24
--- /dev/null
+++ b/app/(home-pages)/reader/layout.tsx
@@ -0,0 +1,23 @@
+import { getIdentityData } from "actions/getIdentityData";
+import { PageTitle } from "components/ActionBar/DesktopNavigation";
+import { DashboardShell } from "components/PageLayouts/DashboardShell";
+import { ReaderUnreadSmall } from "components/Icons/ReaderSmall";
+
+export default async function ReaderLayout(props: {
+ children: React.ReactNode;
+}) {
+ const identity = await getIdentityData();
+ const tabs: { [name: string]: { href: string } } = {};
+ if (identity?.atp_did) tabs.Inbox = { href: "/reader" };
+ tabs.Trending = { href: "/reader/trending" };
+
+ return (
+
} pageTitle="Reader" />}
+ tabs={tabs}
+ >
+ {props.children}
+
+ );
+}
diff --git a/app/(home-pages)/reader/loading.tsx b/app/(home-pages)/reader/loading.tsx
deleted file mode 100644
index 06773957..00000000
--- a/app/(home-pages)/reader/loading.tsx
+++ /dev/null
@@ -1,4 +0,0 @@
-import { FeedSkeleton } from "./FeedSkeleton";
-export default function Loading() {
- return
;
-}
diff --git a/app/(home-pages)/reader/new/page.tsx b/app/(home-pages)/reader/new/page.tsx
index c857832f..002710d0 100644
--- a/app/(home-pages)/reader/new/page.tsx
+++ b/app/(home-pages)/reader/new/page.tsx
@@ -1,7 +1,19 @@
+import { Suspense } from "react";
+import { DashboardPageLayout } from "components/PageLayouts/DashboardPageLayout";
import { getNewFeed } from "../getNewFeed";
import { NewContent } from "../NewContent";
+import { FeedSkeleton } from "../FeedSkeleton";
-export default async function NewPage() {
- const feedPromise = getNewFeed();
- return
;
+export default function NewPage() {
+ return (
+
+ }>
+
+
+
+ );
}
diff --git a/app/(home-pages)/reader/page.tsx b/app/(home-pages)/reader/page.tsx
index 9abef7e4..ea4c247a 100644
--- a/app/(home-pages)/reader/page.tsx
+++ b/app/(home-pages)/reader/page.tsx
@@ -1,17 +1,29 @@
+import { Suspense } from "react";
+import { redirect } from "next/navigation";
import { getIdentityData } from "actions/getIdentityData";
+import { DashboardPageLayout } from "components/PageLayouts/DashboardPageLayout";
import { getReaderFeed } from "./getReaderFeed";
-import { getHotFeed } from "./getHotFeed";
import { InboxContent } from "./InboxContent";
-import { GlobalContent } from "./GlobalContent";
-import { ReaderLayout } from "./ReaderLayout";
+import { FeedSkeleton } from "./FeedSkeleton";
+
+export default async function ReaderPage(props: {
+ searchParams: Promise<{ tab?: string }>;
+}) {
+ const { tab } = await props.searchParams;
+ if (tab === "Trending") redirect("/reader/trending");
+
+ const identity = await getIdentityData();
+ if (!identity?.atp_did) redirect("/reader/trending");
-export default async function Reader() {
- let identityData = await getIdentityData();
return (
-
+
+ }>
+
+
+
);
}
diff --git a/app/(home-pages)/reader/trending/page.tsx b/app/(home-pages)/reader/trending/page.tsx
new file mode 100644
index 00000000..cf1c8fdd
--- /dev/null
+++ b/app/(home-pages)/reader/trending/page.tsx
@@ -0,0 +1,19 @@
+import { Suspense } from "react";
+import { DashboardPageLayout } from "components/PageLayouts/DashboardPageLayout";
+import { getHotFeed } from "../getHotFeed";
+import { GlobalContent } from "../GlobalContent";
+import { FeedSkeleton } from "../FeedSkeleton";
+
+export default function ReaderTrendingPage() {
+ return (
+
+ }>
+
+
+
+ );
+}
diff --git a/app/(home-pages)/tag/[tag]/layout.tsx b/app/(home-pages)/tag/[tag]/layout.tsx
new file mode 100644
index 00000000..2c33995f
--- /dev/null
+++ b/app/(home-pages)/tag/[tag]/layout.tsx
@@ -0,0 +1,24 @@
+import { DashboardShell } from "components/PageLayouts/DashboardShell";
+import { PageTitle } from "components/ActionBar/DesktopNavigation";
+import { TagTiny } from "components/Icons/TagTiny";
+
+export default async function TagLayout(props: {
+ children: React.ReactNode;
+ params: Promise<{ tag: string }>;
+}) {
+ const params = await props.params;
+ const decodedTag = decodeURIComponent(params.tag);
+
+ return (
+
} pageTitle={decodedTag} />}
+ tabs={{
+ Inbox: { href: "/reader/inbox" },
+ Trending: { href: "/reader/trending" },
+ }}
+ >
+ {props.children}
+
+ );
+}
diff --git a/app/(home-pages)/tag/[tag]/page.tsx b/app/(home-pages)/tag/[tag]/page.tsx
index 043b3774..099c1349 100644
--- a/app/(home-pages)/tag/[tag]/page.tsx
+++ b/app/(home-pages)/tag/[tag]/page.tsx
@@ -1,10 +1,7 @@
-import { DashboardLayout } from "components/PageLayouts/DashboardLayout";
import { DashboardPageLayout } from "components/PageLayouts/DashboardPageLayout";
import { PostListing } from "components/PostListing";
import { getDocumentsByTag } from "./getDocumentsByTag";
import { Metadata } from "next";
-import { PageTitle } from "components/ActionBar/DesktopNavigation";
-import { TagTiny } from "components/Icons/TagTiny";
export async function generateMetadata(props: {
params: Promise<{ tag: string }>;
@@ -22,26 +19,13 @@ export default async function TagPage(props: {
const { posts } = await getDocumentsByTag(decodedTag);
return (
-
} pageTitle={decodedTag} />
- tabs={{
- default: {
- content: (
-
-
-
- ),
- },
- }}
- />
+
+
+
);
}
diff --git a/app/[leaflet_id]/publish/PublishPost.tsx b/app/[leaflet_id]/publish/PublishPost.tsx
index 574c6435..90eececd 100644
--- a/app/[leaflet_id]/publish/PublishPost.tsx
+++ b/app/[leaflet_id]/publish/PublishPost.tsx
@@ -34,7 +34,7 @@ import {
PublicationBackgroundProvider,
} from "components/ThemeManager/PublicationThemeProvider";
import { useEntity } from "src/replicache";
-import { LeafletContent } from "app/(home-pages)/home/LeafletList/LeafletContent";
+import { LeafletContent } from "app/(home-pages)/(writer)/home/LeafletList/LeafletContent";
type Props = {
title: string;
diff --git a/app/lish/[did]/[publication]/dashboard/DashboardChrome.tsx b/app/lish/[did]/[publication]/dashboard/DashboardChrome.tsx
new file mode 100644
index 00000000..05fe46f0
--- /dev/null
+++ b/app/lish/[did]/[publication]/dashboard/DashboardChrome.tsx
@@ -0,0 +1,66 @@
+"use client";
+
+import { Actions } from "./Actions";
+import { DashboardShell } from "components/PageLayouts/DashboardShell";
+import { type NormalizedPublication } from "src/utils/normalizeRecords";
+import { useCanSeePro } from "src/hooks/useEntitlement";
+import { PubIcon } from "components/ActionBar/Publications";
+import { PageTitle } from "components/ActionBar/DesktopNavigation";
+import { SettingsSmall } from "components/Icons/SettingsSmall";
+import {
+ PublicationSWRDataProvider,
+} from "./PublicationSWRProvider";
+import type { GetPublicationDataReturnType } from "app/api/rpc/[command]/get_publication_data";
+import { PublicationThemeProviderDashboard } from "components/ThemeManager/PublicationThemeProvider";
+
+export function DashboardChrome(props: {
+ publication_did: string;
+ publication_rkey: string;
+ publication_data: GetPublicationDataReturnType["result"];
+ pubUri: string;
+ record: NormalizedPublication;
+ routeDid: string;
+ routePublication: string;
+ children: React.ReactNode;
+}) {
+ let canSeePro = useCanSeePro();
+ let baseHref = `/lish/${props.routeDid}/${props.routePublication}/dashboard`;
+
+ return (
+
+
+
+ }
+ />
+ }
+ actions={}
+ tabs={{
+ Drafts: { href: baseHref },
+ Posts: { href: `${baseHref}/posts` },
+ Subs: { href: `${baseHref}/subs` },
+ ...(canSeePro
+ ? { Analytics: { href: `${baseHref}/analytics` } }
+ : {}),
+ Settings: {
+ href: `${baseHref}/settings`,
+ icon: ,
+ },
+ }}
+ >
+ {props.children}
+
+
+
+ );
+}
diff --git a/app/lish/[did]/[publication]/dashboard/DraftList.tsx b/app/lish/[did]/[publication]/dashboard/DraftList.tsx
index 49ff4514..ddce3c10 100644
--- a/app/lish/[did]/[publication]/dashboard/DraftList.tsx
+++ b/app/lish/[did]/[publication]/dashboard/DraftList.tsx
@@ -5,7 +5,7 @@ import {
usePublicationData,
useNormalizedPublicationRecord,
} from "./PublicationSWRProvider";
-import { LeafletList } from "app/(home-pages)/home/HomeLayout";
+import { LeafletList } from "app/(home-pages)/(writer)/home/HomeLayout";
export function DraftList(props: {
searchValue: string;
diff --git a/app/lish/[did]/[publication]/dashboard/DraftsTab.tsx b/app/lish/[did]/[publication]/dashboard/DraftsTab.tsx
new file mode 100644
index 00000000..6f98b57b
--- /dev/null
+++ b/app/lish/[did]/[publication]/dashboard/DraftsTab.tsx
@@ -0,0 +1,51 @@
+"use client";
+
+import { useState } from "react";
+import { useDebouncedEffect } from "src/hooks/useDebouncedEffect";
+import { DashboardPageLayout } from "components/PageLayouts/DashboardPageLayout";
+import { DraftList } from "./DraftList";
+import { NewDraftActionButton } from "./NewDraftButton";
+import { PageSearch } from "components/PageLayouts/PageSearch";
+import {
+ usePublicationData,
+ useNormalizedPublicationRecord,
+} from "./PublicationSWRProvider";
+
+export function DraftsTab() {
+ let { data } = usePublicationData();
+ let record = useNormalizedPublicationRecord();
+ let pubUri = data?.publication?.uri || "";
+
+ let [searchValue, setSearchValue] = useState("");
+ let [debouncedSearchValue, setDebouncedSearchValue] = useState("");
+ useDebouncedEffect(
+ () => setDebouncedSearchValue(searchValue),
+ 200,
+ [searchValue],
+ );
+
+ const showPageBackground = !!record?.theme?.showPageBackground;
+
+ return (
+
}
+ search={
+
+ }
+ publication={pubUri}
+ showHeader={true}
+ >
+
+
+ );
+}
diff --git a/app/lish/[did]/[publication]/dashboard/PublicationDashboard.tsx b/app/lish/[did]/[publication]/dashboard/PublicationDashboard.tsx
deleted file mode 100644
index 7b2fbd4e..00000000
--- a/app/lish/[did]/[publication]/dashboard/PublicationDashboard.tsx
+++ /dev/null
@@ -1,160 +0,0 @@
-"use client";
-
-import { DraftList } from "./DraftList";
-import { GetPublicationDataReturnType } from "app/api/rpc/[command]/get_publication_data";
-import { Actions } from "./Actions";
-import React, { useState } from "react";
-import { PublishedPostsList } from "./PublishedPostsLists";
-import { PublicationSubscribers } from "./PublicationSubscribers";
-import { DashboardLayout } from "components/PageLayouts/DashboardLayout";
-import { DashboardPageLayout } from "components/PageLayouts/DashboardPageLayout";
-import { useDebouncedEffect } from "src/hooks/useDebouncedEffect";
-import { type NormalizedPublication } from "src/utils/normalizeRecords";
-import { PublicationAnalytics } from "./PublicationAnalytics";
-import { useCanSeePro } from "src/hooks/useEntitlement";
-import { SettingsContent } from "./settings/SettingsContent";
-import { PageSearch } from "components/PageLayouts/PageSearch";
-import { PubIcon } from "components/ActionBar/Publications";
-import { PageTitle } from "components/ActionBar/DesktopNavigation";
-import { NewDraftActionButton } from "./NewDraftButton";
-import { SettingsSmall } from "components/Icons/SettingsSmall";
-
-export default function PublicationDashboard({
- publication,
- record,
-}: {
- record: NormalizedPublication;
- publication: Exclude<
- GetPublicationDataReturnType["result"]["publication"],
- null
- >;
-}) {
- let canSeePro = useCanSeePro();
- let [searchValue, setSearchValue] = useState("");
- let [debouncedSearchValue, setDebouncedSearchValue] = useState("");
-
- useDebouncedEffect(
- () => {
- setDebouncedSearchValue(searchValue);
- },
- 200,
- [searchValue],
- );
-
- const pubUri = publication.uri;
- const showPageBackground = !!record.theme?.showPageBackground;
-
- return (
-
}
- currentPage="pub"
- publication={pubUri}
- pageTitle={
-
}
- />
- }
- tabs={{
- Drafts: {
- content: (
-
- }
- search={
-
- }
- publication={pubUri}
- showHeader={true}
- >
-
-
- ),
- },
- Posts: {
- content: (
-
- }
- publication={pubUri}
- showHeader={false}
- >
-
-
- ),
- },
- Subs: {
- content: (
-
- }
- publication={pubUri}
- showHeader={false}
- >
-
-
- ),
- },
- ...(canSeePro
- ? {
- Analytics: {
- content: (
-
- }
- publication={pubUri}
- showHeader={false}
- >
-
-
- ),
- },
- }
- : {}),
- Settings: {
- icon:
,
- content: (
-
- }
- publication={pubUri}
- showHeader={false}
- >
-
-
- ),
- },
- }}
- />
- );
-}
diff --git a/app/lish/[did]/[publication]/dashboard/PublishedPostsLists.tsx b/app/lish/[did]/[publication]/dashboard/PublishedPostsLists.tsx
index cbc9e4f9..fe4ab6f1 100644
--- a/app/lish/[did]/[publication]/dashboard/PublishedPostsLists.tsx
+++ b/app/lish/[did]/[publication]/dashboard/PublishedPostsLists.tsx
@@ -17,7 +17,7 @@ import {
import { SpeedyLink } from "components/SpeedyLink";
import { InteractionPreview } from "components/InteractionsPreview";
import { useLocalizedDate } from "src/hooks/useLocalizedDate";
-import { LeafletOptions } from "app/(home-pages)/home/LeafletList/LeafletOptions";
+import { LeafletOptions } from "app/(home-pages)/(writer)/home/LeafletList/LeafletOptions";
import { StaticLeafletDataContext } from "components/PageSWRDataProvider";
export function PublishedPostsList(props: {
diff --git a/app/lish/[did]/[publication]/dashboard/analytics/page.tsx b/app/lish/[did]/[publication]/dashboard/analytics/page.tsx
new file mode 100644
index 00000000..491c56ea
--- /dev/null
+++ b/app/lish/[did]/[publication]/dashboard/analytics/page.tsx
@@ -0,0 +1,39 @@
+"use client";
+
+import { useRouter } from "next/navigation";
+import { useEffect } from "react";
+import { DashboardPageLayout } from "components/PageLayouts/DashboardPageLayout";
+import { PublicationAnalytics } from "../PublicationAnalytics";
+import { NewDraftActionButton } from "../NewDraftButton";
+import {
+ usePublicationData,
+ useNormalizedPublicationRecord,
+} from "../PublicationSWRProvider";
+import { useCanSeePro } from "src/hooks/useEntitlement";
+
+export default function AnalyticsPage() {
+ let canSeePro = useCanSeePro();
+ let router = useRouter();
+ let { data } = usePublicationData();
+ let record = useNormalizedPublicationRecord();
+ let pubUri = data?.publication?.uri || "";
+ const showPageBackground = !!record?.theme?.showPageBackground;
+
+ useEffect(() => {
+ if (canSeePro === false) router.replace("../");
+ }, [canSeePro, router]);
+
+ if (!canSeePro) return null;
+
+ return (
+
}
+ publication={pubUri}
+ showHeader={false}
+ >
+
+
+ );
+}
diff --git a/app/lish/[did]/[publication]/dashboard/layout.tsx b/app/lish/[did]/[publication]/dashboard/layout.tsx
new file mode 100644
index 00000000..46aea374
--- /dev/null
+++ b/app/lish/[did]/[publication]/dashboard/layout.tsx
@@ -0,0 +1,105 @@
+import { supabaseServerClient } from "supabase/serverClient";
+import { Metadata } from "next";
+import { getIdentityData } from "actions/getIdentityData";
+import { get_publication_data } from "app/api/rpc/[command]/get_publication_data";
+import { normalizePublicationRecord } from "src/utils/normalizeRecords";
+import { NotFoundLayout } from "components/PageLayouts/NotFoundLayout";
+import { LoginModal } from "components/LoginButton";
+import { AtUri } from "@atproto/syntax";
+import { DashboardChrome } from "./DashboardChrome";
+
+export async function generateMetadata(props: {
+ params: Promise<{ publication: string; did: string }>;
+}): Promise
{
+ let did = decodeURIComponent((await props.params).did);
+ if (!did) return { title: "Publication 404" };
+
+ let { result: publication_data } = await get_publication_data.handler(
+ {
+ did,
+ publication_name: decodeURIComponent((await props.params).publication),
+ },
+ { supabase: supabaseServerClient },
+ );
+ let { publication } = publication_data;
+ const record = normalizePublicationRecord(publication?.record);
+ if (!publication) return { title: "404 Publication" };
+ return { title: record?.name || "Untitled Publication" };
+}
+
+export default async function PublicationDashboardLayout(props: {
+ children: React.ReactNode;
+ params: Promise<{ publication: string; did: string }>;
+}) {
+ let params = await props.params;
+ let identity = await getIdentityData();
+ if (!identity || !identity.atp_did) {
+ return (
+
+
+ Looks like you're not logged in.{" "}
+ Log in here
+ }
+ />
+ !
+