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 26422a476..9f2217c09 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 e7385ac5d..e4d544334 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 144dc5fa8..2a785a06c 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 164b6b812..761d8298e 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 c11ddb163..c88c75788 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 25f9db487..660968dc2 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 ab7d229fe..da5db67e6 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 282da84b5..b881d5350 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 56fb56b23..1c1032e9f 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 2b12893fe..da18b8654 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 000000000..e6bca5376 --- /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 000000000..385b92e43 --- /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 b615ef7be..1419d53db 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 acb80648c..d7403cd64 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 1e5dadd55..ba4162491 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 5d2ed266c..1a0337960 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 eca352468..c909456f9 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 0d3472a44..777202436 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 1f9828ce2..e9039ca44 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 c4f96144a..36388ff7c 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 f8b245146..d63ca097f 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 9796a4133..e96db136f 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 f91b26475..83f60b868 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 8151ce86d..8a444df42 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 e14c485fd..7e2e41cef 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 1314a5136..94bde16f6 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 000000000..1314a5136 --- /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 82c64fa8f..2509b4949 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]})