a tool for shared writing and social publishing

update to teh layout, wip comment deisgn

+157 -64
+53 -36
app/p/[didOrHandle]/ProfilePageLayout.tsx
··· 69 69 70 70 if (!props.profile) return; 71 71 return ( 72 - <div 73 - className={` 72 + <div className="h-full"> 73 + <div 74 + className={` 74 75 max-w-prose mx-auto w-full h-full 75 76 flex flex-col 76 77 border border-border-light rounded-lg 77 78 text-center px-3 sm:px-4 mt-8`} 78 - > 79 - <Avatar 80 - src={ 81 - profileRecord.avatar?.ref && 82 - blobRefToSrc(profileRecord.avatar?.ref, props.profile.did) 83 - } 84 - displayName={profileRecord.displayName} 85 - className="mx-auto -mt-8" 86 - giant 87 - /> 88 - <h3 className="pt-2 leading-tight"> 89 - {profileRecord.displayName 90 - ? profileRecord.displayName 91 - : `@${props.profile?.handle}`} 92 - </h3> 93 - {profileRecord.displayName && ( 94 - <div className="text-tertiary text-sm pb-1 italic"> 95 - @{props.profile?.handle} 79 + > 80 + <Avatar 81 + src={ 82 + profileRecord.avatar?.ref && 83 + blobRefToSrc(profileRecord.avatar?.ref, props.profile.did) 84 + } 85 + displayName={profileRecord.displayName} 86 + className="mx-auto -mt-8" 87 + giant 88 + /> 89 + <h3 className="pt-2 leading-tight"> 90 + {profileRecord.displayName 91 + ? profileRecord.displayName 92 + : `@${props.profile?.handle}`} 93 + </h3> 94 + {profileRecord.displayName && ( 95 + <div className="text-tertiary text-sm pb-1 italic"> 96 + @{props.profile?.handle} 97 + </div> 98 + )} 99 + <div className="text-secondary">{profileRecord.description}</div> 100 + <div className="flex flex-row gap-2 mx-auto my-3"> 101 + <div>pub 1</div> 102 + <div>pub 2</div> 96 103 </div> 97 - )} 98 - <div className="text-secondary">{profileRecord.description}</div> 99 - <div className="flex flex-row gap-2 mx-auto my-3"> 100 - {props.publications.map((p) => ( 101 - <PublicationCard 102 - key={p.uri} 103 - record={p.record as PubLeafletPublication.Record} 104 - uri={p.uri} 104 + <ProfileTabs tab={tab} setTab={setTab} /> 105 + 106 + <div className="h-full overflow-y-scroll pt-2 flex flex-col"> 107 + <TabContent 108 + tab={tab} 109 + did={props.profile.did} 110 + posts={props.posts} 111 + nextCursor={props.nextCursor} 105 112 /> 106 - ))} 113 + </div> 114 + <div className="text-secondary">{profileRecord.description}</div> 115 + <div className="flex flex-row gap-2 mx-auto my-3"> 116 + {props.publications.map((p) => ( 117 + <PublicationCard 118 + key={p.uri} 119 + record={p.record as PubLeafletPublication.Record} 120 + uri={p.uri} 121 + /> 122 + ))} 123 + </div> 124 + <ProfileTabs tab={tab} setTab={setTab} /> 125 + <TabContent 126 + tab={tab} 127 + did={props.profile.did} 128 + posts={props.posts} 129 + nextCursor={props.nextCursor} 130 + /> 107 131 </div> 108 - <ProfileTabs tab={tab} setTab={setTab} /> 109 - <TabContent 110 - tab={tab} 111 - did={props.profile.did} 112 - posts={props.posts} 113 - nextCursor={props.nextCursor} 114 - /> 115 132 </div> 116 133 ); 117 134 };
-14
app/p/[didOrHandle]/ProfileTabs/Activity/Activity.tsx
··· 1 - export const Activity = (props: { 2 - icon: React.ReactNode; 3 - activity: React.ReactNode; 4 - content: React.ReactNode; 5 - }) => { 6 - return ( 7 - <div className="flex flex-col"> 8 - <div className="flex gap-2 items-center text-tertiary font-bold"> 9 - {props.icon} {props.activity} 10 - </div> 11 - <div>{props.content}</div> 12 - </div> 13 - ); 14 - };
-12
app/p/[didOrHandle]/ProfileTabs/Activity/Comment.tsx
··· 1 - import { CommentTiny } from "components/Icons/CommentTiny"; 2 - import { Activity } from "./Activity"; 3 - 4 - export const CommentActivty = () => { 5 - return ( 6 - <Activity 7 - icon={<CommentTiny />} 8 - activity={"celine commented"} 9 - content={<div>hello</div>} 10 - /> 11 - ); 12 - };
app/p/[didOrHandle]/ProfileTabs/Activity/Post.tsx app/p/[didOrHandle]/ProfileTabs/TabContent.tsx/Post.tsx
app/p/[didOrHandle]/ProfileTabs/Activity/Publication.tsx

This is a binary file and will not be displayed.

app/p/[didOrHandle]/ProfileTabs/Activity/Subscription.tsx app/p/[didOrHandle]/ProfileTabs/TabContent.tsx/Subscription.tsx
+101
app/p/[didOrHandle]/ProfileTabs/TabContent.tsx/Comment.tsx
··· 1 + import Post from "app/lish/[did]/[publication]/[rkey]/l-quote/[quote]/page"; 2 + import { CommentTiny } from "components/Icons/CommentTiny"; 3 + 4 + export const CommentTabContent = () => { 5 + let isReply = true; 6 + return ( 7 + <> 8 + <CommentWrapper2 isReply /> 9 + <CommentWrapper2 /> 10 + <CommentWrapper2 /> 11 + <CommentWrapper2 isReply /> 12 + </> 13 + ); 14 + }; 15 + 16 + const PostListingCompact = (props: { title: string; pubName: string }) => { 17 + return ( 18 + <div className=" flex gap-2 justify-between border-b border-border-light pt-2 pb-0.5 text-xs text-tertiary font-bold text-left"> 19 + {props.title} 20 + <div className="flex gap-2 text-xs text-tertiary font-normal items-center"> 21 + {props.pubName} 22 + </div> 23 + </div> 24 + ); 25 + }; 26 + 27 + const Comment = (props: { 28 + displayName: React.ReactNode; 29 + handle: string; 30 + comment: string; 31 + reply?: boolean; 32 + }) => { 33 + return ( 34 + <div className={`w-full flex flex-col ${props.reply ? "text-xs" : ""}`}> 35 + <div className="flex gap-2"> 36 + <div className="flex flex-col min-h-full shrink-0 "> 37 + <div className={`rounded-full bg-test shrink-0 w-5 h-5`} /> 38 + 39 + {props.reply && ( 40 + <div className={`border-l border-border-light h-full mx-auto`} /> 41 + )} 42 + </div> 43 + <div className={`flex flex-col`}> 44 + <div className="flex flex-row gap-2"> 45 + <div 46 + className={` font-bold ${props.reply ? "text-tertiary" : "text-primary"}`} 47 + > 48 + {props.displayName} 49 + </div> 50 + {props.reply && <div>reply</div>} 51 + </div> 52 + <div 53 + className={`w-full text-left ${props.reply ? "truncate text-tertiary" : "text-secondary"} `} 54 + > 55 + {props.comment} 56 + </div> 57 + </div> 58 + </div> 59 + </div> 60 + ); 61 + }; 62 + 63 + const CommentWrapper1 = (props: { isReply?: boolean }) => { 64 + return ( 65 + <div className="flex flex-col rounded-md pb-8"> 66 + <PostListingCompact title="Post Title Here" pubName="Pub Name" /> 67 + {props.isReply && ( 68 + <Comment 69 + displayName="jared" 70 + handle="awarm.space" 71 + comment="this is some content that i am would like a reply to. It's really really long" 72 + reply 73 + /> 74 + )} 75 + <Comment 76 + displayName="celine" 77 + handle="cozylittle.house" 78 + comment="Here's my reply! I'm hoping i can makie ti long enought to space two lines. Do we want rich text here? Probably not since we dont support that anyway lol" 79 + /> 80 + </div> 81 + ); 82 + }; 83 + 84 + const CommentWrapper2 = (props: { isReply?: boolean }) => { 85 + return ( 86 + <div className="mb-8"> 87 + <Comment 88 + displayName={ 89 + <div className="font-normal text-tertiary text-sm"> 90 + <span className="font-bold">celine </span>commented on{" "} 91 + <span className=" italic text-accent-contrast"> 92 + Leaflet Lab Notes 93 + </span> 94 + </div> 95 + } 96 + handle="cozylittle.house" 97 + comment="Here's my reply! I'm hoping i can makie ti long enought to space two lines. Do we want rich text here? Probably not since we dont support that anyway lol" 98 + /> 99 + </div> 100 + ); 101 + };
+3 -2
app/p/[didOrHandle]/ProfileTabs/Tabs.tsx
··· 6 6 import { getProfilePosts } from "../getProfilePosts"; 7 7 import useSWRInfinite from "swr/infinite"; 8 8 import { useEffect, useRef } from "react"; 9 + import { CommentTabContent } from "./TabContent.tsx/Comment"; 9 10 10 11 export const ProfileTabs = (props: { 11 12 tab: profileTabsType; ··· 38 39 }} 39 40 /> 40 41 </div> 41 - <hr className="border-border-light mb-2 mt-1" /> 42 + <hr className="border-border-light mt-1" /> 42 43 </div> 43 44 ); 44 45 }; ··· 59 60 /> 60 61 ); 61 62 case "comments": 62 - return <div>comments here!</div>; 63 + return <CommentTabContent />; 63 64 case "subscriptions": 64 65 return <div>subscriptions here!</div>; 65 66 }