a tool for shared writing and social publishing
298
fork

Configure Feed

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

moved home theme into settings, adjusted menu styles

+259 -106
+121 -8
app/(home-pages)/home/Actions/AccountSettings.tsx
··· 1 1 "use client"; 2 2 3 3 import { ActionButton } from "components/ActionBar/ActionButton"; 4 - import { Menu, MenuItem } from "components/Layout"; 5 4 import { mutate } from "swr"; 6 5 import { AccountSmall } from "components/Icons/AccountSmall"; 7 6 import { LogoutSmall } from "components/Icons/LogoutSmall"; 7 + import { Popover } from "components/Popover"; 8 + import { ArrowRightTiny } from "components/Icons/ArrowRightTiny"; 9 + import { SpeedyLink } from "components/SpeedyLink"; 10 + import { GoBackSmall } from "components/Icons/GoBackSmall"; 11 + import { useState } from "react"; 12 + import { ThemeSetterContent } from "components/ThemeManager/ThemeSetter"; 8 13 9 - // it was going have a popover with a log out button 10 - export const AccountSettings = () => { 14 + export const AccountSettings = (props: { entityID: string }) => { 15 + let [state, setState] = useState<"menu" | "general" | "theme">("menu"); 16 + 11 17 return ( 12 - <Menu 18 + <Popover 13 19 asChild 20 + onOpenChange={() => setState("menu")} 21 + side="right" 22 + align="start" 23 + className={`max-w-xs w-[1000px] ${state === "theme" && "bg-white!"}`} 14 24 trigger={<ActionButton icon=<AccountSmall /> label="Settings" />} 15 25 > 16 - <MenuItem 17 - onSelect={async () => { 26 + {state === "general" ? ( 27 + <GeneralSettings backToMenu={() => setState("menu")} /> 28 + ) : state === "theme" ? ( 29 + <AccountThemeSettings 30 + entityID={props.entityID} 31 + backToMenu={() => setState("menu")} 32 + /> 33 + ) : ( 34 + <SettingsMenu state={state} setState={setState} /> 35 + )} 36 + </Popover> 37 + ); 38 + }; 39 + 40 + const SettingsMenu = (props: { 41 + state: "menu" | "general" | "theme"; 42 + setState: (s: typeof props.state) => void; 43 + }) => { 44 + let menuItemClassName = 45 + "menuItem -mx-[8px] text-left flex items-center justify-between"; 46 + 47 + return ( 48 + <div className="flex flex-col gap-0.5"> 49 + <AccountSettingsHeader state={"menu"} /> 50 + <button 51 + className={menuItemClassName} 52 + type="button" 53 + onClick={() => { 54 + props.setState("general"); 55 + }} 56 + > 57 + Settings 58 + <ArrowRightTiny /> 59 + </button> 60 + <button 61 + className={menuItemClassName} 62 + type="button" 63 + onClick={() => props.setState("theme")} 64 + > 65 + Theme 66 + <ArrowRightTiny /> 67 + </button> 68 + <SpeedyLink 69 + className={menuItemClassName} 70 + href="https://about.leaflet.pub/ 71 + " 72 + > 73 + About Leaflet 74 + <ArrowRightTiny /> 75 + </SpeedyLink> 76 + </div> 77 + ); 78 + }; 79 + 80 + const GeneralSettings = (props: { backToMenu: () => void }) => { 81 + return ( 82 + <div className="flex flex-col gap-0.5"> 83 + <AccountSettingsHeader 84 + state={"general"} 85 + backToMenu={() => props.backToMenu()} 86 + /> 87 + 88 + <button 89 + className="flex gap-2 font-bold" 90 + onClick={async () => { 18 91 await fetch("/api/auth/logout"); 19 92 mutate("identity", null); 20 93 }} 21 94 > 22 95 <LogoutSmall /> 23 96 Logout 24 - </MenuItem> 25 - </Menu> 97 + </button> 98 + </div> 99 + ); 100 + }; 101 + const AccountThemeSettings = (props: { 102 + entityID: string; 103 + backToMenu: () => void; 104 + }) => { 105 + return ( 106 + <div className="flex flex-col gap-0.5"> 107 + <AccountSettingsHeader 108 + state={"theme"} 109 + backToMenu={() => props.backToMenu()} 110 + /> 111 + <ThemeSetterContent entityID={props.entityID} home /> 112 + </div> 113 + ); 114 + }; 115 + export const AccountSettingsHeader = (props: { 116 + state: "menu" | "general" | "theme"; 117 + backToMenu?: () => void; 118 + }) => { 119 + return ( 120 + <div className="flex justify-between font-bold text-secondary bg-border-light -mx-3 -mt-2 px-3 pt-2 pb-1 mb-1"> 121 + {props.state === "menu" 122 + ? "Settings" 123 + : props.state === "general" 124 + ? "General" 125 + : props.state === "theme" 126 + ? "Publication Theme" 127 + : ""} 128 + {props.backToMenu && ( 129 + <button 130 + type="button" 131 + onClick={() => { 132 + props.backToMenu && props.backToMenu(); 133 + }} 134 + > 135 + <GoBackSmall className="text-accent-contrast" /> 136 + </button> 137 + )} 138 + </div> 26 139 ); 27 140 };
+5 -3
app/(home-pages)/home/Actions/Actions.tsx
··· 13 13 return ( 14 14 <> 15 15 <CreateNewLeafletButton /> 16 - {identity ? <AccountSettings /> : <LoginActionButton />} 17 - {/*<HelpPopover noShortcuts />*/} 18 - <ThemePopover entityID={rootEntity} home /> 16 + {identity ? ( 17 + <AccountSettings entityID={rootEntity} /> 18 + ) : ( 19 + <LoginActionButton /> 20 + )} 19 21 <HelpPopover /> 20 22 </> 21 23 );
+20
app/globals.css
··· 400 400 @apply rounded-md; 401 401 } 402 402 403 + .menuItem { 404 + @apply text-secondary; 405 + @apply hover:text-secondary; 406 + @apply data-highlighted:bg-[var(--accent-light)]; 407 + @apply data-highlighted:outline-none; 408 + @apply hover:bg-[var(--accent-light)]; 409 + text-align: left; 410 + font-weight: 800; 411 + padding: 0.25rem 0.5rem; 412 + border-radius: 0.25rem; 413 + outline: none !important; 414 + cursor: pointer; 415 + background-color: transparent; 416 + 417 + :hover { 418 + text-decoration: none !important; 419 + background-color: rgb(var(--accent-light)); 420 + } 421 + } 422 + 403 423 .pwa-padding { 404 424 padding-top: max(calc(env(safe-area-inset-top) - 8px)) !important; 405 425 }
+6 -5
app/lish/[did]/[publication]/dashboard/Actions.tsx
··· 100 100 return ( 101 101 <Popover 102 102 asChild 103 + onOpenChange={() => setState("menu")} 103 104 side={isMobile ? "top" : "right"} 104 105 align={isMobile ? "center" : "start"} 105 106 className={`max-w-xs w-[1000px] ${state === "theme" && "bg-white!"}`} ··· 114 115 > 115 116 {state === "general" ? ( 116 117 <EditPubForm 117 - goBack={() => setState("menu")} 118 + backToMenu={() => setState("menu")} 118 119 loading={loading} 119 120 setLoading={setLoading} 120 121 /> 121 122 ) : state === "theme" ? ( 122 123 <PubThemeSetter 123 - goBack={() => setState("menu")} 124 + backToMenu={() => setState("menu")} 124 125 loading={loading} 125 126 setLoading={setLoading} 126 127 /> ··· 143 144 setLoading: (l: boolean) => void; 144 145 }) => { 145 146 let menuItemClassName = 146 - "hover:bg-[var(--accent-light)] text-secondary hover:no-underline! rounded-md px-2 py-0.5 -mx-[8px] font-bold text-left flex items-center justify-between"; 147 + "menuItem -mx-[8px] text-left flex items-center justify-between"; 147 148 148 149 return ( 149 150 <div className="flex flex-col gap-0.5"> ··· 184 185 185 186 export const PubSettingsHeader = (props: { 186 187 state: "menu" | "general" | "theme"; 187 - goBackAction?: () => void; 188 + backToMenu?: () => void; 188 189 loading: boolean; 189 190 setLoadingAction: (l: boolean) => void; 190 191 }) => { ··· 202 203 <button 203 204 type="button" 204 205 onClick={() => { 205 - props.goBackAction && props.goBackAction(); 206 + props.backToMenu && props.backToMenu(); 206 207 }} 207 208 > 208 209 <GoBackSmall className="text-accent-contrast" />
+2 -2
app/lish/createPub/UpdatePubForm.tsx
··· 23 23 import { PubSettingsHeader } from "../[did]/[publication]/dashboard/Actions"; 24 24 25 25 export const EditPubForm = (props: { 26 - goBack: () => void; 26 + backToMenu: () => void; 27 27 loading: boolean; 28 28 setLoading: (l: boolean) => void; 29 29 }) => { ··· 85 85 <PubSettingsHeader 86 86 loading={props.loading} 87 87 setLoadingAction={props.setLoading} 88 - goBackAction={props.goBack} 88 + backToMenu={props.backToMenu} 89 89 state={"theme"} 90 90 /> 91 91 <div className="flex flex-col gap-3 w-[1000px] max-w-full pb-2">
+3 -8
components/Layout.tsx
··· 45 45 alignOffset={props.alignOffset ? props.alignOffset : undefined} 46 46 sideOffset={4} 47 47 collisionPadding={16} 48 - className={`dropdownMenu z-20 bg-bg-page flex flex-col py-1 gap-0.5 border border-border rounded-md shadow-md ${props.className}`} 48 + className={`dropdownMenu z-20 bg-bg-page flex flex-col p-1 gap-0.5 border border-border rounded-md shadow-md ${props.className}`} 49 49 > 50 50 {props.children} 51 51 <DropdownMenu.Arrow ··· 86 86 props.onSelect(event); 87 87 }} 88 88 className={` 89 - MenuItem 90 - font-bold z-10 py-1 px-3 91 - text-left text-secondary 89 + menuItem 90 + z-10 py-1! px-2! 92 91 flex gap-2 93 - data-highlighted:bg-border-light data-highlighted:text-secondary 94 - hover:bg-border-light hover:text-secondary 95 - outline-hidden 96 - cursor-pointer 97 92 ${props.className} 98 93 `} 99 94 >
+2 -2
components/ThemeManager/PubThemeSetter.tsx
··· 25 25 repeat: number | null; 26 26 }; 27 27 export const PubThemeSetter = (props: { 28 - goBack: () => void; 28 + backToMenu: () => void; 29 29 loading: boolean; 30 30 setLoading: (l: boolean) => void; 31 31 }) => { ··· 95 95 <PubSettingsHeader 96 96 loading={props.loading} 97 97 setLoadingAction={props.setLoading} 98 - goBackAction={props.goBack} 98 + backToMenu={props.backToMenu} 99 99 state={"theme"} 100 100 /> 101 101 </form>
+100 -78
components/ThemeManager/ThemeSetter.tsx
··· 82 82 align={isMobile ? "center" : "start"} 83 83 trigger={<ActionButton icon={<PaintSmall />} label="Theme" />} 84 84 > 85 - <div className="themeSetterContent flex flex-col w-full overflow-y-scroll no-scrollbar"> 86 - <div className="themeBGLeaflet flex"> 87 - <div 88 - className={`bgPicker flex flex-col gap-0 -mb-[6px] z-10 w-full `} 89 - > 90 - <div className="bgPickerBody w-full flex flex-col gap-2 p-2 mt-1 border border-[#CCCCCC] rounded-md"> 91 - <LeafletBGPicker 92 - entityID={props.entityID} 93 - thisPicker={"leaflet"} 94 - openPicker={openPicker} 95 - setOpenPicker={setOpenPicker} 96 - closePicker={() => setOpenPicker("null")} 97 - setValue={set("theme/page-background")} 98 - /> 99 - <PageBackgroundPicker 100 - entityID={props.entityID} 101 - setValue={set("theme/card-background")} 102 - openPicker={openPicker} 103 - setOpenPicker={setOpenPicker} 104 - home={props.home} 105 - /> 106 - <hr className=" border-[#CCCCCC]" /> 107 - <PageBorderHider 108 - entityID={props.entityID} 109 - openPicker={openPicker} 110 - setOpenPicker={setOpenPicker} 111 - /> 112 - </div> 85 + <ThemeSetterContent {...props} /> 86 + </Popover> 87 + </> 88 + ); 89 + }; 90 + 91 + export const ThemeSetterContent = (props: { 92 + entityID: string; 93 + home?: boolean; 94 + }) => { 95 + let { rep } = useReplicache(); 96 + let { data: pub } = useLeafletPublicationData(); 97 + 98 + // I need to get these variables from replicache and then write them to the DB. I also need to parse them into a state that can be used here. 99 + let permission = useEntitySetContext().permissions.write; 100 + let leafletBGImage = useEntity(props.entityID, "theme/background-image"); 101 + let leafletBGRepeat = useEntity( 102 + props.entityID, 103 + "theme/background-image-repeat", 104 + ); 113 105 114 - <SectionArrow 115 - fill="white" 116 - stroke="#CCCCCC" 117 - className="ml-2 -mt-px" 118 - /> 119 - </div> 120 - </div> 106 + let [openPicker, setOpenPicker] = useState<pickers>( 107 + props.home === true ? "leaflet" : "null", 108 + ); 109 + let set = useMemo(() => { 110 + return setColorAttribute(rep, props.entityID); 111 + }, [rep, props.entityID]); 121 112 122 - <div 123 - onClick={(e) => { 124 - e.currentTarget === e.target && setOpenPicker("leaflet"); 125 - }} 126 - style={{ 127 - backgroundImage: leafletBGImage 128 - ? `url(${leafletBGImage.data.src})` 129 - : undefined, 130 - backgroundRepeat: leafletBGRepeat ? "repeat" : "no-repeat", 131 - backgroundPosition: "center", 132 - backgroundSize: !leafletBGRepeat 133 - ? "cover" 134 - : `calc(${leafletBGRepeat.data.value}px / 2 )`, 135 - }} 136 - className={`bg-bg-leaflet px-3 pt-4 pb-0 mb-2 flex flex-col gap-4 rounded-md border border-border`} 137 - > 138 - <PageThemePickers 113 + if (!permission) return null; 114 + if (pub) return null; 115 + return ( 116 + <div className="themeSetterContent flex flex-col w-full overflow-y-scroll no-scrollbar"> 117 + <div className="themeBGLeaflet flex"> 118 + <div className={`bgPicker flex flex-col gap-0 -mb-[6px] z-10 w-full `}> 119 + <div className="bgPickerBody w-full flex flex-col gap-2 p-2 mt-1 border border-[#CCCCCC] rounded-md"> 120 + <LeafletBGPicker 139 121 entityID={props.entityID} 122 + thisPicker={"leaflet"} 140 123 openPicker={openPicker} 141 - setOpenPicker={(pickers) => setOpenPicker(pickers)} 124 + setOpenPicker={setOpenPicker} 125 + closePicker={() => setOpenPicker("null")} 126 + setValue={set("theme/page-background")} 142 127 /> 143 - <div className="flex flex-col -gap-[6px]"> 144 - <div className={`flex flex-col z-10 -mb-[6px] `}> 145 - <AccentPickers 146 - entityID={props.entityID} 147 - openPicker={openPicker} 148 - setOpenPicker={(pickers) => setOpenPicker(pickers)} 149 - /> 150 - <SectionArrow 151 - fill={theme.colors["accent-2"]} 152 - stroke={theme.colors["accent-1"]} 153 - className="ml-2" 154 - /> 155 - </div> 128 + <PageBackgroundPicker 129 + entityID={props.entityID} 130 + setValue={set("theme/card-background")} 131 + openPicker={openPicker} 132 + setOpenPicker={setOpenPicker} 133 + home={props.home} 134 + /> 135 + <hr className=" border-[#CCCCCC]" /> 136 + <PageBorderHider 137 + entityID={props.entityID} 138 + openPicker={openPicker} 139 + setOpenPicker={setOpenPicker} 140 + /> 141 + </div> 156 142 157 - <SampleButton 158 - entityID={props.entityID} 159 - setOpenPicker={setOpenPicker} 160 - /> 161 - </div> 143 + <SectionArrow fill="white" stroke="#CCCCCC" className="ml-2 -mt-px" /> 144 + </div> 145 + </div> 162 146 163 - <SamplePage 164 - setOpenPicker={setOpenPicker} 165 - home={props.home} 147 + <div 148 + onClick={(e) => { 149 + e.currentTarget === e.target && setOpenPicker("leaflet"); 150 + }} 151 + style={{ 152 + backgroundImage: leafletBGImage 153 + ? `url(${leafletBGImage.data.src})` 154 + : undefined, 155 + backgroundRepeat: leafletBGRepeat ? "repeat" : "no-repeat", 156 + backgroundPosition: "center", 157 + backgroundSize: !leafletBGRepeat 158 + ? "cover" 159 + : `calc(${leafletBGRepeat.data.value}px / 2 )`, 160 + }} 161 + className={`bg-bg-leaflet px-3 pt-4 pb-0 mb-2 flex flex-col gap-4 rounded-md border border-border`} 162 + > 163 + <PageThemePickers 164 + entityID={props.entityID} 165 + openPicker={openPicker} 166 + setOpenPicker={(pickers) => setOpenPicker(pickers)} 167 + /> 168 + <div className="flex flex-col -gap-[6px]"> 169 + <div className={`flex flex-col z-10 -mb-[6px] `}> 170 + <AccentPickers 166 171 entityID={props.entityID} 172 + openPicker={openPicker} 173 + setOpenPicker={(pickers) => setOpenPicker(pickers)} 174 + /> 175 + <SectionArrow 176 + fill={theme.colors["accent-2"]} 177 + stroke={theme.colors["accent-1"]} 178 + className="ml-2" 167 179 /> 168 180 </div> 169 - {!props.home && <WatermarkSetter entityID={props.entityID} />} 181 + 182 + <SampleButton 183 + entityID={props.entityID} 184 + setOpenPicker={setOpenPicker} 185 + /> 170 186 </div> 171 - </Popover> 172 - </> 187 + 188 + <SamplePage 189 + setOpenPicker={setOpenPicker} 190 + home={props.home} 191 + entityID={props.entityID} 192 + /> 193 + </div> 194 + {!props.home && <WatermarkSetter entityID={props.entityID} />} 195 + </div> 173 196 ); 174 197 }; 175 - 176 198 function WatermarkSetter(props: { entityID: string }) { 177 199 let { rep } = useReplicache(); 178 200 let checked = useEntity(props.entityID, "theme/page-leaflet-watermark");