a tool for shared writing and social publishing
0

Configure Feed

Select the types of activity you want to include in your feed.

making page background works in the theme preview

celine (Apr 6, 2026, 3:04 AM EDT) 817febf9 94c367d4

+281 -273
+102 -119
app/lish/[did]/[publication]/PublicationContent.tsx
··· 5 5 getDocumentURL, 6 6 } from "app/lish/createPub/getPublicationURL"; 7 7 import { SubscribeWithBluesky } from "app/lish/Subscribe"; 8 - import { 9 - PublicationBackgroundProvider, 10 - PublicationThemeProvider, 11 - } from "components/ThemeManager/PublicationThemeProvider"; 12 8 import { InteractionPreview } from "components/InteractionsPreview"; 13 9 import { LocalizedDate } from "./LocalizedDate"; 14 10 import { PublicationHomeLayout } from "./PublicationHomeLayout"; ··· 58 54 headingFontId={record?.theme?.headingFont} 59 55 bodyFontId={record?.theme?.bodyFont} 60 56 /> 61 - <PublicationThemeProvider 62 - theme={record?.theme} 63 - pub_creator={publication.identity_did} 57 + <PublicationHomeLayout 58 + uri={publication.uri} 59 + showPageBackground={!!showPageBackground} 64 60 > 65 - <PublicationBackgroundProvider 66 - theme={record?.theme} 67 - pub_creator={publication.identity_did} 68 - > 69 - <PublicationHomeLayout 70 - uri={publication.uri} 71 - showPageBackground={!!showPageBackground} 72 - > 73 - <PublicationHeader 74 - iconUrl={ 75 - record?.icon 76 - ? `/api/atproto_images?did=${did}&cid=${(record.icon.ref as unknown as { $link: string })["$link"]}` 77 - : undefined 78 - } 79 - publicationName={publication.name} 80 - description={record?.description} 81 - author={ 82 - profile ? ( 83 - <PublicationAuthor 84 - did={profile.did} 85 - displayName={profile.displayName} 86 - handle={profile.handle} 87 - /> 88 - ) : undefined 89 - } 90 - subscribeButton={ 91 - <SubscribeWithBluesky 92 - base_url={getPublicationURL(publication)} 93 - pubName={publication.name} 94 - pub_uri={publication.uri} 95 - subscribers={publication.publication_subscriptions} 96 - /> 97 - } 61 + <PublicationHeader 62 + iconUrl={ 63 + record?.icon 64 + ? `/api/atproto_images?did=${did}&cid=${(record.icon.ref as unknown as { $link: string })["$link"]}` 65 + : undefined 66 + } 67 + publicationName={publication.name} 68 + description={record?.description} 69 + author={ 70 + profile ? ( 71 + <PublicationAuthor 72 + did={profile.did} 73 + displayName={profile.displayName} 74 + handle={profile.handle} 75 + /> 76 + ) : undefined 77 + } 78 + subscribeButton={ 79 + <SubscribeWithBluesky 80 + base_url={getPublicationURL(publication)} 81 + pubName={publication.name} 82 + pub_uri={publication.uri} 83 + subscribers={publication.publication_subscriptions} 98 84 /> 99 - <div className="publicationPostList w-full flex flex-col gap-4"> 100 - {publication.documents_in_publications 101 - .filter((d) => !!d?.documents) 102 - .sort((a, b) => { 103 - const aRecord = normalizeDocumentRecord(a.documents?.data); 104 - const bRecord = normalizeDocumentRecord(b.documents?.data); 105 - const aDate = aRecord?.publishedAt 106 - ? new Date(aRecord.publishedAt) 107 - : new Date(0); 108 - const bDate = bRecord?.publishedAt 109 - ? new Date(bRecord.publishedAt) 110 - : new Date(0); 111 - return bDate.getTime() - aDate.getTime(); // Sort by most recent first 112 - }) 113 - .map((doc) => { 114 - if (!doc.documents) return null; 115 - const doc_record = normalizeDocumentRecord( 116 - doc.documents.data, 117 - ); 118 - if (!doc_record) return null; 119 - let uri = new AtUri(doc.documents.uri); 120 - let quotes = 121 - doc.documents.document_mentions_in_bsky[0].count || 0; 122 - let comments = 123 - record?.preferences?.showComments === false 124 - ? 0 125 - : doc.documents.comments_on_documents[0].count || 0; 126 - let recommends = 127 - doc.documents.recommends_on_documents?.[0]?.count || 0; 128 - let tags = doc_record.tags || []; 85 + } 86 + /> 87 + <div className="publicationPostList w-full flex flex-col gap-4"> 88 + {publication.documents_in_publications 89 + .filter((d) => !!d?.documents) 90 + .sort((a, b) => { 91 + const aRecord = normalizeDocumentRecord(a.documents?.data); 92 + const bRecord = normalizeDocumentRecord(b.documents?.data); 93 + const aDate = aRecord?.publishedAt 94 + ? new Date(aRecord.publishedAt) 95 + : new Date(0); 96 + const bDate = bRecord?.publishedAt 97 + ? new Date(bRecord.publishedAt) 98 + : new Date(0); 99 + return bDate.getTime() - aDate.getTime(); // Sort by most recent first 100 + }) 101 + .map((doc) => { 102 + if (!doc.documents) return null; 103 + const doc_record = normalizeDocumentRecord(doc.documents.data); 104 + if (!doc_record) return null; 105 + let uri = new AtUri(doc.documents.uri); 106 + let quotes = 107 + doc.documents.document_mentions_in_bsky[0].count || 0; 108 + let comments = 109 + record?.preferences?.showComments === false 110 + ? 0 111 + : doc.documents.comments_on_documents[0].count || 0; 112 + let recommends = 113 + doc.documents.recommends_on_documents?.[0]?.count || 0; 114 + let tags = doc_record.tags || []; 129 115 130 - const docUrl = getDocumentURL( 131 - doc_record, 132 - doc.documents.uri, 133 - publication, 134 - ); 135 - return ( 136 - <React.Fragment key={doc.documents?.uri}> 137 - <PublicationPostItem 138 - href={docUrl} 139 - title={doc_record.title} 140 - description={ 141 - doc_record.description || 142 - getFirstParagraph(doc_record) 116 + const docUrl = getDocumentURL( 117 + doc_record, 118 + doc.documents.uri, 119 + publication, 120 + ); 121 + return ( 122 + <React.Fragment key={doc.documents?.uri}> 123 + <PublicationPostItem 124 + href={docUrl} 125 + title={doc_record.title} 126 + description={ 127 + doc_record.description || getFirstParagraph(doc_record) 128 + } 129 + date={ 130 + doc_record.publishedAt ? ( 131 + <LocalizedDate 132 + dateString={doc_record.publishedAt} 133 + options={{ 134 + year: "numeric", 135 + month: "long", 136 + day: "2-digit", 137 + }} 138 + /> 139 + ) : undefined 140 + } 141 + interactions={ 142 + <InteractionPreview 143 + quotesCount={quotes} 144 + commentsCount={comments} 145 + recommendsCount={recommends} 146 + documentUri={doc.documents.uri} 147 + tags={tags} 148 + postUrl={docUrl} 149 + showComments={ 150 + record?.preferences?.showComments !== false 143 151 } 144 - date={ 145 - doc_record.publishedAt ? ( 146 - <LocalizedDate 147 - dateString={doc_record.publishedAt} 148 - options={{ 149 - year: "numeric", 150 - month: "long", 151 - day: "2-digit", 152 - }} 153 - /> 154 - ) : undefined 152 + showMentions={ 153 + record?.preferences?.showMentions !== false 155 154 } 156 - interactions={ 157 - <InteractionPreview 158 - quotesCount={quotes} 159 - commentsCount={comments} 160 - recommendsCount={recommends} 161 - documentUri={doc.documents.uri} 162 - tags={tags} 163 - postUrl={docUrl} 164 - showComments={ 165 - record?.preferences?.showComments !== false 166 - } 167 - showMentions={ 168 - record?.preferences?.showMentions !== false 169 - } 170 - showRecommends={ 171 - record?.preferences?.showRecommends !== false 172 - } 173 - /> 155 + showRecommends={ 156 + record?.preferences?.showRecommends !== false 174 157 } 175 158 /> 176 - </React.Fragment> 177 - ); 178 - })} 179 - </div> 180 - </PublicationHomeLayout> 181 - </PublicationBackgroundProvider> 182 - </PublicationThemeProvider> 159 + } 160 + /> 161 + </React.Fragment> 162 + ); 163 + })} 164 + </div> 165 + </PublicationHomeLayout> 183 166 </> 184 167 ); 185 168 };
+21 -9
app/lish/[did]/[publication]/page.tsx
··· 9 9 import { NotFoundLayout } from "components/PageLayouts/NotFoundLayout"; 10 10 import { normalizePublicationRecord } from "src/utils/normalizeRecords"; 11 11 import { PublicationContent } from "./PublicationContent"; 12 + import { 13 + PublicationThemeProvider, 14 + PublicationBackgroundProvider, 15 + } from "components/ThemeManager/PublicationThemeProvider"; 12 16 13 17 export default async function Publication(props: { 14 18 params: Promise<{ publication: string; did: string }>; ··· 47 51 if (!publication) return <PubNotFound />; 48 52 try { 49 53 return ( 50 - <> 51 - <PublicationContent 52 - record={record} 53 - publication={publication} 54 - did={did} 55 - profile={profile} 56 - showPageBackground={showPageBackground} 57 - /> 58 - </> 54 + <PublicationThemeProvider 55 + theme={record?.theme} 56 + pub_creator={publication.identity_did} 57 + > 58 + <PublicationBackgroundProvider 59 + theme={record?.theme} 60 + pub_creator={publication.identity_did} 61 + > 62 + <PublicationContent 63 + record={record} 64 + publication={publication} 65 + did={did} 66 + profile={profile} 67 + showPageBackground={showPageBackground} 68 + /> 69 + </PublicationBackgroundProvider> 70 + </PublicationThemeProvider> 59 71 ); 60 72 } catch (e) { 61 73 console.log(e);
+1 -1
app/lish/[did]/[publication]/theme-settings/PostPreview.tsx
··· 136 136 ], 137 137 }} 138 138 > 139 - <div className="w-fit pointer-events-none"> 139 + <div className="w-fit pointer-events-none h-full py-2 sm:py-6"> 140 140 <LinearDocumentPage 141 141 document={fakeDocument} 142 142 did={profile.did || FAKE_DID}
+82 -87
app/lish/[did]/[publication]/theme-settings/ThemeSettingsContent.tsx
··· 1 1 "use client"; 2 2 3 3 import { useState } from "react"; 4 - import { BaseThemeProvider } from "components/ThemeManager/ThemeProvider"; 4 + import { 5 + BaseThemeProvider, 6 + CardBorderHiddenContext, 7 + } from "components/ThemeManager/ThemeProvider"; 5 8 import { ButtonPrimary } from "components/Buttons"; 6 9 import { DotLoader } from "components/utils/DotLoader"; 7 10 import { ToggleGroup } from "components/ToggleGroup"; ··· 13 16 } from "components/ThemeManager/PubThemeSetter"; 14 17 import { PubPreview } from "./PubPreview"; 15 18 import { PostPreview } from "./PostPreview"; 19 + import { PublicationBackgroundProvider } from "components/ThemeManager/PublicationThemeProvider"; 20 + import { 21 + usePublicationData, 22 + useNormalizedPublicationRecord, 23 + } from "../dashboard/PublicationSWRProvider"; 16 24 17 25 export function ThemeSettingsContent() { 18 26 let [previewMode, setPreviewMode] = useState<"post" | "pub">("post"); 19 27 let [loading, setLoading] = useState(false); 20 - 28 + let { data } = usePublicationData(); 29 + let { publication } = data || {}; 30 + let record = useNormalizedPublicationRecord(); 21 31 let state = usePubThemeEditorState(); 22 32 let { 23 33 localPubTheme, ··· 33 43 } = state; 34 44 35 45 return ( 36 - <BaseThemeProvider 37 - local 38 - {...localPubTheme} 39 - headingFontId={headingFont} 40 - bodyFontId={bodyFont} 41 - hasBackgroundImage={!!image} 42 - pageWidth={pageWidth} 43 - > 44 - <div className="w-full h-full flex relative overflow-hidden"> 45 - {/* Theme Setter Panel */} 46 - <div className="absolute top-6 left-6 z-20"> 47 - <Popover 48 - align="start" 49 - side="bottom" 50 - className="sm:w-sm w-full rounded-lg! max-h-full overflow-y-auto !p-0 bg-white!" 51 - trigger={ 52 - <button 53 - type="button" 54 - className="w-12 h-12 rounded-full bg-accent-1 text-accent-2 data-[state=open]:bg-accent-2 data-[state=open]:text-accent-1 flex items-center justify-center transition-colors cursor-pointer" 46 + <CardBorderHiddenContext.Provider value={!showPageBackground}> 47 + <BaseThemeProvider 48 + local 49 + {...localPubTheme} 50 + headingFontId={headingFont} 51 + bodyFontId={bodyFont} 52 + hasBackgroundImage={!!image} 53 + pageWidth={pageWidth} 54 + > 55 + <div className="w-full h-screen flex relative overflow-hidden"> 56 + {/* Theme Setter Panel */} 57 + <div className="absolute top-6 left-6 z-20"> 58 + <Popover 59 + align="start" 60 + side="bottom" 61 + className="sm:w-sm w-full rounded-lg! max-h-full overflow-y-auto !p-0 bg-white! " 62 + trigger={ 63 + <button 64 + type="button" 65 + className="w-12 h-12 rounded-full bg-accent-1 text-accent-2 data-[state=open]:bg-accent-2 data-[state=open]:text-accent-1 flex items-center justify-center transition-colors cursor-pointer" 66 + > 67 + <PaintSmall /> 68 + </button> 69 + } 70 + asChild 71 + > 72 + <form 73 + className="flex flex-col" 74 + onSubmit={async (e) => { 75 + e.preventDefault(); 76 + let result = await submitTheme(setLoading); 77 + if (result?.success) { 78 + toaster({ content: "Theme updated!", type: "success" }); 79 + } 80 + }} 55 81 > 56 - <PaintSmall /> 57 - </button> 58 - } 59 - asChild 60 - > 61 - <form 62 - className="flex flex-col" 63 - onSubmit={async (e) => { 64 - e.preventDefault(); 65 - let result = await submitTheme(setLoading); 66 - if (result?.success) { 67 - toaster({ content: "Theme updated!", type: "success" }); 68 - } 69 - }} 70 - > 71 - {/* Toggle + Save Header */} 72 - <div className="flex items-center justify-between px-3 pt-3 pb-2"> 73 - <div className="font-bold text-[#272727]">Preview Mode</div> 74 - <ToggleGroup 75 - value={previewMode} 76 - optionClassName="text-base!" 77 - onChange={setPreviewMode} 78 - options={[ 79 - { value: "post", label: "Post" }, 80 - { value: "pub", label: "Pub" }, 81 - ]} 82 - /> 83 - </div> 82 + {/* Toggle + Save Header */} 83 + <div className="flex items-center justify-between px-3 pt-3 pb-2"> 84 + <div className="font-bold text-[#272727]">Preview Mode</div> 85 + <ToggleGroup 86 + value={previewMode} 87 + optionClassName="text-base!" 88 + onChange={setPreviewMode} 89 + options={[ 90 + { value: "post", label: "Post" }, 91 + { value: "pub", label: "Pub" }, 92 + ]} 93 + /> 94 + </div> 84 95 85 - <div className="px-3 pb-3 gap-2 flex flex-col"> 86 - <PubThemePickerPanel state={state} /> 87 - </div> 88 - <div className="p-3 pt-0!"> 89 - <ButtonPrimary fullWidth type="submit" disabled={loading}> 90 - {loading ? <DotLoader /> : "Update"} 91 - </ButtonPrimary> 92 - </div> 93 - </form> 94 - </Popover> 95 - </div> 96 + <div className="px-3 pb-3 gap-2 flex flex-col"> 97 + <PubThemePickerPanel state={state} /> 98 + </div> 99 + <div className="p-3 pt-0!"> 100 + <ButtonPrimary fullWidth type="submit" disabled={loading}> 101 + {loading ? <DotLoader /> : "Update"} 102 + </ButtonPrimary> 103 + </div> 104 + </form> 105 + </Popover> 106 + </div> 96 107 97 - {/* Full-page Preview */} 98 - <div 99 - className="w-full h-full overflow-y-auto" 100 - style={{ 101 - backgroundImage: pubBGImage ? `url(${pubBGImage})` : undefined, 102 - backgroundRepeat: leafletBGRepeat ? "repeat" : "no-repeat", 103 - backgroundPosition: "center", 104 - backgroundSize: !leafletBGRepeat 105 - ? "cover" 106 - : `calc(${leafletBGRepeat}px / 2)`, 107 - }} 108 - > 109 - <div className="w-full h-full bg-bg-leaflet"> 110 - <div 111 - className="w-full min-h-full" 112 - style={{ 113 - backgroundImage: pubBGImage ? `url(${pubBGImage})` : undefined, 114 - backgroundRepeat: leafletBGRepeat ? "repeat" : "no-repeat", 115 - backgroundPosition: "center", 116 - backgroundSize: !leafletBGRepeat 117 - ? "cover" 118 - : `calc(${leafletBGRepeat}px / 2)`, 119 - }} 120 - > 108 + {/* Full-page Preview */} 109 + <PublicationBackgroundProvider 110 + theme={record?.theme} 111 + pub_creator={publication?.identity_did || ""} 112 + localBgImage={pubBGImage} 113 + localBgImageRepeat={leafletBGRepeat} 114 + > 115 + <div className="mx-auto h-full w-fit"> 121 116 {previewMode === "pub" ? ( 122 117 <PubPreview 123 118 showPageBackground={showPageBackground} ··· 130 125 /> 131 126 )} 132 127 </div> 133 - </div> 128 + </PublicationBackgroundProvider> 134 129 </div> 135 - </div> 136 - </BaseThemeProvider> 130 + </BaseThemeProvider> 131 + </CardBorderHiddenContext.Provider> 137 132 ); 138 133 }
+1 -1
components/Pages/Page.tsx
··· 112 112 // this div wraps the contents AND the page options. 113 113 // it needs to be its own div because this container does NOT scroll, and therefore doesn't clip the absolutely positioned pageOptions 114 114 <div 115 - className={`pageWrapper relative shrink-0 ${props.fullPageScroll ? "w-full" : "w-max"}`} 115 + className={`pageWrapper relative shrink-0 h-full ${props.fullPageScroll ? "w-full" : "w-max"}`} 116 116 > 117 117 {/* 118 118 this div is the scrolling container that wraps only the contents div.
+1 -1
components/ThemeManager/PubPickers/PubBackgroundPickers.tsx
··· 103 103 alpha={props.hasPageBackground ? true : false} 104 104 /> 105 105 )} 106 - <hr className="border-border-light" /> 106 + <hr className="border-[#CCCCCC] my-0.5" /> 107 107 <div className="flex gap-2 items-center"> 108 108 <Toggle 109 109 toggle={props.hasPageBackground}
+2 -2
components/ThemeManager/PubPickers/PubPageWidthSetter.tsx
··· 40 40 let open = props.openPicker == props.thisPicker; 41 41 42 42 return ( 43 - <div className="pageWidthSetter flex flex-col gap-2 px-2 py-[6px] border border-[#CCCCCC] rounded-md bg-white"> 43 + <div className="pageWidthSetter flex flex-col gap-2"> 44 44 <button 45 45 type="button" 46 - className="font-bold text-[#000000] shrink-0 grow-0 w-full flex gap-2 text-left items-center" 46 + className="font-bold text-[#595959] shrink-0 grow-0 w-full flex gap-2 text-left items-center" 47 47 onClick={() => { 48 48 if (!open) { 49 49 props.setOpenPicker(props.thisPicker);
+51 -48
components/ThemeManager/PubThemeSetter.tsx
··· 8 8 import { PubLeafletThemeBackgroundImage } from "lexicons/api"; 9 9 import { AtUri } from "@atproto/syntax"; 10 10 import { useLocalPubTheme } from "./PublicationThemeProvider"; 11 - import { BaseThemeProvider } from "./ThemeProvider"; 11 + import { BaseThemeProvider, CardBorderHiddenContext } from "./ThemeProvider"; 12 12 import { blobRefToSrc } from "src/utils/blobRefToSrc"; 13 13 import { updatePublicationTheme } from "app/lish/createPub/updatePublication"; 14 14 import { PagePickers } from "./PubPickers/PubTextPickers"; ··· 169 169 170 170 return ( 171 171 <div className="themeSetterContent flex flex-col w-full"> 172 - <PubPageWidthSetter 173 - pageWidth={pageWidth} 174 - setPageWidth={setPageWidth} 175 - thisPicker="page-width" 176 - openPicker={openPicker} 177 - setOpenPicker={setOpenPicker} 178 - /> 179 172 <div className="themeBGLeaflet flex flex-col"> 180 173 <div 181 174 className={`themeBgPicker flex flex-col gap-0 -mb-[6px] z-10 w-full `} 182 175 > 183 176 <div className="bgPickerBody w-full flex flex-col gap-2 p-2 mt-1 border border-[#CCCCCC] rounded-md text-[#595959] bg-white"> 177 + <PubPageWidthSetter 178 + pageWidth={pageWidth} 179 + setPageWidth={setPageWidth} 180 + thisPicker="page-width" 181 + openPicker={openPicker} 182 + setOpenPicker={setOpenPicker} 183 + /> 184 + <hr className="border-[#CCCCCC] my-0.5" /> 184 185 <BackgroundPicker 185 186 bgImage={image} 186 187 setBgImage={setImage} ··· 280 281 } = state; 281 282 282 283 return ( 283 - <BaseThemeProvider 284 - local 285 - {...localPubTheme} 286 - headingFontId={headingFont} 287 - bodyFontId={bodyFont} 288 - hasBackgroundImage={!!image} 289 - className="min-h-0!" 290 - > 291 - <div className="min-h-0 flex-1 flex flex-col pb-0.5"> 292 - <form 293 - className="flex-shrink-0" 294 - onSubmit={async (e) => { 295 - e.preventDefault(); 296 - await submitTheme(props.setLoading); 297 - }} 298 - > 299 - <button onClick={props.backToMenu}> 300 - <GoToArrow /> 301 - </button> 302 - </form> 284 + <CardBorderHiddenContext.Provider value={!showPageBackground}> 285 + <BaseThemeProvider 286 + local 287 + {...localPubTheme} 288 + headingFontId={headingFont} 289 + bodyFontId={bodyFont} 290 + hasBackgroundImage={!!image} 291 + className="min-h-0!" 292 + > 293 + <div className="min-h-0 flex-1 flex flex-col pb-0.5"> 294 + <form 295 + className="flex-shrink-0" 296 + onSubmit={async (e) => { 297 + e.preventDefault(); 298 + await submitTheme(props.setLoading); 299 + }} 300 + > 301 + <button onClick={props.backToMenu}> 302 + <GoToArrow /> 303 + </button> 304 + </form> 303 305 304 - <div className="themeSetterContent flex flex-col w-full overflow-y-scroll min-h-0 -mb-2 pt-2 "> 305 - <PubThemePickerPanel state={state} /> 306 - <div className="flex flex-col mt-4 "> 307 - <div className="flex gap-2 items-center text-sm text-[#8C8C8C]"> 308 - <div className="text-sm">Preview</div> 309 - <Separator classname="h-4!" />{" "} 310 - <button 311 - className={`${sample === "pub" ? "font-bold text-[#595959]" : ""}`} 312 - onClick={() => setSample("pub")} 313 - > 314 - Pub 315 - </button> 316 - <button 317 - className={`${sample === "post" ? "font-bold text-[#595959]" : ""}`} 318 - onClick={() => setSample("post")} 319 - > 320 - Post 321 - </button> 306 + <div className="themeSetterContent flex flex-col w-full overflow-y-scroll min-h-0 -mb-2 pt-2 "> 307 + <PubThemePickerPanel state={state} /> 308 + <div className="flex flex-col mt-4 "> 309 + <div className="flex gap-2 items-center text-sm text-[#8C8C8C]"> 310 + <div className="text-sm">Preview</div> 311 + <Separator classname="h-4!" />{" "} 312 + <button 313 + className={`${sample === "pub" ? "font-bold text-[#595959]" : ""}`} 314 + onClick={() => setSample("pub")} 315 + > 316 + Pub 317 + </button> 318 + <button 319 + className={`${sample === "post" ? "font-bold text-[#595959]" : ""}`} 320 + onClick={() => setSample("post")} 321 + > 322 + Post 323 + </button> 324 + </div> 322 325 </div> 323 326 </div> 324 327 </div> 325 - </div> 326 - </BaseThemeProvider> 328 + </BaseThemeProvider> 329 + </CardBorderHiddenContext.Provider> 327 330 ); 328 331 }; 329 332
+20 -5
components/ThemeManager/PublicationThemeProvider.tsx
··· 69 69 pub_creator: string; 70 70 className?: string; 71 71 children: React.ReactNode; 72 + localBgImage?: string | null; 73 + localBgImageRepeat?: number | null; 72 74 }) { 73 - let backgroundImage = props.theme?.backgroundImage?.image?.ref 74 - ? blobRefToSrc(props.theme?.backgroundImage?.image?.ref, props.pub_creator) 75 - : null; 75 + let backgroundImage = 76 + props.localBgImage !== undefined 77 + ? props.localBgImage 78 + : props.theme?.backgroundImage?.image?.ref 79 + ? blobRefToSrc( 80 + props.theme?.backgroundImage?.image?.ref, 81 + props.pub_creator, 82 + ) 83 + : null; 76 84 77 - let backgroundImageRepeat = props.theme?.backgroundImage?.repeat; 78 - let backgroundImageSize = props.theme?.backgroundImage?.width || 500; 85 + let backgroundImageRepeat = 86 + props.localBgImageRepeat !== undefined 87 + ? !!props.localBgImageRepeat 88 + : props.theme?.backgroundImage?.repeat; 89 + let backgroundImageSize = 90 + (props.localBgImageRepeat !== undefined 91 + ? props.localBgImageRepeat 92 + : props.theme?.backgroundImage?.width) || 500; 93 + console.log(backgroundImage); 79 94 return ( 80 95 <div 81 96 className="PubBackgroundWrapper w-full bg-bg-leaflet text-primary h-full flex flex-col bg-cover bg-center bg-no-repeat items-stretch"