From 74f9531c5fda3d5b7db5036c36ade4475d38a710 Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Thu, 31 Oct 2024 12:24:40 -0700 Subject: [PATCH] Add space home page --- src/app.html | 5 +- src/app/analytics.ts | 2 + src/app/commands.ts | 2 +- src/app/components/ChannelCompose.svelte | 2 +- src/app/components/ChannelMessage.svelte | 15 +- src/app/components/Chat.svelte | 4 +- src/app/components/ChatMessage.svelte | 24 +-- src/app/components/ConfirmDelete.svelte | 2 +- src/app/components/Content.svelte | 12 +- src/app/components/ContentQuote.svelte | 2 +- src/app/components/EventCreate.svelte | 2 +- src/app/components/InfoBunker.svelte | 15 +- src/app/components/InfoNostr.svelte | 14 +- src/app/components/LogInBunker.svelte | 3 +- src/app/components/MenuSpace.svelte | 5 + src/app/components/NoteItem.svelte | 47 ++++++ src/app/components/ProfileDetail.svelte | 47 ++++++ src/app/components/ProfileFeed.svelte | 52 +++++++ src/app/components/ReactionSummary.svelte | 3 +- src/app/components/ThreadActions.svelte | 2 +- src/app/components/ThreadCreate.svelte | 20 ++- src/app/components/ThreadItem.svelte | 10 +- src/app/components/ThreadReply.svelte | 2 +- src/app/components/ThunkStatus.svelte | 2 +- src/app/routes.ts | 6 +- src/app/state.ts | 4 +- src/app/tracking.ts | 2 +- src/lib/components/Icon.svelte | 2 +- src/lib/components/LongPress.svelte | 9 +- src/lib/editor/index.ts | 4 +- src/routes/settings/+page.svelte | 4 +- src/routes/spaces/[relay]/+page.svelte | 138 +++++++++--------- .../spaces/[relay]/threads/+page.svelte | 91 ++++++++++++ .../spaces/[relay]/threads/[id]/+page.svelte | 2 +- 34 files changed, 401 insertions(+), 155 deletions(-) create mode 100644 src/app/components/NoteItem.svelte create mode 100644 src/app/components/ProfileDetail.svelte create mode 100644 src/app/components/ProfileFeed.svelte create mode 100644 src/routes/spaces/[relay]/threads/+page.svelte diff --git a/src/app.html b/src/app.html index 26422a47..9f2217c0 100644 --- a/src/app.html +++ b/src/app.html @@ -26,6 +26,9 @@
%sveltekit.body%
- + diff --git a/src/app/analytics.ts b/src/app/analytics.ts index e7385ac5..e4d54433 100644 --- a/src/app/analytics.ts +++ b/src/app/analytics.ts @@ -1,3 +1,5 @@ +/* eslint prefer-rest-params: 0 */ + import {page} from "$app/stores" const w = window as any diff --git a/src/app/commands.ts b/src/app/commands.ts index 144dc5fa..2a785a06 100644 --- a/src/app/commands.ts +++ b/src/app/commands.ts @@ -101,7 +101,7 @@ export const subscribePersistent = (request: SubscribeRequestWithHandlers) => { new Promise(resolve => { sub = subscribe(request) sub.emitter.on("close", resolve) - }) + }), ]) if (!done) { diff --git a/src/app/components/ChannelCompose.svelte b/src/app/components/ChannelCompose.svelte index 164b6b81..761d8298 100644 --- a/src/app/components/ChannelCompose.svelte +++ b/src/app/components/ChannelCompose.svelte @@ -17,7 +17,7 @@ const submit = () => { onSubmit({ - content: $editor.getText({blockSeparator: '\n'}), + content: $editor.getText({blockSeparator: "\n"}), tags: getEditorTags($editor), }) diff --git a/src/app/components/ChannelMessage.svelte b/src/app/components/ChannelMessage.svelte index c11ddb16..c88c7578 100644 --- a/src/app/components/ChannelMessage.svelte +++ b/src/app/components/ChannelMessage.svelte @@ -5,7 +5,6 @@ import {deriveProfile, deriveProfileDisplay, formatTimestampAsTime, pubkey} from "@welshman/app" import type {Thunk} from "@welshman/app" import {isMobile} from "@lib/html" - import {slideAndFade, conditionalTransition} from "@lib/transition" import LongPress from "@lib/components/LongPress.svelte" import Avatar from "@lib/components/Avatar.svelte" import Link from "@lib/components/Link.svelte" @@ -36,16 +35,13 @@ const rootEvent = rootId ? deriveEvent(rootId, rootHints) : readable(null) const [_, colorValue] = colors[parseInt(hash(event.pubkey)) % colors.length] - const transition = conditionalTransition(thunk, slideAndFade) - const onClick = () => { const root = $rootEvent || event pushDrawer(ChannelConversation, {url, room, event: root}) } - const onLongPress = () => - pushModal(ChannelMessageMenuMobile, {url, event}) + const onLongPress = () => pushModal(ChannelMessageMenuMobile, {url, event}) const onReactionClick = (content: string, events: TrustedEvent[]) => { const reaction = events.find(e => e.pubkey === $pubkey) @@ -66,14 +62,13 @@ + class="group relative flex w-full flex-col gap-1 p-2 text-left transition-colors {inert + ? 'hover:bg-base-300' + : ''}">
{#if showPubkey} - + {:else}
diff --git a/src/app/components/Chat.svelte b/src/app/components/Chat.svelte index 25f9db48..660968dc 100644 --- a/src/app/components/Chat.svelte +++ b/src/app/components/Chat.svelte @@ -10,7 +10,7 @@ diff --git a/src/app/components/EventCreate.svelte b/src/app/components/EventCreate.svelte index ab7d229f..da5db67e 100644 --- a/src/app/components/EventCreate.svelte +++ b/src/app/components/EventCreate.svelte @@ -41,7 +41,7 @@ const kind = isAllDay ? EVENT_DATE : EVENT_TIME const event = createEvent(kind, { - content: $editor.getText({blockSeparator: '\n'}), + content: $editor.getText({blockSeparator: "\n"}), tags: [ ["d", randomId()], ["title", title], diff --git a/src/app/components/InfoBunker.svelte b/src/app/components/InfoBunker.svelte index 282da84b..b881d535 100644 --- a/src/app/components/InfoBunker.svelte +++ b/src/app/components/InfoBunker.svelte @@ -10,14 +10,14 @@
What is a bunker link?

- Nostr uses "keys" instead of - passwords to identify users. This allows users to own their social identity instead of - renting it from a tech company, and can bring it with them from app to app. + Nostr uses "keys" instead of passwords + to identify users. This allows users to own their social identity instead of renting it from a tech + company, and can bring it with them from app to app.

- A good way to manage your keys is to use a remote signing application. These apps can hold - your keys and log you in remotely to as many applications as you like, without risking - loss or theft of your keys. + A good way to manage your keys is to use a remote signing application. These apps can hold your + keys and log you in remotely to as many applications as you like, without risking loss or theft + of your keys.

One way to log in with a remote signer is using a "bunker link" which is more secure and @@ -25,7 +25,8 @@ copy it into {PLATFORM_NAME}, and you should be good to go!

- If you don't have a signer yet, nsec.app + If you don't have a signer yet, nsec.app is a great way to get started.

diff --git a/src/app/components/InfoNostr.svelte b/src/app/components/InfoNostr.svelte index 56fb56b2..1c1032e9 100644 --- a/src/app/components/InfoNostr.svelte +++ b/src/app/components/InfoNostr.svelte @@ -2,7 +2,6 @@ import Link from "@lib/components/Link.svelte" import Button from "@lib/components/Button.svelte" import ModalHeader from "@lib/components/ModalHeader.svelte" - import {PLATFORM_NAME} from "@app/state"
@@ -10,13 +9,16 @@
What is nostr?

- Nostr is way to build - social apps that talk to each other. Users own their social identity instead of - renting it from a tech company, and can take it with them. + Nostr is way to build social apps that + talk to each other. Users own their social identity instead of renting it from a tech company, and + can take it with them.

- If you'd like to learn more about what other apps exist in the nostr ecosystem, please - visit nostrapps.com. + If you'd like to learn more about what other apps exist in the nostr ecosystem, please visit nostrapps.com.

To learn more about how to manage your keys, or to set up an account, try diff --git a/src/app/components/LogInBunker.svelte b/src/app/components/LogInBunker.svelte index 2b12893f..da18b865 100644 --- a/src/app/components/LogInBunker.svelte +++ b/src/app/components/LogInBunker.svelte @@ -1,6 +1,5 @@ + + + +

+ + + + + +

+ {formatTimestamp(event.created_at)} +

+
+ diff --git a/src/app/components/ProfileDetail.svelte b/src/app/components/ProfileDetail.svelte new file mode 100644 index 00000000..e6bca537 --- /dev/null +++ b/src/app/components/ProfileDetail.svelte @@ -0,0 +1,47 @@ + + +
+
+ {#each sortBy(e => -e.created_at, $events) as event (event.id)} + {#if flatten(Object.values(getAncestorTags(event.tags))).length === 0} + + {/if} + {:else} +

+ +

+ {/each} +
+
diff --git a/src/app/components/ProfileFeed.svelte b/src/app/components/ProfileFeed.svelte new file mode 100644 index 00000000..385b92e4 --- /dev/null +++ b/src/app/components/ProfileFeed.svelte @@ -0,0 +1,52 @@ + + +
+
+ {#each events as event (event.id)} + {#if flatten(Object.values(getAncestorTags(event.tags))).length === 0} + + {/if} + {/each} +

+ +

+
+
diff --git a/src/app/components/ReactionSummary.svelte b/src/app/components/ReactionSummary.svelte index b615ef7b..1419d53d 100644 --- a/src/app/components/ReactionSummary.svelte +++ b/src/app/components/ReactionSummary.svelte @@ -17,7 +17,7 @@ {#if $reactions.length > 0} -
+
{#each groupedReactions.entries() as [content, events]} {@const isOwn = events.some(e => e.pubkey === $pubkey)} {@const onClick = () => onReactionClick(content, events)} @@ -34,5 +34,6 @@ {/if} {/each} +
{/if} diff --git a/src/app/components/ThreadActions.svelte b/src/app/components/ThreadActions.svelte index acb80648..d7403cd6 100644 --- a/src/app/components/ThreadActions.svelte +++ b/src/app/components/ThreadActions.svelte @@ -46,7 +46,7 @@
-
+
{#if $deleted}
Deleted
{/if} diff --git a/src/app/components/ThreadCreate.svelte b/src/app/components/ThreadCreate.svelte index 1e5dadd5..ba416249 100644 --- a/src/app/components/ThreadCreate.svelte +++ b/src/app/components/ThreadCreate.svelte @@ -3,7 +3,6 @@ import type {Readable} from "svelte/store" import {writable} from "svelte/store" import {createEditor, type Editor, EditorContent} from "svelte-tiptap" - import {append} from "@welshman/lib" import {createEvent} from "@welshman/util" import {publishThunk} from "@welshman/app" import Icon from "@lib/components/Icon.svelte" @@ -26,7 +25,6 @@ const loading = writable(false) const submit = () => { - if (!title) { return pushToast({ theme: "error", @@ -34,7 +32,7 @@ }) } - const content = $editor.getText({blockSeparator: '\n'}) + const content = $editor.getText({blockSeparator: "\n"}) if (!content.trim()) { return pushToast({ @@ -43,11 +41,7 @@ }) } - const tags = [ - ["title", title], - tagRoom(GENERAL, url), - ...getEditorTags($editor), - ] + const tags = [["title", title], tagRoom(GENERAL, url), ...getEditorTags($editor)] publishThunk({ event: createEvent(THREAD, {content, tags}), @@ -68,7 +62,7 @@ getPubkeyHints, autofocus: true, placeholder: "What's on your mind?", - }) + }), ) }) @@ -78,11 +72,15 @@
Create a Thread
Share a link, or start a discussion.
-
+

Title*

diff --git a/src/app/components/ThreadItem.svelte b/src/app/components/ThreadItem.svelte index 5d2ed266..1a033796 100644 --- a/src/app/components/ThreadItem.svelte +++ b/src/app/components/ThreadItem.svelte @@ -1,5 +1,5 @@ -
+

{title}

{formatTimestamp(event.created_at)}

-
- +
+ Posted by @ diff --git a/src/app/components/ThreadReply.svelte b/src/app/components/ThreadReply.svelte index eca35246..c909456f 100644 --- a/src/app/components/ThreadReply.svelte +++ b/src/app/components/ThreadReply.svelte @@ -23,7 +23,7 @@ const loading = writable(false) const submit = () => { - const content = $editor.getText({blockSeparator: '\n'}) + const content = $editor.getText({blockSeparator: "\n"}) const tags = append(tagRoom(GENERAL, url), getEditorTags($editor)) if (!content.trim()) { diff --git a/src/app/components/ThunkStatus.svelte b/src/app/components/ThunkStatus.svelte index 0d3472a4..77720243 100644 --- a/src/app/components/ThunkStatus.svelte +++ b/src/app/components/ThunkStatus.svelte @@ -7,7 +7,7 @@ import Tippy from "@lib/components/Tippy.svelte" import Button from "@lib/components/Button.svelte" import ThunkStatusDetail from "@app/components/ThunkStatusDetail.svelte" - import {userSettingValues} from '@app/state' + import {userSettingValues} from "@app/state" export let thunk: Thunk | MergedThunk diff --git a/src/app/routes.ts b/src/app/routes.ts index 1f9828ce..e9039ca4 100644 --- a/src/app/routes.ts +++ b/src/app/routes.ts @@ -1,11 +1,11 @@ import type {Page} from "@sveltejs/kit" import {userMembership, makeChatId, decodeRelay, encodeRelay, getMembershipUrls} from "@app/state" -export const makeSpacePath = (url: string, extra = "") => { +export const makeSpacePath = (url: string, ...extra: string[]) => { let path = `/spaces/${encodeRelay(url)}` - if (extra) { - path += "/" + encodeURIComponent(extra) + if (extra.length > 0) { + path += "/" + extra.map(s => encodeURIComponent(s)).join("/") } return path diff --git a/src/app/state.ts b/src/app/state.ts index c4f96144..36388ff7 100644 --- a/src/app/state.ts +++ b/src/app/state.ts @@ -264,7 +264,7 @@ export type Settings = { values: { show_media: boolean hide_sensitive: boolean - send_delay: number, + send_delay: number } } @@ -528,7 +528,7 @@ export const encodeRelay = (url: string) => encodeURIComponent(normalizeRelayUrl export const decodeRelay = (url: string) => normalizeRelayUrl(decodeURIComponent(url)) export const displayReaction = (content: string) => { - if (content === "+") return "❤️" + if (!content || content === "+") return "❤️" if (content === "-") return "👎" return content } diff --git a/src/app/tracking.ts b/src/app/tracking.ts index f8b24514..d63ca097 100644 --- a/src/app/tracking.ts +++ b/src/app/tracking.ts @@ -6,7 +6,7 @@ export const setupTracking = () => { dsn: import.meta.env.VITE_GLITCHTIP_API_KEY, tracesSampleRate: 0.01, integrations(integrations) { - return integrations.filter(integration => integration.name !== 'Breadcrumbs') + return integrations.filter(integration => integration.name !== "Breadcrumbs") }, }) } diff --git a/src/lib/components/Icon.svelte b/src/lib/components/Icon.svelte index 9796a413..e96db136 100644 --- a/src/lib/components/Icon.svelte +++ b/src/lib/components/Icon.svelte @@ -150,7 +150,7 @@ "smile-circle": SmileCircle, server: Server, settings: Settings, - 'settings-minimalistic': SettingsMinimalistic, + "settings-minimalistic": SettingsMinimalistic, "tag-horizontal": TagHorizontal, "trash-bin-2": TrashBin2, "ufo-3": UFO3, diff --git a/src/lib/components/LongPress.svelte b/src/lib/components/LongPress.svelte index f91b2647..83f60b86 100644 --- a/src/lib/components/LongPress.svelte +++ b/src/lib/components/LongPress.svelte @@ -24,6 +24,13 @@ let timeout: number -
+
diff --git a/src/lib/editor/index.ts b/src/lib/editor/index.ts index 8151ce86..8a444df4 100644 --- a/src/lib/editor/index.ts +++ b/src/lib/editor/index.ts @@ -1,7 +1,7 @@ import type {Writable} from "svelte/store" import {nprofileEncode} from "nostr-tools/nip19" import {SvelteNodeViewRenderer} from "svelte-tiptap" -import Placeholder from '@tiptap/extension-placeholder' +import Placeholder from "@tiptap/extension-placeholder" import Code from "@tiptap/extension-code" import CodeBlock from "@tiptap/extension-code-block" import Document from "@tiptap/extension-document" @@ -65,7 +65,7 @@ export const getModifiedHardBreakExtension = () => "Shift-Enter": () => this.editor.commands.setHardBreak(), "Mod-Enter": () => this.editor.commands.setHardBreak(), Enter: () => { - if (this.editor.getText({blockSeparator: '\n'}).trim()) { + if (this.editor.getText({blockSeparator: "\n"}).trim()) { uploadFiles(this.editor) return true diff --git a/src/routes/settings/+page.svelte b/src/routes/settings/+page.svelte index e14c485f..7e2e41ce 100644 --- a/src/routes/settings/+page.svelte +++ b/src/routes/settings/+page.svelte @@ -75,8 +75,8 @@ step="1000" bind:value={settings.send_delay} />

- Delay sending chat messages for {settings.send_delay/1000} - {settings.send_delay === 1000 ? 'second' : 'seconds'}. + Delay sending chat messages for {settings.send_delay / 1000} + {settings.send_delay === 1000 ? "second" : "seconds"}.

diff --git a/src/routes/spaces/[relay]/+page.svelte b/src/routes/spaces/[relay]/+page.svelte index 1314a513..94bde16f 100644 --- a/src/routes/spaces/[relay]/+page.svelte +++ b/src/routes/spaces/[relay]/+page.svelte @@ -1,91 +1,95 @@ -
+
- +
- Threads + Home
- + {#if pubkey} + + + Contact Owner + + {/if}
-
- {#each $events.slice(0, limit) as event (event.id)} - {#if !event.tags.some(nthEq(0, "e")) && !mutedPubkeys.includes(event.pubkey)} - - {/if} - {/each} -

- - {#if loading} - Looking for threads... - {:else if $events.length === 0} - No threads found. + {#if pubkey} +

+
+
+
+
+
+ {#if $relay?.profile?.icon} + + {:else} + + {/if} +
+
+
+
+

+ +

+

{url}

+
+
+ + {#if $relay?.profile} + {@const {software, version, supported_nips, limitation} = $relay.profile} +
+ {#if limitation?.auth_required} +

Authentication Required

+ {/if} + {#if limitation?.payment_required} +

Payment Required

+ {/if} + {#if limitation?.min_pow_difficulty} +

Requires PoW {limitation?.min_pow_difficulty}

+ {/if} + {#if supported_nips} +

NIPs: {supported_nips.join(", ")}

+ {/if} + {#if software} +

Software: {software}

+ {/if} + {#if version} +

Version: {version}

+ {/if} +
{/if} - -

-
+
+ Recent posts from the relay admin + +
+ {/if}
diff --git a/src/routes/spaces/[relay]/threads/+page.svelte b/src/routes/spaces/[relay]/threads/+page.svelte new file mode 100644 index 00000000..1314a513 --- /dev/null +++ b/src/routes/spaces/[relay]/threads/+page.svelte @@ -0,0 +1,91 @@ + + +
+ +
+ +
+ Threads +
+ + +
+
+
+ {#each $events.slice(0, limit) as event (event.id)} + {#if !event.tags.some(nthEq(0, "e")) && !mutedPubkeys.includes(event.pubkey)} + + {/if} + {/each} +

+ + {#if loading} + Looking for threads... + {:else if $events.length === 0} + No threads found. + {/if} + +

+
+
diff --git a/src/routes/spaces/[relay]/threads/[id]/+page.svelte b/src/routes/spaces/[relay]/threads/[id]/+page.svelte index 82c64fa8..2509b494 100644 --- a/src/routes/spaces/[relay]/threads/[id]/+page.svelte +++ b/src/routes/spaces/[relay]/threads/[id]/+page.svelte @@ -36,7 +36,7 @@ let showReply = false - $: title = $event?.tags.find(nthEq(0, 'title'))?.[1] || "" + $: title = $event?.tags.find(nthEq(0, "title"))?.[1] || "" onMount(() => { const sub = subscribe({filters, relays: [url]})