a tool for shared writing and social publishing
0
fork

Configure Feed

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

sorry, a bit of a mish mash! tweaked some hover states in block options, tweaked spacing in inline and link block subtoolbars, and added delete buttons to card and link blocks

celine 65ae0282 5e966d82

+113 -44
+2 -2
components/Blocks/BlockOptions.tsx
··· 160 160 161 161 return ( 162 162 <div 163 - className={`max-w-sm flex gap-2 hover:text-accent rounded-md ${linkOpen ? "text-secondary" : " text-tertiary"}`} 163 + className={`max-w-sm flex gap-2 rounded-md ${linkOpen ? "text-secondary" : " text-tertiary"}`} 164 164 > 165 165 <ToolbarButton 166 166 tooltipContent="Add a Link" 167 - className="hover:bg-transparent hover:text-accent text-tertiary" 167 + className="hover:bg-transparent text-tertiary" 168 168 onClick={() => { 169 169 setLinkOpen(!linkOpen); 170 170 }}
+70 -22
components/Blocks/CardBlock.tsx
··· 4 4 import { useUIState } from "src/useUIState"; 5 5 import { RenderedTextBlock } from "components/Blocks/TextBlock"; 6 6 import { useDocMetadata } from "src/hooks/queries/useDocMetadata"; 7 + import { CloseTiny } from "components/Icons"; 8 + import { useState } from "react"; 9 + import { useEntitySetContext } from "components/EntitySetProvider"; 7 10 8 11 export function CardBlock(props: BlockProps) { 9 12 let isSelected = useUIState( ··· 12 15 s.selectedBlock.find((b) => b.value === props.entityID), 13 16 ); 14 17 let docMetadata = useDocMetadata(props.entityID); 18 + let permission = useEntitySetContext().permissions.write; 15 19 16 20 let isOpen = useUIState((s) => s.openCards).includes(props.entityID); 21 + let [areYouSure, setAreYouSure] = useState(false); 17 22 18 23 let { rep } = useReplicache(); 19 24 20 25 return ( 21 26 <div 22 27 className={` 23 - cardBlockWrapper relative group 28 + cardBlockWrapper relative group/cardBlock 24 29 w-full h-[104px] 25 30 bg-bg-card border shadow-sm outline outline-1 hover:outline-border-light rounded-lg 26 31 flex overflow-hidden 27 - cursor-pointer 32 + 28 33 ${isSelected || isOpen ? "outline-border border-border" : "outline-transparent border-border-light"} 29 34 `} 30 - onClick={(e) => { 31 - e.stopPropagation(); 32 - useUIState.getState().openCard(props.parent, props.entityID); 33 - if (rep) focusCard(props.entityID, rep); 34 - }} 35 35 > 36 - <div className="py-1 grow min-w-0"> 37 - {docMetadata.heading && ( 38 - <div 39 - className={`cardBlockTitle bg-transparent -mb-3 border-none text-base font-bold outline-none resize-none align-top border line-clamp-1`} 40 - > 41 - <RenderedTextBlock entityID={docMetadata.heading} /> 36 + {areYouSure ? ( 37 + <div className="flex flex-col gap-1 w-full h-full place-items-center items-center font-bold py-4 bg-border-light"> 38 + <div className="">Delete this Page?</div> 39 + <div className="flex gap-2"> 40 + <button 41 + className="bg-accent text-accentText px-2 py-1 rounded-md " 42 + onClick={(e) => { 43 + e.stopPropagation(); 44 + useUIState.getState().closeCard(props.entityID); 45 + 46 + rep && 47 + rep.mutate.removeBlock({ 48 + blockEntity: props.entityID, 49 + }); 50 + }} 51 + > 52 + Delete 53 + </button> 54 + <button 55 + className="text-accent" 56 + onClick={() => setAreYouSure(false)} 57 + > 58 + Nevermind 59 + </button> 42 60 </div> 43 - )} 44 - {docMetadata.content && ( 45 - <div 46 - className={`cardBlockDescription text-sm bg-transparent border-none outline-none resize-none align-top ${docMetadata.heading ? "line-clamp-3 max-h-16" : "line-clamp-4 max-h-[88px]"}`} 47 - > 48 - <RenderedTextBlock entityID={docMetadata.content} /> 61 + </div> 62 + ) : ( 63 + <div 64 + className="w-full flex overflow-hidden cursor-pointer" 65 + onClick={(e) => { 66 + e.stopPropagation(); 67 + useUIState.getState().openCard(props.parent, props.entityID); 68 + if (rep) focusCard(props.entityID, rep); 69 + }} 70 + > 71 + <div className="py-1 grow min-w-0"> 72 + {docMetadata.heading && ( 73 + <div 74 + className={`cardBlockTitle bg-transparent -mb-3 border-none text-base font-bold outline-none resize-none align-top border line-clamp-1`} 75 + > 76 + <RenderedTextBlock entityID={docMetadata.heading} /> 77 + </div> 78 + )} 79 + {docMetadata.content && ( 80 + <div 81 + className={`cardBlockDescription text-sm bg-transparent border-none outline-none resize-none align-top ${docMetadata.heading ? "line-clamp-3 max-h-16" : "line-clamp-4 max-h-[88px]"}`} 82 + > 83 + <RenderedTextBlock entityID={docMetadata.content} /> 84 + </div> 85 + )} 49 86 </div> 50 - )} 51 - </div> 52 - <CardPreview entityID={props.entityID} /> 87 + <CardPreview entityID={props.entityID} /> 88 + {permission && ( 89 + <button 90 + className="absolute p-1 top-0.5 right-0.5 hover:text-accent text-secondary sm:hidden sm:group-hover/cardBlock:block" 91 + onClick={(e) => { 92 + e.stopPropagation(); 93 + setAreYouSure(true); 94 + }} 95 + > 96 + <CloseTiny /> 97 + </button> 98 + )} 99 + </div> 100 + )} 53 101 </div> 54 102 ); 55 103 }
+24 -4
components/Blocks/ExternalLinkBlock.tsx
··· 1 - import { useEntity } from "src/replicache"; 1 + import { useEntity, useReplicache } from "src/replicache"; 2 2 import { CloseTiny } from "components/Icons"; 3 + import { useEntitySetContext } from "components/EntitySetProvider"; 3 4 4 5 export const ExternalLinkBlock = (props: { entityID: string }) => { 5 6 let previewImage = useEntity(props.entityID, "link/preview"); ··· 7 8 let description = useEntity(props.entityID, "link/description"); 8 9 let url = useEntity(props.entityID, "link/url"); 9 10 11 + let permission = useEntitySetContext().permissions.write; 12 + let { rep } = useReplicache(); 13 + 10 14 return ( 11 15 <a 12 16 href={url?.data.value} 13 17 target="_blank" 14 - className="externalLinkBlock relative group h-[104px] bg-bg-card shadow-sm flex border border-border-light hover:border-accent outline outline-1 outline-transparent hover:outline-accent rounded-lg overflow-hidden text-primary no-underline" 18 + className="externalLinkBlock relative group/linkBlock h-[104px] bg-bg-card shadow-sm flex border border-border-light hover:border-accent outline outline-1 outline-transparent hover:outline-accent rounded-lg overflow-hidden text-primary no-underline" 15 19 > 16 20 <div className="pt-2 pb-2 px-2 grow min-w-0"> 17 21 <div className="flex flex-col w-full min-w-0 h-full grow "> ··· 26 30 > 27 31 {description?.data.value} 28 32 </div> 29 - <div className="inline-block place-self-end w-full text-xs text-tertiary italic line-clamp-1 truncate group-hover:text-accent"> 33 + <div className="inline-block place-self-end w-full text-xs text-tertiary italic line-clamp-1 truncate group-hover/linkBlock:text-accent"> 30 34 {url?.data.value} 31 35 </div> 32 36 </div> 33 37 </div> 34 38 35 39 <div 36 - className={`linkBlockPreview w-[120px] m-2 -mb-2 bg-cover shrink-0 rounded-t-md border border-border group-hover:border-accent `} 40 + className={`linkBlockPreview w-[120px] m-2 -mb-2 bg-cover shrink-0 rounded-t-md border border-border rotate-[4deg] origin-center`} 37 41 style={{ 38 42 backgroundImage: `url(${previewImage?.data.src})`, 39 43 backgroundPosition: "center", 40 44 }} 41 45 /> 46 + 47 + {permission && ( 48 + <button 49 + className="absolute p-1 top-0.5 right-0.5 hover:text-accent text-secondary sm:hidden sm:group-hover/linkBlock:block" 50 + onClick={(e) => { 51 + e.preventDefault(); 52 + e.stopPropagation(); 53 + rep && 54 + rep.mutate.removeBlock({ 55 + blockEntity: props.entityID, 56 + }); 57 + }} 58 + > 59 + <CloseTiny /> 60 + </button> 61 + )} 42 62 </a> 43 63 ); 44 64 };
+2 -1
components/Blocks/TextBlock/index.tsx
··· 113 113 preview?: boolean; 114 114 }) { 115 115 let initialFact = useEntity(props.entityID, "block/text"); 116 - if (!initialFact) return <pre className="min-h-9" />; 116 + if (!initialFact) 117 + return <pre className={`${props.preview ? "min-h-1" : "min-h-9"}`} />; 117 118 let doc = new Y.Doc(); 118 119 const update = base64.toByteArray(initialFact.data.value); 119 120 Y.applyUpdate(doc, update);
+1 -1
components/Toolbar/LinkButton.tsx
··· 70 70 let [linkValue, setLinkValue] = useState(content); 71 71 72 72 return ( 73 - <div className="w-full flex items-center gap-[6px]"> 73 + <div className="w-full flex items-center gap-[6px] grow"> 74 74 <LinkTextToolbarSmall /> 75 75 <Separator classname="h-6" /> 76 76 <Input
+14 -14
components/Toolbar/index.tsx
··· 78 78 return ( 79 79 <Tooltip.Provider> 80 80 <div className="flex items-center justify-between w-full gap-6"> 81 - <div className="flex gap-[6px] items-center"> 81 + <div className="flex gap-[6px] items-center grow"> 82 82 {toolbarState === "default" ? ( 83 83 <> 84 84 <TextDecorationButton ··· 261 261 }; 262 262 263 263 return ( 264 - <div className={`max-w-sm flex gap-2 rounded-md "text-secondary`}> 264 + <div className={`flex gap-2 rounded-md text-secondary grow pr-2`}> 265 265 <> 266 + <BlockLinkSmall className="shrink-0" /> 267 + <Separator classname="h-6" /> 266 268 <Input 267 269 autoFocus 268 270 type="url" ··· 276 278 } 277 279 }} 278 280 /> 279 - <div className="flex items-center gap-3 "> 280 - <button 281 - className="hover:text-accent" 282 - onMouseDown={(e) => { 283 - e.preventDefault(); 284 - submit(); 285 - }} 286 - > 287 - <CheckTiny /> 288 - </button> 289 - </div> 281 + <button 282 + className="hover:text-accent -mr-6" 283 + onMouseDown={(e) => { 284 + e.preventDefault(); 285 + submit(); 286 + }} 287 + > 288 + <CheckTiny /> 289 + </button> 290 290 </> 291 291 </div> 292 292 ); ··· 393 393 if (state === "normal") 394 394 return ( 395 395 <div className="flex w-full justify-between items-center gap-4"> 396 - <div className="flex items-center gap-[6px]"> 396 + <div className="flex items-center gap-[6px] w-full"> 397 397 <BlockSmall /> 398 398 <Separator classname="h-6" /> 399 399 <ToolbarButton tooltipContent=<div>Add an Image</div>>