From 525a823862d67e10556e4fc11b26831e4e355a15 Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Wed, 11 Sep 2024 15:21:25 -0700 Subject: [PATCH] Rough out calendar --- package.json | 6 +- src/app/components/ChatCompose.svelte | 5 +- src/app/components/EventCreate.svelte | 107 ++++++++++++++++++ src/app/components/SpaceCreateExternal.svelte | 15 +-- src/app/editor.ts | 65 ++++++++++- src/app/state.ts | 52 +++++---- src/assets/icons/Document.svg | 5 + src/assets/icons/Map Point.svg | 4 + src/assets/icons/Tag Horizontal.svg | 4 + src/assets/icons/Widget Add.svg | 6 + src/lib/components/Icon.svelte | 8 ++ src/lib/components/InputPicture.svelte | 91 +++++++++++++++ src/lib/html.ts | 2 +- src/routes/discover/+page.svelte | 2 +- src/routes/spaces/[nrelay]/+layout.svelte | 9 +- .../spaces/[nrelay]/[[topic]]/+page.svelte | 16 +-- .../spaces/[nrelay]/calendar/+page.svelte | 66 +++++++++++ 17 files changed, 409 insertions(+), 54 deletions(-) create mode 100644 src/app/components/EventCreate.svelte create mode 100644 src/assets/icons/Document.svg create mode 100644 src/assets/icons/Map Point.svg create mode 100644 src/assets/icons/Tag Horizontal.svg create mode 100644 src/assets/icons/Widget Add.svg create mode 100644 src/lib/components/InputPicture.svelte create mode 100644 src/routes/spaces/[nrelay]/calendar/+page.svelte diff --git a/package.json b/package.json index b1e06b90..27c9bc42 100644 --- a/package.json +++ b/package.json @@ -48,12 +48,12 @@ "@tiptap/extension-text": "^2.6.6", "@tiptap/suggestion": "^2.6.4", "@types/throttle-debounce": "^5.0.2", + "@welshman/app": "^0.0.4", "@welshman/lib": "^0.0.17", - "@welshman/util": "^0.0.30", - "@welshman/store": "^0.0.5", "@welshman/net": "^0.0.21", "@welshman/signer": "^0.0.5", - "@welshman/app": "^0.0.4", + "@welshman/store": "^0.0.5", + "@welshman/util": "^0.0.30", "daisyui": "^4.12.10", "fuse.js": "^7.0.0", "idb": "^8.0.0", diff --git a/src/app/components/ChatCompose.svelte b/src/app/components/ChatCompose.svelte index 81231c7b..6c51cd4f 100644 --- a/src/app/components/ChatCompose.svelte +++ b/src/app/components/ChatCompose.svelte @@ -48,8 +48,9 @@
+
+ +
+
+ + +

Location (optional)

+ +
+
+ + +
+ + diff --git a/src/app/components/SpaceCreateExternal.svelte b/src/app/components/SpaceCreateExternal.svelte index e5b5b516..5640fbf0 100644 --- a/src/app/components/SpaceCreateExternal.svelte +++ b/src/app/components/SpaceCreateExternal.svelte @@ -1,6 +1,5 @@

Create a Space

-

- Host your own space, for your community. -

+

Host your own space, for your community.

- relay.tools is a third-party service - that allows anyone to run their own relay for use with Flotilla, or any other - nostr-compatible app. + relay.tools is a third-party + service that allows anyone to run their own relay for use with Flotilla, or any other nostr-compatible + app.

