From d744cf053a8d29a6575a4ca6c67949b349e809c1 Mon Sep 17 00:00:00 2001 From: Kuba Suder Date: Wed, 20 May 2026 15:07:25 +0200 Subject: [PATCH] added profile popover on hover of handle/avatar --- src/api/bluesky_api.ts | 14 +- src/components/ProfilePopover.svelte | 71 ++++++++++ src/components/ProfilePopoverContents.svelte | 142 +++++++++++++++++++ src/components/posts/PostHeader.svelte | 40 ++++-- 4 files changed, 251 insertions(+), 16 deletions(-) create mode 100644 src/components/ProfilePopover.svelte create mode 100644 src/components/ProfilePopoverContents.svelte diff --git a/src/api/bluesky_api.ts b/src/api/bluesky_api.ts index 6b34788..b0781bc 100644 --- a/src/api/bluesky_api.ts +++ b/src/api/bluesky_api.ts @@ -1,6 +1,6 @@ import { HandleCache } from './handle_cache.js'; import { appView, constellationAPI } from '../api.js'; -import { APIError, Minisky, type FetchAllOnPageLoad, type MiniskyConfig, type MiniskyOptions } from './minisky.js'; +import { APIError, Minisky, type FetchAllOnPageLoad, type MiniskyConfig, type MiniskyOptions, type MiniskyRequestOptions } from './minisky.js'; import { atURI, feedPostTime } from '../utils.js'; import { Post } from '../models/posts.js'; import { parseBlueskyPostURL } from '../router.js'; @@ -101,14 +101,14 @@ export class BlueskyAPI extends Minisky { return await this.getRequest('app.bsky.feed.getPostThread', { uri: uri, depth: 10 }); } - async loadUserProfile(handle: string): Promise { - if (this.profiles[handle]) { + async loadUserProfile(handle: string, full: boolean = false, options: MiniskyRequestOptions = {}): Promise { + if (this.profiles[handle] && (!full || 'description' in this.profiles[handle])) { return this.profiles[handle]; - } else { - let profile = await this.getRequest('app.bsky.actor.getProfile', { actor: handle }); - this.cacheProfile(profile); - return profile; } + + let profile = await this.getRequest('app.bsky.actor.getProfile', { actor: handle }, options); + this.cacheProfile(profile); + return profile; } async autocompleteUsers(query: string): Promise { diff --git a/src/components/ProfilePopover.svelte b/src/components/ProfilePopover.svelte new file mode 100644 index 0000000..47d1d60 --- /dev/null +++ b/src/components/ProfilePopover.svelte @@ -0,0 +1,71 @@ + + + + +{#if profile} + +{/if} diff --git a/src/components/ProfilePopoverContents.svelte b/src/components/ProfilePopoverContents.svelte new file mode 100644 index 0000000..b7543ff --- /dev/null +++ b/src/components/ProfilePopoverContents.svelte @@ -0,0 +1,142 @@ + + +
+
+
+ {#if profile.viewer?.muted} + + {:else if profile.avatar} + Avatar + {:else} + + {/if} +
+ +
+

{displayName}

+
{handle}
+ + {#if profile.pronouns} +
{profile.pronouns}
+ {/if} + + {#if profile.description} +

{profile.description}

+ {/if} +
+
+
+ + diff --git a/src/components/posts/PostHeader.svelte b/src/components/posts/PostHeader.svelte index 70992fc..fba88b1 100644 --- a/src/components/posts/PostHeader.svelte +++ b/src/components/posts/PostHeader.svelte @@ -3,11 +3,13 @@ import { avatarPreloader } from '../../utils.js'; import { PostPresenter } from '../../utils/post_presenter.js'; import PostSubtreeLink from './PostSubtreeLink.svelte'; + import ProfilePopover from '../ProfilePopover.svelte'; let { post, placement } = getPostContext(); let presenter = new PostPresenter(post, placement); let avatar: HTMLImageElement | undefined = $state(); + let activeAnchor: HTMLElement | undefined = $state(); $effect(() => { if (avatar) { @@ -18,24 +20,35 @@ avatar && avatarPreloader.unobserve(avatar); }; }); + + function showPopover(event: MouseEvent) { + activeAnchor = event.currentTarget as HTMLElement; + } + + function hidePopover() { + activeAnchor = undefined; + } +

- {#if post.muted} - - {:else if post.author.avatar} - Avatar - {:else} - - {/if} + + {#if post.muted} + + {:else if post.author.avatar} + Avatar + {:else} + + {/if} + {post.authorDisplayName} {#if post.isFediPost} - @{post.authorFediHandle} + @{post.authorFediHandle} Mastodon logo {:else} - {post.hasValidHandle ? `@${post.author.handle}` : '[invalid handle]'} + {post.hasValidHandle ? `@${post.author.handle}` : '[invalid handle]'} {/if} • @@ -53,7 +66,16 @@ {/if}

+{#if activeAnchor} + +{/if} +
+