a tool for shared writing and social publishing

fixed some layout with popover, now opens on tap rather than hover (#255)

* fixed some layout with popover, now opens on tap rather than hover

* little popover fixes

authored by cozylittle.house and committed by

GitHub 4e80ae0c 96ed3674

+90 -64
+56 -36
app/(home-pages)/p/[didOrHandle]/ProfileHeader.tsx
··· 1 1 "use client"; 2 2 import { Avatar } from "components/Avatar"; 3 - import { AppBskyActorProfile, PubLeafletPublication } from "lexicons/api"; 4 - import { blobRefToSrc } from "src/utils/blobRefToSrc"; 5 - import type { ProfileData } from "./layout"; 3 + import { PubLeafletPublication } from "lexicons/api"; 6 4 import { usePubTheme } from "components/ThemeManager/PublicationThemeProvider"; 7 5 import { colorToString } from "components/ThemeManager/useColorAttribute"; 8 6 import { PubIcon } from "components/ActionBar/Publications"; ··· 25 23 <Avatar 26 24 src={profileRecord.avatar} 27 25 displayName={profileRecord.displayName} 28 - className="mx-auto mt-3 sm:mt-4" 26 + className="profileAvatar mx-auto mt-3 sm:mt-4" 29 27 giant 30 28 /> 31 29 ); 32 30 33 31 const displayNameElement = ( 34 - <h3 className=" px-3 sm:px-4 pt-2 leading-tight"> 32 + <h3 className="profileName px-3 sm:px-4 pt-2 leading-tight"> 35 33 {profileRecord.displayName 36 34 ? profileRecord.displayName 37 35 : `@${props.profile.handle}`} ··· 40 38 41 39 const handleElement = profileRecord.displayName && ( 42 40 <div 43 - className={`text-tertiary ${props.popover ? "text-xs" : "text-sm"} pb-1 italic px-3 sm:px-4 truncate`} 41 + className={`profileHandle text-secondary ${props.popover ? "text-sm" : "text-sm"} px-3 sm:px-4 truncate`} 44 42 > 45 43 @{props.profile.handle} 46 44 </div> 47 45 ); 46 + console.log(props.profile); 48 47 49 48 return ( 50 49 <div 51 - className={`flex flex-col relative ${props.popover && "text-sm"}`} 50 + className={`profileHeader flex flex-col relative `} 52 51 id="profile-header" 53 52 > 54 - <ProfileLinks handle={props.profile.handle || ""} /> 55 - <div className="flex flex-col"> 56 - <div className="flex flex-col group"> 53 + {!props.popover && <ProfileLinks handle={props.profile.handle || ""} />} 54 + <div className="profileInfo flex flex-col gap-3"> 55 + <div className="profileNameAndHandle flex flex-col "> 57 56 {props.popover ? ( 58 57 <SpeedyLink className={"hover:no-underline!"} href={profileUrl}> 59 58 {avatarElement} ··· 61 60 ) : ( 62 61 avatarElement 63 62 )} 64 - {props.popover ? ( 65 - <SpeedyLink 66 - className={" text-primary group-hover:underline"} 67 - href={profileUrl} 68 - > 69 - {displayNameElement} 70 - </SpeedyLink> 71 - ) : ( 72 - displayNameElement 73 - )} 74 - {props.popover && handleElement ? ( 75 - <SpeedyLink className={"group-hover:underline"} href={profileUrl}> 76 - {handleElement} 77 - </SpeedyLink> 78 - ) : ( 79 - handleElement 80 - )} 63 + {displayNameElement} 64 + 65 + {handleElement} 66 + <KnownFollowers 67 + viewer={props.profile.viewer} 68 + did={props.profile.did} 69 + /> 70 + 71 + <pre className="profileDescription pt-1 px-3 sm:px-4 whitespace-pre-wrap"> 72 + {profileRecord.description 73 + ? parseDescription(profileRecord.description) 74 + : null} 75 + </pre> 81 76 </div> 82 - <pre className="text-secondary px-3 sm:px-4 whitespace-pre-wrap"> 83 - {profileRecord.description 84 - ? parseDescription(profileRecord.description) 85 - : null} 86 - </pre> 87 - <div className=" w-full overflow-x-scroll py-3 mb-3 "> 77 + 78 + <div className="profilePublicationCards w-full overflow-x-scroll"> 88 79 <div 89 80 className={`grid grid-flow-col gap-2 mx-auto w-fit px-3 sm:px-4 ${props.popover ? "auto-cols-[164px]" : "auto-cols-[164px] sm:auto-cols-[240px]"}`} 90 81 > ··· 104 95 105 96 const ProfileLinks = (props: { handle: string }) => { 106 97 return ( 107 - <div className="absolute sm:top-4 top-3 sm:right-4 right-3 flex flex-row gap-2"> 98 + <div className="profileLinks absolute sm:top-4 top-3 sm:right-4 right-3 flex flex-row gap-2"> 108 99 <a 109 100 className="text-tertiary hover:text-accent-contrast hover:no-underline!" 110 101 href={`https://bsky.app/profile/${props.handle}`} ··· 124 115 return ( 125 116 <a 126 117 href={`https://${record.base_path}`} 127 - className="border border-border p-2 rounded-lg hover:no-underline! text-primary basis-1/2" 118 + className="profilePublicationCard border border-border p-2 rounded-lg hover:no-underline! text-primary basis-1/2 " 128 119 style={{ backgroundColor: `rgb(${colorToString(bgLeaflet, "rgb")})` }} 129 120 > 130 121 <div ··· 225 216 ? urlWithoutProtocol.slice(0, 50) + "…" 226 217 : urlWithoutProtocol; 227 218 parts.push( 228 - <a key={key++} href={match.href} target="_blank" rel="noopener noreferrer"> 219 + <a 220 + key={key++} 221 + href={match.href} 222 + target="_blank" 223 + rel="noopener noreferrer" 224 + > 229 225 {displayText} 230 226 </a>, 231 227 ); ··· 241 237 242 238 return parts; 243 239 } 240 + 241 + const KnownFollowers = (props: { 242 + viewer: ProfileViewDetailed["viewer"]; 243 + did: string; 244 + }) => { 245 + if (!props.viewer?.knownFollowers) return null; 246 + let count = props.viewer.knownFollowers.count; 247 + 248 + return ( 249 + <> 250 + <div className="profileKnownFollowers sm:px-4 px-3 text-xs text-tertiary italic"> 251 + Followed by{" "} 252 + <a 253 + className="hover:underline" 254 + href={`https://bsky.app/profile/${props.did}/known-followers`} 255 + target="_blank" 256 + > 257 + {props.viewer?.knownFollowers?.followers[0]?.displayName}{" "} 258 + {count > 1 ? `and ${count - 1} other${count > 2 ? "s" : ""}` : ""} 259 + </a> 260 + </div> 261 + </> 262 + ); 263 + };
+1 -1
app/(home-pages)/p/[didOrHandle]/ProfileTabs.tsx
··· 41 41 const bgColor = cardBorderHidden ? "var(--bg-leaflet)" : "var(--bg-page)"; 42 42 43 43 return ( 44 - <div className="flex flex-col w-full sticky top-3 sm:top-4 z-20 sm:px-4 px-3"> 44 + <div className="flex flex-col w-full sticky top-3 sm:top-4 z-20 sm:px-4 px-3 pt-6"> 45 45 <div 46 46 style={ 47 47 scrollPosWithinTabContent < 20
+33 -27
components/ProfilePopover.tsx
··· 7 7 import { SpeedyLink } from "./SpeedyLink"; 8 8 import { Tooltip } from "./Tooltip"; 9 9 import { ProfileViewDetailed } from "@atproto/api/dist/client/types/app/bsky/actor/defs"; 10 + import { BlueskyTiny } from "./Icons/BlueskyTiny"; 11 + import { ArrowRightTiny } from "./Icons/ArrowRightTiny"; 10 12 11 13 export const ProfilePopover = (props: { 12 14 trigger: React.ReactNode; ··· 27 29 ); 28 30 29 31 return ( 30 - <Tooltip 32 + <Popover 31 33 className="max-w-sm p-0! text-center" 32 - asChild 33 34 trigger={ 34 - <a 35 + <div 35 36 className="no-underline" 36 - href={`https://leaflet.pub/p/${props.didOrHandle}`} 37 - target="_blank" 38 37 onPointerEnter={(e) => { 39 38 if (hoverTimeout.current) { 40 39 window.clearTimeout(hoverTimeout.current); ··· 53 52 }} 54 53 > 55 54 {props.trigger} 56 - </a> 55 + </div> 57 56 } 58 57 onOpenChange={setIsOpen} 59 58 > ··· 66 65 publications={data.publications} 67 66 popover 68 67 /> 69 - <KnownFollowers viewer={data.profile.viewer} did={data.profile.did} /> 68 + 69 + <ProfileLinks handle={data.profile.handle} /> 70 70 </div> 71 71 ) : ( 72 - <div className="text-secondary py-2 px-4">Profile not found</div> 72 + <div className="text-secondary py-2 px-4">No profile found...</div> 73 73 )} 74 - </Tooltip> 74 + </Popover> 75 75 ); 76 76 }; 77 77 78 - let KnownFollowers = (props: { 79 - viewer: ProfileViewDetailed["viewer"]; 80 - did: string; 81 - }) => { 82 - if (!props.viewer?.knownFollowers) return null; 83 - let count = props.viewer.knownFollowers.count; 78 + const ProfileLinks = (props: { handle: string }) => { 79 + let linkClassName = 80 + "flex gap-1.5 text-tertiary items-center border border-transparent px-1 rounded-md hover:bg-[var(--accent-light)] hover:border-accent-contrast hover:text-accent-contrast no-underline hover:no-underline"; 84 81 return ( 85 - <> 86 - <hr className="border-border" /> 87 - Followed by{" "} 88 - <a 89 - className="hover:underline" 90 - href={`https://bsky.social/profile/${props.did}/known-followers`} 91 - target="_blank" 92 - > 93 - {props.viewer?.knownFollowers?.followers[0]?.displayName}{" "} 94 - {count > 1 ? `and ${count - 1} other${count > 2 ? "s" : ""}` : ""} 95 - </a> 96 - </> 82 + <div className="w-full flex-col"> 83 + <hr className="border-border-light mt-3" /> 84 + <div className="flex gap-2 justify-between sm:px-4 px-3 py-2"> 85 + <div className="flex gap-2"> 86 + <a 87 + href={`https://bsky.app/profile/${props.handle}`} 88 + target="_blank" 89 + className={linkClassName} 90 + > 91 + <BlueskyTiny /> 92 + Bluesky 93 + </a> 94 + </div> 95 + <SpeedyLink 96 + href={`https://leaflet.pub/p/${props.handle}`} 97 + className={linkClassName} 98 + > 99 + Full profile <ArrowRightTiny /> 100 + </SpeedyLink> 101 + </div> 102 + </div> 97 103 ); 98 104 };