mirror of
https://github.com/coracle-social/flotilla.git
synced 2025-12-10 10:57:04 +00:00
Display thread title
This commit is contained in:
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
onSubmit({
|
onSubmit({
|
||||||
content: $editor.getText(),
|
content: $editor.getText({blockSeparator: '\n'}),
|
||||||
tags: getEditorTags($editor),
|
tags: getEditorTags($editor),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
export let maxLength = 700
|
export let maxLength = 700
|
||||||
export let showEntire = false
|
export let showEntire = false
|
||||||
export let hideMedia = false
|
export let hideMedia = false
|
||||||
export let expandable = true
|
export let expandMode = "block"
|
||||||
export let depth = 0
|
export let depth = 0
|
||||||
|
|
||||||
const fullContent = parse(event)
|
const fullContent = parse(event)
|
||||||
@@ -80,7 +80,9 @@
|
|||||||
mediaLength: hideMedia ? 20 : 200,
|
mediaLength: hideMedia ? 20 : 200,
|
||||||
})
|
})
|
||||||
|
|
||||||
$: ellipsize = expandable && shortContent.find(isEllipsis)
|
$: hasEllipsis = shortContent.find(isEllipsis)
|
||||||
|
$: expandInline = hasEllipsis && expandMode === "inline"
|
||||||
|
$: expandBlock = hasEllipsis && expandMode === "block"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
@@ -95,10 +97,10 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<div
|
<div
|
||||||
class="overflow-hidden text-ellipsis"
|
class="overflow-hidden text-ellipsis"
|
||||||
style={ellipsize ? "mask-image: linear-gradient(0deg, transparent 0px, black 100px)" : ""}>
|
style={expandBlock ? "mask-image: linear-gradient(0deg, transparent 0px, black 100px)" : ""}>
|
||||||
{#each shortContent as parsed, i}
|
{#each shortContent as parsed, i}
|
||||||
{#if isNewline(parsed)}
|
{#if isNewline(parsed)}
|
||||||
<ContentNewline value={parsed.value.slice(isNextToBlock(i) ? 1 : 0)} />
|
<ContentNewline value={parsed.value.slice(1)} />
|
||||||
{:else if isTopic(parsed)}
|
{:else if isTopic(parsed)}
|
||||||
<ContentTopic value={parsed.value} />
|
<ContentTopic value={parsed.value} />
|
||||||
{:else if isCode(parsed)}
|
{:else if isCode(parsed)}
|
||||||
@@ -128,12 +130,17 @@
|
|||||||
{fromNostrURI(parsed.raw).slice(0, 16) + "…"}
|
{fromNostrURI(parsed.raw).slice(0, 16) + "…"}
|
||||||
</Link>
|
</Link>
|
||||||
{/if}
|
{/if}
|
||||||
|
{:else if isEllipsis(parsed) && expandInline}
|
||||||
|
{@html renderParsed(parsed)}
|
||||||
|
<button type="button" class="underline text-sm">
|
||||||
|
Read more
|
||||||
|
</button>
|
||||||
{:else}
|
{:else}
|
||||||
{@html renderParsed(parsed)}
|
{@html renderParsed(parsed)}
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
{#if ellipsize}
|
{#if expandBlock}
|
||||||
<div class="relative z-feature -mt-6 flex justify-center bg-gradient-to-t from-base-100 py-2">
|
<div class="relative z-feature -mt-6 flex justify-center bg-gradient-to-t from-base-100 py-2">
|
||||||
<button type="button" class="btn" on:click|stopPropagation|preventDefault={expand}>
|
<button type="button" class="btn" on:click|stopPropagation|preventDefault={expand}>
|
||||||
See more
|
See more
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
const kind = isAllDay ? EVENT_DATE : EVENT_TIME
|
const kind = isAllDay ? EVENT_DATE : EVENT_TIME
|
||||||
const event = createEvent(kind, {
|
const event = createEvent(kind, {
|
||||||
content: $editor.getText(),
|
content: $editor.getText({blockSeparator: '\n'}),
|
||||||
tags: [
|
tags: [
|
||||||
["d", randomId()],
|
["d", randomId()],
|
||||||
["title", title],
|
["title", title],
|
||||||
|
|||||||
@@ -16,19 +16,23 @@
|
|||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#each groupedReactions.entries() as [content, events]}
|
{#if $reactions.length > 0}
|
||||||
{@const isOwn = events.some(e => e.pubkey === $pubkey)}
|
<div class="flex gap-2">
|
||||||
{@const onClick = () => onReactionClick(content, events)}
|
{#each groupedReactions.entries() as [content, events]}
|
||||||
<button
|
{@const isOwn = events.some(e => e.pubkey === $pubkey)}
|
||||||
type="button"
|
{@const onClick = () => onReactionClick(content, events)}
|
||||||
class="flex-inline btn btn-neutral btn-xs gap-1 rounded-full"
|
<button
|
||||||
class:border={isOwn}
|
type="button"
|
||||||
class:border-solid={isOwn}
|
class="flex-inline btn btn-neutral btn-xs gap-1 rounded-full"
|
||||||
class:border-primary={isOwn}
|
class:border={isOwn}
|
||||||
on:click|stopPropagation={onClick}>
|
class:border-solid={isOwn}
|
||||||
<span>{displayReaction(content)}</span>
|
class:border-primary={isOwn}
|
||||||
{#if events.length > 1}
|
on:click|stopPropagation={onClick}>
|
||||||
<span>{events.length}</span>
|
<span>{displayReaction(content)}</span>
|
||||||
{/if}
|
{#if events.length > 1}
|
||||||
</button>
|
<span>{events.length}</span>
|
||||||
{/each}
|
{/if}
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|||||||
@@ -45,10 +45,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center justify-between gap-2">
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
<Button class="flex gap-2">
|
<ReactionSummary {event} {onReactionClick} />
|
||||||
<ReactionSummary {event} {onReactionClick} />
|
<div class="flex flex-wrap flex-grow justify-end gap-2">
|
||||||
</Button>
|
|
||||||
<div class="flex flex-grow justify-end gap-2">
|
|
||||||
{#if $deleted}
|
{#if $deleted}
|
||||||
<div class="btn btn-error btn-xs rounded-full">Deleted</div>
|
<div class="btn btn-error btn-xs rounded-full">Deleted</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = $editor.getText()
|
const content = $editor.getText({blockSeparator: '\n'})
|
||||||
|
|
||||||
if (!content.trim()) {
|
if (!content.trim()) {
|
||||||
return pushToast({
|
return pushToast({
|
||||||
|
|||||||
@@ -1,25 +1,35 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import {nthEq} from '@welshman/lib'
|
||||||
import {formatTimestamp} from "@welshman/app"
|
import {formatTimestamp} from "@welshman/app"
|
||||||
import Link from "@lib/components/Link.svelte"
|
import Link from "@lib/components/Link.svelte"
|
||||||
import Content from "@app/components/Content.svelte"
|
import Content from "@app/components/Content.svelte"
|
||||||
import Profile from "@app/components/Profile.svelte"
|
import ProfileName from "@app/components/ProfileName.svelte"
|
||||||
import ThreadActions from "@app/components/ThreadActions.svelte"
|
import ThreadActions from "@app/components/ThreadActions.svelte"
|
||||||
import {makeThreadPath} from "@app/routes"
|
import {makeThreadPath} from "@app/routes"
|
||||||
|
import {pubkeyLink} from "@app/state"
|
||||||
|
|
||||||
export let url
|
export let url
|
||||||
export let event
|
export let event
|
||||||
export let hideActions = false
|
export let hideActions = false
|
||||||
|
|
||||||
|
const title = event.tags.find(nthEq(0, 'title'))?.[1]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Link class="col-2 card2 bg-alt w-full cursor-pointer" href={makeThreadPath(url, event.id)}>
|
<Link class="col-2 card2 bg-alt w-full cursor-pointer" href={makeThreadPath(url, event.id)}>
|
||||||
<div class="flex w-full justify-between gap-2">
|
<div class="flex w-full justify-between items-center gap-2">
|
||||||
<Profile pubkey={event.pubkey} />
|
<p class="text-xl">{title}</p>
|
||||||
<p class="text-sm opacity-75">
|
<p class="text-sm opacity-75">
|
||||||
{formatTimestamp(event.created_at)}
|
{formatTimestamp(event.created_at)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4 w-full pl-12">
|
<Content {event} expandMode="inline" />
|
||||||
<Content {event} />
|
<div class="flex gap-2 items-end justify-between w-full">
|
||||||
|
<span class="text-sm opacity-75 whitespace-nowrap py-1">
|
||||||
|
Posted by
|
||||||
|
<Link external href={pubkeyLink(event.pubkey)} class="link-content">
|
||||||
|
@<ProfileName pubkey={event.pubkey} />
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
{#if !hideActions}
|
{#if !hideActions}
|
||||||
<ThreadActions showActivity {url} {event} />
|
<ThreadActions showActivity {url} {event} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
const loading = writable(false)
|
const loading = writable(false)
|
||||||
|
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
const content = $editor.getText()
|
const content = $editor.getText({blockSeparator: '\n'})
|
||||||
const tags = append(tagRoom(GENERAL, url), getEditorTags($editor))
|
const tags = append(tagRoom(GENERAL, url), getEditorTags($editor))
|
||||||
|
|
||||||
if (!content.trim()) {
|
if (!content.trim()) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<div class="relative z-feature mx-2 rounded-xl pt-4">
|
<div class="relative z-feature mx-2 rounded-xl pt-4 {$$props.class}">
|
||||||
<div
|
<div
|
||||||
class="flex min-h-12 items-center justify-between gap-4 rounded-xl bg-base-100 px-4 shadow-xl">
|
class="flex min-h-12 items-center justify-between gap-4 rounded-xl bg-base-100 px-4 shadow-xl">
|
||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export const getModifiedHardBreakExtension = () =>
|
|||||||
"Shift-Enter": () => this.editor.commands.setHardBreak(),
|
"Shift-Enter": () => this.editor.commands.setHardBreak(),
|
||||||
"Mod-Enter": () => this.editor.commands.setHardBreak(),
|
"Mod-Enter": () => this.editor.commands.setHardBreak(),
|
||||||
Enter: () => {
|
Enter: () => {
|
||||||
if (this.editor.getText().trim()) {
|
if (this.editor.getText({blockSeparator: '\n'}).trim()) {
|
||||||
uploadFiles(this.editor)
|
uploadFiles(this.editor)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {onMount} from "svelte"
|
import {onMount} from "svelte"
|
||||||
import {sortBy, sleep} from "@welshman/lib"
|
import {sortBy, nthEq, sleep} from "@welshman/lib"
|
||||||
import {page} from "$app/stores"
|
import {page} from "$app/stores"
|
||||||
import {repository, subscribe} from "@welshman/app"
|
import {repository, subscribe} from "@welshman/app"
|
||||||
import {deriveEvents} from "@welshman/store"
|
import {deriveEvents} from "@welshman/store"
|
||||||
@@ -36,6 +36,8 @@
|
|||||||
|
|
||||||
let showReply = false
|
let showReply = false
|
||||||
|
|
||||||
|
$: title = $event?.tags.find(nthEq(0, 'title'))?.[1] || ""
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const sub = subscribe({filters, relays: [url]})
|
const sub = subscribe({filters, relays: [url]})
|
||||||
|
|
||||||
@@ -44,7 +46,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="relative flex flex-col-reverse gap-3 px-2">
|
<div class="relative flex flex-col-reverse gap-3 px-2">
|
||||||
<div class="absolute left-[51px] top-20 h-[calc(100%-200px)] w-[2px] bg-neutral" />
|
<div class="absolute left-[51px] top-32 h-[calc(100%-248px)] w-[2px] bg-neutral" />
|
||||||
{#if $event}
|
{#if $event}
|
||||||
{#if !showReply}
|
{#if !showReply}
|
||||||
<div class="flex justify-end p-2">
|
<div class="flex justify-end p-2">
|
||||||
@@ -57,14 +59,14 @@
|
|||||||
{#each sortBy(e => -e.created_at, $replies) as reply (reply.id)}
|
{#each sortBy(e => -e.created_at, $replies) as reply (reply.id)}
|
||||||
<NoteCard event={reply} class="card2 bg-alt z-feature w-full">
|
<NoteCard event={reply} class="card2 bg-alt z-feature w-full">
|
||||||
<div class="col-3 ml-12">
|
<div class="col-3 ml-12">
|
||||||
<Content event={reply} />
|
<Content showEntire event={reply} />
|
||||||
<ThreadActions event={reply} {url} />
|
<ThreadActions event={reply} {url} />
|
||||||
</div>
|
</div>
|
||||||
</NoteCard>
|
</NoteCard>
|
||||||
{/each}
|
{/each}
|
||||||
<NoteCard event={$event} class="card2 bg-alt z-feature w-full">
|
<NoteCard event={$event} class="card2 bg-alt z-feature w-full">
|
||||||
<div class="col-3 ml-12">
|
<div class="col-3 ml-12">
|
||||||
<Content event={$event} />
|
<Content showEntire event={$event} />
|
||||||
<ThreadActions event={$event} {url} />
|
<ThreadActions event={$event} {url} />
|
||||||
</div>
|
</div>
|
||||||
</NoteCard>
|
</NoteCard>
|
||||||
@@ -75,13 +77,14 @@
|
|||||||
<p>Failed to load thread.</p>
|
<p>Failed to load thread.</p>
|
||||||
{/await}
|
{/await}
|
||||||
{/if}
|
{/if}
|
||||||
<PageBar>
|
<PageBar class="mx-0">
|
||||||
<div slot="icon">
|
<div slot="icon">
|
||||||
<Button class="btn btn-neutral btn-sm" on:click={back}>
|
<Button class="btn btn-neutral btn-sm" on:click={back}>
|
||||||
<Icon icon="alt-arrow-left" />
|
<Icon icon="alt-arrow-left" />
|
||||||
Go back
|
Go back
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
<h1 slot="title" class="text-xl">{title}</h1>
|
||||||
<div slot="action">
|
<div slot="action">
|
||||||
<Button on:click={openMenu} class="btn btn-neutral btn-sm md:hidden">
|
<Button on:click={openMenu} class="btn btn-neutral btn-sm md:hidden">
|
||||||
<Icon icon="menu-dots" />
|
<Icon icon="menu-dots" />
|
||||||
|
|||||||
Reference in New Issue
Block a user