personal web client for Bluesky
typescript solidjs bluesky atcute

root author like

mary.my.id 6334e783 c0360923

verified
Changed files
+36 -5
src
api
models
queries
components
+2
src/api/models/post-thread.tsx
··· 69 69 export interface PostDescendantItem extends BaseDescendant { 70 70 type: 'post'; 71 71 post: AppBskyFeedDefs.PostView; 72 + context: AppBskyFeedDefs.ThreadContext | undefined; 72 73 prev: boolean; 73 74 next: boolean; 74 75 } ··· 329 330 id: post.uri, 330 331 type: 'post', 331 332 post: post, 333 + context: reply.threadContext, 332 334 prev: depth !== 0, 333 335 next: children.length !== 0, 334 336 lines: nlines,
+10 -2
src/api/queries/profile.ts
··· 1 1 import { modifyMutable, reconcile } from 'solid-js/store'; 2 2 3 - import type { AppBskyActorDefs } from '@atcute/client/lexicons'; 3 + import type { AppBskyActorDefs, At } from '@atcute/client/lexicons'; 4 4 import { createQuery } from '@mary/solid-query'; 5 5 6 6 import { useAgent } from '~/lib/states/agent'; 7 7 import { useSession } from '~/lib/states/session'; 8 8 9 + import { findProfilesInCache } from '../cache/profile-shadow'; 9 10 import { dequal } from '../utils/dequal'; 10 11 11 12 export interface ProfileQueryOptions { ··· 50 51 return data; 51 52 }, 52 53 placeholderData(): AppBskyActorDefs.ProfileViewDetailed | undefined { 53 - return queryClient.getQueryData(['profile-precache', $didOrHandle]); 54 + const precache = queryClient.getQueryData(['profile-precache', $didOrHandle]); 55 + if (precache) { 56 + return precache as any; 57 + } 58 + 59 + for (const profile of findProfilesInCache(queryClient, $didOrHandle as At.DID)) { 60 + return profile as any; 61 + } 54 62 }, 55 63 initialData(): AppBskyActorDefs.ProfileViewDetailed | undefined { 56 64 if (currentAccount !== undefined && currentAccount.did === $didOrHandle) {
+1
src/components/threads/post-thread-item.tsx
··· 113 113 <div class="min-w-0 grow py-3"> 114 114 <PostMeta 115 115 post={/* @once */ post()} 116 + context={(item() as PostDescendantItem).context} 116 117 href={href} 117 118 authorHref={authorHref} 118 119 gutterBottom
+23 -3
src/components/timeline/post-meta.tsx
··· 5 5 6 6 import { openModal } from '~/globals/modals'; 7 7 8 + import Avatar from '../avatar'; 9 + import HeartSolidIcon from '../icons-central/heart-solid'; 8 10 import MoreHorizOutlinedIcon from '../icons-central/more-horiz-outline'; 9 11 import TimeAgo from '../time-ago'; 10 12 ··· 13 15 export interface PostMetaProps { 14 16 /** Expected to be static */ 15 17 post: AppBskyFeedDefs.PostView; 18 + context?: AppBskyFeedDefs.ThreadContext; 19 + /** Expected to be static */ 16 20 authorHref: string; 21 + /** Expected to be static */ 17 22 href: string; 18 - compact?: boolean; 23 + /** Expected to be static */ 19 24 gutterBottom?: boolean; 20 25 onPostDelete?: () => void; 21 26 onPostRedraft?: () => void; 22 27 } 23 28 24 - const PostMeta = ({ post, authorHref, href, gutterBottom, onPostDelete, onPostRedraft }: PostMetaProps) => { 29 + const PostMeta = (props: PostMetaProps) => { 25 30 const queryClient = useQueryClient(); 26 31 32 + const post = props.post; 33 + const href = props.href; 34 + const authorHref = props.authorHref; 35 + const gutterBottom = props.gutterBottom; 36 + 37 + const onPostDelete = props.onPostDelete; 38 + const onPostRedraft = props.onPostRedraft; 39 + 27 40 const author = post.author; 28 41 const indexedAt = post.indexedAt; 29 42 ··· 53 66 </TimeAgo> 54 67 </div> 55 68 56 - <div class="shrink-0"> 69 + <div class="flex shrink-0 items-center gap-4"> 70 + {props.context?.rootAuthorLike && ( 71 + <div class="relative"> 72 + <Avatar type="user" size={null} class="h-[18px] w-[18px]" /> 73 + <HeartSolidIcon class="absolute -bottom-1 -left-1.5 h-[14px] w-[14px] stroke-background stroke-[3] text-p-red-600" /> 74 + </div> 75 + )} 76 + 57 77 <button 58 78 onClick={(ev) => { 59 79 const anchor = ev.currentTarget;