a tool for shared writing and social publishing

don't show the toolbar on blocks without toolbar actions

+66 -71
+17 -1
app/[leaflet_id]/Footer.tsx
··· 8 8 import { HomeButton } from "app/[leaflet_id]/actions/HomeButton"; 9 9 import { PublishButton } from "./actions/PublishButton"; 10 10 import { useEntitySetContext } from "components/EntitySetProvider"; 11 - import { HelpButton } from "app/[leaflet_id]/actions/HelpButton"; 12 11 import { Watermark } from "components/Watermark"; 13 12 import { BackToPubButton } from "./actions/BackToPubButton"; 14 13 import { useLeafletPublicationData } from "components/PageSWRDataProvider"; 15 14 import { useIdentityData } from "components/IdentityProvider"; 15 + import { useEntity } from "src/replicache"; 16 + import { block } from "sharp"; 16 17 18 + export function hasBlockToolbar(blockType: string | null | undefined) { 19 + return ( 20 + blockType === "text" || 21 + blockType === "heading" || 22 + blockType === "blockquote" || 23 + blockType === "button" || 24 + blockType === "datetime" || 25 + blockType === "image" 26 + ); 27 + } 17 28 export function LeafletFooter(props: { entityID: string }) { 18 29 let focusedBlock = useUIState((s) => s.focusedEntity); 30 + 19 31 let entity_set = useEntitySetContext(); 20 32 let { identity } = useIdentityData(); 21 33 let { data: pub } = useLeafletPublicationData(); 34 + let blockType = useEntity(focusedBlock?.entityID || null, "block/type")?.data 35 + .value; 22 36 23 37 return ( 24 38 <Media mobile className="mobileFooter w-full z-10 touch-none -mt-[54px] "> 25 39 {focusedBlock && 26 40 focusedBlock.entityType == "block" && 41 + hasBlockToolbar(blockType) && 27 42 entity_set.permissions.write ? ( 28 43 <div 29 44 className="w-full z-10 p-2 flex bg-bg-page pwa-padding-bottom" ··· 34 49 <Toolbar 35 50 pageID={focusedBlock.parent} 36 51 blockID={focusedBlock.entityID} 52 + blockType={blockType} 37 53 /> 38 54 </div> 39 55 ) : entity_set.permissions.write ? (
-1
app/lish/[did]/[publication]/icon/route.ts
··· 14 14 request: NextRequest, 15 15 props: { params: Promise<{ did: string; publication: string }> }, 16 16 ) { 17 - console.log("are we getting here?"); 18 17 const params = await props.params; 19 18 try { 20 19 let did = decodeURIComponent(params.did);
+7
components/DesktopFooter.tsx
··· 4 4 import { Toolbar } from "./Toolbar"; 5 5 import { useEntitySetContext } from "./EntitySetProvider"; 6 6 import { focusBlock } from "src/utils/focusBlock"; 7 + import { hasBlockToolbar } from "app/[leaflet_id]/Footer"; 8 + import { useEntity } from "src/replicache"; 7 9 8 10 export function DesktopPageFooter(props: { pageID: string }) { 9 11 let focusedEntity = useUIState((s) => s.focusedEntity); ··· 13 15 : focusedEntity?.parent; 14 16 let entity_set = useEntitySetContext(); 15 17 18 + let blockType = useEntity(focusedEntity?.entityID || null, "block/type")?.data 19 + .value; 20 + 16 21 return ( 17 22 <Media 18 23 mobile={false} ··· 20 25 > 21 26 {focusedEntity && 22 27 focusedEntity.entityType === "block" && 28 + hasBlockToolbar(blockType) && 23 29 entity_set.permissions.write && 24 30 focusedBlockParentID === props.pageID && ( 25 31 <div ··· 29 35 }} 30 36 > 31 37 <Toolbar 38 + blockType={blockType} 32 39 pageID={focusedBlockParentID} 33 40 blockID={focusedEntity.entityID} 34 41 />
-39
components/Toolbar/BlockToolbar.tsx
··· 1 - import { useEntity } from "src/replicache"; 2 - import { Separator } from "components/Layout"; 3 - import { useUIState } from "src/useUIState"; 4 - import { TextAlignmentButton } from "./TextAlignmentToolbar"; 5 - import { 6 - ImageFullBleedButton, 7 - ImageAltTextButton, 8 - ImageCoverButton, 9 - } from "./ImageToolbar"; 10 - 11 - export const ImageToolbar = (props: { 12 - setToolbarState: (state: "image" | "text-alignment") => void; 13 - }) => { 14 - let focusedEntity = useUIState((s) => s.focusedEntity); 15 - let focusedEntityType = useEntity( 16 - focusedEntity?.entityType === "page" 17 - ? focusedEntity.entityID 18 - : focusedEntity?.parent || null, 19 - "page/type", 20 - ); 21 - let blockType = useEntity( 22 - focusedEntity?.entityType === "block" ? focusedEntity?.entityID : null, 23 - "block/type", 24 - )?.data.value; 25 - 26 - return ( 27 - <div className="flex items-center gap-2 justify-between w-full"> 28 - <div className="flex items-center gap-2"> 29 - <TextAlignmentButton setToolbarState={props.setToolbarState} /> 30 - <ImageFullBleedButton /> 31 - <ImageAltTextButton /> 32 - <ImageCoverButton /> 33 - {focusedEntityType?.data.value !== "canvas" && ( 34 - <Separator classname="h-6!" /> 35 - )} 36 - </div> 37 - </div> 38 - ); 39 - };
+28 -1
components/Toolbar/ImageToolbar.tsx
··· 7 7 import { useLeafletPublicationData } from "components/PageSWRDataProvider"; 8 8 import { useSubscribe } from "src/replicache/useSubscribe"; 9 9 import { ImageCoverImage } from "components/Icons/ImageCoverImage"; 10 + import { Separator } from "components/Layout"; 11 + import { TextAlignmentButton } from "./TextAlignmentToolbar"; 12 + 13 + export const ImageToolbar = (props: { 14 + setToolbarState: (state: "image" | "text-alignment") => void; 15 + }) => { 16 + let focusedEntity = useUIState((s) => s.focusedEntity); 17 + let focusedEntityType = useEntity( 18 + focusedEntity?.entityType === "page" 19 + ? focusedEntity.entityID 20 + : focusedEntity?.parent || null, 21 + "page/type", 22 + ); 23 + 24 + return ( 25 + <div className="flex items-center gap-2 justify-between w-full"> 26 + <div className="flex items-center gap-2"> 27 + <TextAlignmentButton setToolbarState={props.setToolbarState} /> 28 + <ImageAltTextButton /> 29 + <ImageFullBleedButton /> 30 + <ImageCoverButton /> 31 + {focusedEntityType?.data.value !== "canvas" && ( 32 + <Separator classname="h-6!" /> 33 + )} 34 + </div> 35 + </div> 36 + ); 37 + }; 10 38 11 39 export const ImageFullBleedButton = (props: {}) => { 12 40 let { rep } = useReplicache(); ··· 46 74 let altEditorOpen = useUIState((s) => s.openPopover === focusedBlock); 47 75 let hasSrc = useEntity(focusedBlock, "block/image")?.data; 48 76 if (!hasSrc) return null; 49 - console.log("alt: " + altText); 50 77 return ( 51 78 <ToolbarButton 52 79 active={altText !== undefined}
+14 -29
components/Toolbar/index.tsx
··· 11 11 import { ListToolbar } from "./ListToolbar"; 12 12 import { HighlightToolbar } from "./HighlightToolbar"; 13 13 import { TextToolbar } from "./TextToolbar"; 14 - import { ImageToolbar } from "./BlockToolbar"; 14 + import { ImageToolbar } from "./ImageToolbar"; 15 15 import { MultiselectToolbar } from "./MultiSelectToolbar"; 16 - import { AreYouSure } from "components/Blocks/DeleteBlock"; 17 - import { deleteBlock } from "src/utils/deleteBlock"; 18 16 import { TooltipButton } from "components/Buttons"; 19 17 import { TextAlignmentToolbar } from "./TextAlignmentToolbar"; 20 18 import { useIsMobile } from "src/hooks/isMobile"; ··· 32 30 | "img-alt-text" 33 31 | "image"; 34 32 35 - export const Toolbar = (props: { pageID: string; blockID: string }) => { 36 - let { rep } = useReplicache(); 37 - 33 + export const Toolbar = (props: { 34 + pageID: string; 35 + blockID: string; 36 + blockType: string | null | undefined; 37 + }) => { 38 38 let [toolbarState, setToolbarState] = useState<ToolbarTypes>("default"); 39 39 40 - let focusedEntity = useUIState((s) => s.focusedEntity); 41 - let selectedBlocks = useUIState((s) => s.selectedBlocks); 42 40 let activeEditor = useEditorStates((s) => s.editorStates[props.blockID]); 43 - 44 - let blockType = useEntity(props.blockID, "block/type")?.data.value; 45 41 46 42 let lastUsedHighlight = useUIState((s) => s.lastUsedHighlight); 47 43 let setLastUsedHighlight = (color: "1" | "2" | "3") => ··· 64 60 }, [toolbarState]); 65 61 66 62 let isTextBlock = 67 - blockType === "heading" || 68 - blockType === "text" || 69 - blockType === "blockquote"; 63 + props.blockType === "heading" || 64 + props.blockType === "text" || 65 + props.blockType === "blockquote"; 70 66 71 67 useEffect(() => { 72 68 if (isTextBlock) { 73 69 setToolbarState("default"); 74 70 } 75 - if (blockType === "image") { 71 + if (props.blockType === "image") { 76 72 setToolbarState("image"); 77 73 } 78 - if (blockType === "button" || blockType === "datetime") { 74 + if (props.blockType === "button" || props.blockType === "datetime") { 79 75 setToolbarState("text-alignment"); 80 - } else return; 81 - }, [blockType]); 76 + } else null; 77 + }, [props.blockType]); 82 78 83 - useEffect(() => { 84 - if ( 85 - selectedBlocks.length > 1 && 86 - !["areYousure", "text-alignment"].includes(toolbarState) 87 - ) { 88 - setToolbarState("multiselect"); 89 - } else if (toolbarState === "multiselect") { 90 - setToolbarState("default"); 91 - } 92 - }, [selectedBlocks.length, toolbarState]); 93 79 let isMobile = useIsMobile(); 94 - 95 80 return ( 96 81 <Tooltip.Provider> 97 82 <div ··· 154 139 selectedBlocks: [], 155 140 })); 156 141 } else { 157 - if (blockType === "image") { 142 + if (props.blockType === "image") { 158 143 setToolbarState("image"); 159 144 } 160 145 if (isTextBlock) {