a tool for shared writing and social publishing

title input in publish post details form now pulls first block content as title

+26 -9
+1 -1
app/[leaflet_id]/Sidebar.tsx
··· 28 28 <div className="sidebarContainer flex flex-col justify-end h-full w-16 relative"> 29 29 {entity_set.permissions.write && ( 30 30 <Sidebar> 31 - <PublishButton /> 31 + <PublishButton entityID={rootEntity} /> 32 32 <ShareOptions /> 33 33 <ThemePopover entityID={rootEntity} /> 34 34 <HelpButton />
+25 -8
app/[leaflet_id]/actions/PublishButton.tsx
··· 19 19 import { DotLoader } from "components/utils/DotLoader"; 20 20 import { PubLeafletPublication } from "lexicons/api"; 21 21 import { useParams, useRouter } from "next/navigation"; 22 - import { useState } from "react"; 22 + import { useState, useMemo } from "react"; 23 23 import { useIsMobile } from "src/hooks/isMobile"; 24 - import { useReplicache } from "src/replicache"; 24 + import { useReplicache, useEntity } from "src/replicache"; 25 25 import { Json } from "supabase/database.types"; 26 + import { useBlocks } from "src/hooks/queries/useBlocks"; 27 + import * as Y from "yjs"; 28 + import * as base64 from "base64-js"; 29 + import { YJSFragmentToString } from "components/Blocks/TextBlock/RenderYJSFragment"; 26 30 27 - export const PublishButton = () => { 31 + export const PublishButton = (props: { entityID: string }) => { 28 32 let { data: pub } = useLeafletPublicationData(); 29 33 let params = useParams(); 30 34 let router = useRouter(); 31 35 32 - if (!pub) return <PublishToPublicationButton />; 36 + if (!pub) return <PublishToPublicationButton entityID={props.entityID} />; 33 37 if (!pub?.doc) 34 38 return ( 35 39 <ActionButton ··· 86 90 ); 87 91 }; 88 92 89 - const PublishToPublicationButton = () => { 93 + const PublishToPublicationButton = (props: { entityID: string }) => { 90 94 let { identity } = useIdentityData(); 91 95 92 96 let isMobile = useIsMobile(); ··· 115 119 </div> 116 120 ) : ( 117 121 <div className="flex flex-col"> 118 - <PostDetailsForm /> 122 + <PostDetailsForm entityID={props.entityID} /> 119 123 <hr className="border-border-light my-3" /> 120 124 <div> 121 125 <PubSelector ··· 138 142 ); 139 143 }; 140 144 141 - const PostDetailsForm = () => { 145 + const PostDetailsForm = (props: { entityID: string }) => { 142 146 let [description, setDescription] = useState(""); 143 147 148 + let rootPage = useEntity(props.entityID, "root/page")[0].data.value; 149 + let firstBlock = useBlocks(rootPage)[0]; 150 + let firstBlockText = useEntity(firstBlock?.value, "block/text")?.data.value; 151 + 152 + const leafletTitle = useMemo(() => { 153 + if (!firstBlockText) return "Untitled"; 154 + let doc = new Y.Doc(); 155 + const update = base64.toByteArray(firstBlockText); 156 + Y.applyUpdate(doc, update); 157 + let nodes = doc.getXmlElement("prosemirror").toArray(); 158 + return YJSFragmentToString(nodes[0]) || "Untitled"; 159 + }, [firstBlockText]); 160 + 144 161 return ( 145 162 <div className=" flex flex-col gap-1"> 146 163 <div className="text-sm text-tertiary">Post Details</div> 147 164 <div className="flex flex-col gap-2"> 148 - <InputWithLabel label="Title" value={"Title goes here"} disabled /> 165 + <InputWithLabel label="Title" value={leafletTitle} disabled /> 149 166 <InputWithLabel 150 167 label="Description (optional)" 151 168 textarea