a tool for shared writing and social publishing
0
fork

Configure Feed

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

Merge branch 'main' into feature/create-publication

+231 -205
+20 -17
app/[leaflet_id]/Sidebar.tsx
··· 22 22 e.currentTarget === e.target && blurPage(); 23 23 }} 24 24 > 25 - <Media mobile={false}> 26 - <div className="sidebarContainer relative flex flex-col justify-between h-full w-16 bg-bg-pge bg-opacity-50 border-bg-page"> 27 - <Sidebar> 28 - {entity_set.permissions.write ? ( 29 - <> 30 - <ShareOptions /> 31 - <ThemePopover entityID={props.leaflet_id} /> 32 - <HelpPopover /> 33 - <hr className="text-border" /> 34 - <HomeButton /> 35 - </> 36 - ) : ( 37 - <div> 38 - <HomeButton /> 39 - </div> 40 - )} 41 - </Sidebar> 25 + <Media 26 + mobile={false} 27 + className="sidebarContainer relative flex flex-col justify-between h-full w-16 bg-bg-page/50 border-bg-page" 28 + > 29 + <Sidebar> 30 + {entity_set.permissions.write ? ( 31 + <> 32 + <ShareOptions /> 33 + <ThemePopover entityID={props.leaflet_id} /> 34 + <HelpPopover /> 35 + <hr className="text-border" /> 36 + <HomeButton /> 37 + </> 38 + ) : ( 39 + <div> 40 + <HomeButton /> 41 + </div> 42 + )} 43 + </Sidebar> 44 + <div className="justify-end justify-self-end"> 42 45 <Watermark /> 43 46 </div> 44 47 </Media>
+1 -2
app/globals.css
··· 245 245 } 246 246 247 247 .container { 248 - @apply bg-bg-page; 248 + background: rgba(var(--bg-page), 0.5); 249 249 @apply border; 250 250 @apply border-bg-page; 251 - @apply bg-opacity-50; 252 251 @apply rounded-md; 253 252 } 254 253
+4 -1
app/home/AccountSettings.tsx
··· 9 9 // it was going have a popover with a log out button 10 10 export const AccountSettings = () => { 11 11 return ( 12 - <Menu trigger={<ActionButton icon=<AccountSmall /> label="Settings" />}> 12 + <Menu 13 + asChild 14 + trigger={<ActionButton icon=<AccountSmall /> label="Settings" />} 15 + > 13 16 <MenuItem 14 17 onSelect={async () => { 15 18 await logout();
+17 -6
components/ActionBar/ActionButton.tsx
··· 1 - import { useContext } from "react"; 2 - import { SidebarOpenContext } from "./Sidebar"; 1 + "use client"; 2 + import { useContext, useEffect } from "react"; 3 + import { SidebarContext } from "./Sidebar"; 3 4 import React, { forwardRef, type JSX } from "react"; 5 + import { PopoverOpenContext } from "components/Popover"; 4 6 5 7 type ButtonProps = Omit<JSX.IntrinsicElements["button"], "content">; 6 8 ··· 15 17 } 16 18 >((props, ref) => { 17 19 let { id, icon, label, primary, secondary, ...buttonProps } = props; 18 - 19 - let sidebarExpanded = useContext(SidebarOpenContext); 20 + let sidebar = useContext(SidebarContext); 21 + let inOpenPopover = useContext(PopoverOpenContext); 22 + useEffect(() => { 23 + if (inOpenPopover) { 24 + console.log("inOpenPopover"); 25 + sidebar.setChildForceOpen(true); 26 + return () => { 27 + sidebar.setChildForceOpen(false); 28 + }; 29 + } 30 + }, [sidebar, inOpenPopover]); 20 31 return ( 21 32 <button 22 33 {...buttonProps} ··· 26 37 actionButton relative font-bold 27 38 rounded-md border 28 39 flex gap-2 items-center sm:justify-start justify-center 29 - p-1 sm:mr-0 last:mr-0 first:mr-2 40 + p-1 sm:mr-0 last:mr-0 first:mr-2 sm:first:mr-0 30 41 ${ 31 42 props.primary 32 43 ? "w-full bg-accent-1 border-accent-1 text-accent-2 transparent-outline sm:hover:outline-accent-contrast focus:outline-accent-1 outline-offset-1 mr-2" ··· 38 49 > 39 50 <div className="shrink-0">{props.icon}</div> 40 51 <div 41 - className={`pr-1 w-max ${sidebarExpanded ? "block" : props.primary || props.secondary ? "sm:hidden block" : "hidden"}`} 52 + className={`pr-1 w-max ${sidebar.open ? "block" : props.primary || props.secondary ? "sm:hidden block" : "hidden"}`} 42 53 > 43 54 {props.label} 44 55 </div>
+1 -1
components/ActionBar/Footer.tsx
··· 10 10 px-2 pt-1 pwa-padding-bottom 11 11 flex justify-start 12 12 h-[calc(45px+var(--safe-padding-bottom))] 13 - bg-bg-page bg-opacity-50 border-top border-bg-page`} 13 + bg-[rgba(var(--bg-page),0.5)] border-top border-bg-page`} 14 14 > 15 15 {props.children} 16 16 </Media>
+15 -4
components/ActionBar/Sidebar.tsx
··· 1 1 "use client"; 2 + import { uv } from "colorjs.io/fn"; 2 3 import { Media } from "components/Media"; 3 4 import { createContext, useState } from "react"; 4 5 5 - export const SidebarOpenContext = createContext(false); 6 + export const SidebarContext = createContext({ 7 + open: false, 8 + setChildForceOpen: (b: boolean) => {}, 9 + }); 6 10 7 11 export function Sidebar(props: { 8 12 children?: React.ReactNode; ··· 10 14 className?: string; 11 15 }) { 12 16 let [sidebarExpanded, setSidebarExpanded] = useState(false); 17 + let [childForceOpen, setChildForceOpen] = useState(false); 18 + let open = sidebarExpanded || childForceOpen; 13 19 return ( 14 20 <Media mobile={false}> 15 - <SidebarOpenContext value={props.alwaysOpen ? true : sidebarExpanded}> 21 + <SidebarContext 22 + value={{ 23 + open: props.alwaysOpen ? true : open, 24 + setChildForceOpen, 25 + }} 26 + > 16 27 <div 17 28 className={` 18 29 actionSidebar 19 30 ${!props.alwaysOpen && "absolute top-0 left-0 z-10"} 20 31 h-fit w-max p-[6px] 21 32 flex flex-col gap-2 justify-start border 22 - rounded-md bg-bg-page ${sidebarExpanded && !props.alwaysOpen ? "border-border-light" : "bg-opacity-50 border-bg-page"} 33 + rounded-md bg-bg-page ${open && !props.alwaysOpen ? "border-border-light" : "container"} 23 34 ${props.className} 24 35 `} 25 36 onMouseOver={() => { ··· 31 42 > 32 43 {props.children} 33 44 </div> 34 - </SidebarOpenContext> 45 + </SidebarContext> 35 46 </Media> 36 47 ); 37 48 }
+6 -5
components/Blocks/TextBlock/index.tsx
··· 403 403 /> 404 404 )} 405 405 </div> 406 - <BlockifyLink entityID={props.entityID} /> 406 + <BlockifyLink entityID={props.entityID} editorState={editorState} /> 407 407 </> 408 408 ); 409 409 } 410 410 411 - const BlockifyLink = (props: { entityID: string }) => { 411 + const BlockifyLink = (props: { 412 + entityID: string; 413 + editorState: EditorState | undefined; 414 + }) => { 415 + let { editorState } = props; 412 416 let rep = useReplicache(); 413 417 let smoker = useSmoker(); 414 418 let isLocked = useEntity(props.entityID, "block/is-locked"); 415 419 let focused = useUIState((s) => s.focusedEntity?.entityID === props.entityID); 416 - let editorState = useEditorStates( 417 - (s) => s.editorStates[props.entityID], 418 - )?.editor; 419 420 420 421 let isBlueskyPost = 421 422 editorState?.doc.textContent.includes("bsky.app/") &&
+2 -2
components/Input.tsx
··· 68 68 } & JSX.IntrinsicElements["input"] & 69 69 JSX.IntrinsicElements["textarea"], 70 70 ) => { 71 - let { label, ...inputProps } = props; 71 + let { label, textarea, ...inputProps } = props; 72 72 let style = `appearance-none w-full font-normal bg-transparent text-base text-primary focus:outline-0 ${props.className} outline-none resize-none`; 73 73 return ( 74 74 <label className=" input-with-border flex flex-col text-sm text-tertiary font-bold italic leading-tight !py-1 !px-[6px]"> 75 75 {props.label} 76 - {props.textarea ? ( 76 + {textarea ? ( 77 77 <textarea {...inputProps} className={style} /> 78 78 ) : ( 79 79 <Input {...inputProps} className={style} />
+43 -30
components/Popover.tsx
··· 2 2 import { PopoverArrow } from "./Icons"; 3 3 import { theme } from "tailwind.config"; 4 4 import { NestedCardThemeProvider } from "./ThemeManager/ThemeProvider"; 5 + import { createContext, useState } from "react"; 5 6 7 + export const PopoverOpenContext = createContext(false); 6 8 export const Popover = (props: { 7 9 trigger: React.ReactNode; 8 10 disabled?: boolean; ··· 15 17 onOpenChange?: (open: boolean) => void; 16 18 asChild?: boolean; 17 19 }) => { 20 + let [open, setOpen] = useState(props.open || false); 18 21 return ( 19 - <RadixPopover.Root open={props.open} onOpenChange={props.onOpenChange}> 20 - <RadixPopover.Trigger disabled={props.disabled} asChild={props.asChild}> 21 - {props.trigger} 22 - </RadixPopover.Trigger> 23 - <RadixPopover.Portal> 24 - <NestedCardThemeProvider> 25 - <RadixPopover.Content 26 - className={` 22 + <RadixPopover.Root 23 + open={props.open} 24 + onOpenChange={(o) => { 25 + setOpen(o); 26 + props.onOpenChange?.(open); 27 + }} 28 + > 29 + <PopoverOpenContext value={open}> 30 + <RadixPopover.Trigger disabled={props.disabled} asChild={props.asChild}> 31 + {props.trigger} 32 + </RadixPopover.Trigger> 33 + <RadixPopover.Portal> 34 + <NestedCardThemeProvider> 35 + <RadixPopover.Content 36 + className={` 27 37 z-20 bg-bg-page 28 38 px-3 py-2 29 39 max-w-[var(--radix-popover-content-available-width)] ··· 32 42 overflow-y-scroll no-scrollbar 33 43 ${props.className} 34 44 `} 35 - align={props.align ? props.align : "center"} 36 - sideOffset={4} 37 - collisionPadding={16} 38 - > 39 - {props.children} 40 - <RadixPopover.Arrow 41 - asChild 42 - width={16} 43 - height={8} 44 - viewBox="0 0 16 8" 45 + align={props.align ? props.align : "center"} 46 + sideOffset={4} 47 + collisionPadding={16} 45 48 > 46 - <PopoverArrow 47 - arrowFill={ 48 - props.background ? props.background : theme.colors["bg-page"] 49 - } 50 - arrowStroke={ 51 - props.border ? props.border : theme.colors["border"] 52 - } 53 - /> 54 - </RadixPopover.Arrow> 55 - </RadixPopover.Content> 56 - </NestedCardThemeProvider> 57 - </RadixPopover.Portal> 49 + {props.children} 50 + <RadixPopover.Arrow 51 + asChild 52 + width={16} 53 + height={8} 54 + viewBox="0 0 16 8" 55 + > 56 + <PopoverArrow 57 + arrowFill={ 58 + props.background 59 + ? props.background 60 + : theme.colors["bg-page"] 61 + } 62 + arrowStroke={ 63 + props.border ? props.border : theme.colors["border"] 64 + } 65 + /> 66 + </RadixPopover.Arrow> 67 + </RadixPopover.Content> 68 + </NestedCardThemeProvider> 69 + </RadixPopover.Portal> 70 + </PopoverOpenContext> 58 71 </RadixPopover.Root> 59 72 ); 60 73 };
+122 -137
components/ThemeManager/ThemeSetter.tsx
··· 1 1 "use client"; 2 - import * as Popover from "@radix-ui/react-popover"; 2 + import { Popover } from "components/Popover"; 3 3 import * as Slider from "@radix-ui/react-slider"; 4 4 import { theme } from "../../tailwind.config"; 5 5 ··· 118 118 119 119 return ( 120 120 <> 121 - <Popover.Root> 122 - <Popover.Trigger asChild> 123 - <ActionButton icon={<PaintSmall />} label="Theme" /> 124 - </Popover.Trigger> 125 - <Popover.Portal> 126 - <Popover.Content 127 - className="z-20 themeSetterWrapper w-80 h-fit bg-white rounded-md border border-border flex max-w-[var(--radix-popover-content-available-width)] 128 - max-h-[var(--radix-popover-content-available-height)]" 129 - align="center" 130 - sideOffset={4} 131 - collisionPadding={16} 132 - > 133 - <div className="themeSetterContent flex flex-col w-full overflow-y-scroll no-scrollbar"> 134 - <div className="themeBGLeaflet flex"> 135 - <div 136 - className={`bgPicker flex flex-col gap-0 -mb-[6px] z-10 w-full px-2 pt-3`} 137 - > 138 - <div className="bgPickerBody w-full flex flex-col gap-2 p-2 border border-[#CCCCCC] rounded-md"> 139 - <LeafletBGPicker 140 - entityID={props.entityID} 141 - thisPicker={"leaflet"} 142 - openPicker={openPicker} 143 - setOpenPicker={setOpenPicker} 144 - closePicker={() => setOpenPicker("null")} 145 - setValue={set("theme/page-background")} 146 - /> 147 - </div> 148 - 149 - <SectionArrow 150 - fill="white" 151 - stroke="#CCCCCC" 152 - className="ml-2 -mt-[1px]" 153 - /> 154 - </div> 121 + <Popover 122 + className="w-80" 123 + asChild 124 + trigger={<ActionButton icon={<PaintSmall />} label="Theme" />} 125 + > 126 + <div className="themeSetterContent flex flex-col w-full overflow-y-scroll no-scrollbar"> 127 + <div className="themeBGLeaflet flex"> 128 + <div 129 + className={`bgPicker flex flex-col gap-0 -mb-[6px] z-10 w-full px-2 pt-3`} 130 + > 131 + <div className="bgPickerBody w-full flex flex-col gap-2 p-2 border border-[#CCCCCC] rounded-md"> 132 + <LeafletBGPicker 133 + entityID={props.entityID} 134 + thisPicker={"leaflet"} 135 + openPicker={openPicker} 136 + setOpenPicker={setOpenPicker} 137 + closePicker={() => setOpenPicker("null")} 138 + setValue={set("theme/page-background")} 139 + /> 155 140 </div> 156 141 142 + <SectionArrow 143 + fill="white" 144 + stroke="#CCCCCC" 145 + className="ml-2 -mt-[1px]" 146 + /> 147 + </div> 148 + </div> 149 + 150 + <div 151 + onClick={(e) => { 152 + e.currentTarget === e.target && setOpenPicker("leaflet"); 153 + }} 154 + style={{ 155 + backgroundImage: leafletBGImage 156 + ? `url(${leafletBGImage.data.src})` 157 + : undefined, 158 + backgroundRepeat: leafletBGRepeat ? "repeat" : "no-repeat", 159 + backgroundPosition: "center", 160 + backgroundSize: !leafletBGRepeat 161 + ? "cover" 162 + : `calc(${leafletBGRepeat.data.value}px / 2 )`, 163 + }} 164 + className={`bg-bg-leaflet mx-2 p-3 mb-2 flex flex-col rounded-md border border-border pb-0`} 165 + > 166 + <div className={`flex flex-col z-10 mt-4 -mb-[6px] `}> 157 167 <div 158 - onClick={(e) => { 159 - e.currentTarget === e.target && setOpenPicker("leaflet"); 160 - }} 168 + className="themeLeafletControls text-accent-2 flex flex-col gap-2 h-full bg-bg-leaflet p-2 rounded-md border border-accent-2 shadow-[0_0_0_1px_rgb(var(--accent-1))]" 161 169 style={{ 162 - backgroundImage: leafletBGImage 163 - ? `url(${leafletBGImage.data.src})` 164 - : undefined, 165 - backgroundRepeat: leafletBGRepeat ? "repeat" : "no-repeat", 166 - backgroundPosition: "center", 167 - backgroundSize: !leafletBGRepeat 168 - ? "cover" 169 - : `calc(${leafletBGRepeat.data.value}px / 2 )`, 170 + backgroundColor: "rgba(var(--accent-1), 0.6)", 170 171 }} 171 - className={`bg-bg-leaflet mx-2 p-3 mb-2 flex flex-col rounded-md border border-border pb-0`} 172 172 > 173 - <div className={`flex flex-col z-10 mt-4 -mb-[6px] `}> 174 - <div 175 - className="themeLeafletControls text-accent-2 flex flex-col gap-2 h-full bg-bg-leaflet p-2 rounded-md border border-accent-2 shadow-[0_0_0_1px_rgb(var(--accent-1))]" 176 - style={{ 177 - backgroundColor: "rgba(var(--accent-1), 0.6)", 178 - }} 179 - > 180 - <ColorPicker 181 - label="Accent" 182 - value={accent1Value} 183 - setValue={set("theme/accent-background")} 184 - thisPicker={"accent-1"} 185 - openPicker={openPicker} 186 - setOpenPicker={setOpenPicker} 187 - closePicker={() => setOpenPicker("null")} 188 - /> 189 - <ColorPicker 190 - label="Text on Accent" 191 - value={accent2Value} 192 - setValue={set("theme/accent-text")} 193 - thisPicker={"accent-2"} 194 - openPicker={openPicker} 195 - setOpenPicker={setOpenPicker} 196 - closePicker={() => setOpenPicker("null")} 197 - /> 198 - </div> 199 - <SectionArrow 200 - fill={theme.colors["accent-2"]} 201 - stroke={theme.colors["accent-1"]} 202 - className="ml-2" 203 - /> 204 - </div> 173 + <ColorPicker 174 + label="Accent" 175 + value={accent1Value} 176 + setValue={set("theme/accent-background")} 177 + thisPicker={"accent-1"} 178 + openPicker={openPicker} 179 + setOpenPicker={setOpenPicker} 180 + closePicker={() => setOpenPicker("null")} 181 + /> 182 + <ColorPicker 183 + label="Text on Accent" 184 + value={accent2Value} 185 + setValue={set("theme/accent-text")} 186 + thisPicker={"accent-2"} 187 + openPicker={openPicker} 188 + setOpenPicker={setOpenPicker} 189 + closePicker={() => setOpenPicker("null")} 190 + /> 191 + </div> 192 + <SectionArrow 193 + fill={theme.colors["accent-2"]} 194 + stroke={theme.colors["accent-1"]} 195 + className="ml-2" 196 + /> 197 + </div> 205 198 206 - <div 207 - onClick={(e) => { 208 - e.target === e.currentTarget && setOpenPicker("accent-1"); 209 - }} 210 - className="pointer-cursor font-bold relative text-center text-lg py-2 rounded-md bg-accent-1 text-accent-2 shadow-md flex items-center justify-center" 211 - > 212 - <div 213 - className="cursor-pointer w-fit" 214 - onClick={() => { 215 - setOpenPicker("accent-2"); 216 - }} 217 - > 218 - Example Button 219 - </div> 220 - </div> 199 + <div 200 + onClick={(e) => { 201 + e.target === e.currentTarget && setOpenPicker("accent-1"); 202 + }} 203 + className="pointer-cursor font-bold relative text-center text-lg py-2 rounded-md bg-accent-1 text-accent-2 shadow-md flex items-center justify-center" 204 + > 205 + <div 206 + className="cursor-pointer w-fit" 207 + onClick={() => { 208 + setOpenPicker("accent-2"); 209 + }} 210 + > 211 + Example Button 212 + </div> 213 + </div> 221 214 222 - <div className="flex flex-col mt-8 -mb-[6px] z-10"> 223 - <div 224 - className="themeLeafletControls flex flex-col gap-2 h-full text-primary bg-bg-leaflet p-2 rounded-md border border-primary shadow-[0_0_0_1px_rgb(var(--bg-page))]" 225 - style={{ backgroundColor: "rgba(var(--bg-page, 0.6)" }} 226 - > 227 - <ColorPicker 228 - label={props.home ? "Menu" : "Page"} 229 - alpha 230 - value={pageValue} 231 - setValue={set("theme/card-background")} 232 - thisPicker={"page"} 233 - openPicker={openPicker} 234 - setOpenPicker={setOpenPicker} 235 - closePicker={() => setOpenPicker("null")} 236 - /> 237 - <ColorPicker 238 - label={props.home ? "Menu Text" : "Text"} 239 - value={primaryValue} 240 - setValue={set("theme/primary")} 241 - thisPicker={"text"} 242 - openPicker={openPicker} 243 - setOpenPicker={setOpenPicker} 244 - closePicker={() => setOpenPicker("null")} 245 - /> 246 - </div> 247 - <SectionArrow 248 - fill={theme.colors["primary"]} 249 - stroke={theme.colors["bg-page"]} 250 - className=" ml-2" 251 - /> 252 - </div> 253 - 254 - <SamplePage setOpenPicker={setOpenPicker} home={props.home} /> 215 + <div className="flex flex-col mt-8 -mb-[6px] z-10"> 216 + <div 217 + className="themeLeafletControls flex flex-col gap-2 h-full text-primary bg-bg-leaflet p-2 rounded-md border border-primary shadow-[0_0_0_1px_rgb(var(--bg-page))]" 218 + style={{ backgroundColor: "rgba(var(--bg-page, 0.6)" }} 219 + > 220 + <ColorPicker 221 + label={props.home ? "Menu" : "Page"} 222 + alpha 223 + value={pageValue} 224 + setValue={set("theme/card-background")} 225 + thisPicker={"page"} 226 + openPicker={openPicker} 227 + setOpenPicker={setOpenPicker} 228 + closePicker={() => setOpenPicker("null")} 229 + /> 230 + <ColorPicker 231 + label={props.home ? "Menu Text" : "Text"} 232 + value={primaryValue} 233 + setValue={set("theme/primary")} 234 + thisPicker={"text"} 235 + openPicker={openPicker} 236 + setOpenPicker={setOpenPicker} 237 + closePicker={() => setOpenPicker("null")} 238 + /> 255 239 </div> 256 - {!props.home && <WatermarkSetter entityID={props.entityID} />} 257 - </div> 258 - <Popover.Arrow asChild width={16} height={8} viewBox="0 0 16 8"> 259 - <PopoverArrow 260 - arrowFill={theme.colors["white"]} 261 - arrowStroke={theme.colors["border"]} 240 + <SectionArrow 241 + fill={theme.colors["primary"]} 242 + stroke={theme.colors["bg-page"]} 243 + className=" ml-2" 262 244 /> 263 - </Popover.Arrow> 264 - </Popover.Content> 265 - </Popover.Portal> 266 - </Popover.Root> 245 + </div> 246 + 247 + <SamplePage setOpenPicker={setOpenPicker} home={props.home} /> 248 + </div> 249 + {!props.home && <WatermarkSetter entityID={props.entityID} />} 250 + </div> 251 + </Popover> 267 252 </> 268 253 ); 269 254 };