a tool for shared writing and social publishing

adjusting some issues in popover

+177 -164
+4 -2
app/[leaflet_id]/actions/HelpButton.tsx
··· 19 side={isMobile ? "top" : "right"} 20 align={isMobile ? "center" : "start"} 21 asChild 22 - className="max-w-xs w-full" 23 trigger={<ActionButton icon={<HelpSmall />} label="About" />} 24 > 25 - <div className="flex flex-col text-sm gap-2 text-secondary"> 26 {/* about links */} 27 <HelpLink text="📖 Leaflet Manual" url="https://about.leaflet.pub" /> 28 <HelpLink text="💡 Make with Leaflet" url="https://make.leaflet.pub" />
··· 19 side={isMobile ? "top" : "right"} 20 align={isMobile ? "center" : "start"} 21 asChild 22 + className="max-w-xs w-full p-0!" 23 trigger={<ActionButton icon={<HelpSmall />} label="About" />} 24 > 25 + <div 26 + className={`flex flex-col text-sm gap-2 p-3 text-secondary max-h-[70vh] overflow-y-auto p-2" : ""}`} 27 + > 28 {/* about links */} 29 <HelpLink text="📖 Leaflet Manual" url="https://about.leaflet.pub" /> 30 <HelpLink text="💡 Make with Leaflet" url="https://make.leaflet.pub" />
+8 -7
app/lish/[did]/[publication]/dashboard/settings/PublicationSettings.tsx
··· 27 onOpenChange={() => setState("menu")} 28 side={isMobile ? "top" : "right"} 29 align={isMobile ? "center" : "start"} 30 - className={`max-w-xs w-[1000px] ${state === "theme" && "bg-white!"}`} 31 arrowFill={theme.colors["border-light"]} 32 trigger={ 33 <ActionButton ··· 64 setLoading={setLoading} 65 /> 66 )} 67 </Popover> 68 ); 69 } ··· 93 props.setState("general"); 94 }} 95 > 96 - General Settings 97 <ArrowRightTiny /> 98 </button> 99 <button 100 className={menuItemClassName} 101 type="button" 102 - onClick={() => props.setState("theme")} 103 > 104 - Theme and Layout 105 <ArrowRightTiny /> 106 </button> 107 <button 108 className={menuItemClassName} 109 type="button" 110 - onClick={() => props.setState("post-options")} 111 > 112 - Post Options 113 <ArrowRightTiny /> 114 </button> 115 </div> ··· 124 children: React.ReactNode; 125 }) => { 126 return ( 127 - <div className="flex justify-between font-bold text-secondary bg-border-light -mx-3 -mt-2 px-3 py-2 mb-1"> 128 {props.children} 129 {props.state !== "menu" && ( 130 <div className="flex gap-2">
··· 27 onOpenChange={() => setState("menu")} 28 side={isMobile ? "top" : "right"} 29 align={isMobile ? "center" : "start"} 30 + className={`flex flex-col max-w-xs w-[1000px] ${state === "theme" && "bg-white!"} pb-0!`} 31 arrowFill={theme.colors["border-light"]} 32 trigger={ 33 <ActionButton ··· 64 setLoading={setLoading} 65 /> 66 )} 67 + <div className="spacer h-2 w-full" aria-hidden /> 68 </Popover> 69 ); 70 } ··· 94 props.setState("general"); 95 }} 96 > 97 + Publication Settings 98 <ArrowRightTiny /> 99 </button> 100 <button 101 className={menuItemClassName} 102 type="button" 103 + onClick={() => props.setState("post-options")} 104 > 105 + Post Settings 106 <ArrowRightTiny /> 107 </button> 108 <button 109 className={menuItemClassName} 110 type="button" 111 + onClick={() => props.setState("theme")} 112 > 113 + Theme and Layout 114 <ArrowRightTiny /> 115 </button> 116 </div> ··· 125 children: React.ReactNode; 126 }) => { 127 return ( 128 + <div className="flex justify-between font-bold text-secondary bg-border-light -mx-3 -mt-2 px-3 py-2 mb-1 flex-shrink-0"> 129 {props.children} 130 {props.state !== "menu" && ( 131 <div className="flex gap-2">
+2 -1
app/lish/createPub/UpdatePubForm.tsx
··· 74 75 return ( 76 <form 77 onSubmit={async (e) => { 78 if (!pubData) return; 79 e.preventDefault(); ··· 104 > 105 General Settings 106 </PubSettingsHeader> 107 - <div className="flex flex-col gap-3 w-[1000px] max-w-full pb-2"> 108 <div className="flex items-center justify-between gap-2 mt-2 "> 109 <p className="pl-0.5 pb-0.5 text-tertiary italic text-sm font-bold"> 110 Logo <span className="font-normal">(optional)</span>
··· 74 75 return ( 76 <form 77 + className="min-h-0 flex-1 flex flex-col pb-2" 78 onSubmit={async (e) => { 79 if (!pubData) return; 80 e.preventDefault(); ··· 105 > 106 General Settings 107 </PubSettingsHeader> 108 + <div className="flex flex-col gap-3 w-[1000px] max-w-full pb-2 overflow-y-auto min-h-0"> 109 <div className="flex items-center justify-between gap-2 mt-2 "> 110 <p className="pl-0.5 pb-0.5 text-tertiary italic text-sm font-bold"> 111 Logo <span className="font-normal">(optional)</span>
+1 -1
components/Icons/PopoverArrow.tsx
··· 11 height="8" 12 viewBox="0 0 16 8" 13 fill="none" 14 - className="-mt-px" 15 xmlns="http://www.w3.org/2000/svg" 16 > 17 <path
··· 11 height="8" 12 viewBox="0 0 16 8" 13 fill="none" 14 + className="" 15 xmlns="http://www.w3.org/2000/svg" 16 > 17 <path
-1
components/Popover/index.tsx
··· 47 max-w-(--radix-popover-content-available-width) 48 max-h-(--radix-popover-content-available-height) 49 border border-border rounded-md shadow-md 50 - overflow-y-scroll 51 ${props.className} 52 `} 53 side={props.side}
··· 47 max-w-(--radix-popover-content-available-width) 48 max-h-(--radix-popover-content-available-height) 49 border border-border rounded-md shadow-md 50 ${props.className} 51 `} 52 side={props.side}
+159 -151
components/ThemeManager/PubThemeSetter.tsx
··· 65 let toaster = useToaster(); 66 67 return ( 68 - <BaseThemeProvider local {...localPubTheme} hasBackgroundImage={!!image}> 69 - <form 70 - onSubmit={async (e) => { 71 - e.preventDefault(); 72 - if (!pub) return; 73 - props.setLoading(true); 74 - let result = await updatePublicationTheme({ 75 - uri: pub.uri, 76 - theme: { 77 - pageBackground: ColorToRGBA(localPubTheme.bgPage), 78 - showPageBackground: showPageBackground, 79 - backgroundColor: image 80 - ? ColorToRGBA(localPubTheme.bgLeaflet) 81 - : ColorToRGB(localPubTheme.bgLeaflet), 82 - backgroundRepeat: image?.repeat, 83 - backgroundImage: image ? image.file : null, 84 - pageWidth: pageWidth, 85 - primary: ColorToRGB(localPubTheme.primary), 86 - accentBackground: ColorToRGB(localPubTheme.accent1), 87 - accentText: ColorToRGB(localPubTheme.accent2), 88 - }, 89 - }); 90 91 - if (!result.success) { 92 - props.setLoading(false); 93 - if (result.error && isOAuthSessionError(result.error)) { 94 - toaster({ 95 - content: <OAuthErrorMessage error={result.error} />, 96 - type: "error", 97 - }); 98 - } else { 99 - toaster({ 100 - content: "Failed to update theme", 101 - type: "error", 102 - }); 103 } 104 - return; 105 - } 106 107 - mutate((pub) => { 108 - if (result.publication && pub?.publication) 109 - return { 110 - ...pub, 111 - publication: { ...pub.publication, ...result.publication }, 112 - }; 113 - return pub; 114 - }, false); 115 - props.setLoading(false); 116 - }} 117 - > 118 - <PubSettingsHeader 119 - loading={props.loading} 120 - setLoadingAction={props.setLoading} 121 - backToMenuAction={props.backToMenu} 122 - state={"theme"} 123 > 124 - Theme and Layout 125 - </PubSettingsHeader> 126 - </form> 127 128 - <div className="themeSetterContent flex flex-col w-full overflow-y-scroll -mb-2 mt-2 "> 129 - <PubPageWidthSetter 130 - pageWidth={pageWidth} 131 - setPageWidth={setPageWidth} 132 - thisPicker="page-width" 133 - openPicker={openPicker} 134 - setOpenPicker={setOpenPicker} 135 - /> 136 - <div className="themeBGLeaflet flex flex-col"> 137 <div 138 - className={`themeBgPicker flex flex-col gap-0 -mb-[6px] z-10 w-full `} 139 > 140 - <div className="bgPickerBody w-full flex flex-col gap-2 p-2 mt-1 border border-[#CCCCCC] rounded-md text-[#595959] bg-white"> 141 - <BackgroundPicker 142 - bgImage={image} 143 - setBgImage={setImage} 144 - backgroundColor={localPubTheme.bgLeaflet} 145 pageBackground={localPubTheme.bgPage} 146 setPageBackground={(color) => { 147 setTheme((t) => ({ ...t, bgPage: color })); 148 }} 149 - setBackgroundColor={(color) => { 150 - setTheme((t) => ({ ...t, bgLeaflet: color })); 151 }} 152 openPicker={openPicker} 153 - setOpenPicker={setOpenPicker} 154 - hasPageBackground={!!showPageBackground} 155 - setHasPageBackground={setShowPageBackground} 156 /> 157 </div> 158 - 159 - <SectionArrow 160 - fill="white" 161 - stroke="#CCCCCC" 162 - className="ml-2 -mt-[1px]" 163 - /> 164 </div> 165 - </div> 166 - 167 - <div 168 - style={{ 169 - backgroundImage: pubBGImage ? `url(${pubBGImage})` : undefined, 170 - backgroundRepeat: leafletBGRepeat ? "repeat" : "no-repeat", 171 - backgroundPosition: "center", 172 - backgroundSize: !leafletBGRepeat 173 - ? "cover" 174 - : `calc(${leafletBGRepeat}px / 2 )`, 175 - }} 176 - className={` relative bg-bg-leaflet px-3 py-4 flex flex-col rounded-md border border-border `} 177 - > 178 - <div className={`flex flex-col gap-3 z-10`}> 179 - <PagePickers 180 - pageBackground={localPubTheme.bgPage} 181 - primary={localPubTheme.primary} 182 - setPageBackground={(color) => { 183 - setTheme((t) => ({ ...t, bgPage: color })); 184 - }} 185 - setPrimary={(color) => { 186 - setTheme((t) => ({ ...t, primary: color })); 187 - }} 188 - openPicker={openPicker} 189 - setOpenPicker={(pickers) => setOpenPicker(pickers)} 190 - hasPageBackground={showPageBackground} 191 - /> 192 - <PubAccentPickers 193 - accent1={localPubTheme.accent1} 194 - setAccent1={(color) => { 195 - setTheme((t) => ({ ...t, accent1: color })); 196 - }} 197 - accent2={localPubTheme.accent2} 198 - setAccent2={(color) => { 199 - setTheme((t) => ({ ...t, accent2: color })); 200 - }} 201 - openPicker={openPicker} 202 - setOpenPicker={(pickers) => setOpenPicker(pickers)} 203 - /> 204 </div> 205 - </div> 206 - <div className="flex flex-col mt-4 "> 207 - <div className="flex gap-2 items-center text-sm text-[#8C8C8C]"> 208 - <div className="text-sm">Preview</div> 209 - <Separator classname="h-4!" />{" "} 210 - <button 211 - className={`${sample === "pub" ? "font-bold text-[#595959]" : ""}`} 212 - onClick={() => setSample("pub")} 213 - > 214 - Pub 215 - </button> 216 - <button 217 - className={`${sample === "post" ? "font-bold text-[#595959]" : ""}`} 218 - onClick={() => setSample("post")} 219 - > 220 - Post 221 - </button> 222 - </div> 223 - {sample === "pub" ? ( 224 - <SamplePub 225 - pubBGImage={pubBGImage} 226 - pubBGRepeat={leafletBGRepeat} 227 - showPageBackground={showPageBackground} 228 - /> 229 - ) : ( 230 - <SamplePost 231 - pubBGImage={pubBGImage} 232 - pubBGRepeat={leafletBGRepeat} 233 - showPageBackground={showPageBackground} 234 - /> 235 - )} 236 </div> 237 </div> 238 </BaseThemeProvider>
··· 65 let toaster = useToaster(); 66 67 return ( 68 + <BaseThemeProvider 69 + local 70 + {...localPubTheme} 71 + hasBackgroundImage={!!image} 72 + className="min-h-0!" 73 + > 74 + <div className="min-h-0 flex-1 flex flex-col pb-0.5"> 75 + <form 76 + className="flex-shrink-0" 77 + onSubmit={async (e) => { 78 + e.preventDefault(); 79 + if (!pub) return; 80 + props.setLoading(true); 81 + let result = await updatePublicationTheme({ 82 + uri: pub.uri, 83 + theme: { 84 + pageBackground: ColorToRGBA(localPubTheme.bgPage), 85 + showPageBackground: showPageBackground, 86 + backgroundColor: image 87 + ? ColorToRGBA(localPubTheme.bgLeaflet) 88 + : ColorToRGB(localPubTheme.bgLeaflet), 89 + backgroundRepeat: image?.repeat, 90 + backgroundImage: image ? image.file : null, 91 + pageWidth: pageWidth, 92 + primary: ColorToRGB(localPubTheme.primary), 93 + accentBackground: ColorToRGB(localPubTheme.accent1), 94 + accentText: ColorToRGB(localPubTheme.accent2), 95 + }, 96 + }); 97 98 + if (!result.success) { 99 + props.setLoading(false); 100 + if (result.error && isOAuthSessionError(result.error)) { 101 + toaster({ 102 + content: <OAuthErrorMessage error={result.error} />, 103 + type: "error", 104 + }); 105 + } else { 106 + toaster({ 107 + content: "Failed to update theme", 108 + type: "error", 109 + }); 110 + } 111 + return; 112 } 113 114 + mutate((pub) => { 115 + if (result.publication && pub?.publication) 116 + return { 117 + ...pub, 118 + publication: { ...pub.publication, ...result.publication }, 119 + }; 120 + return pub; 121 + }, false); 122 + props.setLoading(false); 123 + }} 124 > 125 + <PubSettingsHeader 126 + loading={props.loading} 127 + setLoadingAction={props.setLoading} 128 + backToMenuAction={props.backToMenu} 129 + state={"theme"} 130 + > 131 + Theme and Layout 132 + </PubSettingsHeader> 133 + </form> 134 135 + <div className="themeSetterContent flex flex-col w-full overflow-y-scroll min-h-0 -mb-2 pt-2 "> 136 + <PubPageWidthSetter 137 + pageWidth={pageWidth} 138 + setPageWidth={setPageWidth} 139 + thisPicker="page-width" 140 + openPicker={openPicker} 141 + setOpenPicker={setOpenPicker} 142 + /> 143 + <div className="themeBGLeaflet flex flex-col"> 144 + <div 145 + className={`themeBgPicker flex flex-col gap-0 -mb-[6px] z-10 w-full `} 146 + > 147 + <div className="bgPickerBody w-full flex flex-col gap-2 p-2 mt-1 border border-[#CCCCCC] rounded-md text-[#595959] bg-white"> 148 + <BackgroundPicker 149 + bgImage={image} 150 + setBgImage={setImage} 151 + backgroundColor={localPubTheme.bgLeaflet} 152 + pageBackground={localPubTheme.bgPage} 153 + setPageBackground={(color) => { 154 + setTheme((t) => ({ ...t, bgPage: color })); 155 + }} 156 + setBackgroundColor={(color) => { 157 + setTheme((t) => ({ ...t, bgLeaflet: color })); 158 + }} 159 + openPicker={openPicker} 160 + setOpenPicker={setOpenPicker} 161 + hasPageBackground={!!showPageBackground} 162 + setHasPageBackground={setShowPageBackground} 163 + /> 164 + </div> 165 + 166 + <SectionArrow 167 + fill="white" 168 + stroke="#CCCCCC" 169 + className="ml-2 -mt-[1px]" 170 + /> 171 + </div> 172 + </div> 173 + 174 <div 175 + style={{ 176 + backgroundImage: pubBGImage ? `url(${pubBGImage})` : undefined, 177 + backgroundRepeat: leafletBGRepeat ? "repeat" : "no-repeat", 178 + backgroundPosition: "center", 179 + backgroundSize: !leafletBGRepeat 180 + ? "cover" 181 + : `calc(${leafletBGRepeat}px / 2 )`, 182 + }} 183 + className={` relative bg-bg-leaflet px-3 py-4 flex flex-col rounded-md border border-border `} 184 > 185 + <div className={`flex flex-col gap-3 z-10`}> 186 + <PagePickers 187 pageBackground={localPubTheme.bgPage} 188 + primary={localPubTheme.primary} 189 setPageBackground={(color) => { 190 setTheme((t) => ({ ...t, bgPage: color })); 191 }} 192 + setPrimary={(color) => { 193 + setTheme((t) => ({ ...t, primary: color })); 194 }} 195 openPicker={openPicker} 196 + setOpenPicker={(pickers) => setOpenPicker(pickers)} 197 + hasPageBackground={showPageBackground} 198 + /> 199 + <PubAccentPickers 200 + accent1={localPubTheme.accent1} 201 + setAccent1={(color) => { 202 + setTheme((t) => ({ ...t, accent1: color })); 203 + }} 204 + accent2={localPubTheme.accent2} 205 + setAccent2={(color) => { 206 + setTheme((t) => ({ ...t, accent2: color })); 207 + }} 208 + openPicker={openPicker} 209 + setOpenPicker={(pickers) => setOpenPicker(pickers)} 210 /> 211 </div> 212 </div> 213 + <div className="flex flex-col mt-4 "> 214 + <div className="flex gap-2 items-center text-sm text-[#8C8C8C]"> 215 + <div className="text-sm">Preview</div> 216 + <Separator classname="h-4!" />{" "} 217 + <button 218 + className={`${sample === "pub" ? "font-bold text-[#595959]" : ""}`} 219 + onClick={() => setSample("pub")} 220 + > 221 + Pub 222 + </button> 223 + <button 224 + className={`${sample === "post" ? "font-bold text-[#595959]" : ""}`} 225 + onClick={() => setSample("post")} 226 + > 227 + Post 228 + </button> 229 + </div> 230 + {sample === "pub" ? ( 231 + <SamplePub 232 + pubBGImage={pubBGImage} 233 + pubBGRepeat={leafletBGRepeat} 234 + showPageBackground={showPageBackground} 235 + /> 236 + ) : ( 237 + <SamplePost 238 + pubBGImage={pubBGImage} 239 + pubBGRepeat={leafletBGRepeat} 240 + showPageBackground={showPageBackground} 241 + /> 242 + )} 243 </div> 244 </div> 245 </div> 246 </BaseThemeProvider>
+3 -1
components/ThemeManager/ThemeProvider.tsx
··· 122 showPageBackground, 123 pageWidth, 124 hasBackgroundImage, 125 children, 126 }: { 127 local?: boolean; ··· 136 highlight2: AriaColor; 137 highlight3: AriaColor; 138 pageWidth?: number; 139 children: React.ReactNode; 140 }) => { 141 // When showPageBackground is false and there's no background image, ··· 239 ]); 240 return ( 241 <div 242 - className="leafletWrapper w-full text-primary h-full min-h-fit flex flex-col bg-center items-stretch " 243 style={ 244 { 245 "--bg-leaflet": colorToString(bgLeaflet, "rgb"),
··· 122 showPageBackground, 123 pageWidth, 124 hasBackgroundImage, 125 + className, 126 children, 127 }: { 128 local?: boolean; ··· 137 highlight2: AriaColor; 138 highlight3: AriaColor; 139 pageWidth?: number; 140 + className?: string; 141 children: React.ReactNode; 142 }) => { 143 // When showPageBackground is false and there's no background image, ··· 241 ]); 242 return ( 243 <div 244 + className={`leafletWrapper w-full text-primary h-full min-h-fit flex flex-col bg-center items-stretch ${className || ""}`} 245 style={ 246 { 247 "--bg-leaflet": colorToString(bgLeaflet, "rgb"),