a tool for shared writing and social publishing

formatting for desktop text toolbar, added a param on block in database to inlcude parent id

+51 -32
-2
app/[doc_id]/page.tsx
··· 6 6 import { Cards } from "components/Cards"; 7 7 import { ThemeProvider } from "components/ThemeManager/ThemeProvider"; 8 8 import { MobileFooter } from "components/MobileFooter"; 9 - import { DesktopFooter } from "components/DesktopFooter"; 10 9 11 10 export const preferredRegion = ["sfo1"]; 12 11 export const dynamic = "force-dynamic"; ··· 33 32 <Cards rootCard={props.params.doc_id} /> 34 33 </div> 35 34 <MobileFooter entityID={props.params.doc_id} /> 36 - <DesktopFooter /> 37 35 </ThemeProvider> 38 36 </ReplicacheProvider> 39 37 );
+36 -21
components/Cards.tsx
··· 5 5 import { elementId } from "src/utils/elementId"; 6 6 import { ThemePopover } from "./ThemeManager/ThemeSetter"; 7 7 import { Media } from "./Media"; 8 + import { DesktopFooter } from "./DesktopFooter"; 9 + import { TextToolbar } from "./Toolbar"; 8 10 9 11 export function Cards(props: { rootCard: string }) { 10 12 let cards = useUIState((s) => s.openCards); ··· 13 15 return ( 14 16 <div className="pageContent flex pt-2 pb-8 sm:py-6"> 15 17 <div 16 - className="flex justify-end items-start" 17 - style={{ width: `calc((100vw - ${cardWidth}px)/2)` }} 18 + className="spacer flex justify-end items-start" 19 + style={{ width: `calc(50vw - ${cardWidth}px/2)` }} 18 20 > 19 21 <Media mobile={false} className="flex flex-col gap-2 mr-4 mt-2"> 20 22 <PageOptions entityID={props.rootCard} /> 21 23 </Media> 22 24 </div> 23 - <Card entityID={props.rootCard} first /> 24 - {cards.map((card, index) => ( 25 - <div 26 - className="flex items-stretch" 27 - key={card} 28 - ref={index === 0 ? cardRef : null} 29 - > 25 + <div className="flex items-stretch" ref={cardRef}> 26 + <Card entityID={props.rootCard} first /> 27 + </div> 28 + {cards.map((card) => ( 29 + <div className="flex items-stretch" key={card}> 30 30 <Card entityID={card} /> 31 31 </div> 32 32 ))} 33 - <div style={{ width: `calc((100vw - ${cardWidth}px)/2)` }} /> 33 + <div 34 + className="spacer" 35 + style={{ width: `calc((100vw - ${cardWidth}px)/2)` }} 36 + /> 34 37 </div> 35 38 ); 36 39 } ··· 44 47 }; 45 48 46 49 function Card(props: { entityID: string; first?: boolean }) { 50 + let focusedTextBlock = useUIState((s) => s.focusedBlock); 51 + let focusedBlockParent = 52 + focusedTextBlock?.type === "card" ? null : focusedTextBlock?.parent; 47 53 return ( 48 54 <> 49 55 {!props.first && <div className="w-6 md:snap-center" />} 50 - <div 51 - id={elementId.card(props.entityID).container} 52 - style={{ 53 - backgroundColor: "rgba(var(--bg-card), var(--bg-card-alpha))", 54 - }} 55 - className={` 56 - cardWrapper w-[calc(100vw-12px)] md:w-[calc(50vw-32px)] max-w-prose 57 - relative 56 + <div className="cardWrapper w-fit flex relative snap-center"> 57 + <div 58 + id={elementId.card(props.entityID).container} 59 + style={{ 60 + backgroundColor: "rgba(var(--bg-card), var(--bg-card-alpha))", 61 + }} 62 + className={` 63 + card w-[calc(100vw-12px)] md:w-[calc(50vw-32px)] max-w-prose 58 64 grow flex flex-col 59 65 overflow-y-scroll no-scrollbar 60 - snap-center 61 66 rounded-lg border 62 67 ${false ? "shadow-md border-border" : "border-border-light"} 63 68 64 69 `} 65 - > 66 - <Blocks entityID={props.entityID} /> 70 + > 71 + <Media mobile={false} className="absolute bottom-4 w-full z-10 "> 72 + {focusedTextBlock && 73 + focusedTextBlock.type === "block" && 74 + focusedBlockParent === props.entityID && ( 75 + <div className="w-fit mx-auto py-1 px-4 flex gap-2 items-center bg-bg-card border border-border rounded-full shadow-md"> 76 + <TextToolbar /> 77 + </div> 78 + )} 79 + </Media> 80 + <Blocks entityID={props.entityID} /> 81 + </div> 67 82 </div> 68 83 </> 69 84 );
+5 -6
components/DesktopFooter.tsx
··· 6 6 export function DesktopFooter() { 7 7 let focusedTextBlock = useUIState((s) => s.focusedBlock); 8 8 return ( 9 - <Media mobile={false} className="w-full flex gap-2 items-center z-10"> 10 - <div className="flex flex-row gap-2"> 11 - {focusedTextBlock && focusedTextBlock.type === "block" && ( 12 - <TextToolbar /> 13 - )} 14 - </div> 9 + <Media 10 + mobile={false} 11 + className=" absolute bottom-4 w-fit py-1 px-4 bg-bg-card flex gap-2 items-center border border-border rounded-full shadow-md z-10" 12 + > 13 + {focusedTextBlock && focusedTextBlock.type === "block" && <TextToolbar />} 15 14 </Media> 16 15 ); 17 16 }
+1 -1
components/Media.tsx
··· 4 4 export function Media(props: { 5 5 mobile: boolean; 6 6 children: React.ReactNode; 7 - className: string; 7 + className?: string; 8 8 }) { 9 9 let initialRender = useIsInitialRender(); 10 10 let isMobile = useIsMobile();
+5 -1
components/TextBlock/index.tsx
··· 249 249 onFocus={() => { 250 250 useUIState.getState().setSelectedBlock(props.entityID); 251 251 useUIState.setState(() => ({ 252 - focusedBlock: { type: "block", entityID: props.entityID }, 252 + focusedBlock: { 253 + type: "block", 254 + entityID: props.entityID, 255 + parent: props.parent, 256 + }, 253 257 })); 254 258 }} 255 259 onSelect={() => {
+4 -1
src/useUIState.ts
··· 4 4 export const useUIState = create( 5 5 combine( 6 6 { 7 - focusedBlock: null as { type: "block" | "card"; entityID: string } | null, 7 + focusedBlock: null as 8 + | { type: "card"; entityID: string } 9 + | { type: "block"; entityID: string; parent: string } 10 + | null, 8 11 openCards: [] as string[], 9 12 selectedBlock: [] as string[], 10 13 },