mirror of
https://github.com/coracle-social/flotilla.git
synced 2025-12-11 11:27:03 +00:00
Tweak profiles/search
This commit is contained in:
@@ -2,15 +2,18 @@
|
|||||||
import {onMount} from "svelte"
|
import {onMount} from "svelte"
|
||||||
import {formatTimestampRelative} from "@welshman/lib"
|
import {formatTimestampRelative} from "@welshman/lib"
|
||||||
import type {Filter} from "@welshman/util"
|
import type {Filter} from "@welshman/util"
|
||||||
|
import {NOTE, GROUPS, MESSAGE, THREAD, COMMENT, getRelayTags, getListTags} from "@welshman/util"
|
||||||
import {deriveEvents} from "@welshman/store"
|
import {deriveEvents} from "@welshman/store"
|
||||||
import {load} from "@welshman/net"
|
import {load} from "@welshman/net"
|
||||||
import {Router} from "@welshman/router"
|
import {Router} from "@welshman/router"
|
||||||
import {repository, loadRelaySelections} from "@welshman/app"
|
import {repository, loadRelaySelections} from "@welshman/app"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Link from "@lib/components/Link.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import Profile from "@app/components/Profile.svelte"
|
import Profile from "@app/components/Profile.svelte"
|
||||||
import ProfileInfo from "@app/components/ProfileInfo.svelte"
|
import ProfileInfo from "@app/components/ProfileInfo.svelte"
|
||||||
import {pubkeyLink} from "@app/state"
|
import ProfileDetail from "@app/components/ProfileDetail.svelte"
|
||||||
|
import {membershipsByPubkey} from "@app/state"
|
||||||
|
import {pushModal} from "@app/modal"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
pubkey: string
|
pubkey: string
|
||||||
@@ -18,17 +21,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const {pubkey, url}: Props = $props()
|
const {pubkey, url}: Props = $props()
|
||||||
|
|
||||||
const filters: Filter[] = [{authors: [pubkey], limit: 1}]
|
const filters: Filter[] = [{authors: [pubkey], limit: 1}]
|
||||||
const events = deriveEvents(repository, {filters})
|
const events = deriveEvents(repository, {filters})
|
||||||
|
const membership = $derived($membershipsByPubkey.get(pubkey))
|
||||||
|
const relays = $derived(getRelayTags(getListTags(membership)))
|
||||||
|
|
||||||
|
const openProfile = () => pushModal(ProfileDetail, {pubkey, url})
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
// Make sure we have their relay selections before we load their posts
|
// Make sure we have their relay selections before we load their posts
|
||||||
await loadRelaySelections(pubkey)
|
await loadRelaySelections(pubkey)
|
||||||
|
|
||||||
// Load at least one note, regardless of time frame
|
// Load groups and at least one note, regardless of time frame
|
||||||
load({
|
load({
|
||||||
filters: [{authors: [pubkey], limit: 1}],
|
filters: [
|
||||||
|
{authors: [pubkey], kinds: [GROUPS]},
|
||||||
|
{authors: [pubkey], limit: 1, kinds: [NOTE, MESSAGE, THREAD, COMMENT]},
|
||||||
|
],
|
||||||
relays: Router.get().FromPubkeys([pubkey]).getUrls(),
|
relays: Router.get().FromPubkeys([pubkey]).getUrls(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -37,19 +46,27 @@
|
|||||||
<div class="card2 bg-alt col-2 shadow-xl">
|
<div class="card2 bg-alt col-2 shadow-xl">
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<Profile {pubkey} {url} />
|
<Profile {pubkey} {url} />
|
||||||
<Link external href={pubkeyLink(pubkey)} class="btn btn-primary hidden sm:flex">
|
<Button onclick={openProfile} class="btn btn-primary hidden sm:flex">
|
||||||
<Icon icon="user-circle" />
|
<Icon icon="user-circle" />
|
||||||
See Complete Profile
|
View Profile
|
||||||
</Link>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<ProfileInfo {pubkey} {url} />
|
<ProfileInfo {pubkey} {url} />
|
||||||
{#if $events.length > 0}
|
<div class="flex flex-wrap gap-2">
|
||||||
<div class="bg-alt badge badge-neutral border-none">
|
{#if $events.length > 0}
|
||||||
Last active {formatTimestampRelative($events[0].created_at)}
|
<div class="badge badge-neutral">
|
||||||
</div>
|
Last active {formatTimestampRelative($events[0].created_at)}
|
||||||
{/if}
|
</div>
|
||||||
<Link external href={pubkeyLink(pubkey)} class="btn btn-primary sm:hidden">
|
{/if}
|
||||||
|
{#if relays.length > 0}
|
||||||
|
<div class="badge badge-neutral">
|
||||||
|
{relays.length}
|
||||||
|
{relays.length === 1 ? "space" : "spaces"}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<Button onclick={openProfile} class="btn btn-primary sm:hidden">
|
||||||
<Icon icon="user-circle" />
|
<Icon icon="user-circle" />
|
||||||
See Complete Profile
|
View Profile
|
||||||
</Link>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as nip19 from "nostr-tools/nip19"
|
import * as nip19 from "nostr-tools/nip19"
|
||||||
import {removeNil} from "@welshman/lib"
|
import {removeNil} from "@welshman/lib"
|
||||||
import {displayPubkey, getPubkeyTagValues, getListTags} from "@welshman/util"
|
import {displayPubkey} from "@welshman/util"
|
||||||
import {
|
import {
|
||||||
session,
|
|
||||||
userFollows,
|
|
||||||
deriveUserWotScore,
|
|
||||||
deriveHandleForPubkey,
|
deriveHandleForPubkey,
|
||||||
displayHandle,
|
displayHandle,
|
||||||
deriveProfile,
|
deriveProfile,
|
||||||
@@ -14,7 +11,7 @@
|
|||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import Avatar from "@lib/components/Avatar.svelte"
|
import Avatar from "@lib/components/Avatar.svelte"
|
||||||
import WotScore from "@lib/components/WotScore.svelte"
|
import WotScore from "@app/components/WotScore.svelte"
|
||||||
import ProfileDetail from "@app/components/ProfileDetail.svelte"
|
import ProfileDetail from "@app/components/ProfileDetail.svelte"
|
||||||
import {pushModal} from "@app/modal"
|
import {pushModal} from "@app/modal"
|
||||||
import {clip} from "@app/toast"
|
import {clip} from "@app/toast"
|
||||||
@@ -32,15 +29,10 @@
|
|||||||
const profile = deriveProfile(pubkey, relays)
|
const profile = deriveProfile(pubkey, relays)
|
||||||
const profileDisplay = deriveProfileDisplay(pubkey, relays)
|
const profileDisplay = deriveProfileDisplay(pubkey, relays)
|
||||||
const handle = deriveHandleForPubkey(pubkey)
|
const handle = deriveHandleForPubkey(pubkey)
|
||||||
const score = deriveUserWotScore(pubkey)
|
|
||||||
|
|
||||||
const openProfile = () => pushModal(ProfileDetail, {pubkey, url})
|
const openProfile = () => pushModal(ProfileDetail, {pubkey, url})
|
||||||
|
|
||||||
const copyPubkey = () => clip(nip19.npubEncode(pubkey))
|
const copyPubkey = () => clip(nip19.npubEncode(pubkey))
|
||||||
|
|
||||||
const following = $derived(
|
|
||||||
pubkey === $session!.pubkey || getPubkeyTagValues(getListTags($userFollows)).includes(pubkey),
|
|
||||||
)
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex max-w-full items-start gap-3">
|
<div class="flex max-w-full items-start gap-3">
|
||||||
@@ -52,7 +44,7 @@
|
|||||||
<Button onclick={openProfile} class="text-bold overflow-hidden text-ellipsis">
|
<Button onclick={openProfile} class="text-bold overflow-hidden text-ellipsis">
|
||||||
{$profileDisplay}
|
{$profileDisplay}
|
||||||
</Button>
|
</Button>
|
||||||
<WotScore score={$score} active={following} />
|
<WotScore {pubkey} />
|
||||||
</div>
|
</div>
|
||||||
{#if $handle}
|
{#if $handle}
|
||||||
<div class="overflow-hidden text-ellipsis text-sm opacity-75">
|
<div class="overflow-hidden text-ellipsis text-sm opacity-75">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {goto} from "$app/navigation"
|
import {goto} from "$app/navigation"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
|
import Avatar from "@lib/components/Avatar.svelte"
|
||||||
import Link from "@lib/components/Link.svelte"
|
import Link from "@lib/components/Link.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||||
@@ -35,8 +36,8 @@
|
|||||||
</Button>
|
</Button>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<Link external href={pubkeyLink(pubkey)} class="btn btn-neutral">
|
<Link external href={pubkeyLink(pubkey)} class="btn btn-neutral">
|
||||||
<Icon icon="user-circle" />
|
<Avatar src="/coracle.png" />
|
||||||
See Complete Profile
|
Open in Coracle
|
||||||
</Link>
|
</Link>
|
||||||
<Button onclick={openChat} class="btn btn-primary">
|
<Button onclick={openChat} class="btn btn-primary">
|
||||||
<Icon icon="letter" />
|
<Icon icon="letter" />
|
||||||
|
|||||||
@@ -14,5 +14,5 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $profile}
|
{#if $profile}
|
||||||
<Content event={{content: $profile.about, tags: []}} hideMediaAtDepth={0} />
|
<Content event={{content: $profile.about || "", tags: []}} hideMediaAtDepth={0} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -15,19 +15,21 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {clamp} from "@welshman/lib"
|
import {clamp} from "@welshman/lib"
|
||||||
|
import {pubkey, getFollows, deriveUserWotScore} from "@welshman/app"
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
score: any
|
pubkey: string
|
||||||
max?: number
|
|
||||||
active?: boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const {score, max = 100, active = false}: Props = $props()
|
const {pubkey: target}: Props = $props()
|
||||||
|
|
||||||
|
const max = 100
|
||||||
const radius = 6
|
const radius = 6
|
||||||
const center = radius + 1
|
const center = radius + 1
|
||||||
|
|
||||||
const normalizedScore = $derived(clamp([0, max], score) / max)
|
const score = deriveUserWotScore(target)
|
||||||
|
const active = $derived(getFollows($pubkey!).includes(target))
|
||||||
|
const normalizedScore = $derived(clamp([0, max], $score) / max)
|
||||||
const dashOffset = $derived(100 - 44 * normalizedScore)
|
const dashOffset = $derived(100 - 44 * normalizedScore)
|
||||||
const style = $derived(`transform: rotate(${135 - normalizedScore * 180}deg)`)
|
const style = $derived(`transform: rotate(${135 - normalizedScore * 180}deg)`)
|
||||||
const stroke = $derived(active ? "var(--primary)" : "var(--base-content)")
|
const stroke = $derived(active ? "var(--primary)" : "var(--base-content)")
|
||||||
@@ -1,14 +1,8 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {removeNil} from "@welshman/lib"
|
import {removeNil} from "@welshman/lib"
|
||||||
import {displayPubkey, getPubkeyTagValues, getListTags} from "@welshman/util"
|
import {displayPubkey} from "@welshman/util"
|
||||||
import {
|
import {deriveHandleForPubkey, displayHandle, deriveProfileDisplay} from "@welshman/app"
|
||||||
userFollows,
|
import WotScore from "@app/components/WotScore.svelte"
|
||||||
deriveUserWotScore,
|
|
||||||
deriveHandleForPubkey,
|
|
||||||
displayHandle,
|
|
||||||
deriveProfileDisplay,
|
|
||||||
} from "@welshman/app"
|
|
||||||
import WotScore from "@lib/components/WotScore.svelte"
|
|
||||||
import ProfileCircle from "@app/components/ProfileCircle.svelte"
|
import ProfileCircle from "@app/components/ProfileCircle.svelte"
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -21,9 +15,6 @@
|
|||||||
const pubkey = value
|
const pubkey = value
|
||||||
const profileDisplay = deriveProfileDisplay(pubkey, removeNil([url]))
|
const profileDisplay = deriveProfileDisplay(pubkey, removeNil([url]))
|
||||||
const handle = deriveHandleForPubkey(pubkey)
|
const handle = deriveHandleForPubkey(pubkey)
|
||||||
const score = deriveUserWotScore(pubkey)
|
|
||||||
|
|
||||||
const following = $derived(getPubkeyTagValues(getListTags($userFollows)).includes(pubkey))
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex max-w-full gap-3">
|
<div class="flex max-w-full gap-3">
|
||||||
@@ -35,7 +26,7 @@
|
|||||||
<div class="text-bold overflow-hidden text-ellipsis text-base">
|
<div class="text-bold overflow-hidden text-ellipsis text-base">
|
||||||
{$profileDisplay}
|
{$profileDisplay}
|
||||||
</div>
|
</div>
|
||||||
<WotScore score={$score} active={following} />
|
<WotScore {pubkey} />
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-hidden text-ellipsis text-sm opacity-75">
|
<div class="overflow-hidden text-ellipsis text-sm opacity-75">
|
||||||
{$handle ? displayHandle($handle) : displayPubkey(pubkey)}
|
{$handle ? displayHandle($handle) : displayPubkey(pubkey)}
|
||||||
|
|||||||
@@ -405,7 +405,7 @@ export const memberships = deriveEventsMapped<PublishedList>(repository, {
|
|||||||
})
|
})
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
indexStore: membershipByPubkey,
|
indexStore: membershipsByPubkey,
|
||||||
deriveItem: deriveMembership,
|
deriveItem: deriveMembership,
|
||||||
loadItem: loadMembership,
|
loadItem: loadMembership,
|
||||||
} = collection({
|
} = collection({
|
||||||
@@ -593,12 +593,12 @@ export const userSettingValues = withGetter(
|
|||||||
export const getSetting = <T>(key: keyof Settings["values"]) => userSettingValues.get()[key] as T
|
export const getSetting = <T>(key: keyof Settings["values"]) => userSettingValues.get()[key] as T
|
||||||
|
|
||||||
export const userMembership = withGetter(
|
export const userMembership = withGetter(
|
||||||
derived([pubkey, membershipByPubkey], ([$pubkey, $membershipByPubkey]) => {
|
derived([pubkey, membershipsByPubkey], ([$pubkey, $membershipsByPubkey]) => {
|
||||||
if (!$pubkey) return undefined
|
if (!$pubkey) return undefined
|
||||||
|
|
||||||
loadMembership($pubkey)
|
loadMembership($pubkey)
|
||||||
|
|
||||||
return $membershipByPubkey.get($pubkey)
|
return $membershipsByPubkey.get($pubkey)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
{@render props.input?.()}
|
{@render props.input?.()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="scroll-container content-sizing overflow-auto pt-2">
|
<div class="scroll-container content-sizing h-full overflow-auto pt-2">
|
||||||
{@render props.content?.()}
|
{@render props.content?.()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
import SpaceCheck from "@app/components/SpaceCheck.svelte"
|
import SpaceCheck from "@app/components/SpaceCheck.svelte"
|
||||||
import ProfileCircles from "@app/components/ProfileCircles.svelte"
|
import ProfileCircles from "@app/components/ProfileCircles.svelte"
|
||||||
import {
|
import {
|
||||||
membershipByPubkey,
|
membershipsByPubkey,
|
||||||
getMembershipUrls,
|
getMembershipUrls,
|
||||||
loadMembership,
|
loadMembership,
|
||||||
userRoomsByUrl,
|
userRoomsByUrl,
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
const scores = new Map<string, Set<string>>()
|
const scores = new Map<string, Set<string>>()
|
||||||
|
|
||||||
for (const pubkey of getDefaultPubkeys()) {
|
for (const pubkey of getDefaultPubkeys()) {
|
||||||
for (const url of getMembershipUrls($membershipByPubkey.get(pubkey))) {
|
for (const url of getMembershipUrls($membershipsByPubkey.get(pubkey))) {
|
||||||
addToMapKey(scores, url, pubkey)
|
addToMapKey(scores, url, pubkey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
</label>
|
</label>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet content()}
|
{#snippet content()}
|
||||||
<div class="col-2" bind:this={element}>
|
<div class="col-2 h-full" bind:this={element}>
|
||||||
{#each pubkeys.slice(0, limit) as pubkey (pubkey)}
|
{#each pubkeys.slice(0, limit) as pubkey (pubkey)}
|
||||||
<PeopleItem {pubkey} />
|
<PeopleItem {pubkey} />
|
||||||
{/each}
|
{/each}
|
||||||
|
|||||||
BIN
static/coracle.png
Normal file
BIN
static/coracle.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 89 KiB |
Reference in New Issue
Block a user