diff --git a/package.json b/package.json
index 3eb07e02..720941da 100644
--- a/package.json
+++ b/package.json
@@ -88,6 +88,7 @@
"@welshman/util": "^0.9.0-pre5",
"cheerio": "^1.2.0",
"compressorjs-next": "^1.1.2",
+ "dompurify": "^3.4.13",
"dotenv": "^16.6.1",
"emoji-picker-element": "^1.28.1",
"emoji-picker-element-data": "^1.8.0",
@@ -96,6 +97,7 @@
"husky": "^9.1.7",
"idb": "^8.0.3",
"livekit-client": "^2.17.2",
+ "marked": "^18.0.9",
"nostr-signer-capacitor-plugin": "github:coracle-social/nostr-signer-capacitor-plugin#main",
"nostr-tools": "^2.19.4",
"prettier-plugin-tailwindcss": "^0.7.2",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index de31a8f8..24b0f1f5 100644
Binary files a/pnpm-lock.yaml and b/pnpm-lock.yaml differ
diff --git a/src/app/components/ArticleActions.svelte b/src/app/components/ArticleActions.svelte
new file mode 100644
index 00000000..05bd459e
--- /dev/null
+++ b/src/app/components/ArticleActions.svelte
@@ -0,0 +1,55 @@
+
+
+
+ {#if h && showRoom}
+
+ Posted in #
+
+ {/if}
+
+ {#each uniq(topics) as topic (topic)}
+
+ {/each}
+
+
+
+ {#if showActivity}
+
+ {/if}
+
+
diff --git a/src/app/components/ArticleCreate.svelte b/src/app/components/ArticleCreate.svelte
new file mode 100644
index 00000000..0d1ab32c
--- /dev/null
+++ b/src/app/components/ArticleCreate.svelte
@@ -0,0 +1,215 @@
+
+
+
+
+
+ Write an Article
+ Publish a long-form post to this space.
+
+
+
+ {#snippet label()}
+ Title*
+ {/snippet}
+ {#snippet input()}
+
+ {/snippet}
+
+
+ {#snippet label()}
+ Summary
+ {/snippet}
+ {#snippet input()}
+
+ {/snippet}
+
+
+ {#snippet label()}
+ Topics
+ {/snippet}
+ {#snippet input()}
+
+ {/snippet}
+
+
+ {#snippet label()}
+ Content*
+ {/snippet}
+ {#snippet input()}
+
+
+
+ {/snippet}
+
+
+
+
+
+
+
+
+
diff --git a/src/app/components/ArticleItem.svelte b/src/app/components/ArticleItem.svelte
new file mode 100644
index 00000000..53f4f9ad
--- /dev/null
+++ b/src/app/components/ArticleItem.svelte
@@ -0,0 +1,57 @@
+
+
+
+ {#if image}
+
+ {/if}
+
+
{title || "Untitled"}
+
+ {formatTimestamp(article.publishedAt())}
+
+
+
+
+
+ Written by
+
+ {#if h}
+ in
+ {/if}
+
+
+
+
diff --git a/src/app/components/ArticleSidebar.svelte b/src/app/components/ArticleSidebar.svelte
new file mode 100644
index 00000000..304336dc
--- /dev/null
+++ b/src/app/components/ArticleSidebar.svelte
@@ -0,0 +1,80 @@
+
+
+
diff --git a/src/app/components/CommentActions.svelte b/src/app/components/CommentActions.svelte
index 4c379480..b675888f 100644
--- a/src/app/components/CommentActions.svelte
+++ b/src/app/components/CommentActions.svelte
@@ -11,7 +11,7 @@
type Props = {
url: string
event: TrustedEvent
- segment: string
+ segment?: string
showActivity?: boolean
}
@@ -19,7 +19,7 @@
const h = tagValue(tagSpec("h"), event.tags)
- const path = makeSpacePath(url, segment, event.id)
+ const path = segment && makeSpacePath(url, segment, event.id)
const deleteReaction = (reaction: TrustedEvent) => retractReaction(reaction, {url, h})
@@ -30,7 +30,7 @@
- {#if showActivity}
+ {#if showActivity && path}
{/if}
diff --git a/src/app/components/CommentCompose.svelte b/src/app/components/CommentCompose.svelte
new file mode 100644
index 00000000..63f1c200
--- /dev/null
+++ b/src/app/components/CommentCompose.svelte
@@ -0,0 +1,121 @@
+
+
+
diff --git a/src/app/components/CommentTree.svelte b/src/app/components/CommentTree.svelte
new file mode 100644
index 00000000..427b6e5a
--- /dev/null
+++ b/src/app/components/CommentTree.svelte
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+ {#if url}
+
+
+
+
+ {/if}
+
+
+ {#if composing && url}
+
+
+
+ {/if}
+ {#if node.children.length > 0}
+
+ {#each node.children as child (child.comment.id)}
+
+ {/each}
+
+ {/if}
+
diff --git a/src/app/components/ComposeMenu.svelte b/src/app/components/ComposeMenu.svelte
index cc55fada..0fba2249 100644
--- a/src/app/components/ComposeMenu.svelte
+++ b/src/app/components/ComposeMenu.svelte
@@ -4,12 +4,14 @@
import StarFallMinimalistic from "@assets/icons/star-fall-minimalistic.svg?dataurl"
import NotesMinimalistic from "@assets/icons/notes-minimalistic.svg?dataurl"
import CaseMinimalistic from "@assets/icons/case-minimalistic.svg?dataurl"
+ import DocumentText from "@assets/icons/document-text.svg?dataurl"
import Revote from "@assets/icons/revote.svg?dataurl"
import Button from "@lib/components/Button.svelte"
import Icon from "@lib/components/Icon.svelte"
import {pushModal} from "@app/modal"
import CalendarEventCreate from "@app/components/CalendarEventCreate.svelte"
import ThreadCreate from "@app/components/ThreadCreate.svelte"
+ import ArticleCreate from "@app/components/ArticleCreate.svelte"
import ClassifiedCreate from "@app/components/ClassifiedCreate.svelte"
import GoalCreate from "@app/components/GoalCreate.svelte"
import PollCreate from "@app/components/PollCreate.svelte"
@@ -32,6 +34,8 @@
const createPoll = () => pushModal(PollCreate, {url, h, shareToChat: true})
+ const createArticle = () => pushModal(ArticleCreate, {url, h, shareToChat: true})
+
let ul: Element
onMount(() => {
@@ -64,6 +68,12 @@
Create Thread
+
+
+