diff --git a/app/(home-pages)/p/[didOrHandle]/layout.tsx b/app/(home-pages)/p/[didOrHandle]/layout.tsx index 4108fe28..1f61b5cc 100644 --- a/app/(home-pages)/p/[didOrHandle]/layout.tsx +++ b/app/(home-pages)/p/[didOrHandle]/layout.tsx @@ -82,6 +82,7 @@ export default async function ProfilePageLayout(props: { id="profile" defaultTab="default" currentPage="profile" + profileDid={did} actions={null} tabs={{ default: { diff --git a/components/ActionBar/ActionButton.tsx b/components/ActionBar/ActionButton.tsx index 17dac49e..b66a762e 100644 --- a/components/ActionBar/ActionButton.tsx +++ b/components/ActionBar/ActionButton.tsx @@ -55,7 +55,7 @@ export const ActionButton = ( rounded-md border flex gap-2 items-start sm:justify-start justify-center p-1 sm:mx-0 - ${showLabelOnMobile && !secondary ? "w-full" : "sm:w-full w-max"} + ${showLabelOnMobile && "sm:w-full w-max"} ${ primary ? "bg-accent-1 border-accent-1 text-accent-2 transparent-outline sm:hover:outline-accent-contrast focus:outline-accent-1 outline-offset-1 mx-1 first:ml-0" diff --git a/components/ActionBar/DesktopNavigation.tsx b/components/ActionBar/DesktopNavigation.tsx new file mode 100644 index 00000000..489c2016 --- /dev/null +++ b/components/ActionBar/DesktopNavigation.tsx @@ -0,0 +1,42 @@ +import { useIdentityData } from "components/IdentityProvider"; +import { + navPages, + HomeButton, + ReaderButton, + NotificationButton, +} from "./NavigationButtons"; +import { PublicationButtons } from "./Publications"; +import { Sidebar } from "./Sidebar"; + +export const DesktopNavigation = (props: { + currentPage: navPages; + publication?: string; +}) => { + let { identity } = useIdentityData(); + let thisPublication = identity?.publications?.find( + (pub) => pub.uri === props.publication, + ); + return ( +
+ + + + {identity?.atp_did && ( + + )} + + + + +
+ ); +}; diff --git a/components/ActionBar/Footer.tsx b/components/ActionBar/Footer.tsx index 67d191ee..2b28cf6a 100644 --- a/components/ActionBar/Footer.tsx +++ b/components/ActionBar/Footer.tsx @@ -8,7 +8,7 @@ export function Footer(props: { children?: React.ReactNode }) { actionFooter touch-none shrink-0 w-full z-10 px-2 pt-1 pwa-padding-bottom - flex justify-start gap-1 + flex justify-between gap-1 h-[calc(38px+var(--safe-padding-bottom))] bg-[rgba(var(--bg-page),0.5)] border-top border-bg-page`} > diff --git a/components/ActionBar/MobileNavigation.tsx b/components/ActionBar/MobileNavigation.tsx new file mode 100644 index 00000000..05edd69d --- /dev/null +++ b/components/ActionBar/MobileNavigation.tsx @@ -0,0 +1,129 @@ +import { MenuSmall } from "components/Icons/MenuSmall"; +import { useIdentityData } from "components/IdentityProvider"; +import { Popover } from "components/Popover"; +import { Separator } from "components/Layout"; +import { + HomeButton, + navPages, + NotificationButton, + ReaderButton, +} from "./NavigationButtons"; +import { PubIcon, PublicationButtons } from "./Publications"; +import { HomeSmall } from "components/Icons/HomeSmall"; +import { ReaderReadSmall } from "components/Icons/ReaderSmall"; +import { LooseLeafSmall } from "components/Icons/LooseleafSmall"; +import { normalizePublicationRecord } from "src/utils/normalizeRecords"; +import { + NotificationsReadSmall, + NotificationsUnreadSmall, +} from "components/Icons/NotificationSmall"; +import { TagSmall } from "components/Icons/TagSmall"; +import { Avatar } from "components/Avatar"; +import { useProfileFromDid } from "src/utils/getRecordFromDid"; + +export const MobileNavigation = (props: { + currentPage: navPages; + currentPublicationUri?: string; + currentProfileDid?: string; +}) => { + let { identity } = useIdentityData(); + let thisPublication = identity?.publications?.find( + (pub) => pub.uri === props.currentPublicationUri, + ); + return ( +
+ e.preventDefault()} + asChild + className="px-2! !max-w-[256px]" + trigger={ +
+ + + +
+ } + > + + +
+ +
+ {identity?.atp_did && ( + <> + + + + )} +
+ ); +}; + +const CurrentPageIcon = (props: { + currentPage: navPages; + currentPubUri?: string; + currentProfileDid?: string; +}) => { + let { identity } = useIdentityData(); + let currentPub = identity?.publications?.find( + (pub) => pub.uri === props.currentPubUri, + ); + let pubRecord = currentPub + ? normalizePublicationRecord(currentPub.record) + : null; + let unreads = identity?.notifications[0]?.count; + + const { data: profile } = useProfileFromDid( + props.currentPage === "profile" ? props.currentProfileDid : undefined, + ); + + switch (props.currentPage) { + case "home": + return ; + case "reader": + return ; + case "profile": + if (profile) { + return ( + + ); + } + return ; + case "tag": + return ; + case "notifications": + if (unreads) { + return ; + } else { + return ; + } + + case "looseleafs": + return ; + + case "pub": + if (currentPub && pubRecord) { + return ; + } + return null; + default: + return null; + } +}; diff --git a/components/ActionBar/Navigation.tsx b/components/ActionBar/Navigation.tsx deleted file mode 100644 index 636dc851..00000000 --- a/components/ActionBar/Navigation.tsx +++ /dev/null @@ -1,179 +0,0 @@ -import { HomeSmall } from "components/Icons/HomeSmall"; -import { ActionButton } from "./ActionButton"; -import { Sidebar } from "./Sidebar"; -import { useIdentityData } from "components/IdentityProvider"; -import Link from "next/link"; -import { DiscoverSmall } from "components/Icons/DiscoverSmall"; -import { PublicationButtons } from "./Publications"; -import { Popover } from "components/Popover"; -import { MenuSmall } from "components/Icons/MenuSmall"; -import { - ReaderReadSmall, - ReaderUnreadSmall, -} from "components/Icons/ReaderSmall"; -import { - NotificationsReadSmall, - NotificationsUnreadSmall, -} from "components/Icons/NotificationSmall"; -import { SpeedyLink } from "components/SpeedyLink"; -import { Separator } from "components/Layout"; - -export type navPages = - | "home" - | "reader" - | "pub" - | "discover" - | "notifications" - | "looseleafs" - | "tag" - | "profile"; - -export const DesktopNavigation = (props: { - currentPage: navPages; - publication?: string; -}) => { - let { identity } = useIdentityData(); - return ( -
- - - - {identity?.atp_did && ( - - - - )} -
- ); -}; - -export const MobileNavigation = (props: { - currentPage: navPages; - publication?: string; -}) => { - let { identity } = useIdentityData(); - - return ( -
- e.preventDefault()} - asChild - className="px-2! !max-w-[256px]" - trigger={ -
- -
- } - > - -
- {identity?.atp_did && ( - <> - - - - )} -
- ); -}; - -const NavigationOptions = (props: { - currentPage: navPages; - publication?: string; - isMobile?: boolean; -}) => { - let { identity } = useIdentityData(); - let thisPublication = identity?.publications?.find( - (pub) => pub.uri === props.publication, - ); - return ( - <> - - - - -
- - - ); -}; - -const HomeButton = (props: { current?: boolean }) => { - return ( - - } - label="Home" - className={props.current ? "bg-bg-page! border-border-light!" : ""} - /> - - ); -}; - -const ReaderButton = (props: { current?: boolean; subs: boolean }) => { - if (!props.subs) return; - return ( - - } - label="Reader" - className={props.current ? "bg-bg-page! border-border-light!" : ""} - /> - - ); -}; - -const DiscoverButton = (props: { current?: boolean }) => { - return ( - - } - label="Discover" - subtext="" - className={props.current ? "bg-bg-page! border-border-light!" : ""} - /> - - ); -}; - -export function NotificationButton(props: { current?: boolean }) { - let { identity } = useIdentityData(); - let unreads = identity?.notifications[0]?.count; - - return ( - - - ) : ( - - ) - } - label="Notifications" - className={`${props.current ? "bg-bg-page! border-border-light!" : ""} ${unreads ? "text-accent-contrast!" : ""}`} - /> - - ); -} diff --git a/components/ActionBar/NavigationButtons.tsx b/components/ActionBar/NavigationButtons.tsx new file mode 100644 index 00000000..a41b42eb --- /dev/null +++ b/components/ActionBar/NavigationButtons.tsx @@ -0,0 +1,71 @@ +import { HomeSmall } from "components/Icons/HomeSmall"; +import { ActionButton } from "./ActionButton"; +import { useIdentityData } from "components/IdentityProvider"; +import Link from "next/link"; +import { DiscoverSmall } from "components/Icons/DiscoverSmall"; +import { PublicationButtons } from "./Publications"; +import { ReaderUnreadSmall } from "components/Icons/ReaderSmall"; +import { + NotificationsReadSmall, + NotificationsUnreadSmall, +} from "components/Icons/NotificationSmall"; +import { SpeedyLink } from "components/SpeedyLink"; + +export type navPages = + | "home" + | "reader" + | "pub" + | "notifications" + | "looseleafs" + | "tag" + | "profile"; + +export const HomeButton = (props: { current?: boolean }) => { + return ( + + } + label="Home" + className={props.current ? "bg-bg-page! border-border-light!" : ""} + /> + + ); +}; + +export const ReaderButton = (props: { current?: boolean; subs: boolean }) => { + if (!props.subs) return; + return ( + + } + label="Reader" + className={props.current ? "bg-bg-page! border-border-light!" : ""} + /> + + ); +}; + +export function NotificationButton(props: { current?: boolean }) { + let { identity } = useIdentityData(); + let unreads = identity?.notifications[0]?.count; + + return ( + + + ) : ( + + ) + } + label="Notifications" + className={`${props.current ? "bg-bg-page! border-border-light!" : ""} ${unreads ? "text-accent-contrast!" : ""}`} + /> + + ); +} diff --git a/components/ActionBar/Publications.tsx b/components/ActionBar/Publications.tsx index 305db983..c45d5f4d 100644 --- a/components/ActionBar/Publications.tsx +++ b/components/ActionBar/Publications.tsx @@ -19,7 +19,7 @@ import { ButtonSecondary } from "components/Buttons"; import { useIsMobile } from "src/hooks/isMobile"; import { useState } from "react"; import { LooseLeafSmall } from "components/Icons/LooseleafSmall"; -import { navPages } from "./Navigation"; +import { navPages } from "./NavigationButtons"; export const PublicationButtons = (props: { currentPage: navPages; @@ -38,7 +38,7 @@ export const PublicationButtons = (props: { return ; return ( -
+
{hasLooseleafs && ( <> -
)} diff --git a/components/Icons/NotificationSmall.tsx b/components/Icons/NotificationSmall.tsx index 4577ae3a..39296a94 100644 --- a/components/Icons/NotificationSmall.tsx +++ b/components/Icons/NotificationSmall.tsx @@ -19,41 +19,6 @@ export const NotificationsUnreadSmall = (props: Props) => { }; export const NotificationsReadSmall = (props: Props) => { - return ( - - - - ); -}; - -export const ReaderUnread = (props: Props) => { - return ( - - - - ); -}; - -export const ReaderRead = (props: Props) => { return ( { {...props} > diff --git a/components/Icons/TagSmall.tsx b/components/Icons/TagSmall.tsx new file mode 100644 index 00000000..5180884e --- /dev/null +++ b/components/Icons/TagSmall.tsx @@ -0,0 +1,19 @@ +import { Props } from "./Props"; + +export const TagSmall = (props: Props) => { + return ( + + + + ); +}; diff --git a/components/PageLayouts/DashboardLayout.tsx b/components/PageLayouts/DashboardLayout.tsx index 5521275e..da12cc1d 100644 --- a/components/PageLayouts/DashboardLayout.tsx +++ b/components/PageLayouts/DashboardLayout.tsx @@ -4,12 +4,13 @@ import { useSearchParams } from "next/navigation"; import { Header } from "../PageHeader"; import { Footer } from "components/ActionBar/Footer"; import { Sidebar } from "components/ActionBar/Sidebar"; +import { DesktopNavigation } from "components/ActionBar/DesktopNavigation"; + +import { MobileNavigation } from "components/ActionBar/MobileNavigation"; import { - DesktopNavigation, - MobileNavigation, navPages, NotificationButton, -} from "components/ActionBar/Navigation"; +} from "components/ActionBar/NavigationButtons"; import { create } from "zustand"; import { Popover } from "components/Popover"; import { Checkbox } from "components/Checkbox"; @@ -138,6 +139,7 @@ export function DashboardLayout< defaultTab: keyof T; currentPage: navPages; publication?: string; + profileDid?: string; actions: React.ReactNode; }) { const searchParams = useSearchParams(); @@ -240,13 +242,11 @@ export function DashboardLayout<
diff --git a/src/utils/getRecordFromDid.ts b/src/utils/getRecordFromDid.ts new file mode 100644 index 00000000..2ff42679 --- /dev/null +++ b/src/utils/getRecordFromDid.ts @@ -0,0 +1,12 @@ +import { callRPC } from "app/api/rpc/client"; +import { ProfileViewDetailed } from "@atproto/api/dist/client/types/app/bsky/actor/defs"; +import useSWR from "swr"; + +export function useProfileFromDid(did: string | undefined) { + return useSWR(did ? ["profile-data", did] : null, async () => { + const response = await callRPC("get_profile_data", { + didOrHandle: did!, + }); + return response.result.profile as ProfileViewDetailed | undefined; + }); +}