a tool for shared writing and social publishing
0

Configure Feed

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

in the theme setter, moved the theme menu to the top of the page, added a back button that drops a warning if there are unsaved changes in the theme

celine (Apr 9, 2026, 3:07 PM EDT) dac182ff 93f6b6de

+79 -20
+1 -1
components/ThemeManager/PublicationThemeProvider.tsx
··· 93 93 94 94 return ( 95 95 <div 96 - className="PubBackgroundWrapper w-full bg-bg-leaflet text-primary h-full flex flex-col bg-cover bg-center bg-no-repeat items-stretch" 96 + className={`PubBackgroundWrapper w-full bg-bg-leaflet text-primary h-full flex flex-col bg-cover bg-center bg-no-repeat items-stretch ${props.className}`} 97 97 style={{ 98 98 backgroundImage: backgroundImage 99 99 ? `url(${backgroundImage})`
+77 -16
app/lish/[did]/[publication]/theme-settings/ThemeSettingsContent.tsx
··· 1 1 "use client"; 2 2 3 3 import { useRef, useState } from "react"; 4 + import { useParams, useRouter } from "next/navigation"; 4 5 import { 5 6 BaseThemeProvider, 6 7 CardBorderHiddenContext, 7 8 } from "components/ThemeManager/ThemeProvider"; 8 - import { ButtonPrimary } from "components/Buttons"; 9 + import { ButtonPrimary, ButtonSecondary } from "components/Buttons"; 9 10 import { DotLoader } from "components/utils/DotLoader"; 10 11 import { ToggleGroup } from "components/ToggleGroup"; 11 12 import { PaintSmall } from "components/Icons/PaintSmall"; ··· 22 23 useNormalizedPublicationRecord, 23 24 } from "../dashboard/PublicationSWRProvider"; 24 25 import { Separator } from "components/Layout"; 26 + import { GoToArrow } from "components/Icons/GoToArrow"; 25 27 26 28 export function ThemeSettingsContent() { 27 29 let toolbarRef = useRef<HTMLDivElement>(null); 28 30 let [previewMode, setPreviewMode] = useState<"post" | "pub">("post"); 31 + let params = useParams<{ did: string; publication: string }>(); 29 32 let { data } = usePublicationData(); 30 33 let { publication } = data || {}; 31 34 let record = useNormalizedPublicationRecord(); ··· 39 42 pubBGImage, 40 43 leafletBGRepeat, 41 44 showPageBackground, 45 + changes, 42 46 } = state; 47 + let router = useRouter(); 48 + let [showLeaveWarning, setShowLeaveWarning] = useState(false); 49 + let settingsHref = `/lish/${params.did}/${params.publication}/dashboard?tab=Settings`; 50 + 51 + let hasUnsavedChanges = 52 + changes || 53 + headingFont !== record?.theme?.headingFont || 54 + bodyFont !== record?.theme?.bodyFont || 55 + pageWidth !== (record?.theme?.pageWidth || 624) || 56 + showPageBackground !== !!record?.theme?.showPageBackground; 43 57 44 58 return ( 45 59 <CardBorderHiddenContext.Provider value={!showPageBackground}> ··· 51 65 hasBackgroundImage={!!image} 52 66 pageWidth={pageWidth} 53 67 > 54 - <div className="w-full h-screen flex relative overflow-hidden"> 68 + <div className="w-full h-screen flex flex-col overflow-hidden"> 55 69 {/* Theme Setter Panel */} 56 70 <div 57 71 ref={toolbarRef} 58 - className="absolute sm:top-6 sm:left-6 top-4 right-4 z-20 flex gap-1 bg-accent-1 w-fit p-1 pl-2 rounded-md items-center" 72 + className=" bg-accent-1 items-center -mb-2 pb-[10px] pt-2 " 59 73 > 60 - <PubThemePopover state={state} toolbarRef={toolbarRef} /> 61 - <Separator classname="h-8! ml-1" /> 62 - <ToggleGroup 63 - value={previewMode} 64 - optionClassName="text-base! py-1! px-2!" 65 - onChange={setPreviewMode} 66 - options={[ 67 - { value: "post", label: "Post" }, 68 - { value: "pub", label: "Pub" }, 69 - ]} 70 - /> 74 + <div className=" sm:w-[var(--page-width-units)] mx-auto flex justify-between items-center px-3 sm:px-4 "> 75 + <Popover 76 + align="start" 77 + side="bottom" 78 + open={showLeaveWarning} 79 + onOpenChange={setShowLeaveWarning} 80 + className="w-76 flex flex-col p-3" 81 + trigger={ 82 + <button 83 + type="button" 84 + className="cursor-pointer" 85 + onClick={() => { 86 + if (hasUnsavedChanges) { 87 + setShowLeaveWarning(true); 88 + } else { 89 + router.push(settingsHref); 90 + } 91 + }} 92 + > 93 + <GoToArrow className="rotate-180 text-accent-2" /> 94 + </button> 95 + } 96 + > 97 + <h4 className=" text-primary">Discard unsaved changes?</h4> 98 + <p className="text-sm texttext-tertiary"> 99 + You have unsaved changes to your theme. Leaving the page will 100 + lose your edits! 101 + </p> 102 + <div className="flex gap-4 w-full pt-3"> 103 + <ButtonPrimary 104 + className="shrink-0" 105 + onClick={() => router.push(settingsHref)} 106 + > 107 + Discard and Leave 108 + </ButtonPrimary> 109 + <button 110 + className="font-bold text-accent-contrast grow" 111 + onClick={() => setShowLeaveWarning(false)} 112 + > 113 + Nevermind 114 + </button> 115 + </div> 116 + </Popover> 117 + <div className="flex gap-1 items-center "> 118 + <ToggleGroup 119 + value={previewMode} 120 + optionClassName="text-base! py-1! px-2!" 121 + onChange={setPreviewMode} 122 + options={[ 123 + { value: "post", label: "Post" }, 124 + { value: "pub", label: "Pub" }, 125 + ]} 126 + /> 127 + <Separator classname="h-8! mr-1" /> 128 + <PubThemePopover state={state} toolbarRef={toolbarRef} /> 129 + </div> 130 + </div> 71 131 </div> 72 132 73 133 {/* Full-page Preview */} 74 134 <PublicationBackgroundProvider 135 + className="rounded-t-lg" 75 136 theme={record?.theme} 76 137 pub_creator={publication?.identity_did || ""} 77 138 localBgImage={pubBGImage} ··· 162 223 let result = await submitTheme(setLoading); 163 224 if (result?.success) { 164 225 toaster({ 165 - content: "Theme updated!", 226 + content: "Theme saved!", 166 227 type: "success", 167 228 }); 168 229 } 169 230 }} 170 231 > 171 - {loading ? <DotLoader /> : "Update"} 232 + {loading ? <DotLoader /> : "Save Changes"} 172 233 </ButtonPrimary> 173 234 </div> 174 235
+1 -3
app/lish/[did]/[publication]/theme-settings/page.tsx
··· 46 46 publication_rkey={uri.rkey} 47 47 publication_data={publication_data} 48 48 > 49 - <PublicationThemeProviderDashboard> 50 - <ThemeSettingsContent /> 51 - </PublicationThemeProviderDashboard> 49 + <ThemeSettingsContent /> 52 50 </PublicationSWRDataProvider> 53 51 ); 54 52 } catch (e) {