3 changed files with 90 additions and 0 deletions
@ -0,0 +1,29 @@ |
|||||||
|
<script lang='ts'> |
||||||
|
import { Tooltip } from 'flowbite-svelte'; |
||||||
|
import { FileCopyOutline } from 'flowbite-svelte-icons'; |
||||||
|
export let displayText = ""; // Shown in UI |
||||||
|
export let copyText = displayText; // Copied to clipboard (default to same if not provided) |
||||||
|
|
||||||
|
async function copyToClipboard() { |
||||||
|
try { |
||||||
|
await navigator.clipboard.writeText(copyText); |
||||||
|
} catch (err) { |
||||||
|
console.error("Failed to copy: ", err); |
||||||
|
} |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<div role='tooltip'> |
||||||
|
<span> |
||||||
|
{displayText} <button class='btn-leather' id='copy-button' onclick={copyToClipboard}><FileCopyOutline class='w-4 h-4 !fill-none dark:!fill-none' /></button> |
||||||
|
</span> |
||||||
|
<Tooltip |
||||||
|
class='tooltip-leather' |
||||||
|
triggeredBy='#copy-button' |
||||||
|
trigger='click' |
||||||
|
placement='bottom' |
||||||
|
type="auto" |
||||||
|
> |
||||||
|
Copied! |
||||||
|
</Tooltip> |
||||||
|
</div> |
||||||
@ -0,0 +1,49 @@ |
|||||||
|
<script lang='ts'> |
||||||
|
import { Avatar } from 'flowbite-svelte'; |
||||||
|
import { type NDKUserProfile } from '@nostr-dev-kit/ndk'; |
||||||
|
import { ndkInstance } from '$lib/ndk'; |
||||||
|
|
||||||
|
let { pubkey } = $props(); |
||||||
|
|
||||||
|
const externalProfileDestination = 'https://nostree.me/' |
||||||
|
let loading = $state(true); |
||||||
|
let npub = $state(''); |
||||||
|
|
||||||
|
let profile = $state<NDKUserProfile | null>(null); |
||||||
|
let pfp = $derived(profile?.image); |
||||||
|
let username = $derived(profile?.name); |
||||||
|
|
||||||
|
async function fetchUserData(pubkey: string) { |
||||||
|
const user = $ndkInstance |
||||||
|
.getUser({ pubkey: pubkey ?? undefined }); |
||||||
|
|
||||||
|
npub = user.npub; |
||||||
|
|
||||||
|
user.fetchProfile() |
||||||
|
.then(userProfile => { |
||||||
|
profile = userProfile; |
||||||
|
loading = false; |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
// Fetch data when component mounts |
||||||
|
$effect(() => { |
||||||
|
if (pubkey) { |
||||||
|
fetchUserData(pubkey); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
|
||||||
|
</script> |
||||||
|
|
||||||
|
{#if loading} |
||||||
|
<span>…</span> |
||||||
|
{:else if pubkey} |
||||||
|
<Avatar rounded |
||||||
|
class='h-6 w-6 mx-1 cursor-pointer inline' |
||||||
|
src={pfp} |
||||||
|
alt={username} /> |
||||||
|
<a class='text-indigo-600 underline' href='{externalProfileDestination}{npub}' target='_blank'>{username}</a> |
||||||
|
{:else} |
||||||
|
<span>Not found</span> |
||||||
|
{/if} |
||||||
Loading…
Reference in new issue