Move space add buttons around

This commit is contained in:
Jon Staab
2024-10-15 12:02:11 -07:00
parent 4e83e59249
commit c9826449f2
27 changed files with 82 additions and 74 deletions
+1 -1
View File
@@ -109,7 +109,7 @@
} }
.ellipsize { .ellipsize {
@apply text-ellipsis overflow-hidden; @apply overflow-hidden text-ellipsis;
} }
.content { .content {
+1 -1
View File
@@ -190,7 +190,7 @@ export const setInboxRelayPolicy = (url: string, enabled: boolean) => {
// Relay access // Relay access
export const checkRelayAccess = async (url: string, claim = "") => { export const checkRelayAccess = async (url: string, claim = "") => {
const connection = ctx.net.pool.get(url) const connection = ctx.net.pool.get(url)
await connection.auth.attemptIfRequested() await connection.auth.attemptIfRequested()
await connection.auth.waitIfPending() await connection.auth.waitIfPending()
+1 -4
View File
@@ -70,10 +70,7 @@
<div class="-mt-1 flex-grow pr-1"> <div class="-mt-1 flex-grow pr-1">
{#if showPubkey} {#if showPubkey}
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<Button <Button class="text-bold text-sm" style="color: {colorValue}" on:click={showProfile}>
class="text-bold text-sm"
style="color: {colorValue}"
on:click={showProfile}>
{$profileDisplay} {$profileDisplay}
</Button> </Button>
<span class="text-xs opacity-50">{formatTimestampAsTime(event.created_at)}</span> <span class="text-xs opacity-50">{formatTimestampAsTime(event.created_at)}</span>
+1 -1
View File
@@ -1,6 +1,6 @@
<script lang="ts"> <script lang="ts">
import {goto} from "$app/navigation" import {goto} from "$app/navigation"
import {pubkey} from '@welshman/app' import {pubkey} from "@welshman/app"
import Field from "@lib/components/Field.svelte" import Field from "@lib/components/Field.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
+1 -1
View File
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import {nip19} from 'nostr-tools' import {nip19} from "nostr-tools"
import {Address} from "@welshman/util" import {Address} from "@welshman/util"
import Link from "@lib/components/Link.svelte" import Link from "@lib/components/Link.svelte"
import Spinner from "@lib/components/Spinner.svelte" import Spinner from "@lib/components/Spinner.svelte"
+11 -9
View File
@@ -9,19 +9,21 @@
<div slot="title">What is a private key?</div> <div slot="title">What is a private key?</div>
</ModalHeader> </ModalHeader>
<p> <p>
Most software keeps track of users by giving them a username and password. This gives the service Most software keeps track of users by giving them a username and password. This gives the
<strong>total control</strong> over their users, allowing them to ban them at any time, or sell their activity. service
<strong>total control</strong> over their users, allowing them to ban them at any time, or sell their
activity.
</p> </p>
<p> <p>
On <Link external href="https://nostr.com/">Nostr</Link>, <strong>you</strong> control your own identity and On <Link external href="https://nostr.com/">Nostr</Link>, <strong>you</strong> control your own
social data, through the magic of crytography. The basic idea is that you have a <strong>public key</strong>, identity and social data, through the magic of crytography. The basic idea is that you have a
which acts as your user id, and a <strong>private key</strong> which allows you to authenticate any message <strong>public key</strong>, which acts as your user id, and a <strong>private key</strong> which
you send. allows you to authenticate any message you send.
</p> </p>
<p> <p>
It's very important to keep private keys safe, but this can sometimes be confusing for newcomers. This is why It's very important to keep private keys safe, but this can sometimes be confusing for
flotilla supports <strong>remote signer</strong> login. These services can store your keys securely for you, newcomers. This is why flotilla supports <strong>remote signer</strong> login. These services can
giving you access using a username and password. store your keys securely for you, giving you access using a username and password.
</p> </p>
<Button class="btn btn-primary" on:click={() => history.back()}>Got it</Button> <Button class="btn btn-primary" on:click={() => history.back()}>Got it</Button>
</div> </div>
+16 -10
View File
@@ -2,12 +2,10 @@
import {makeSecret, getNip07, Nip46Broker} from "@welshman/signer" import {makeSecret, getNip07, Nip46Broker} from "@welshman/signer"
import {addSession, loadHandle, nip46Perms, type Session} from "@welshman/app" import {addSession, loadHandle, nip46Perms, type Session} from "@welshman/app"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Field from "@lib/components/Field.svelte"
import Tippy from "@lib/components/Tippy.svelte" import Tippy from "@lib/components/Tippy.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Divider from "@lib/components/Divider.svelte" import Divider from "@lib/components/Divider.svelte"
import Spinner from "@lib/components/Spinner.svelte" import Spinner from "@lib/components/Spinner.svelte"
import SearchSelect from "@lib/components/SearchSelect.svelte"
import SignUp from "@app/components/SignUp.svelte" import SignUp from "@app/components/SignUp.svelte"
import InfoNostr from "@app/components/InfoNostr.svelte" import InfoNostr from "@app/components/InfoNostr.svelte"
import LogInInfoRemoteSigner from "@app/components/LogInInfoRemoteSigner.svelte" import LogInInfoRemoteSigner from "@app/components/LogInInfoRemoteSigner.svelte"
@@ -47,7 +45,7 @@
} }
const secret = makeSecret() const secret = makeSecret()
const {pubkey, nip46, relays = []} = await loadHandle(`${username}@${domain}`) || {} const {pubkey, nip46, relays = []} = (await loadHandle(`${username}@${domain}`)) || {}
if (!pubkey) { if (!pubkey) {
return pushToast({ return pushToast({
@@ -88,7 +86,7 @@
}) })
let username = "" let username = ""
let domain = 'nsec.app' let domain = "nsec.app"
let loading = false let loading = false
</script> </script>
@@ -99,19 +97,24 @@
<Button class="link" on:click={() => pushModal(InfoNostr)}>nostr protocol</Button>, which allows <Button class="link" on:click={() => pushModal(InfoNostr)}>nostr protocol</Button>, which allows
you to own your social identity. you to own your social identity.
</p> </p>
<div class="grid grid-cols-3 gap-3 items-center"> <div class="grid grid-cols-3 items-center gap-3">
<p class="font-bold">Username</p> <p class="font-bold">Username</p>
<label class="input input-bordered flex w-full items-center gap-2 col-span-2"> <label class="input input-bordered col-span-2 flex w-full items-center gap-2">
<Icon icon="user-circle" /> <Icon icon="user-circle" />
<input bind:value={username} disabled={loading} class="grow" type="text" placeholder="username" /> <input
bind:value={username}
disabled={loading}
class="grow"
type="text"
placeholder="username" />
</label> </label>
<Tippy component={LogInInfoRemoteSigner} params={{interactive: true}}> <Tippy component={LogInInfoRemoteSigner} params={{interactive: true}}>
<p class="font-bold cursor-pointer flex gap-2 items-center"> <p class="flex cursor-pointer items-center gap-2 font-bold">
Remote Signer Remote Signer
<Icon icon="info-circle" class="opacity-50" /> <Icon icon="info-circle" class="opacity-50" />
</p> </p>
</Tippy> </Tippy>
<label class="input input-bordered flex w-full items-center gap-2 col-span-2"> <label class="input input-bordered col-span-2 flex w-full items-center gap-2">
<Icon icon="key-minimalistic-square-3" /> <Icon icon="key-minimalistic-square-3" />
<input bind:value={domain} disabled={loading} class="grow" type="text" /> <input bind:value={domain} disabled={loading} class="grow" type="text" />
</label> </label>
@@ -122,7 +125,10 @@
</Button> </Button>
<Divider>Or</Divider> <Divider>Or</Divider>
{#if getNip07()} {#if getNip07()}
<Button disabled={loading} on:click={loginWithNip07} class="btn {username ? 'btn-neutral' : 'btn-primary'}"> <Button
disabled={loading}
on:click={loginWithNip07}
class="btn {username ? 'btn-neutral' : 'btn-primary'}">
<Icon icon="widget" /> <Icon icon="widget" />
Log in with Extension Log in with Extension
</Button> </Button>
@@ -4,7 +4,7 @@
import {pushModal} from "@app/modal" import {pushModal} from "@app/modal"
</script> </script>
<p class="text-sm card2 bg-alt transition-all"> <p class="card2 bg-alt text-sm transition-all">
A remote signer is a simple way to protect your private key. A remote signer is a simple way to protect your private key.
<Button class="link" on:click={() => pushModal(InfoKeys)}>What is a private key?</Button> <Button class="link" on:click={() => pushModal(InfoKeys)}>What is a private key?</Button>
</p> </p>
+5 -3
View File
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import {nip19} from 'nostr-tools' import {nip19} from "nostr-tools"
import {onMount} from "svelte" import {onMount} from "svelte"
import {ago, append, first, sortBy, WEEK, ctx} from "@welshman/lib" import {ago, append, first, sortBy, WEEK, ctx} from "@welshman/lib"
import {NOTE, getAncestorTags, getListTags, getPubkeyTagValues} from "@welshman/util" import {NOTE, getAncestorTags, getListTags, getPubkeyTagValues} from "@welshman/util"
@@ -59,10 +59,12 @@
</div> </div>
</Link> </Link>
<div class="flex gap-2"> <div class="flex gap-2">
<div class="badge badge-neutral bg-alt border-none"> <div class="bg-alt badge badge-neutral border-none">
{roots.length} recent {roots.length === 1 ? "note" : "notes"} {roots.length} recent {roots.length === 1 ? "note" : "notes"}
</div> </div>
<div class="badge badge-neutral bg-alt border-none">Last posted {formatTimestampRelative(event.created_at)}</div> <div class="bg-alt badge badge-neutral border-none">
Last posted {formatTimestampRelative(event.created_at)}
</div>
</div> </div>
{/if} {/if}
</Button> </Button>
+1 -1
View File
@@ -38,7 +38,7 @@
<input bind:value={term} class="grow" type="text" placeholder="Search for relays..." /> <input bind:value={term} class="grow" type="text" placeholder="Search for relays..." />
</label> </label>
</div> </div>
<div class="overflow-auto column gap-2 h-[50vh] mt-16" bind:this={element}> <div class="column mt-16 h-[50vh] gap-2 overflow-auto" bind:this={element}>
{#each $relaySearch {#each $relaySearch
.searchValues(term) .searchValues(term)
.filter(url => !$relays.includes(url)) .filter(url => !$relays.includes(url))
+4 -4
View File
@@ -13,8 +13,8 @@
</script> </script>
<div class="card2 card2-sm bg-alt column gap-2"> <div class="card2 card2-sm bg-alt column gap-2">
<div class="flex items-center gap-4 justify-between"> <div class="flex items-center justify-between gap-4">
<div class="flex items-center gap-2 ellipsize"> <div class="ellipsize flex items-center gap-2">
<Icon icon="remote-controller-minimalistic" /> <Icon icon="remote-controller-minimalistic" />
<p class="ellipsize">{displayRelayUrl(url)}</p> <p class="ellipsize">{displayRelayUrl(url)}</p>
</div> </div>
@@ -23,9 +23,9 @@
{#if $relay?.profile?.description} {#if $relay?.profile?.description}
<p class="ellipsize">{$relay?.profile.description}</p> <p class="ellipsize">{$relay?.profile.description}</p>
{/if} {/if}
<span class="flex items-center gap-1 text-sm whitespace-nowrap"> <span class="flex items-center gap-1 whitespace-nowrap text-sm">
{#if $relay?.profile?.contact} {#if $relay?.profile?.contact}
<Link external class="underline ellipsize" href={$relay.profile.contact} <Link external class="ellipsize underline" href={$relay.profile.contact}
>{displayUrl($relay.profile.contact)}</Link> >{displayUrl($relay.profile.contact)}</Link>
&bull; &bull;
{/if} {/if}
+8
View File
@@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
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 Button from "@lib/components/Button.svelte"
import CardButton from "@lib/components/CardButton.svelte" import CardButton from "@lib/components/CardButton.svelte"
import ModalHeader from "@lib/components/ModalHeader.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte"
@@ -26,6 +27,13 @@
<div slot="info">Enter an invite code or url to join an existing space.</div> <div slot="info">Enter an invite code or url to join an existing space.</div>
</CardButton> </CardButton>
</Button> </Button>
<Link href="/discover">
<CardButton>
<div slot="icon"><Icon icon="compass" size={7} /></div>
<div slot="title">Find a space</div>
<div slot="info">Browse spaces on the discover page.</div>
</CardButton>
</Link>
<Button on:click={startCreate}> <Button on:click={startCreate}>
<CardButton> <CardButton>
<div slot="icon"><Icon icon="add-circle" size={7} /></div> <div slot="icon"><Icon icon="add-circle" size={7} /></div>
@@ -2,7 +2,6 @@
import {goto} from "$app/navigation" import {goto} from "$app/navigation"
import {ctx, tryCatch} from "@welshman/lib" import {ctx, tryCatch} from "@welshman/lib"
import {isRelayUrl, normalizeRelayUrl} from "@welshman/util" import {isRelayUrl, normalizeRelayUrl} from "@welshman/util"
import CardButton from "@lib/components/CardButton.svelte"
import Spinner from "@lib/components/Spinner.svelte" import Spinner from "@lib/components/Spinner.svelte"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import Field from "@lib/components/Field.svelte" import Field from "@lib/components/Field.svelte"
@@ -18,8 +17,6 @@
const back = () => history.back() const back = () => history.back()
const browse = () => goto("/discover")
const confirm = async (url: string) => { const confirm = async (url: string) => {
await addSpaceMembership(url) await addSpaceMembership(url)
@@ -84,13 +81,6 @@
<Button class="link" on:click={() => pushModal(InfoRelay)}>What is a relay?</Button> <Button class="link" on:click={() => pushModal(InfoRelay)}>What is a relay?</Button>
</p> </p>
</Field> </Field>
<Button on:click={browse}>
<CardButton>
<div slot="icon"><Icon icon="compass" size={7} /></div>
<div slot="title">Don't have an invite?</div>
<div slot="info">Browse other spaces on the discover page.</div>
</CardButton>
</Button>
<ModalFooter> <ModalFooter>
<Button class="btn btn-link" on:click={back}> <Button class="btn btn-link" on:click={back}>
<Icon icon="alt-arrow-left" /> <Icon icon="alt-arrow-left" />
+1 -1
View File
@@ -1,4 +1,4 @@
<div class="flex items-center gap-2 p-2 text-xs opacity-50 uppercase"> <div class="flex items-center gap-2 p-2 text-xs uppercase opacity-50">
<div class="h-px flex-grow bg-base-content opacity-25" /> <div class="h-px flex-grow bg-base-content opacity-25" />
<p><slot /></p> <p><slot /></p>
<div class="h-px flex-grow bg-base-content opacity-25" /> <div class="h-px flex-grow bg-base-content opacity-25" />
+1 -1
View File
@@ -118,7 +118,7 @@
"info-circle": InfoCircle, "info-circle": InfoCircle,
"info-square": InfoSquare, "info-square": InfoSquare,
key: Key, key: Key,
'key-minimalistic-square-3': KeyMinimalisticSquare3, "key-minimalistic-square-3": KeyMinimalisticSquare3,
"link-round": LinkRound, "link-round": LinkRound,
login: Login, login: Login,
"login-2": Login2, "login-2": Login2,
+1 -1
View File
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import {goto} from '$app/navigation' import {goto} from "$app/navigation"
export let href export let href
export let external = false export let external = false
+1 -1
View File
@@ -5,6 +5,6 @@
export let props = {} export let props = {}
</script> </script>
<div class="bg-alt modal-box overflow-y-auto overflow-visible" transition:fly={{duration: 100}}> <div class="bg-alt modal-box overflow-visible overflow-y-auto" transition:fly={{duration: 100}}>
<svelte:component this={component} {...props} /> <svelte:component this={component} {...props} />
</div> </div>
+2 -3
View File
@@ -1,13 +1,12 @@
<script lang="ts"> <script lang="ts">
import {page} from "$app/stores" import {page} from "$app/stores"
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import {getPrimaryNavItem} from '@app/routes'
export let title = "" export let title = ""
export let href = "" export let href = ""
$: itemSegment = href.split('/')[1] $: itemSegment = href.split("/")[1]
$: currentSegment = $page.route?.id?.split('/')[1] $: currentSegment = $page.route?.id?.split("/")[1]
$: active = itemSegment === currentSegment $: active = itemSegment === currentSegment
</script> </script>
+10 -5
View File
@@ -1,12 +1,11 @@
<script lang="ts"> <script lang="ts">
import type {SvelteComponent} from "svelte" import type {SvelteComponent} from "svelte"
import {readable} from 'svelte/store' import {readable} from "svelte/store"
import {type Instance} from "tippy.js" import {type Instance} from "tippy.js"
import {append, identity, remove, uniq} from "@welshman/lib" import {identity} from "@welshman/lib"
import {createSearch} from "@welshman/app" import {createSearch} from "@welshman/app"
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Tippy from "@lib/components/Tippy.svelte" import Tippy from "@lib/components/Tippy.svelte"
import Button from "@lib/components/Button.svelte"
import Suggestions from "@lib/editor/Suggestions.svelte" import Suggestions from "@lib/editor/Suggestions.svelte"
import SuggestionString from "@lib/editor/SuggestionString.svelte" import SuggestionString from "@lib/editor/SuggestionString.svelte"
@@ -22,7 +21,7 @@
createSearch(options, { createSearch(options, {
getValue: identity, getValue: identity,
fuseOptions: {keys: [""]}, fuseOptions: {keys: [""]},
}) }),
) )
const select = (newValue: string) => { const select = (newValue: string) => {
@@ -48,7 +47,13 @@
<div class={$$props.class}> <div class={$$props.class}>
<label class="input input-bordered flex w-full items-center gap-3" bind:this={input}> <label class="input input-bordered flex w-full items-center gap-3" bind:this={input}>
<slot name="before" /> <slot name="before" />
<input class="grow" type="text" bind:value={value} on:keydown={onKeyDown} on:focus={onFocus} on:blur={onBlur} /> <input
class="grow"
type="text"
bind:value
on:keydown={onKeyDown}
on:focus={onFocus}
on:blur={onBlur} />
<Icon icon="alt-arrow-down" class="cursor-pointer" /> <Icon icon="alt-arrow-down" class="cursor-pointer" />
</label> </label>
<Tippy <Tippy
+2 -2
View File
@@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import 'tippy.js/animations/shift-away.css' import "tippy.js/animations/shift-away.css"
import {onMount} from "svelte" import {onMount} from "svelte"
import type {SvelteComponent, ComponentType, ComponentProps} from "svelte" import type {SvelteComponent, ComponentType, ComponentProps} from "svelte"
@@ -19,7 +19,7 @@
if (element) { if (element) {
const target = document.createElement("div") const target = document.createElement("div")
popover = tippy(element, {content: target, animation: 'shift-away', ...params}) popover = tippy(element, {content: target, animation: "shift-away", ...params})
instance = new component({target, props}) instance = new component({target, props})
+1 -1
View File
@@ -81,7 +81,7 @@
on:mousedown|preventDefault on:mousedown|preventDefault
on:click|preventDefault={() => select(value)}> on:click|preventDefault={() => select(value)}>
{#if index === i} {#if index === i}
<div transition:slide|local={{axis: "x"}} class="pr-2 flex items-center"> <div transition:slide|local={{axis: "x"}} class="flex items-center pr-2">
<Icon icon="alt-arrow-right" /> <Icon icon="alt-arrow-right" />
</div> </div>
{/if} {/if}
+6 -4
View File
@@ -61,11 +61,13 @@ export const getEditorTags = (editor: Editor) => {
attrs.tag.replace(/^#/, "").toLowerCase(), attrs.tag.replace(/^#/, "").toLowerCase(),
]) ])
const naddrTags = findNodes("naddr", json).map(({attrs: {kind, pubkey, identifier, relays = []}}: any) => { const naddrTags = findNodes("naddr", json).map(
const address = new Address(kind, pubkey, identifier).toString() ({attrs: {kind, pubkey, identifier, relays = []}}: any) => {
const address = new Address(kind, pubkey, identifier).toString()
return ["q", address, ctx.app.router.fromRelays(relays).getUrl(), pubkey] return ["q", address, ctx.app.router.fromRelays(relays).getUrl(), pubkey]
}) },
)
const neventTags = findNodes("nevent", json).map(({attrs: {id, author, relays = []}}: any) => [ const neventTags = findNodes("nevent", json).map(({attrs: {id, author, relays = []}}: any) => [
"q", "q",
-1
View File
@@ -62,4 +62,3 @@ export const createScroller = ({
}, },
} }
} }
+1 -1
View File
@@ -69,7 +69,7 @@
<input bind:value={term} class="grow" type="text" /> <input bind:value={term} class="grow" type="text" />
</label> </label>
<div class="overflow-auto"> <div class="overflow-auto">
{#each chats as {id, pubkeys, messages} (id)} {#each chats as { id, pubkeys, messages } (id)}
<ChatItem {id} {pubkeys} {messages} /> <ChatItem {id} {pubkeys} {messages} />
{/each} {/each}
</div> </div>
+3 -5
View File
@@ -109,7 +109,7 @@
{#if others.length === 1} {#if others.length === 1}
{@const pubkey = others[0]} {@const pubkey = others[0]}
{@const showProfile = () => pushModal(ProfileDetail, {pubkey})} {@const showProfile = () => pushModal(ProfileDetail, {pubkey})}
<Button on:click={showProfile}> <Button on:click={showProfile} class="row-2">
<ProfileCircle {pubkey} size={5} /> <ProfileCircle {pubkey} size={5} />
<ProfileName {pubkey} /> <ProfileName {pubkey} />
</Button> </Button>
@@ -119,16 +119,14 @@
<ProfileName pubkey={others[0]} /> <ProfileName pubkey={others[0]} />
and {others.length - 1} and {others.length - 1}
{others.length > 2 ? "others" : "other"} {others.length > 2 ? "others" : "other"}
<Button on:click={showMembers} class="btn btn-link"> <Button on:click={showMembers} class="btn btn-link">Show all members</Button>
Show all members
</Button>
</p> </p>
{/if} {/if}
</div> </div>
<div slot="action"> <div slot="action">
{#if remove($pubkey, $missingInboxes).length > 0} {#if remove($pubkey, $missingInboxes).length > 0}
{@const count = remove($pubkey, $missingInboxes).length} {@const count = remove($pubkey, $missingInboxes).length}
{@const label = count > 0 ? 'inboxes are' : 'inbox is'} {@const label = count > 1 ? "inboxes are" : "inbox is"}
<div <div
class="row-2 badge badge-error badge-lg tooltip tooltip-left cursor-pointer" class="row-2 badge badge-error badge-lg tooltip tooltip-left cursor-pointer"
data-tip="{count} {label} not configured."> data-tip="{count} {label} not configured.">
+1 -1
View File
@@ -31,7 +31,7 @@
<input bind:value={term} class="grow" type="text" placeholder="Search for conversations..." /> <input bind:value={term} class="grow" type="text" placeholder="Search for conversations..." />
</label> </label>
<div class="column gap-2 overflow-auto"> <div class="column gap-2 overflow-auto">
{#each chats as {id, pubkeys, messages} (id)} {#each chats as { id, pubkeys, messages } (id)}
<ChatItem {id} {pubkeys} {messages} /> <ChatItem {id} {pubkeys} {messages} />
{/each} {/each}
</div> </div>
+1 -1
View File
@@ -10,7 +10,7 @@
const defaultPubkeys = uniq([ const defaultPubkeys = uniq([
...shuffle(getPubkeyTagValues(getListTags($userFollows))), ...shuffle(getPubkeyTagValues(getListTags($userFollows))),
...import.meta.env.VITE_DEFAULT_PUBKEYS.split(','), ...import.meta.env.VITE_DEFAULT_PUBKEYS.split(","),
]) ])
let term = "" let term = ""