Once you've created a relay of your own, come back here to link Flotilla with your new relay. diff --git a/src/app/editor.ts b/src/app/editor.ts index 0b0b3a72..bc0cd53a 100644 --- a/src/app/editor.ts +++ b/src/app/editor.ts @@ -37,12 +37,12 @@ export const addFile = (editor: Editor) => editor.chain().selectFiles().run() export const uploadFiles = (editor: Editor) => editor.chain().uploadFiles().run() -type ChatComposeEditorOptions = { +type EditorOptions = { uploading: Writable sendMessage: () => void } -export const getChatEditorOptions = ({uploading, sendMessage}: ChatComposeEditorOptions) => ({ +export const getChatEditorOptions = ({uploading, sendMessage}: EditorOptions) => ({ content: "", autofocus: true, extensions: [ @@ -146,3 +146,64 @@ export const getChatViewOptions = (content: string) => ({ VideoExtension.extend(asInline({addNodeView: () => SvelteNodeViewRenderer(ChatComposeVideo)})), ], }) + +export const getNoteEditorOptions = ({uploading, sendMessage}: EditorOptions) => ({ + content: "", + autofocus: true, + extensions: [ + Document, + Dropcursor, + Gapcursor, + History, + Paragraph, + Text, + HardBreakExtension, + LinkExtension.extend({ + addNodeView: () => SvelteNodeViewRenderer(ChatComposeLink), + }), + Bolt11Extension.extend( + asInline({addNodeView: () => SvelteNodeViewRenderer(ChatComposeBolt11)}), + ), + NProfileExtension.extend({ + addNodeView: () => SvelteNodeViewRenderer(ChatComposeMention), + addProseMirrorPlugins() { + return [ + createSuggestions({ + char: "@", + name: "nprofile", + editor: this.editor, + search: profileSearch, + select: (pubkey: string, props: any) => { + const relays = getPubkeyHints(pubkey) + const nprofile = nprofileEncode({pubkey, relays}) + + return props.command({pubkey, nprofile, relays}) + }, + suggestionComponent: ChatSuggestionProfile, + suggestionsComponent: ChatComposeSuggestions, + }), + ] + }, + }), + NEventExtension.extend(asInline({addNodeView: () => SvelteNodeViewRenderer(ChatComposeEvent)})), + NAddrExtension.extend(asInline({addNodeView: () => SvelteNodeViewRenderer(ChatComposeEvent)})), + ImageExtension.extend( + asInline({addNodeView: () => SvelteNodeViewRenderer(ChatComposeImage)}), + ).configure({defaultUploadUrl: "https://nostr.build", defaultUploadType: "nip96"}), + VideoExtension.extend( + asInline({addNodeView: () => SvelteNodeViewRenderer(ChatComposeVideo)}), + ).configure({defaultUploadUrl: "https://nostr.build", defaultUploadType: "nip96"}), + FileUploadExtension.configure({ + immediateUpload: false, + sign: (event: StampedEvent) => { + uploading.set(true) + + return signer.get()!.sign(event) + }, + onComplete: () => { + uploading.set(false) + sendMessage() + }, + }), + ], +}) diff --git a/src/app/state.ts b/src/app/state.ts index 5ae4a280..0904de42 100644 --- a/src/app/state.ts +++ b/src/app/state.ts @@ -1,12 +1,14 @@ import {nip19} from "nostr-tools" -import {get, derived, writable} from "svelte/store" +import {get, derived} from "svelte/store" import type {Maybe} from "@welshman/lib" -import {setContext, max, groupBy, pushToMapKey, nthEq} from "@welshman/lib" +import {setContext, max, pushToMapKey, nthEq} from "@welshman/lib" import { getIdFilters, RELAYS, REACTION, ZAP_RESPONSE, + EVENT_DATE, + EVENT_TIME, getRelayTagValues, getTopicTagValues, isShareableRelayUrl, @@ -150,27 +152,23 @@ export const makeChatId = (url: string, topic: string) => `${url}'${topic}` export const splitChatId = (id: string) => id.split("'") -export const chats = derived( - [trackerStore, messages], - ([$tracker, $messages]) => { - const messagesByChatId = new Map() +export const chats = derived([trackerStore, messages], ([$tracker, $messages]) => { + const messagesByChatId = new Map() - for (const message of $messages) { - for (const url of $tracker.getRelays(message.event.id)) { - const chatId = makeChatId(url, message.topic) + for (const message of $messages) { + for (const url of $tracker.getRelays(message.event.id)) { + const chatId = makeChatId(url, message.topic) - pushToMapKey(messagesByChatId, chatId, message) - } + pushToMapKey(messagesByChatId, chatId, message) } - - return Array.from(messagesByChatId.entries()) - .map(([id, messages]) => { - const [url, topic] = splitChatId(id) - - return {id, url, topic, messages} - }) } -) + + return Array.from(messagesByChatId.entries()).map(([id, messages]) => { + const [url, topic] = splitChatId(id) + + return {id, url, topic, messages} + }) +}) export const { indexStore: chatsById, @@ -190,6 +188,22 @@ export const { }, }) +// Calendar vents + +export const events = deriveEvents(repository, {filters: [{kinds: [EVENT_DATE, EVENT_TIME]}]}) + +export const eventsByUrl = derived([trackerStore, events], ([$tracker, $events]) => { + const eventsByUrl = new Map() + + for (const event of $events) { + for (const url of $tracker.getRelays(event.id)) { + pushToMapKey(eventsByUrl, url, event) + } + } + + return eventsByUrl +}) + // Topics export const topicsByUrl = derived(chats, $chats => { diff --git a/src/assets/icons/Document.svg b/src/assets/icons/Document.svg new file mode 100644 index 00000000..01463b62 --- /dev/null +++ b/src/assets/icons/Document.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/Map Point.svg b/src/assets/icons/Map Point.svg new file mode 100644 index 00000000..92a9d1ed --- /dev/null +++ b/src/assets/icons/Map Point.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/Tag Horizontal.svg b/src/assets/icons/Tag Horizontal.svg new file mode 100644 index 00000000..353307e9 --- /dev/null +++ b/src/assets/icons/Tag Horizontal.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/assets/icons/Widget Add.svg b/src/assets/icons/Widget Add.svg new file mode 100644 index 00000000..8f21b574 --- /dev/null +++ b/src/assets/icons/Widget Add.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/lib/components/Icon.svelte b/src/lib/components/Icon.svelte index f1b5b902..8792fe79 100644 --- a/src/lib/components/Icon.svelte +++ b/src/lib/components/Icon.svelte @@ -11,6 +11,7 @@ import AddSquare from "@assets/icons/Add Square.svg?dataurl" import ArrowsALogout2 from "@assets/icons/Arrows ALogout 2.svg?dataurl" import Code2 from "@assets/icons/Code 2.svg?dataurl" + import Document from "@assets/icons/Document.svg?dataurl" import Earth from "@assets/icons/Earth.svg?dataurl" import Pen from "@assets/icons/Pen.svg?dataurl" import HeadphonesRound from "@assets/icons/Headphones Round.svg?dataurl" @@ -44,6 +45,7 @@ import Login from "@assets/icons/Login.svg?dataurl" import Login2 from "@assets/icons/Login 2.svg?dataurl" import Magnifer from "@assets/icons/Magnifer.svg?dataurl" + import MapPoint from "@assets/icons/Map Point.svg?dataurl" import MenuDots from "@assets/icons/Menu Dots.svg?dataurl" import NotesMinimalistic from "@assets/icons/Notes Minimalistic.svg?dataurl" import Pallete2 from "@assets/icons/Pallete 2.svg?dataurl" @@ -52,6 +54,7 @@ import RemoteControllerMinimalistic from "@assets/icons/Remote Controller Minimalistic.svg?dataurl" import Reply from "@assets/icons/Reply.svg?dataurl" import Settings from "@assets/icons/Settings.svg?dataurl" + import TagHorizontal from "@assets/icons/Tag Horizontal.svg?dataurl" import ShopMinimalistic from "@assets/icons/Shop Minimalistic.svg?dataurl" import SmileCircle from "@assets/icons/Smile Circle.svg?dataurl" import SquareShareLine from "@assets/icons/Square Share Line.svg?dataurl" @@ -60,6 +63,7 @@ import UserCircle from "@assets/icons/User Circle.svg?dataurl" import UserRounded from "@assets/icons/User Rounded.svg?dataurl" import Widget from "@assets/icons/Widget.svg?dataurl" + import WidgetAdd from "@assets/icons/Widget Add.svg?dataurl" import WiFiRouterRound from "@assets/icons/Wi-Fi Router Round.svg?dataurl" export let icon @@ -71,6 +75,7 @@ "add-square": AddSquare, "arrows-a-logout-2": ArrowsALogout2, "code-2": Code2, + document: Document, earth: Earth, pen: Pen, "headphones-round": HeadphonesRound, @@ -104,6 +109,7 @@ login: Login, "login-2": Login2, magnifer: Magnifer, + 'map-point': MapPoint, "menu-dots": MenuDots, "notes-minimalistic": NotesMinimalistic, "pallete-2": Pallete2, @@ -114,12 +120,14 @@ "shop-minimalistic": ShopMinimalistic, "smile-circle": SmileCircle, settings: Settings, + 'tag-horizontal': TagHorizontal, "ufo-3": UFO3, "square-share-line": SquareShareLine, "user-heart": UserHeart, "user-circle": UserCircle, "user-rounded": UserRounded, widget: Widget, + 'widget-add': WidgetAdd, "wifi-router-round": WiFiRouterRound, }) diff --git a/src/lib/components/InputPicture.svelte b/src/lib/components/InputPicture.svelte new file mode 100644 index 00000000..c787c2a7 --- /dev/null +++ b/src/lib/components/InputPicture.svelte @@ -0,0 +1,91 @@ + + + + +

+ {#if file} + + + + {:else} + + {/if} +
+ {#if !file} + + {/if} + + diff --git a/src/lib/html.ts b/src/lib/html.ts index c0336797..63e53fb9 100644 --- a/src/lib/html.ts +++ b/src/lib/html.ts @@ -1,4 +1,4 @@ -import {sleep} from '@welshman/lib' +import {sleep} from "@welshman/lib" export const copyToClipboard = (text: string) => { const {activeElement} = document diff --git a/src/routes/discover/+page.svelte b/src/routes/discover/+page.svelte index 7cb8f4e8..92157a6d 100644 --- a/src/routes/discover/+page.svelte +++ b/src/routes/discover/+page.svelte @@ -3,7 +3,7 @@ import Masonry from "svelte-bricks" import {displayRelayUrl} from "@welshman/util" import {relaySearch} from "@welshman/app" - import {createScroller} from '@lib/html' + import {createScroller} from "@lib/html" import Icon from "@lib/components/Icon.svelte" import {makeSpacePath} from "@app/routes" import {userMembership, discoverRelays} from "@app/state" diff --git a/src/routes/spaces/[nrelay]/+layout.svelte b/src/routes/spaces/[nrelay]/+layout.svelte index 8bdb99c3..4da92f2a 100644 --- a/src/routes/spaces/[nrelay]/+layout.svelte +++ b/src/routes/spaces/[nrelay]/+layout.svelte @@ -1,5 +1,5 @@ + +
+
+
+
+ + Calendar +
+
+
+
+ {#each events as event, i (event.id)} + {@const dateDisplay = getDateDisplay(event, i === 0)} + {#if dateDisplay} +
{dateDisplay}
+ {/if} +
{event.id}
+ {/each} +

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

+
+ +