diff --git a/actions/getIdentityData.ts b/actions/getIdentityData.ts index 2a4acbbd..97e0fc14 100644 --- a/actions/getIdentityData.ts +++ b/actions/getIdentityData.ts @@ -25,7 +25,7 @@ export async function getIdentityData() { id, root_entity, permission_token_rights(*), - leaflets_in_publications(*) + leaflets_in_publications(*, publications(*)) ) ) )`, diff --git a/app/[leaflet_id]/Actions.tsx b/app/[leaflet_id]/Actions.tsx index 06349af8..bbf8656d 100644 --- a/app/[leaflet_id]/Actions.tsx +++ b/app/[leaflet_id]/Actions.tsx @@ -5,17 +5,15 @@ import { } from "app/lish/createPub/getPublicationURL"; import { ActionButton } from "components/ActionBar/ActionButton"; import { GoBackSmall } from "components/Icons/GoBackSmall"; +import { PaintSmall } from "components/Icons/PaintSmall"; import { PublishSmall } from "components/Icons/PublishSmall"; -import { useIdentityData } from "components/IdentityProvider"; import { useLeafletPublicationData } from "components/PageSWRDataProvider"; import { useToaster } from "components/Toast"; import { DotLoader } from "components/utils/DotLoader"; import Link from "next/link"; import { useParams, useRouter } from "next/navigation"; -import router from "next/router"; import { useState } from "react"; -import { useBlocks } from "src/hooks/queries/useBlocks"; -import { useReplicache, useEntity } from "src/replicache"; +import { useReplicache } from "src/replicache"; import { Json } from "supabase/database.types"; export const BackToPubButton = (props: { diff --git a/app/[leaflet_id]/Footer.tsx b/app/[leaflet_id]/Footer.tsx index a00f058c..27dba913 100644 --- a/app/[leaflet_id]/Footer.tsx +++ b/app/[leaflet_id]/Footer.tsx @@ -44,6 +44,7 @@ export function LeafletFooter(props: { entityID: string }) { + ) : ( diff --git a/app/[leaflet_id]/Sidebar.tsx b/app/[leaflet_id]/Sidebar.tsx index 7fecbf27..6deffc0f 100644 --- a/app/[leaflet_id]/Sidebar.tsx +++ b/app/[leaflet_id]/Sidebar.tsx @@ -38,6 +38,7 @@ export function LeafletSidebar(props: { leaflet_id: string }) { <> +
diff --git a/app/[leaflet_id]/publish/PublishPost.tsx b/app/[leaflet_id]/publish/PublishPost.tsx index dbdb8aa4..2953ff9c 100644 --- a/app/[leaflet_id]/publish/PublishPost.tsx +++ b/app/[leaflet_id]/publish/PublishPost.tsx @@ -29,7 +29,7 @@ export function PublishPost(props: Props) { { state: "default" } | { state: "success"; post_url: string } >({ state: "default" }); return ( -
+
{publishState.state === "default" ? ( ) : ( diff --git a/app/home/LeafletList.tsx b/app/home/LeafletList.tsx index 03fa9748..597eb11f 100644 --- a/app/home/LeafletList.tsx +++ b/app/home/LeafletList.tsx @@ -64,7 +64,7 @@ export function LeafletList(props: { return (
-
+
{leaflets.map((leaflet, index) => ( - +
{state === "normal" ? (
diff --git a/app/home/Publications.tsx b/app/home/Publications.tsx index 4f7c1e27..f20fe628 100644 --- a/app/home/Publications.tsx +++ b/app/home/Publications.tsx @@ -13,6 +13,8 @@ import { import { Json } from "supabase/database.types"; import { PubLeafletPublication } from "lexicons/api"; import { AtUri } from "@atproto/syntax"; +import { blobRefToSrc } from "src/utils/blobRefToSrc"; +import { PublicationThemeProvider } from "components/ThemeManager/PublicationThemeProvider"; export const MyPublicationList = () => { let { identity } = useIdentityData(); @@ -53,26 +55,47 @@ const PublicationList = (props: { function Publication(props: { uri: string; name: string; record: Json }) { let record = props.record as PubLeafletPublication.Record | null; + let pub_creator = new AtUri(props.uri).host; + let backgroundImage = record?.theme?.backgroundImage?.image?.ref + ? blobRefToSrc(record?.theme?.backgroundImage?.image?.ref, pub_creator) + : null; + + let backgroundImageRepeat = record?.theme?.backgroundImage?.repeat; + let backgroundImageSize = record?.theme?.backgroundImage?.width || 500; + let showPageBackground = !!record?.theme?.showPageBackground; return ( - -
- {record?.icon && ( -
- )} -

{props.name}

-
- + + +
+ {record?.icon && ( +
+ )} +

+ {props.name} +

+
+ + ); } diff --git a/app/lish/PostList.tsx b/app/lish/PostList.tsx deleted file mode 100644 index 74da7e3b..00000000 --- a/app/lish/PostList.tsx +++ /dev/null @@ -1,91 +0,0 @@ -"use client"; -import Link from "next/link"; -import { Json } from "supabase/database.types"; -import { PubLeafletDocument } from "lexicons/api"; -import { useIdentityData } from "components/IdentityProvider"; -import { useParams } from "next/navigation"; -import { AtUri } from "@atproto/syntax"; -import { getPublicationURL } from "./createPub/getPublicationURL"; - -export const PostList = (props: { - isFeed?: boolean; - publication: { uri: string; record: Json; name: string }; - posts: { - documents: { - data: Json; - indexed_at: string; - uri: string; - } | null; - }[]; -}) => { - if (props.posts.length === 0) { - if (props.isFeed) { - return ( -
- Subscribe to publications to see posts in your feed -
- ); - } - return null; - } - - return ( -
- {props.posts - .sort((a, b) => { - return a.documents?.indexed_at! > b.documents?.indexed_at! ? -1 : 1; - }) - .map((post, index) => { - let p = post.documents?.data as PubLeafletDocument.Record; - let uri = new AtUri(post.documents?.uri!); - - return ( - - ); - })} -
- ); -}; - -const PostListItem = ( - props: { - publication_data: { uri: string; record: Json; name: string }; - isFeed?: boolean; - uri: AtUri; - } & PubLeafletDocument.Record, -) => { - let { identity } = useIdentityData(); - let params = useParams(); - return ( -
- {props.isFeed && ( - - {props.publication} - - )} - - -

{props.title}

- {/*
placeholder description
*/} -
- {/*
{props.publishedAt}
*/} - {/* */} -
by {params.handle}
-
-
- -
- ); -}; diff --git a/app/lish/[did]/[publication]/[rkey]/page.tsx b/app/lish/[did]/[publication]/[rkey]/page.tsx index ab7b66f4..77ec511d 100644 --- a/app/lish/[did]/[publication]/[rkey]/page.tsx +++ b/app/lish/[did]/[publication]/[rkey]/page.tsx @@ -5,14 +5,21 @@ import { ids } from "lexicons/api/lexicons"; import { PubLeafletDocument, PubLeafletPagesLinearDocument, + PubLeafletPublication, + PubLeafletThemeColor, } from "lexicons/api"; import { Metadata } from "next"; import { getPublicationURL } from "app/lish/createPub/getPublicationURL"; -import { ThemeProvider } from "components/ThemeManager/ThemeProvider"; +import { TextBlock } from "./TextBlock"; import { BskyAgent } from "@atproto/api"; import { SubscribeWithBluesky } from "app/lish/Subscribe"; +import { + PublicationBackgroundProvider, + PublicationThemeProvider, +} from "components/ThemeManager/PublicationThemeProvider"; import { PostContent } from "./PostContent"; import { getIdentityData } from "actions/getIdentityData"; +import { EditTiny } from "components/Icons/EditTiny"; export async function generateMetadata(props: { params: Promise<{ publication: string; did: string; rkey: string }>; @@ -86,91 +93,115 @@ export default async function Post(props: { if (PubLeafletPagesLinearDocument.isMain(firstPage)) { blocks = firstPage.blocks || []; } - return ( - -
-
-
- - {decodeURIComponent((await props.params).publication)} - -

{record.title}

- {record.description ? ( -

{record.description}

- ) : null} -
- {profile ? ( - <> - - by {profile.displayName || profile.handle} - - - ) : null} - {record.publishedAt ? ( - <> - {" "} - | -

- Published{" "} - {new Date(record.publishedAt).toLocaleDateString( - undefined, - { - year: "numeric", - month: "long", - day: "2-digit", - }, - )} -

- + let pubRecord = document.documents_in_publications[0]?.publications + .record as PubLeafletPublication.Record; + + let hasPageBackground = !!pubRecord.theme?.showPageBackground; + + return ( + + +
+
+
+ + {decodeURIComponent((await props.params).publication)} + +

{record.title}

+ {record.description ? ( +

+ {record.description} +

) : null} - {identity && - identity.atp_did === - document.documents_in_publications[0]?.publications - .identity_did && ( + +
+ {profile ? ( <> - {" "} - | - Edit Post + by {profile.displayName || profile.handle} - )} + ) : null} + {record.publishedAt ? ( + <> + | +

+ {new Date(record.publishedAt).toLocaleDateString( + undefined, + { + year: "numeric", + month: "long", + day: "2-digit", + }, + )} +

+ + ) : null} + {identity && + identity.atp_did === + document.documents_in_publications[0]?.publications + .identity_did && ( + <> + {" "} + | + + Edit Post + + + )} +
+ +
+ {identity && + identity.atp_did === + document.documents_in_publications[0]?.publications + .identity_did ? ( + + Edit Post + + ) : ( + + )}
- -
- {identity && - identity.atp_did === - document.documents_in_publications[0]?.publications.identity_did ? ( - - Edit Post - - ) : ( - - )}
-
- + + ); } diff --git a/app/lish/[did]/[publication]/dashboard/Actions.tsx b/app/lish/[did]/[publication]/dashboard/Actions.tsx index 801b6032..a023f47d 100644 --- a/app/lish/[did]/[publication]/dashboard/Actions.tsx +++ b/app/lish/[did]/[publication]/dashboard/Actions.tsx @@ -15,6 +15,8 @@ import { EditPubForm } from "app/lish/createPub/UpdatePubForm"; import { getPublicationURL } from "app/lish/createPub/getPublicationURL"; import { usePublicationData } from "./PublicationSWRProvider"; import { useSmoker } from "components/Toast"; +import { PaintSmall } from "components/Icons/PaintSmall"; +import { PubThemeSetter } from "components/ThemeManager/PubThemeSetter"; export const Actions = (props: { publication: string }) => { return ( @@ -31,6 +33,7 @@ export const Actions = (props: { publication: string }) => { +
@@ -104,7 +107,7 @@ function PublicationSettingsButton(props: { publication: string }) { return ( ); } + +function PublicationThemeButton() { + return ( + label="Theme" /> + } + > + + + ); +} diff --git a/app/lish/[did]/[publication]/dashboard/DraftList.tsx b/app/lish/[did]/[publication]/dashboard/DraftList.tsx index cb42f65f..e6776f41 100644 --- a/app/lish/[did]/[publication]/dashboard/DraftList.tsx +++ b/app/lish/[did]/[publication]/dashboard/DraftList.tsx @@ -5,17 +5,17 @@ import { NewDraftSecondaryButton } from "./NewDraftButton"; import React, { useState } from "react"; import { usePublicationData } from "./PublicationSWRProvider"; import { Menu, MenuItem } from "components/Layout"; -import { MoreOptionsTiny } from "components/Icons/MoreOptionsTiny"; import { deleteDraft } from "./deleteDraft"; import { DeleteSmall } from "components/Icons/DeleteSmall"; import { PrimaryKey } from "drizzle-orm/sqlite-core"; import { ButtonPrimary } from "components/Buttons"; +import { MoreOptionsVerticalTiny } from "components/Icons/MoreOptionsVerticalTiny"; export function DraftList() { let { data: pub_data } = usePublicationData(); if (!pub_data) return null; return ( -
+
{pub_data.leaflets_in_publications .filter((d) => !d.doc) @@ -53,8 +53,8 @@ function Draft(props: { id: string; title: string; description: string }) { align="end" asChild trigger={ - } > diff --git a/app/lish/[did]/[publication]/dashboard/PublicationDashboard.tsx b/app/lish/[did]/[publication]/dashboard/PublicationDashboard.tsx index fc1807d1..a370791c 100644 --- a/app/lish/[did]/[publication]/dashboard/PublicationDashboard.tsx +++ b/app/lish/[did]/[publication]/dashboard/PublicationDashboard.tsx @@ -1,6 +1,10 @@ "use client"; import { BlobRef } from "@atproto/lexicon"; import { useState } from "react"; +import { useIsMobile } from "src/hooks/isMobile"; +import { theme } from "tailwind.config"; +import { usePublicationData } from "./PublicationSWRProvider"; +import { PubLeafletPublication } from "lexicons/api"; type Tabs = { [tabName: string]: React.ReactNode }; export function PublicationDashboard(props: { @@ -10,46 +14,65 @@ export function PublicationDashboard(props: { icon: BlobRef | null; did: string; }) { + let { data: pub } = usePublicationData(); + let showPageBackground = !!(pub?.record as PubLeafletPublication.Record) + ?.theme?.showPageBackground; let [tab, setTab] = useState(props.defaultTab); let content = props.tabs[tab]; return ( -
-
- {props.icon && ( + <> +
+
- )}{" "} -
- {props.name} + className={`flex gap-2 h-fit py-0.5 pl-1 pr-2 w-fit rounded-md ${showPageBackground ? "bg-[rgba(var(--bg-page),0.8)]" : ""}`} + > + {props.icon && ( +
+ )} +
+ {props.name} +
+
-
+
{Object.keys(props.tabs).map((t) => ( setTab(t)} + showPageBackground={showPageBackground} /> ))}
-
{content}
-
+
+ {content} +
+ ); } -function Tab(props: { name: string; selected: boolean; onSelect: () => void }) { +function Tab(props: { + name: string; + selected: boolean; + showPageBackground: boolean; + onSelect: () => void; +}) { return (
props.onSelect()} > {props.name} diff --git a/app/lish/[did]/[publication]/dashboard/PublicationSubscribers.tsx b/app/lish/[did]/[publication]/dashboard/PublicationSubscribers.tsx index c9f607ee..6c239856 100644 --- a/app/lish/[did]/[publication]/dashboard/PublicationSubscribers.tsx +++ b/app/lish/[did]/[publication]/dashboard/PublicationSubscribers.tsx @@ -2,12 +2,40 @@ import { AppBskyActorProfile } from "lexicons/api"; import { usePublicationData } from "./PublicationSWRProvider"; import { blobRefToSrc } from "src/utils/blobRefToSrc"; +import { ButtonPrimary } from "components/Buttons"; +import { getPublicationURL } from "app/lish/createPub/getPublicationURL"; +import { useSmoker } from "components/Toast"; export function PublicationSubscribers() { let { data: publication } = usePublicationData(); + let smoker = useSmoker(); + if (!publication) return
null
; if (publication.publication_subscriptions.length === 0) - return
No subscribers yet!
; + return ( +
+

No subscribers yet

+

Start sharing your publication!

+ { + e.preventDefault(); + let rect = (e.currentTarget as Element)?.getBoundingClientRect(); + navigator.clipboard.writeText(getPublicationURL(publication!)); + smoker({ + position: { + x: rect ? rect.left + (rect.right - rect.left) / 2 : 0, + y: rect ? rect.top + 26 : 0, + }, + text: "Copied Publication URL!", + }); + }} + > + Copy Share Link + +
+ ); + return (

{publication.publication_subscriptions.length} Subscribers

diff --git a/app/lish/[did]/[publication]/dashboard/PublishedPostsLists.tsx b/app/lish/[did]/[publication]/dashboard/PublishedPostsLists.tsx index 4b40e13a..1362271f 100644 --- a/app/lish/[did]/[publication]/dashboard/PublishedPostsLists.tsx +++ b/app/lish/[did]/[publication]/dashboard/PublishedPostsLists.tsx @@ -9,11 +9,11 @@ import { Fragment, useState } from "react"; import { useParams } from "next/navigation"; import { getPublicationURL } from "app/lish/createPub/getPublicationURL"; import { Menu, MenuItem } from "components/Layout"; -import { MoreOptionsTiny } from "components/Icons/MoreOptionsTiny"; import { deletePost } from "./deletePost"; import { mutate } from "swr"; import { Button } from "react-aria-components"; import { ButtonPrimary } from "components/Buttons"; +import { MoreOptionsVerticalTiny } from "components/Icons/MoreOptionsVerticalTiny"; export function PublishedPostsList() { let { data: publication } = usePublicationData(); @@ -26,7 +26,7 @@ export function PublishedPostsList() {
); return ( -
+
{publication.documents_in_publications .sort((a, b) => { let aRecord = a.documents?.data! as PubLeafletDocument.Record; @@ -49,13 +49,28 @@ export function PublishedPostsList() { return ( -
- -

{record.title}

+
+
+
+ +

+ {record.title} +

+
+
+ {leaflet && ( + + + + )} + +
+
+ {record.description ? (

{record.description} @@ -74,14 +89,6 @@ export function PublishedPostsList() { )}

) : null} - -
- {leaflet && ( - - - - )} -

@@ -98,8 +105,8 @@ let Options = (props: { document_uri: string }) => { align="end" asChild trigger={ - } > diff --git a/app/lish/[did]/[publication]/dashboard/page.tsx b/app/lish/[did]/[publication]/dashboard/page.tsx index bb6533f6..8cd06f37 100644 --- a/app/lish/[did]/[publication]/dashboard/page.tsx +++ b/app/lish/[did]/[publication]/dashboard/page.tsx @@ -8,14 +8,18 @@ import { Footer } from "components/ActionBar/Footer"; import { PublicationDashboard } from "./PublicationDashboard"; import { DraftList } from "./DraftList"; import { getIdentityData } from "actions/getIdentityData"; -import { ThemeProvider } from "components/ThemeManager/ThemeProvider"; import { Actions } from "./Actions"; import React from "react"; import { get_publication_data } from "app/api/rpc/[command]/get_publication_data"; import { PublicationSWRDataProvider } from "./PublicationSWRProvider"; import { PublishedPostsList } from "./PublishedPostsLists"; -import { PubLeafletPublication } from "lexicons/api"; +import { PubLeafletPublication, PubLeafletThemeColor } from "lexicons/api"; import { PublicationSubscribers } from "./PublicationSubscribers"; +import { + PublicationThemeProvider, + PublicationThemeProviderDashboard, +} from "components/ThemeManager/PublicationThemeProvider"; +import { blobRefToSrc } from "src/utils/blobRefToSrc"; export async function generateMetadata(props: { params: Promise<{ publication: string; did: string }>; @@ -61,6 +65,9 @@ export default async function Publication(props: { ); let record = publication?.record as PubLeafletPublication.Record | null; + + let showPageBackground = !!record?.theme?.showPageBackground; + if (!publication || identity.atp_did !== publication.identity_did) return ; @@ -71,21 +78,21 @@ export default async function Publication(props: { publication_name={publication.name} publication_data={publication} > - -
-
+ +
+
-
+
- + ); } catch (e) { diff --git a/app/lish/[did]/[publication]/page.tsx b/app/lish/[did]/[publication]/page.tsx index 9b90f359..96c0e592 100644 --- a/app/lish/[did]/[publication]/page.tsx +++ b/app/lish/[did]/[publication]/page.tsx @@ -4,12 +4,20 @@ import { Metadata } from "next"; import { ThemeProvider } from "components/ThemeManager/ThemeProvider"; import { get_publication_data } from "app/api/rpc/[command]/get_publication_data"; import { AtUri } from "@atproto/syntax"; -import { PubLeafletDocument, PubLeafletPublication } from "lexicons/api"; +import { + PubLeafletDocument, + PubLeafletPublication, + PubLeafletThemeColor, +} from "lexicons/api"; import Link from "next/link"; import { getPublicationURL } from "app/lish/createPub/getPublicationURL"; import { BskyAgent } from "@atproto/api"; import { SubscribeWithBluesky } from "app/lish/Subscribe"; import React from "react"; +import { + PublicationBackgroundProvider, + PublicationThemeProvider, +} from "components/ThemeManager/PublicationThemeProvider"; export async function generateMetadata(props: { params: Promise<{ publication: string; did: string }>; @@ -58,17 +66,29 @@ export default async function Publication(props: { let record = publication?.record as PubLeafletPublication.Record | null; + let showPageBackground = record?.theme?.showPageBackground; + if (!publication) return ; try { return ( - -
-
-
-
+ + +
+
+
{record?.icon && (
)} -

+

{publication.name}

-
-

- {record?.description}{" "} -

- {profile && ( -

- by {profile.displayName}{" "} - - @{profile.handle} - +

+ {record?.description}{" "}

- )} -
- + {profile && ( +

+ by {profile.displayName}{" "} + + @{profile.handle} + +

+ )} +
+ +
+
+
+ {publication.documents_in_publications + .filter((d) => !!d?.documents) + .sort((a, b) => { + let aRecord = a.documents + ?.data! as PubLeafletDocument.Record; + let bRecord = b.documents + ?.data! as PubLeafletDocument.Record; + const aDate = aRecord.publishedAt + ? new Date(aRecord.publishedAt) + : new Date(0); + const bDate = bRecord.publishedAt + ? new Date(bRecord.publishedAt) + : new Date(0); + return bDate.getTime() - aDate.getTime(); // Sort by most recent first + }) + .map((doc) => { + if (!doc.documents) return null; + let uri = new AtUri(doc.documents.uri); + let record = doc.documents + .data as PubLeafletDocument.Record; + return ( + +
+ +

{record.title}

+

+ {record.description} +

+

+ {record.publishedAt && + new Date(record.publishedAt).toLocaleDateString( + undefined, + { + year: "numeric", + month: "long", + day: "2-digit", + }, + )}{" "} +

+ +
+
+
+ ); + })}
-
-
- {publication.documents_in_publications - .filter((d) => !!d?.documents) - .sort((a, b) => { - let aRecord = a.documents?.data! as PubLeafletDocument.Record; - let bRecord = b.documents?.data! as PubLeafletDocument.Record; - const aDate = aRecord.publishedAt - ? new Date(aRecord.publishedAt) - : new Date(0); - const bDate = bRecord.publishedAt - ? new Date(bRecord.publishedAt) - : new Date(0); - return bDate.getTime() - aDate.getTime(); // Sort by most recent first - }) - .map((doc) => { - if (!doc.documents) return null; - let uri = new AtUri(doc.documents.uri); - let record = doc.documents.data as PubLeafletDocument.Record; - return ( - -
- -

{record.title}

-

- {record.description} -

-

- {record.publishedAt && - new Date(record.publishedAt).toLocaleDateString( - undefined, - { - year: "numeric", - month: "long", - day: "2-digit", - }, - )}{" "} -

- -
-
-
- ); - })}
-
- +
+
); } catch (e) { console.log(e); diff --git a/app/lish/[did]/[publication]/subscribeSuccess/page.tsx b/app/lish/[did]/[publication]/subscribeSuccess/page.tsx index 975f8500..b0d572cd 100644 --- a/app/lish/[did]/[publication]/subscribeSuccess/page.tsx +++ b/app/lish/[did]/[publication]/subscribeSuccess/page.tsx @@ -3,7 +3,7 @@ import { RSSSmall } from "components/Icons/RSSSmall"; export default function SubscribeSuccess() { return ( -
+

You've Subscribed!

diff --git a/app/lish/createPub/updatePublication.ts b/app/lish/createPub/updatePublication.ts index b7be9ac6..d83025c7 100644 --- a/app/lish/createPub/updatePublication.ts +++ b/app/lish/createPub/updatePublication.ts @@ -1,12 +1,18 @@ "use server"; import { TID } from "@atproto/common"; -import { AtpBaseClient, PubLeafletPublication } from "lexicons/api"; +import { + AtpBaseClient, + PubLeafletPublication, + PubLeafletThemeColor, +} from "lexicons/api"; import { createOauthClient } from "src/atproto-oauth"; import { getIdentityData } from "actions/getIdentityData"; import { supabaseServerClient } from "supabase/serverClient"; import { Json } from "supabase/database.types"; import { AtUri } from "@atproto/syntax"; import { redirect } from "next/navigation"; +import { $Typed } from "@atproto/api"; +import { ids } from "lexicons/api/lexicons"; export async function updatePublication({ uri, @@ -130,3 +136,100 @@ export async function updatePublicationBasePath({ .single(); return { success: true, publication }; } + +type Color = + | $Typed + | $Typed; +export async function updatePublicationTheme({ + uri, + theme, +}: { + uri: string; + theme: { + backgroundImage?: File | null; + backgroundRepeat?: number | null; + backgroundColor: Color; + primary: Color; + pageBackground: Color; + showPageBackground: boolean; + accentBackground: Color; + accentText: Color; + }; +}) { + const oauthClient = await createOauthClient(); + let identity = await getIdentityData(); + if (!identity || !identity.atp_did) return; + + let credentialSession = await oauthClient.restore(identity.atp_did); + let agent = new AtpBaseClient( + credentialSession.fetchHandler.bind(credentialSession), + ); + let { data: existingPub } = await supabaseServerClient + .from("publications") + .select("*") + .eq("uri", uri) + .single(); + if (!existingPub || existingPub.identity_did !== identity.atp_did) return; + let aturi = new AtUri(existingPub.uri); + + let oldRecord = existingPub.record as PubLeafletPublication.Record; + let record: PubLeafletPublication.Record = { + ...oldRecord, + $type: "pub.leaflet.publication", + theme: { + backgroundImage: theme.backgroundImage + ? { + $type: "pub.leaflet.theme.backgroundImage", + image: ( + await agent.com.atproto.repo.uploadBlob( + new Uint8Array(await theme.backgroundImage.arrayBuffer()), + { encoding: theme.backgroundImage.type }, + ) + )?.data.blob, + width: theme.backgroundRepeat || undefined, + repeat: !!theme.backgroundRepeat, + } + : theme.backgroundImage === null + ? undefined + : oldRecord.theme?.backgroundImage, + backgroundColor: theme.backgroundColor + ? { + ...theme.backgroundColor, + } + : undefined, + primary: { + ...theme.primary, + }, + pageBackground: { + ...theme.pageBackground, + }, + showPageBackground: theme.showPageBackground, + accentBackground: { + ...theme.accentBackground, + }, + accentText: { + ...theme.accentText, + }, + }, + }; + + let result = await agent.com.atproto.repo.putRecord({ + repo: credentialSession.did!, + rkey: aturi.rkey, + record, + collection: record.$type, + validate: false, + }); + + //optimistically write to our db! + let { data: publication, error } = await supabaseServerClient + .from("publications") + .update({ + name: record.name, + record: record as Json, + }) + .eq("uri", uri) + .select() + .single(); + return { success: true, publication }; +} diff --git a/components/ActionBar/Footer.tsx b/components/ActionBar/Footer.tsx index e284c521..67d191ee 100644 --- a/components/ActionBar/Footer.tsx +++ b/components/ActionBar/Footer.tsx @@ -5,7 +5,7 @@ export function Footer(props: { children?: React.ReactNode }) { ) => void; - id: string; - name: string; - value: string; - children: React.ReactNode; - radioEmptyClassName?: string; - radioCheckedClassName?: string; -}) { +type RadioProps = Omit; + +export function Radio( + props: { + onChange: (e: React.ChangeEvent) => void; + children: React.ReactNode; + radioEmptyClassName?: string; + radioCheckedClassName?: string; + } & JSX.IntrinsicElements["input"], +) { return (