a tool for shared writing and social publishing

Compare changes

Choose any two refs to compare.

+134 -357
-2
actions/publishToPublication.ts
··· 784 784 root_entity, 785 785 "theme/background-image-repeat", 786 786 )?.[0]; 787 - let pageWidth = scan.eav(root_entity, "theme/page-width")?.[0]; 788 787 789 788 let theme: PubLeafletPublication.Theme = { 790 789 showPageBackground: showPageBackground ?? true, 791 790 }; 792 791 793 - if (pageWidth) theme.pageWidth = pageWidth.data.value; 794 792 if (pageBackground) 795 793 theme.backgroundColor = ColorToRGBA(parseColor(`hsba(${pageBackground})`)); 796 794 if (cardBackground)
+2 -2
app/[leaflet_id]/actions/PublishButton.tsx
··· 136 136 content: ( 137 137 <div> 138 138 {pub.doc ? "Updated! " : "Published! "} 139 - <SpeedyLink className="underline" href={docUrl}> 140 - See Published Post 139 + <SpeedyLink className="underline font-bold" href={docUrl}> 140 + See Post 141 141 </SpeedyLink> 142 142 </div> 143 143 ),
+1 -6
app/lish/[did]/[publication]/[rkey]/CanvasPage.tsx
··· 202 202 isSubpage: boolean | undefined; 203 203 data: PostPageData; 204 204 profile: ProfileViewDetailed; 205 - preferences: { 206 - showComments?: boolean; 207 - showMentions?: boolean; 208 - showPrevNext?: boolean; 209 - }; 205 + preferences: { showComments?: boolean }; 210 206 quotesCount: number | undefined; 211 207 commentsCount: number | undefined; 212 208 }) => { ··· 217 213 quotesCount={props.quotesCount || 0} 218 214 commentsCount={props.commentsCount || 0} 219 215 showComments={props.preferences.showComments} 220 - showMentions={props.preferences.showMentions} 221 216 pageId={props.pageId} 222 217 /> 223 218 {!props.isSubpage && (
+1 -4
app/lish/[did]/[publication]/[rkey]/Interactions/Comments/index.tsx
··· 51 51 }, []); 52 52 53 53 return ( 54 - <div 55 - id={"commentsDrawer"} 56 - className="flex flex-col gap-2 relative text-sm text-secondary" 57 - > 54 + <div id={"commentsDrawer"} className="flex flex-col gap-2 relative"> 58 55 <div className="w-full flex justify-between text-secondary font-bold"> 59 56 Comments 60 57 <button
+1 -2
app/lish/[did]/[publication]/[rkey]/Interactions/InteractionDrawer.tsx
··· 9 9 import { decodeQuotePosition } from "../quotePosition"; 10 10 11 11 export const InteractionDrawer = (props: { 12 - showPageBackground: boolean | undefined; 13 12 document_uri: string; 14 13 quotesAndMentions: { uri: string; link?: string }[]; 15 14 comments: Comment[]; ··· 39 38 <div className="snap-center h-full flex z-10 shrink-0 w-[calc(var(--page-width-units)-6px)] sm:w-[calc(var(--page-width-units))]"> 40 39 <div 41 40 id="interaction-drawer" 42 - className={`opaque-container h-full w-full px-3 sm:px-4 pt-2 sm:pt-3 pb-6 overflow-scroll -ml-[1px] ${props.showPageBackground ? "rounded-l-none! rounded-r-lg!" : "rounded-lg! sm:mx-2"}`} 41 + className="opaque-container rounded-l-none! rounded-r-lg! h-full w-full px-3 sm:px-4 pt-2 sm:pt-3 pb-6 overflow-scroll -ml-[1px] " 43 42 > 44 43 {drawer.drawer === "quotes" ? ( 45 44 <Quotes {...props} quotesAndMentions={filteredQuotesAndMentions} />
+44 -68
app/lish/[did]/[publication]/[rkey]/Interactions/Interactions.tsx
··· 108 108 commentsCount: number; 109 109 className?: string; 110 110 showComments?: boolean; 111 - showMentions?: boolean; 112 111 pageId?: string; 113 112 }) => { 114 113 const data = useContext(PostPageContext); ··· 132 131 <div className={`flex gap-2 text-tertiary text-sm ${props.className}`}> 133 132 {tagCount > 0 && <TagPopover tags={tags} tagCount={tagCount} />} 134 133 135 - {props.quotesCount === 0 || props.showMentions === false ? null : ( 134 + {props.quotesCount > 0 && ( 136 135 <button 137 136 className="flex w-fit gap-2 items-center" 138 137 onClick={() => { ··· 169 168 commentsCount: number; 170 169 className?: string; 171 170 showComments?: boolean; 172 - showMentions?: boolean; 173 171 pageId?: string; 174 172 }) => { 175 173 const data = useContext(PostPageContext); ··· 191 189 const tags = (data?.data as any)?.tags as string[] | undefined; 192 190 const tagCount = tags?.length || 0; 193 191 194 - let noInteractions = !props.showComments && !props.showMentions; 195 - 196 192 let subscribed = 197 193 identity?.atp_did && 198 194 publication?.publication_subscriptions && ··· 233 229 <TagList tags={tags} className="mb-3" /> 234 230 </> 235 231 )} 236 - 237 232 <hr className="border-border-light mb-3 " /> 238 - 239 233 <div className="flex gap-2 justify-between"> 240 - {noInteractions ? ( 241 - <div /> 242 - ) : ( 243 - <> 244 - <div className="flex gap-2"> 245 - {props.quotesCount === 0 || 246 - props.showMentions === false ? null : ( 247 - <button 248 - className="flex w-fit gap-2 items-center px-1 py-0.5 border border-border-light rounded-lg trasparent-outline selected-outline" 249 - onClick={() => { 250 - if (!drawerOpen || drawer !== "quotes") 251 - openInteractionDrawer( 252 - "quotes", 253 - document_uri, 254 - props.pageId, 255 - ); 256 - else 257 - setInteractionState(document_uri, { drawerOpen: false }); 258 - }} 259 - onMouseEnter={handleQuotePrefetch} 260 - onTouchStart={handleQuotePrefetch} 261 - aria-label="Post quotes" 262 - > 263 - <QuoteTiny aria-hidden /> {props.quotesCount}{" "} 264 - <span 265 - aria-hidden 266 - >{`Mention${props.quotesCount === 1 ? "" : "s"}`}</span> 267 - </button> 268 - )} 269 - {props.showComments === false ? null : ( 270 - <button 271 - className="flex gap-2 items-center w-fit px-1 py-0.5 border border-border-light rounded-lg trasparent-outline selected-outline" 272 - onClick={() => { 273 - if ( 274 - !drawerOpen || 275 - drawer !== "comments" || 276 - pageId !== props.pageId 277 - ) 278 - openInteractionDrawer( 279 - "comments", 280 - document_uri, 281 - props.pageId, 282 - ); 283 - else 284 - setInteractionState(document_uri, { drawerOpen: false }); 285 - }} 286 - aria-label="Post comments" 287 - > 288 - <CommentTiny aria-hidden />{" "} 289 - {props.commentsCount > 0 ? ( 290 - <span aria-hidden> 291 - {`${props.commentsCount} Comment${props.commentsCount === 1 ? "" : "s"}`} 292 - </span> 293 - ) : ( 294 - "Comment" 295 - )} 296 - </button> 234 + <div className="flex gap-2"> 235 + {props.quotesCount > 0 && ( 236 + <button 237 + className="flex w-fit gap-2 items-center px-1 py-0.5 border border-border-light rounded-lg trasparent-outline selected-outline" 238 + onClick={() => { 239 + if (!drawerOpen || drawer !== "quotes") 240 + openInteractionDrawer("quotes", document_uri, props.pageId); 241 + else setInteractionState(document_uri, { drawerOpen: false }); 242 + }} 243 + onMouseEnter={handleQuotePrefetch} 244 + onTouchStart={handleQuotePrefetch} 245 + aria-label="Post quotes" 246 + > 247 + <QuoteTiny aria-hidden /> {props.quotesCount}{" "} 248 + <span 249 + aria-hidden 250 + >{`Mention${props.quotesCount === 1 ? "" : "s"}`}</span> 251 + </button> 252 + )} 253 + {props.showComments === false ? null : ( 254 + <button 255 + className="flex gap-2 items-center w-fit px-1 py-0.5 border border-border-light rounded-lg trasparent-outline selected-outline" 256 + onClick={() => { 257 + if ( 258 + !drawerOpen || 259 + drawer !== "comments" || 260 + pageId !== props.pageId 261 + ) 262 + openInteractionDrawer("comments", document_uri, props.pageId); 263 + else setInteractionState(document_uri, { drawerOpen: false }); 264 + }} 265 + aria-label="Post comments" 266 + > 267 + <CommentTiny aria-hidden />{" "} 268 + {props.commentsCount > 0 ? ( 269 + <span aria-hidden> 270 + {`${props.commentsCount} Comment${props.commentsCount === 1 ? "" : "s"}`} 271 + </span> 272 + ) : ( 273 + "Comment" 297 274 )} 298 - </div> 299 - </> 300 - )} 301 - 275 + </button> 276 + )} 277 + </div> 302 278 <EditButton document={data} /> 303 279 {subscribed && publication && ( 304 280 <ManageSubscription
+2 -7
app/lish/[did]/[publication]/[rkey]/LinearDocumentPage.tsx
··· 14 14 ExpandedInteractions, 15 15 getCommentCount, 16 16 getQuoteCount, 17 + Interactions, 17 18 } from "./Interactions/Interactions"; 18 19 import { PostContent } from "./PostContent"; 19 20 import { PostHeader } from "./PostHeader/PostHeader"; ··· 24 25 import { decodeQuotePosition } from "./quotePosition"; 25 26 import { PollData } from "./fetchPollData"; 26 27 import { SharedPageProps } from "./PostPages"; 27 - import { PostPrevNextButtons } from "./PostPrevNextButtons"; 28 28 29 29 export function LinearDocumentPage({ 30 30 blocks, ··· 56 56 57 57 const isSubpage = !!pageId; 58 58 59 - console.log("prev/next?: " + preferences.showPrevNext); 60 - 61 59 return ( 62 60 <> 63 61 <PageWrapper ··· 85 83 did={did} 86 84 prerenderedCodeBlocks={prerenderedCodeBlocks} 87 85 /> 88 - <PostPrevNextButtons 89 - showPrevNext={preferences.showPrevNext && !isSubpage} 90 - /> 86 + 91 87 <ExpandedInteractions 92 88 pageId={pageId} 93 89 showComments={preferences.showComments} 94 - showMentions={preferences.showMentions} 95 90 commentsCount={getCommentCount(document, pageId) || 0} 96 91 quotesCount={getQuoteCount(document, pageId) || 0} 97 92 />
+1 -2
app/lish/[did]/[publication]/[rkey]/PostHeader/PostHeader.tsx
··· 23 23 export function PostHeader(props: { 24 24 data: PostPageData; 25 25 profile: ProfileViewDetailed; 26 - preferences: { showComments?: boolean; showMentions?: boolean }; 26 + preferences: { showComments?: boolean }; 27 27 }) { 28 28 let { identity } = useIdentityData(); 29 29 let document = props.data; ··· 91 91 </div> 92 92 <Interactions 93 93 showComments={props.preferences.showComments} 94 - showMentions={props.preferences.showMentions} 95 94 quotesCount={getQuoteCount(document) || 0} 96 95 commentsCount={getCommentCount(document) || 0} 97 96 />
+4 -22
app/lish/[did]/[publication]/[rkey]/PostPages.tsx
··· 147 147 document: PostPageData; 148 148 did: string; 149 149 profile: ProfileViewDetailed; 150 - preferences: { 151 - showComments?: boolean; 152 - showMentions?: boolean; 153 - showPrevNext?: boolean; 154 - }; 150 + preferences: { showComments?: boolean }; 155 151 pubRecord?: PubLeafletPublication.Record; 156 152 theme?: PubLeafletPublication.Theme | null; 157 153 prerenderedCodeBlocks?: Map<string, string>; ··· 210 206 did: string; 211 207 prerenderedCodeBlocks?: Map<string, string>; 212 208 bskyPostData: AppBskyFeedDefs.PostView[]; 213 - preferences: { 214 - showComments?: boolean; 215 - showMentions?: boolean; 216 - showPrevNext?: boolean; 217 - }; 209 + preferences: { showComments?: boolean }; 218 210 pollData: PollData[]; 219 211 }) { 220 212 let drawer = useDrawerOpen(document_uri); ··· 269 261 270 262 {drawer && !drawer.pageId && ( 271 263 <InteractionDrawer 272 - showPageBackground={pubRecord?.theme?.showPageBackground} 273 264 document_uri={document.uri} 274 265 comments={ 275 266 pubRecord?.preferences?.showComments === false 276 267 ? [] 277 268 : document.comments_on_documents 278 269 } 279 - quotesAndMentions={ 280 - pubRecord?.preferences?.showMentions === false 281 - ? [] 282 - : quotesAndMentions 283 - } 270 + quotesAndMentions={quotesAndMentions} 284 271 did={did} 285 272 /> 286 273 )} ··· 360 347 /> 361 348 {drawer && drawer.pageId === page.id && ( 362 349 <InteractionDrawer 363 - showPageBackground={pubRecord?.theme?.showPageBackground} 364 350 pageId={page.id} 365 351 document_uri={document.uri} 366 352 comments={ ··· 368 354 ? [] 369 355 : document.comments_on_documents 370 356 } 371 - quotesAndMentions={ 372 - pubRecord?.preferences?.showMentions === false 373 - ? [] 374 - : quotesAndMentions 375 - } 357 + quotesAndMentions={quotesAndMentions} 376 358 did={did} 377 359 /> 378 360 )}
-58
app/lish/[did]/[publication]/[rkey]/PostPrevNextButtons.tsx
··· 1 - "use client"; 2 - import { PubLeafletDocument } from "lexicons/api"; 3 - import { usePublicationData } from "../dashboard/PublicationSWRProvider"; 4 - import { getPublicationURL } from "app/lish/createPub/getPublicationURL"; 5 - import { AtUri } from "@atproto/api"; 6 - import { useParams } from "next/navigation"; 7 - import { getPostPageData } from "./getPostPageData"; 8 - import { PostPageContext } from "./PostPageContext"; 9 - import { useContext } from "react"; 10 - import { SpeedyLink } from "components/SpeedyLink"; 11 - import { ArrowRightTiny } from "components/Icons/ArrowRightTiny"; 12 - 13 - export const PostPrevNextButtons = (props: { 14 - showPrevNext: boolean | undefined; 15 - }) => { 16 - let postData = useContext(PostPageContext); 17 - let pub = postData?.documents_in_publications[0]?.publications; 18 - 19 - if (!props.showPrevNext || !pub || !postData) return; 20 - 21 - function getPostLink(uri: string) { 22 - return pub && uri 23 - ? `${getPublicationURL(pub)}/${new AtUri(uri).rkey}` 24 - : "leaflet.pub/not-found"; 25 - } 26 - let prevPost = postData?.prevNext?.prev; 27 - let nextPost = postData?.prevNext?.next; 28 - 29 - return ( 30 - <div className="flex flex-col gap-1 w-full px-3 sm:px-4 pb-2 pt-2"> 31 - {/*<hr className="border-border-light" />*/} 32 - <div className="flex justify-between w-full gap-8 "> 33 - {nextPost ? ( 34 - <SpeedyLink 35 - href={getPostLink(nextPost.uri)} 36 - className="flex gap-1 items-center truncate min-w-0 basis-1/2" 37 - > 38 - <ArrowRightTiny className="rotate-180 shrink-0" /> 39 - <div className="min-w-0 truncate">{nextPost.title}</div> 40 - </SpeedyLink> 41 - ) : ( 42 - <div /> 43 - )} 44 - {prevPost ? ( 45 - <SpeedyLink 46 - href={getPostLink(prevPost.uri)} 47 - className="flex gap-1 items-center truncate min-w-0 basis-1/2 justify-end" 48 - > 49 - <div className="min-w-0 truncate">{prevPost.title}</div> 50 - <ArrowRightTiny className="shrink-0" /> 51 - </SpeedyLink> 52 - ) : ( 53 - <div /> 54 - )} 55 - </div> 56 - </div> 57 - ); 58 - };
+2 -3
app/lish/[did]/[publication]/[rkey]/QuoteHandler.tsx
··· 186 186 <BlueskyLinkTiny className="shrink-0" /> 187 187 Bluesky 188 188 </a> 189 - <Separator classname="h-4!" /> 189 + <Separator classname="h-4" /> 190 190 <button 191 191 id="copy-quote-link" 192 192 className="flex gap-1 items-center hover:font-bold px-1" ··· 211 211 </button> 212 212 {pubRecord?.preferences?.showComments !== false && identity?.atp_did && ( 213 213 <> 214 - <Separator classname="h-4! " /> 215 - 214 + <Separator classname="h-4" /> 216 215 <button 217 216 className="flex gap-1 items-center hover:font-bold px-1" 218 217 onClick={() => {
+1 -58
app/lish/[did]/[publication]/[rkey]/getPostPageData.ts
··· 10 10 data, 11 11 uri, 12 12 comments_on_documents(*, bsky_profiles(*)), 13 - documents_in_publications(publications(*, 14 - documents_in_publications(documents(uri, data)), 15 - publication_subscriptions(*)) 16 - ), 13 + documents_in_publications(publications(*, publication_subscriptions(*))), 17 14 document_mentions_in_bsky(*), 18 15 leaflets_in_publications(*) 19 16 `, ··· 54 51 ?.record as PubLeafletPublication.Record 55 52 )?.theme || (document?.data as PubLeafletDocument.Record)?.theme; 56 53 57 - // Calculate prev/next documents from the fetched publication documents 58 - let prevNext: 59 - | { 60 - prev?: { uri: string; title: string }; 61 - next?: { uri: string; title: string }; 62 - } 63 - | undefined; 64 - 65 - const currentPublishedAt = (document.data as PubLeafletDocument.Record) 66 - ?.publishedAt; 67 - const allDocs = 68 - document.documents_in_publications[0]?.publications 69 - ?.documents_in_publications; 70 - 71 - if (currentPublishedAt && allDocs) { 72 - // Filter and sort documents by publishedAt 73 - const sortedDocs = allDocs 74 - .map((dip) => ({ 75 - uri: dip?.documents?.uri, 76 - title: (dip?.documents?.data as PubLeafletDocument.Record).title, 77 - publishedAt: (dip?.documents?.data as PubLeafletDocument.Record) 78 - .publishedAt, 79 - })) 80 - .filter((doc) => doc.publishedAt) // Only include docs with publishedAt 81 - .sort( 82 - (a, b) => 83 - new Date(a.publishedAt!).getTime() - 84 - new Date(b.publishedAt!).getTime(), 85 - ); 86 - 87 - // Find current document index 88 - const currentIndex = sortedDocs.findIndex((doc) => doc.uri === uri); 89 - 90 - if (currentIndex !== -1) { 91 - prevNext = { 92 - prev: 93 - currentIndex > 0 94 - ? { 95 - uri: sortedDocs[currentIndex - 1].uri || "", 96 - title: sortedDocs[currentIndex - 1].title, 97 - } 98 - : undefined, 99 - next: 100 - currentIndex < sortedDocs.length - 1 101 - ? { 102 - uri: sortedDocs[currentIndex + 1].uri || "", 103 - title: sortedDocs[currentIndex + 1].title, 104 - } 105 - : undefined, 106 - }; 107 - } 108 - } 109 - 110 54 return { 111 55 ...document, 112 56 quotesAndMentions, 113 57 theme, 114 - prevNext, 115 58 }; 116 59 } 117 60
-1
app/lish/[did]/[publication]/dashboard/PublishedPostsLists.tsx
··· 140 140 commentsCount={comments} 141 141 tags={tags} 142 142 showComments={pubRecord?.preferences?.showComments} 143 - showMentions={pubRecord?.preferences?.showMentions} 144 143 postUrl={`${getPublicationURL(publication)}/${uri.rkey}`} 145 144 /> 146 145 </div>
+25 -31
app/lish/[did]/[publication]/dashboard/settings/PostOptions.tsx
··· 22 22 ? true 23 23 : record.preferences.showComments, 24 24 ); 25 - let [showMentions, setShowMentions] = useState( 26 - record?.preferences?.showMentions === undefined 27 - ? true 28 - : record.preferences.showMentions, 29 - ); 30 - let [showPrevNext, setShowPrevNext] = useState( 31 - record?.preferences?.showPrevNext === undefined 32 - ? true 33 - : record.preferences.showPrevNext, 34 - ); 25 + let [showMentions, setShowMentions] = useState(true); 26 + let [showPrevNext, setShowPrevNext] = useState(true); 35 27 36 28 let toast = useToaster(); 37 29 return ( 38 30 <form 39 31 onSubmit={async (e) => { 40 - if (!pubData) return; 41 - e.preventDefault(); 42 - props.setLoading(true); 43 - let data = await updatePublication({ 44 - name: record.name, 45 - uri: pubData.uri, 46 - preferences: { 47 - showInDiscover: 48 - record?.preferences?.showInDiscover === undefined 49 - ? true 50 - : record.preferences.showInDiscover, 51 - showComments: showComments, 52 - showMentions: showMentions, 53 - showPrevNext: showPrevNext, 54 - }, 55 - }); 56 - toast({ type: "success", content: <strong>Posts Updated!</strong> }); 57 - console.log(record.preferences?.showPrevNext); 58 - props.setLoading(false); 59 - mutate("publication-data"); 32 + // if (!pubData) return; 33 + // e.preventDefault(); 34 + // props.setLoading(true); 35 + // let data = await updatePublication({ 36 + // uri: pubData.uri, 37 + // name: nameValue, 38 + // description: descriptionValue, 39 + // iconFile: iconFile, 40 + // preferences: { 41 + // showInDiscover: showInDiscover, 42 + // showComments: showComments, 43 + // }, 44 + // }); 45 + // toast({ type: "success", content: "Posts Updated!" }); 46 + // props.setLoading(false); 47 + // mutate("publication-data"); 60 48 }} 61 49 className="text-primary flex flex-col" 62 50 > ··· 69 57 Post Options 70 58 </PubSettingsHeader> 71 59 <h4 className="mb-1">Layout</h4> 60 + {/*<div>Max Post Width</div>*/} 72 61 <Toggle 73 62 toggle={showPrevNext} 74 63 onToggle={() => { 75 64 setShowPrevNext(!showPrevNext); 76 65 }} 77 66 > 78 - <div className="font-bold">Show Prev/Next Buttons</div> 67 + <div className="flex flex-col justify-start"> 68 + <div className="font-bold">Show Prev/Next Buttons</div> 69 + <div className="text-tertiary text-sm leading-tight"> 70 + Show buttons that navigate to the previous and next posts 71 + </div> 72 + </div> 79 73 </Toggle> 80 74 <hr className="my-2 border-border-light" /> 81 75 <h4 className="mb-1">Interactions</h4>
+2 -2
app/lish/[did]/[publication]/dashboard/settings/PublicationSettings.tsx
··· 103 103 Theme and Layout 104 104 <ArrowRightTiny /> 105 105 </button> 106 - <button 106 + {/*<button 107 107 className={menuItemClassName} 108 108 type="button" 109 109 onClick={() => props.setState("post-options")} 110 110 > 111 111 Post Options 112 112 <ArrowRightTiny /> 113 - </button> 113 + </button>*/} 114 114 </div> 115 115 ); 116 116 };
-1
app/lish/[did]/[publication]/page.tsx
··· 172 172 tags={tags} 173 173 postUrl={`${getPublicationURL(publication)}/${uri.rkey}`} 174 174 showComments={record?.preferences?.showComments} 175 - showMentions={record?.preferences?.showMentions} 176 175 /> 177 176 </div> 178 177 </div>
+2 -9
app/lish/createPub/CreatePubForm.tsx
··· 53 53 description: descriptionValue, 54 54 iconFile: logoFile, 55 55 subdomain: domainValue, 56 - preferences: { 57 - showInDiscover, 58 - showComments: true, 59 - showMentions: true, 60 - showPrevNext: false, 61 - }, 56 + preferences: { showInDiscover, showComments: true }, 62 57 }); 63 58 64 59 if (!result.success) { ··· 73 68 setTimeout(() => { 74 69 setFormState("normal"); 75 70 if (result.publication) 76 - router.push( 77 - `${getBasePublicationURL(result.publication)}/dashboard`, 78 - ); 71 + router.push(`${getBasePublicationURL(result.publication)}/dashboard`); 79 72 }, 500); 80 73 }} 81 74 >
+14 -19
app/lish/createPub/UpdatePubForm.tsx
··· 21 21 import { Checkbox } from "components/Checkbox"; 22 22 import type { GetDomainConfigResponseBody } from "@vercel/sdk/esm/models/getdomainconfigop"; 23 23 import { PubSettingsHeader } from "../[did]/[publication]/dashboard/settings/PublicationSettings"; 24 - import { Toggle } from "components/Toggle"; 25 24 26 25 export const EditPubForm = (props: { 27 26 backToMenuAction: () => void; ··· 44 43 ? true 45 44 : record.preferences.showComments, 46 45 ); 47 - let showMentions = 48 - record?.preferences?.showMentions === undefined 49 - ? true 50 - : record.preferences.showMentions; 51 - let showPrevNext = 52 - record?.preferences?.showPrevNext === undefined 53 - ? true 54 - : record.preferences.showPrevNext; 55 - 56 46 let [descriptionValue, setDescriptionValue] = useState( 57 47 record?.description || "", 58 48 ); ··· 84 74 preferences: { 85 75 showInDiscover: showInDiscover, 86 76 showComments: showComments, 87 - showMentions: showMentions, 88 - showPrevNext: showPrevNext, 89 77 }, 90 78 }); 91 79 toast({ type: "success", content: "Updated!" }); ··· 102 90 General Settings 103 91 </PubSettingsHeader> 104 92 <div className="flex flex-col gap-3 w-[1000px] max-w-full pb-2"> 105 - <div className="flex items-center justify-between gap-2 mt-2 "> 93 + <div className="flex items-center justify-between gap-2 "> 106 94 <p className="pl-0.5 pb-0.5 text-tertiary italic text-sm font-bold"> 107 95 Logo <span className="font-normal">(optional)</span> 108 96 </p> ··· 172 160 <CustomDomainForm /> 173 161 <hr className="border-border-light" /> 174 162 175 - <Toggle 176 - toggle={showInDiscover} 177 - onToggle={() => setShowInDiscover(!showInDiscover)} 163 + <Checkbox 164 + checked={showInDiscover} 165 + onChange={(e) => setShowInDiscover(e.target.checked)} 178 166 > 179 - <div className=" pt-0.5 flex flex-col text-sm text-tertiary "> 167 + <div className=" pt-0.5 flex flex-col text-sm italic text-tertiary "> 180 168 <p className="font-bold"> 181 169 Show In{" "} 182 170 <a href="/discover" target="_blank"> ··· 191 179 page. You can change this at any time! 192 180 </p> 193 181 </div> 194 - </Toggle> 182 + </Checkbox> 195 183 196 - 184 + <Checkbox 185 + checked={showComments} 186 + onChange={(e) => setShowComments(e.target.checked)} 187 + > 188 + <div className=" pt-0.5 flex flex-col text-sm italic text-tertiary "> 189 + <p className="font-bold">Show comments on posts</p> 190 + </div> 191 + </Checkbox> 197 192 </div> 198 193 </form> 199 194 );
+2 -2
app/lish/createPub/updatePublication.ts
··· 25 25 }: { 26 26 uri: string; 27 27 name: string; 28 - description?: string; 29 - iconFile?: File | null; 28 + description: string; 29 + iconFile: File | null; 30 30 preferences?: Omit<PubLeafletPublication.Preferences, "$type">; 31 31 }): Promise<UpdatePublicationResult> { 32 32 let identity = await getIdentityData();
+3 -6
components/Canvas.tsx
··· 170 170 171 171 let pubRecord = pub.publications.record as PubLeafletPublication.Record; 172 172 let showComments = pubRecord.preferences?.showComments; 173 - let showMentions = pubRecord.preferences?.showMentions; 174 173 175 174 return ( 176 175 <div className="flex flex-row gap-3 items-center absolute top-6 right-3 sm:top-4 sm:right-4 bg-bg-page border-border-light rounded-md px-2 py-1 h-fit z-20"> ··· 179 178 <CommentTiny className="text-border" /> โ€” 180 179 </div> 181 180 )} 182 - {showComments && ( 183 - <div className="flex gap-1 text-tertiary items-center"> 184 - <QuoteTiny className="text-border" /> โ€” 185 - </div> 186 - )} 181 + <div className="flex gap-1 text-tertiary items-center"> 182 + <QuoteTiny className="text-border" /> โ€” 183 + </div> 187 184 188 185 {!props.isSubpage && ( 189 186 <>
+2 -4
components/InteractionsPreview.tsx
··· 14 14 tags?: string[]; 15 15 postUrl: string; 16 16 showComments: boolean | undefined; 17 - showMentions: boolean | undefined; 18 - 19 17 share?: boolean; 20 18 }) => { 21 19 let smoker = useSmoker(); 22 20 let interactionsAvailable = 23 - (props.quotesCount > 0 && props.showMentions !== false) || 21 + props.quotesCount > 0 || 24 22 (props.showComments !== false && props.commentsCount > 0); 25 23 26 24 const tagsCount = props.tags?.length || 0; ··· 38 36 </> 39 37 )} 40 38 41 - {props.showMentions === false || props.quotesCount === 0 ? null : ( 39 + {props.quotesCount === 0 ? null : ( 42 40 <SpeedyLink 43 41 aria-label="Post quotes" 44 42 href={`${props.postUrl}?interactionDrawer=quotes`}
+3 -5
components/Pages/PublicationMetadata.tsx
··· 121 121 <Separator classname="h-4!" /> 122 122 </> 123 123 )} 124 - {pubRecord?.preferences?.showMentions && ( 125 - <div className="flex gap-1 items-center"> 126 - <QuoteTiny />โ€” 127 - </div> 128 - )} 124 + <div className="flex gap-1 items-center"> 125 + <QuoteTiny />โ€” 126 + </div> 129 127 {pubRecord?.preferences?.showComments && ( 130 128 <div className="flex gap-1 items-center"> 131 129 <CommentTiny />โ€”
-1
components/PostListing.tsx
··· 97 97 commentsCount={comments} 98 98 tags={tags} 99 99 showComments={pubRecord?.preferences?.showComments} 100 - showMentions={pubRecord?.preferences?.showMentions} 101 100 share 102 101 /> 103 102 </div>
+7 -7
components/ThemeManager/PublicationThemeProvider.tsx
··· 2 2 import { useMemo, useState } from "react"; 3 3 import { parseColor } from "react-aria-components"; 4 4 import { useEntity } from "src/replicache"; 5 - import { getColorDifference } from "./themeUtils"; 5 + import { getColorContrast } from "./themeUtils"; 6 6 import { useColorAttribute, colorToString } from "./useColorAttribute"; 7 7 import { BaseThemeProvider, CardBorderHiddenContext } from "./ThemeProvider"; 8 8 import { PubLeafletPublication, PubLeafletThemeColor } from "lexicons/api"; ··· 174 174 let newAccentContrast; 175 175 let sortedAccents = [newTheme.accent1, newTheme.accent2].sort((a, b) => { 176 176 return ( 177 - getColorDifference( 177 + getColorContrast( 178 178 colorToString(b, "rgb"), 179 179 colorToString( 180 180 showPageBackground ? newTheme.bgPage : newTheme.bgLeaflet, 181 181 "rgb", 182 182 ), 183 183 ) - 184 - getColorDifference( 184 + getColorContrast( 185 185 colorToString(a, "rgb"), 186 186 colorToString( 187 187 showPageBackground ? newTheme.bgPage : newTheme.bgLeaflet, ··· 191 191 ); 192 192 }); 193 193 if ( 194 - getColorDifference( 194 + getColorContrast( 195 195 colorToString(sortedAccents[0], "rgb"), 196 196 colorToString(newTheme.primary, "rgb"), 197 - ) < 0.15 && 198 - getColorDifference( 197 + ) < 30 && 198 + getColorContrast( 199 199 colorToString(sortedAccents[1], "rgb"), 200 200 colorToString( 201 201 showPageBackground ? newTheme.bgPage : newTheme.bgLeaflet, 202 202 "rgb", 203 203 ), 204 - ) > 0.08 204 + ) > 12 205 205 ) { 206 206 newAccentContrast = sortedAccents[1]; 207 207 } else newAccentContrast = sortedAccents[0];
+9 -9
components/ThemeManager/ThemeProvider.tsx
··· 22 22 PublicationThemeProvider, 23 23 } from "./PublicationThemeProvider"; 24 24 import { PubLeafletPublication } from "lexicons/api"; 25 - import { getColorDifference } from "./themeUtils"; 25 + import { getColorContrast } from "./themeUtils"; 26 26 27 27 // define a function to set an Aria Color to a CSS Variable in RGB 28 28 function setCSSVariableToColor( ··· 140 140 //sorting the accents by contrast on background 141 141 let sortedAccents = [accent1, accent2].sort((a, b) => { 142 142 return ( 143 - getColorDifference( 143 + getColorContrast( 144 144 colorToString(b, "rgb"), 145 145 colorToString(showPageBackground ? bgPage : bgLeaflet, "rgb"), 146 146 ) - 147 - getColorDifference( 147 + getColorContrast( 148 148 colorToString(a, "rgb"), 149 149 colorToString(showPageBackground ? bgPage : bgLeaflet, "rgb"), 150 150 ) ··· 156 156 // then use the not contrasty option 157 157 158 158 if ( 159 - getColorDifference( 159 + getColorContrast( 160 160 colorToString(sortedAccents[0], "rgb"), 161 161 colorToString(primary, "rgb"), 162 - ) < 0.15 && 163 - getColorDifference( 162 + ) < 30 && 163 + getColorContrast( 164 164 colorToString(sortedAccents[1], "rgb"), 165 165 colorToString(showPageBackground ? bgPage : bgLeaflet, "rgb"), 166 - ) > 0.08 166 + ) > 12 167 167 ) { 168 168 accentContrast = sortedAccents[1]; 169 169 } else accentContrast = sortedAccents[0]; ··· 286 286 bgPage && accent1 && accent2 287 287 ? [accent1, accent2].sort((a, b) => { 288 288 return ( 289 - getColorDifference( 289 + getColorContrast( 290 290 colorToString(b, "rgb"), 291 291 colorToString(bgPage, "rgb"), 292 292 ) - 293 - getColorDifference( 293 + getColorContrast( 294 294 colorToString(a, "rgb"), 295 295 colorToString(bgPage, "rgb"), 296 296 )
+3 -2
components/ThemeManager/ThemeSetter.tsx
··· 1 1 "use client"; 2 2 import { Popover } from "components/Popover"; 3 + import { theme } from "../../tailwind.config"; 3 4 4 5 import { Color } from "react-aria-components"; 5 6 ··· 165 166 setOpenPicker={(pickers) => setOpenPicker(pickers)} 166 167 /> 167 168 <SectionArrow 168 - fill="rgb(var(--accent-2))" 169 - stroke="rgb(var(--accent-1))" 169 + fill={theme.colors["accent-2"]} 170 + stroke={theme.colors["accent-1"]} 170 171 className="ml-2" 171 172 /> 172 173 </div>
+3 -4
components/ThemeManager/themeUtils.ts
··· 1 - import { parse, ColorSpace, sRGB, distance, OKLab } from "colorjs.io/fn"; 1 + import { parse, contrastLstar, ColorSpace, sRGB } from "colorjs.io/fn"; 2 2 3 3 // define the color defaults for everything 4 4 export const ThemeDefaults = { ··· 17 17 }; 18 18 19 19 // used to calculate the contrast between page and accent1, accent2, and determin which is higher contrast 20 - export function getColorDifference(color1: string, color2: string) { 20 + export function getColorContrast(color1: string, color2: string) { 21 21 ColorSpace.register(sRGB); 22 - ColorSpace.register(OKLab); 23 22 24 23 let parsedColor1 = parse(`rgb(${color1})`); 25 24 let parsedColor2 = parse(`rgb(${color2})`); 26 25 27 - return distance(parsedColor1, parsedColor2, "oklab"); 26 + return contrastLstar(parsedColor1, parsedColor2); 28 27 }
-8
lexicons/api/lexicons.ts
··· 1810 1810 type: 'boolean', 1811 1811 default: true, 1812 1812 }, 1813 - showMentions: { 1814 - type: 'boolean', 1815 - default: true, 1816 - }, 1817 - showPrevNext: { 1818 - type: 'boolean', 1819 - default: false, 1820 - }, 1821 1813 }, 1822 1814 }, 1823 1815 theme: {
-2
lexicons/api/types/pub/leaflet/publication.ts
··· 37 37 $type?: 'pub.leaflet.publication#preferences' 38 38 showInDiscover: boolean 39 39 showComments: boolean 40 - showMentions: boolean 41 - showPrevNext: boolean 42 40 } 43 41 44 42 const hashPreferences = 'preferences'
-8
lexicons/pub/leaflet/publication.json
··· 51 51 "showComments": { 52 52 "type": "boolean", 53 53 "default": true 54 - }, 55 - "showMentions": { 56 - "type": "boolean", 57 - "default": true 58 - }, 59 - "showPrevNext": { 60 - "type": "boolean", 61 - "default": false 62 54 } 63 55 } 64 56 },
-2
lexicons/src/publication.ts
··· 27 27 properties: { 28 28 showInDiscover: { type: "boolean", default: true }, 29 29 showComments: { type: "boolean", default: true }, 30 - showMentions: { type: "boolean", default: true }, 31 - showPrevNext: { type: "boolean", default: false }, 32 30 }, 33 31 }, 34 32 theme: {