a tool for shared writing and social publishing

Added a action menu for post drafts

+153 -25
+38
app/[leaflet_id]/Actions.tsx
··· 1 + import { ActionButton } from "components/ActionBar/ActionButton"; 2 + import { ArrowRightTiny } from "components/Icons/ArrowRightTiny"; 3 + import { GoBackSmall } from "components/Icons/GoBackSmall"; 4 + import { PublishSmall } from "components/Icons/PublishSmall"; 5 + import { useIdentityData } from "components/IdentityProvider"; 6 + import { publications } from "drizzle/schema"; 7 + import Link from "next/link"; 8 + export const BackToPubButton = (props: { 9 + publication: { 10 + identity_did: string; 11 + indexed_at: string; 12 + name: string; 13 + uri: string; 14 + }; 15 + }) => { 16 + let { identity } = useIdentityData(); 17 + 18 + let handle = identity?.resolved_did?.alsoKnownAs?.[0].slice(5)!; 19 + let name = props.publication.name; 20 + return ( 21 + <Link href={`/lish/${handle}/${name}/`} className="hover:!no-underline"> 22 + <ActionButton 23 + icon={<GoBackSmall className="shrink-0" />} 24 + label="To Pub" 25 + /> 26 + </Link> 27 + ); 28 + }; 29 + 30 + export const PublishButton = () => { 31 + return ( 32 + <ActionButton 33 + primary 34 + icon={<PublishSmall className="shrink-0" />} 35 + label="Publish!" 36 + /> 37 + ); 38 + };
+19 -6
app/[leaflet_id]/Footer.tsx
··· 9 9 import { useEntitySetContext } from "components/EntitySetProvider"; 10 10 import { HelpPopover } from "components/HelpPopover"; 11 11 import { Watermark } from "components/Watermark"; 12 + import { BackToPubButton, PublishButton } from "./Actions"; 13 + import { useLeafletPublicationData } from "components/PageSWRDataProvider"; 12 14 13 15 export function LeafletFooter(props: { entityID: string }) { 14 16 let focusedBlock = useUIState((s) => s.focusedEntity); 15 17 let entity_set = useEntitySetContext(); 18 + let { data: publicationData } = useLeafletPublicationData(); 19 + let pub = publicationData?.[0]; 16 20 17 21 return ( 18 22 <Media mobile className="mobileFooter w-full z-10 touch-none -mt-4 "> ··· 31 35 /> 32 36 </div> 33 37 ) : entity_set.permissions.write ? ( 34 - <ActionFooter> 35 - <HomeButton /> 36 - <ShareOptions /> 37 - <HelpPopover /> 38 - <ThemePopover entityID={props.entityID} /> 39 - </ActionFooter> 38 + pub?.publications ? ( 39 + <ActionFooter> 40 + <BackToPubButton publication={pub.publications} /> 41 + <PublishButton /> 42 + <ShareOptions /> 43 + <HelpPopover /> 44 + </ActionFooter> 45 + ) : ( 46 + <ActionFooter> 47 + <HomeButton /> 48 + <ShareOptions /> 49 + <HelpPopover /> 50 + <ThemePopover entityID={props.entityID} /> 51 + </ActionFooter> 52 + ) 40 53 ) : ( 41 54 <div className="pb-2 px-2 z-10 flex justify-end"> 42 55 <Watermark mobile />
+23 -7
app/[leaflet_id]/Sidebar.tsx
··· 1 1 "use client"; 2 + import { ActionButton } from "components/ActionBar/ActionButton"; 2 3 import { Sidebar } from "components/ActionBar/Sidebar"; 3 4 import { useEntitySetContext } from "components/EntitySetProvider"; 4 5 import { HelpPopover } from "components/HelpPopover"; 5 6 import { HomeButton } from "components/HomeButton"; 6 7 import { Media } from "components/Media"; 8 + import { useLeafletPublicationData } from "components/PageSWRDataProvider"; 7 9 import { ShareOptions } from "components/ShareOptions"; 8 10 import { ThemePopover } from "components/ThemeManager/ThemeSetter"; 9 11 import { Watermark } from "components/Watermark"; 10 12 import { useUIState } from "src/useUIState"; 13 + import { BackToPubButton, PublishButton } from "./Actions"; 11 14 12 15 export function LeafletSidebar(props: { leaflet_id: string }) { 13 16 let entity_set = useEntitySetContext(); 17 + let { data: publicationData } = useLeafletPublicationData(); 18 + let pub = publicationData?.[0]; 19 + 14 20 return ( 15 21 <div 16 22 className="spacer flex justify-end items-start" ··· 25 31 > 26 32 <Sidebar> 27 33 {entity_set.permissions.write ? ( 28 - <> 29 - <ShareOptions /> 30 - <ThemePopover entityID={props.leaflet_id} /> 31 - <HelpPopover /> 32 - <hr className="text-border" /> 33 - <HomeButton /> 34 - </> 34 + pub?.publications ? ( 35 + <> 36 + <PublishButton /> 37 + <ShareOptions /> 38 + <HelpPopover /> 39 + <hr className="text-border" /> 40 + <BackToPubButton publication={pub.publications} /> 41 + </> 42 + ) : ( 43 + <> 44 + <ShareOptions /> 45 + <ThemePopover entityID={props.leaflet_id} /> 46 + <HelpPopover /> 47 + <hr className="text-border" /> 48 + <HomeButton /> 49 + </> 50 + ) 35 51 ) : ( 36 52 <div> 37 53 <HomeButton />
+2 -2
app/lish/[handle]/[publication]/Actions.tsx
··· 47 47 <Link href={"/"} className="text-secondary hover:no-underline"> 48 48 <div>Viewer Mode</div> 49 49 <div className="font-normal text-tertiary text-sm"> 50 - View your publication as a reader would 50 + View your publication as a reader 51 51 </div> 52 52 </Link> 53 53 </MenuItem> ··· 55 55 <div> 56 56 <div>Share Your Publication</div> 57 57 <div className="font-normal text-tertiary text-sm"> 58 - Copy the reader link for this publication{" "} 58 + Copy link for the published site 59 59 </div> 60 60 </div> 61 61 </MenuItem>
+5 -4
app/lish/[handle]/[publication]/DraftList.tsx
··· 9 9 import { Menu, MenuItem } from "components/Layout"; 10 10 import { MoreOptionsVerticalTiny } from "components/Icons/MoreOptionsVerticalTiny"; 11 11 import { DeleteSmall } from "components/Icons/DeleteSmall"; 12 + import React from "react"; 12 13 13 14 export function DraftList(props: { 14 15 publication: string; ··· 23 24 if (!publication) return null; 24 25 if (!rel?.isAuthor) return null; 25 26 return ( 26 - <div className="flex flex-col gap-4"> 27 + <div className="flex flex-col gap-4 pb-6"> 27 28 <NewDraftSecondaryButton fullWidth publication={props.publication} /> 28 29 {props.drafts.map((d) => { 29 30 return ( 30 - <> 31 - <Draft id={d.leaflet} key={d.leaflet} {...d} /> 31 + <React.Fragment key={d.leaflet}> 32 + <Draft id={d.leaflet} {...d} /> 32 33 <hr className="last:hidden border-border-light" /> 33 - </> 34 + </React.Fragment> 34 35 ); 35 36 })} 36 37 </div>
+18
components/Icons/GoBackSmall.tsx
··· 1 + import { Props } from "./Props"; 2 + 3 + export const GoBackSmall = (props: Props) => { 4 + return ( 5 + <svg 6 + width="24" 7 + height="24" 8 + viewBox="0 0 24 24" 9 + fill="none" 10 + xmlns="http://www.w3.org/2000/svg" 11 + > 12 + <path 13 + d="M12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2ZM12.6826 5.96582C12.2921 5.57556 11.659 5.57557 11.2686 5.96582L5.94141 11.293C5.55114 11.6834 5.55114 12.3166 5.94141 12.707L11.2686 18.0332L11.3438 18.1025C11.7365 18.4229 12.3165 18.3993 12.6826 18.0332C13.0484 17.6671 13.0712 17.088 12.751 16.6953L12.6826 16.6191L9.06348 13H17.9473L18.0498 12.9951C18.5538 12.9438 18.9471 12.5175 18.9473 12C18.9472 11.4824 18.5538 11.0563 18.0498 11.0049L17.9473 11H9.06152L12.6826 7.37988C13.0729 6.98941 13.0729 6.35629 12.6826 5.96582Z" 14 + fill="currentColor" 15 + /> 16 + </svg> 17 + ); 18 + };
+20
components/Icons/PublishSmall.tsx
··· 1 + import { Props } from "./Props"; 2 + 3 + export const PublishSmall = (props: Props) => { 4 + return ( 5 + <svg 6 + width="24" 7 + height="24" 8 + viewBox="0 0 24 24" 9 + fill="none" 10 + xmlns="http://www.w3.org/2000/svg" 11 + > 12 + <path 13 + fillRule="evenodd" 14 + clipRule="evenodd" 15 + d="M9.22186 7.92684C10.1774 6.18312 11.5332 4.90336 12.9251 4.2286C13.1335 4.12754 13.3416 4.04046 13.5484 3.96745C14.6049 3.60869 15.7766 3.54735 16.7819 4.09825C17.8692 4.69405 18.5671 5.88122 18.7476 7.41916C18.9279 8.95543 18.5788 10.7869 17.6233 12.5306C16.6678 14.2743 15.312 15.5541 13.9201 16.2288C12.5267 16.9043 11.1506 16.955 10.0633 16.3592C9.19584 15.8839 8.57626 15.0321 8.26951 13.9262C8.25817 13.8746 8.24668 13.8234 8.23523 13.7724L8.23523 13.7724C8.18078 13.5299 8.12744 13.2924 8.09762 13.0383C7.91733 11.502 8.26635 9.67055 9.22186 7.92684ZM9.46946 4.78715C9.67119 4.78662 9.8633 4.78121 10.0481 4.7711C9.3182 5.48646 8.66218 6.34702 8.12565 7.32615C7.55376 8.36979 7.16847 9.45536 6.96726 10.519C6.87184 10.3382 6.77397 10.1659 6.67468 10.0061C6.66248 9.63279 6.756 9.17519 6.92538 8.67954C7.12252 8.10267 7.40257 7.53025 7.65185 7.07532C7.87489 6.6683 8.26315 6.06477 8.68993 5.5499C8.9033 5.29248 9.11698 5.06859 9.31569 4.90418C9.37126 4.8582 9.42255 4.81949 9.46946 4.78715ZM8.11028 4.69028C7.79498 4.62946 7.4876 4.54412 7.23739 4.46669C6.91656 4.36741 6.66099 4.27202 6.54912 4.22896C6.41134 4.17536 6.19445 4.14 6.05859 4.21094C5.71409 4.39084 5.01295 4.92363 4.69271 5.51519C4.53469 5.8071 4.40424 6.2273 4.30596 6.64793C4.29259 6.70518 4.27708 6.76449 4.26123 6.82511L4.26123 6.82512L4.26122 6.82514C4.18998 7.09762 4.11179 7.39666 4.18884 7.65503C4.24062 7.82867 4.31432 7.93693 4.39162 8.00286C4.59287 8.12133 4.78982 8.24738 4.98348 8.37782C5.22591 8.54111 5.52054 8.75196 5.79607 8.98466C5.84667 8.7703 5.90975 8.55912 5.97911 8.35617C6.20171 7.70478 6.51068 7.07692 6.77488 6.59477C7.02425 6.1397 7.44733 5.482 7.92003 4.91174C7.98204 4.83692 8.04556 4.76282 8.11028 4.69028ZM4.21574 3.89626L4.62051 4.02189C4.3203 4.30946 4.01949 4.65825 3.8133 5.03912C3.59059 5.45053 3.43618 5.9753 3.33219 6.42041C3.30438 6.53942 3.27957 6.65546 3.25762 6.7656L2.81215 6.40882C2.81215 6.40882 2.81126 6.40681 2.80986 6.40423C2.79662 6.37992 2.73103 6.25944 2.74152 5.96321C2.75269 5.6481 2.85108 5.26172 3.04578 4.90642C3.25394 4.52653 3.50079 4.23769 3.73458 4.06623C3.95711 3.90302 4.11635 3.8793 4.21574 3.89626ZM5.25013 10.1776C5.49632 10.4247 5.83445 10.991 6.17145 11.7406C5.73841 12.4265 5.41616 12.6857 5.21838 12.7691C5.07131 12.8312 4.93508 12.822 4.70214 12.656C4.11675 12.2388 3.60414 11.8264 3.21764 11.4066C2.8298 10.9853 2.60401 10.594 2.53069 10.2224L2.52687 10.2031C2.4802 9.9669 2.45604 9.84466 2.51608 9.58542C2.57686 9.32295 2.72752 8.9236 3.07623 8.2506C3.19924 8.54228 3.38803 8.81394 3.66359 9.02041C3.77639 9.10493 3.89934 9.17816 4.02211 9.25128L4.02211 9.25128C4.11121 9.30434 4.20021 9.35735 4.28517 9.41458C4.61144 9.63434 4.98505 9.91153 5.25013 10.1776ZM1.49231 5.91896C1.47179 6.49822 1.63299 7.06591 2.09331 7.43458C1.64229 8.27701 1.40278 8.85224 1.2983 9.30341C1.17766 9.82436 1.24402 10.1596 1.29968 10.4408L1.30433 10.4643C1.43907 11.1472 1.82601 11.7405 2.29799 12.2532C2.77132 12.7673 3.36564 13.2385 3.9767 13.6739C4.42074 13.9904 5.0195 14.2097 5.70419 13.9209C6.06177 13.77 6.39891 13.496 6.72728 13.1045C6.81994 13.3603 6.90026 13.6093 6.96835 13.8644C7.28444 15.3377 8.1138 16.7163 9.46258 17.4554C10.998 18.2968 12.8155 18.1535 14.4654 17.3536C16.1168 16.5531 17.6539 15.0761 18.7195 13.1313C19.7852 11.1865 20.203 9.09618 19.9891 7.27346C19.7753 5.4524 18.918 3.84341 17.3826 3.00204C16.1201 2.31022 14.6669 2.28413 13.2729 2.74137C13.2652 2.74368 13.2574 2.74615 13.2497 2.74878C11.4939 3.34572 10.626 3.60952 8.78711 3.52059C8.44675 3.50414 7.99961 3.39408 7.60693 3.27256C7.49582 3.23818 7.38646 3.19733 7.27712 3.15649C7.15008 3.10903 7.02308 3.06159 6.89344 3.02433C6.45975 2.89969 6.03009 2.91392 5.62971 3.0263C5.50956 2.98901 5.3892 2.94865 5.26851 2.90817C5.01835 2.82428 4.76678 2.73992 4.51267 2.68142C3.94356 2.55041 3.41069 2.75363 2.99533 3.05825C2.57846 3.36398 2.22138 3.8097 1.94957 4.30573C1.66428 4.82635 1.5106 5.40259 1.49231 5.91896ZM10.6051 8.68425C10.9866 7.98795 11.4394 7.38085 11.9278 6.8783C12.6769 7.53018 13.1717 8.17432 13.4238 8.75106C13.6893 9.35867 13.6744 9.85621 13.4617 10.2444C13.2546 10.6223 12.8385 10.9029 12.1709 11.0084C11.5426 11.1076 10.7313 11.0418 9.794 10.7741C9.95466 10.091 10.2229 9.3816 10.6051 8.68425ZM13.4264 5.71995C13.1758 5.85571 12.9254 6.0188 12.6791 6.20754C13.4537 6.89902 14.0241 7.62766 14.3401 8.35057C14.6935 9.15932 14.7389 9.99457 14.3386 10.7249C13.9392 11.4539 13.1982 11.8584 12.327 11.9961C11.5454 12.1196 10.6234 12.0373 9.63348 11.7675C9.60713 12.0758 9.60447 12.3739 9.62485 12.6574C9.70968 13.8381 10.1817 14.6978 10.9166 15.1005C11.6516 15.5033 12.6302 15.4385 13.671 14.8746C14.7064 14.3136 15.7384 13.2861 16.4923 11.9103C16.776 11.3925 16.9977 10.8667 17.159 10.3487C17.2411 10.0851 17.5214 9.93788 17.785 10.02C18.0487 10.1021 18.1959 10.3824 18.1138 10.646C17.9324 11.2285 17.6845 11.8156 17.3693 12.3909C16.5368 13.91 15.3756 15.0884 14.1473 15.7539C12.9245 16.4164 11.569 16.5983 10.4361 15.9775C9.30313 15.3567 8.72709 14.1163 8.62742 12.7291C8.52731 11.3358 8.89565 9.72284 9.72809 8.2037C10.5605 6.68456 11.7218 5.50611 12.95 4.84069C14.1729 4.17819 15.5283 3.99622 16.6613 4.61705C17.5803 5.12063 18.1356 6.03691 18.3631 7.10207C18.4208 7.37213 18.2486 7.6378 17.9785 7.69548C17.7085 7.75315 17.4428 7.58098 17.3851 7.31093C17.201 6.44889 16.7798 5.82228 16.1807 5.49401C15.4458 5.09129 14.4672 5.15607 13.4264 5.71995ZM20.2049 14.5155C19.8187 14.3656 19.3842 14.5572 19.2343 14.9434C19.0845 15.3295 19.2761 15.764 19.6622 15.9139L21.4114 16.5926C21.7976 16.7425 22.2321 16.5509 22.382 16.1648C22.5318 15.7786 22.3402 15.3441 21.9541 15.1942L20.2049 14.5155ZM17.9326 16.6232C18.2114 16.3169 18.6857 16.2945 18.9921 16.5733L22.8336 20.0686C23.1399 20.3474 23.1623 20.8218 22.8836 21.1281C22.6048 21.4345 22.1304 21.4569 21.8241 21.1781L17.9826 17.6827C17.6762 17.404 17.6539 16.9296 17.9326 16.6232ZM16.8269 17.9194C16.6484 17.5456 16.2007 17.3874 15.8269 17.5659C15.4531 17.7444 15.2949 18.1921 15.4734 18.5659L16.8786 21.5078C17.0572 21.8816 17.5049 22.0398 17.8787 21.8613C18.2524 21.6828 18.4107 21.235 18.2322 20.8613L16.8269 17.9194Z" 16 + fill="currentColor" 17 + /> 18 + </svg> 19 + ); 20 + };
+28 -6
components/ShareOptions/index.tsx
··· 10 10 import LoginForm from "app/login/LoginForm"; 11 11 import { CustomDomainMenu } from "./DomainOptions"; 12 12 import { useIdentityData } from "components/IdentityProvider"; 13 - import { useLeafletDomains } from "components/PageSWRDataProvider"; 13 + import { 14 + useLeafletDomains, 15 + useLeafletPublicationData, 16 + } from "components/PageSWRDataProvider"; 14 17 import { ShareSmall } from "components/Icons/ShareSmall"; 15 18 16 19 export type ShareMenuStates = "default" | "login" | "domain"; ··· 38 41 }; 39 42 40 43 export function ShareOptions() { 41 - let { permission_token } = useReplicache(); 42 44 let [menuState, setMenuState] = useState<ShareMenuStates>("default"); 45 + let { data: publicationData } = useLeafletPublicationData(); 46 + let pub = publicationData?.[0]; 43 47 44 48 return ( 45 49 <Menu ··· 48 52 onOpenChange={() => { 49 53 setMenuState("default"); 50 54 }} 51 - trigger={<ActionButton icon=<ShareSmall /> primary label="Share" />} 55 + trigger={ 56 + <ActionButton 57 + icon=<ShareSmall /> 58 + primary={!!!pub} 59 + secondary={!!pub} 60 + label={`Share ${pub && "Draft"}`} 61 + /> 62 + } 52 63 > 53 64 {menuState === "login" ? ( 54 65 <div className="px-3 py-1"> ··· 57 68 ) : menuState === "domain" ? ( 58 69 <CustomDomainMenu setShareMenuState={setMenuState} /> 59 70 ) : ( 60 - <ShareMenu setMenuState={setMenuState} domainConnected={false} /> 71 + <ShareMenu 72 + setMenuState={setMenuState} 73 + domainConnected={false} 74 + isPub={!!pub} 75 + /> 61 76 )} 62 77 </Menu> 63 78 ); ··· 66 81 const ShareMenu = (props: { 67 82 setMenuState: (state: ShareMenuStates) => void; 68 83 domainConnected: boolean; 84 + isPub?: boolean; 69 85 }) => { 70 86 let { permission_token } = useReplicache(); 87 + 71 88 let publishLink = usePublishLink(); 72 89 let [collabLink, setCollabLink] = useState<null | string>(null); 73 90 useEffect(() => { ··· 79 96 let isTemplate = useTemplateState( 80 97 (s) => !!s.templates.find((t) => t.id === permission_token.id), 81 98 ); 99 + 82 100 return ( 83 101 <> 84 102 {isTemplate && ( ··· 124 142 } 125 143 link={publishLink || ""} 126 144 /> 127 - <hr className="border-border mt-1" /> 128 - <DomainMenuItem setMenuState={props.setMenuState} /> 145 + {!props.isPub && ( 146 + <> 147 + <hr className="border-border mt-1" /> 148 + <DomainMenuItem setMenuState={props.setMenuState} /> 149 + </> 150 + )} 129 151 </> 130 152 ); 131 153 };