a tool for shared writing and social publishing

started up on the publish button, WIP

+102 -41
+7 -24
app/[leaflet_id]/Sidebar.tsx
··· 1 1 "use client"; 2 - import { ActionButton } from "components/ActionBar/ActionButton"; 3 2 import { Sidebar } from "components/ActionBar/Sidebar"; 4 3 import { useEntitySetContext } from "components/EntitySetProvider"; 5 4 import { HelpButton } from "app/[leaflet_id]/actions/HelpButton"; ··· 10 9 import { ThemePopover } from "components/ThemeManager/ThemeSetter"; 11 10 import { PublishButton } from "./actions/PublishButton"; 12 11 import { Watermark } from "components/Watermark"; 13 - import { useUIState } from "src/useUIState"; 14 12 import { BackToPubButton } from "./actions/BackToPubButton"; 15 13 import { useIdentityData } from "components/IdentityProvider"; 16 14 import { useReplicache } from "src/replicache"; ··· 30 28 <div className="sidebarContainer flex flex-col justify-end h-full w-16 relative"> 31 29 {entity_set.permissions.write && ( 32 30 <Sidebar> 31 + <PublishButton /> 32 + <ShareOptions /> 33 + <ThemePopover entityID={rootEntity} /> 34 + <HelpButton /> 35 + <hr className="text-border" /> 33 36 {pub?.publications && 34 37 identity?.atp_did && 35 38 pub.publications.identity_did === identity.atp_did ? ( 36 - <> 37 - <PublishButton /> 38 - <ShareOptions /> 39 - <ThemePopover entityID={rootEntity} /> 40 - <HelpButton /> 41 - <hr className="text-border" /> 42 - <BackToPubButton publication={pub.publications} /> 43 - </> 39 + <BackToPubButton publication={pub.publications} /> 44 40 ) : ( 45 - <> 46 - <ShareOptions /> 47 - <ThemePopover entityID={rootEntity} /> 48 - <HelpButton /> 49 - <hr className="text-border" /> 50 - <HomeButton /> 51 - </> 41 + <HomeButton /> 52 42 )} 53 43 </Sidebar> 54 44 )} ··· 60 50 </Media> 61 51 ); 62 52 } 63 - 64 - const blurPage = () => { 65 - useUIState.setState(() => ({ 66 - focusedEntity: null, 67 - selectedBlocks: [], 68 - })); 69 - };
+89 -10
app/[leaflet_id]/actions/PublishButton.tsx
··· 1 1 import { publishToPublication } from "actions/publishToPublication"; 2 2 import { getPublicationURL } from "app/lish/createPub/getPublicationURL"; 3 3 import { ActionButton } from "components/ActionBar/ActionButton"; 4 + import { 5 + PubIcon, 6 + PubListEmptyContent, 7 + } from "components/ActionBar/Publications"; 8 + import { ArchiveSmall } from "components/Icons/ArchiveSmall"; 4 9 import { PublishSmall } from "components/Icons/PublishSmall"; 10 + import { useIdentityData } from "components/IdentityProvider"; 11 + import { Menu, MenuItem } from "components/Layout"; 5 12 import { useLeafletPublicationData } from "components/PageSWRDataProvider"; 13 + import { Popover } from "components/Popover"; 6 14 import { SpeedyLink } from "components/SpeedyLink"; 7 15 import { useToaster } from "components/Toast"; 8 16 import { DotLoader } from "components/utils/DotLoader"; 9 - import { useParams } from "next/navigation"; 10 - import { useRouter } from "next/router"; 17 + import { PubLeafletPublication } from "lexicons/api"; 18 + import { useParams, useRouter } from "next/navigation"; 11 19 import { useState } from "react"; 20 + import { useIsMobile } from "src/hooks/isMobile"; 12 21 import { useReplicache } from "src/replicache"; 13 22 14 23 export const PublishButton = () => { 15 24 let { data: pub } = useLeafletPublicationData(); 16 25 let params = useParams(); 17 26 let router = useRouter(); 18 - if (!pub) 19 - return ( 20 - <ActionButton 21 - primary 22 - icon={<PublishSmall className="shrink-0" />} 23 - label={"Publish on ATP"} 24 - /> 25 - ); 27 + 28 + if (!pub) return <PublishToPublication />; 26 29 if (!pub?.doc) 27 30 return ( 28 31 <ActionButton ··· 78 81 /> 79 82 ); 80 83 }; 84 + 85 + const PublishToPublication = () => { 86 + let { identity } = useIdentityData(); 87 + let params = useParams(); 88 + let router = useRouter(); 89 + let isMobile = useIsMobile(); 90 + let hasPubs = 91 + identity && identity.atp_did && identity.publications.length > 0; 92 + 93 + if (!hasPubs) 94 + return ( 95 + <Menu 96 + asChild 97 + side={isMobile ? "top" : "right"} 98 + align={isMobile ? "center" : "start"} 99 + className="flex flex-col max-w-xs text-secondary" 100 + trigger={ 101 + <ActionButton 102 + primary 103 + icon={<PublishSmall className="shrink-0" />} 104 + label={"Publish on ATP"} 105 + /> 106 + } 107 + > 108 + <div className="text-sm text-tertiary">Publish to…</div> 109 + {identity?.publications?.map((d) => { 110 + return ( 111 + <MenuItem 112 + onSelect={async () => { 113 + // TODO 114 + // make this a draft of the selected Publication 115 + // redirect to the publication publish page 116 + }} 117 + > 118 + <PubIcon 119 + record={d.record as PubLeafletPublication.Record} 120 + uri={d.uri} 121 + /> 122 + <div className=" w-full truncate font-bold">{d.name}</div> 123 + </MenuItem> 124 + ); 125 + })} 126 + <hr className="border-border-light my-1" /> 127 + <MenuItem 128 + onSelect={() => { 129 + // TODO 130 + // send to one-off /publish page 131 + }} 132 + > 133 + <ArchiveSmall /> 134 + <div className="font-bold pb-1">Publish as One-Off</div> 135 + </MenuItem> 136 + </Menu> 137 + ); 138 + else 139 + return ( 140 + <Popover 141 + asChild 142 + side={isMobile ? "top" : "right"} 143 + align={isMobile ? "center" : "start"} 144 + className="p-1!" 145 + trigger={ 146 + <ActionButton 147 + primary 148 + icon={<PublishSmall className="shrink-0" />} 149 + label={"Publish on ATP"} 150 + /> 151 + } 152 + > 153 + {/* this component is also used on Home to populate the sidebar when PubList is empty */} 154 + {/* however, this component needs to redirect to sign in, pub creation, AND publish so we might need to just make a new component */} 155 + 156 + <PubListEmptyContent /> 157 + </Popover> 158 + ); 159 + };
+6 -7
components/ActionBar/Publications.tsx
··· 12 12 import { PublishSmall } from "components/Icons/PublishSmall"; 13 13 import { Popover } from "components/Popover"; 14 14 import { BlueskyLogin } from "app/login/LoginForm"; 15 - import { ButtonPrimary } from "components/Buttons"; 15 + import { ButtonSecondary } from "components/Buttons"; 16 16 import { useIsMobile } from "src/hooks/isMobile"; 17 17 import { useState } from "react"; 18 18 ··· 81 81 }; 82 82 83 83 const PubListEmpty = () => { 84 - let { identity } = useIdentityData(); 85 84 let isMobile = useIsMobile(); 86 85 87 86 let [state, setState] = useState<"default" | "info">("default"); ··· 98 97 /> 99 98 ); 100 99 101 - if (isMobile && state === "info") return <PublishPopoverContent />; 100 + if (isMobile && state === "info") return <PubListEmptyContent />; 102 101 else 103 102 return ( 104 103 <Popover ··· 114 113 /> 115 114 } 116 115 > 117 - <PublishPopoverContent /> 116 + <PubListEmptyContent /> 118 117 </Popover> 119 118 ); 120 119 }; 121 120 122 - const PublishPopoverContent = () => { 121 + export const PubListEmptyContent = () => { 123 122 let { identity } = useIdentityData(); 124 123 125 124 return ( ··· 136 135 on AT Proto 137 136 </div> 138 137 <SpeedyLink href={`lish/createPub`} className=" hover:no-underline!"> 139 - <ButtonPrimary className="text-sm mx-auto" compact> 138 + <ButtonSecondary className="text-sm mx-auto" compact> 140 139 Start a Publication! 141 - </ButtonPrimary> 140 + </ButtonSecondary> 142 141 </SpeedyLink> 143 142 </> 144 143 ) : (