mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-19 11:43:35 +00:00
Fix some layout stuff with replies
This commit is contained in:
parent
d9ab565b5f
commit
b9b669af7c
@ -1,12 +1,9 @@
|
|||||||
# Current
|
# Current
|
||||||
|
|
||||||
- [ ] Refactor
|
- [ ] Refactor
|
||||||
- Split out Note pieces
|
|
||||||
- Move global modals to child components?
|
- Move global modals to child components?
|
||||||
- Combine app/agent, rename app2
|
- Combine app/agent, rename app2
|
||||||
- Some elements bleed through reply image modal
|
|
||||||
- DM view pushes user back to the bottom
|
- DM view pushes user back to the bottom
|
||||||
- note.replies might be empty in note detail pre-load
|
|
||||||
- [ ] Improve topic suggestions and rendering
|
- [ ] Improve topic suggestions and rendering
|
||||||
- [ ] Add topic search
|
- [ ] Add topic search
|
||||||
- [ ] Relays bounty
|
- [ ] Relays bounty
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
export let invertColors = false
|
export let invertColors = false
|
||||||
|
|
||||||
let reply = null
|
let reply = null
|
||||||
|
let replyIsActive = false
|
||||||
let actions = null
|
let actions = null
|
||||||
let visibleNotes = []
|
let visibleNotes = []
|
||||||
let collapsed = false
|
let collapsed = false
|
||||||
@ -106,123 +107,140 @@
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div bind:this={noteContainer} class="note group relative">
|
<div class="note">
|
||||||
<Card class="relative flex gap-4" on:click={onClick} {interactive} {invertColors}>
|
<div bind:this={noteContainer} class="group relative">
|
||||||
{#if !showParent}
|
<Card class="relative flex gap-4" on:click={onClick} {interactive} {invertColors}>
|
||||||
<div class={`absolute -ml-4 h-px w-4 bg-${borderColor} z-10`} style="left: 0px; top: 27px;" />
|
{#if !showParent}
|
||||||
{/if}
|
<div
|
||||||
<div>
|
class={`absolute -ml-4 h-px w-4 bg-${borderColor} z-10`}
|
||||||
<Anchor class="text-lg font-bold" href={routes.person($author.pubkey)}>
|
style="left: 0px; top: 27px;" />
|
||||||
<PersonCircle size={10} person={$author} />
|
{/if}
|
||||||
</Anchor>
|
<div>
|
||||||
</div>
|
<Anchor class="text-lg font-bold" href={routes.person($author.pubkey)}>
|
||||||
<div class="flex min-w-0 flex-grow flex-col gap-2">
|
<PersonCircle size={10} person={$author} />
|
||||||
<div class="flex flex-col items-start justify-between sm:flex-row sm:items-center">
|
|
||||||
<Popover triggerType={isMobile ? "click" : "mouseenter"}>
|
|
||||||
<div slot="trigger">
|
|
||||||
<Anchor
|
|
||||||
type="unstyled"
|
|
||||||
class="flex items-center gap-2 pr-16 text-lg font-bold sm:pr-0"
|
|
||||||
href={isMobile ? null : routes.person($author.pubkey)}>
|
|
||||||
<span>{displayPerson($author)}</span>
|
|
||||||
{#if $author.verified_as}
|
|
||||||
<i class="fa fa-circle-check text-sm text-accent" />
|
|
||||||
{/if}
|
|
||||||
</Anchor>
|
|
||||||
</div>
|
|
||||||
<div slot="tooltip">
|
|
||||||
<PersonSummary pubkey={$author.pubkey} />
|
|
||||||
</div>
|
|
||||||
</Popover>
|
|
||||||
<Anchor
|
|
||||||
href={"/" + nip19.neventEncode({id: note.id, relays: note.seen_on})}
|
|
||||||
class="text-sm text-gray-1"
|
|
||||||
type="unstyled">
|
|
||||||
{timestamp}
|
|
||||||
</Anchor>
|
</Anchor>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2">
|
<div class="flex min-w-0 flex-grow flex-col gap-2">
|
||||||
<div class="flex gap-2">
|
<div class="flex flex-col items-start justify-between sm:flex-row sm:items-center">
|
||||||
{#if findReplyId(note) && showParent}
|
<Popover triggerType={isMobile ? "click" : "mouseenter"}>
|
||||||
<small class="text-gray-1">
|
<div slot="trigger">
|
||||||
<i class="fa fa-code-merge" />
|
<Anchor
|
||||||
<Anchor on:click={goToParent}>View Parent</Anchor>
|
type="unstyled"
|
||||||
</small>
|
class="flex items-center gap-2 pr-16 text-lg font-bold sm:pr-0"
|
||||||
{/if}
|
href={isMobile ? null : routes.person($author.pubkey)}>
|
||||||
{#if findRootId(note) && findRootId(note) !== findReplyId(note) && showParent}
|
<span>{displayPerson($author)}</span>
|
||||||
<small class="text-gray-1">
|
{#if $author.verified_as}
|
||||||
<i class="fa fa-code-pull-request" />
|
<i class="fa fa-circle-check text-sm text-accent" />
|
||||||
<Anchor on:click={goToRoot}>View Thread</Anchor>
|
{/if}
|
||||||
</small>
|
</Anchor>
|
||||||
{/if}
|
</div>
|
||||||
|
<div slot="tooltip">
|
||||||
|
<PersonSummary pubkey={$author.pubkey} />
|
||||||
|
</div>
|
||||||
|
</Popover>
|
||||||
|
<Anchor
|
||||||
|
href={"/" + nip19.neventEncode({id: note.id, relays: note.seen_on})}
|
||||||
|
class="text-sm text-gray-1"
|
||||||
|
type="unstyled">
|
||||||
|
{timestamp}
|
||||||
|
</Anchor>
|
||||||
</div>
|
</div>
|
||||||
{#if muted}
|
<div class="flex flex-col gap-2">
|
||||||
<p class="border-l-2 border-solid border-gray-6 pl-4 text-gray-1">
|
<div class="flex gap-2">
|
||||||
You have muted this note.
|
{#if findReplyId(note) && showParent}
|
||||||
</p>
|
<small class="text-gray-1">
|
||||||
{:else}
|
<i class="fa fa-code-merge" />
|
||||||
<NoteContent {note} {showEntire} />
|
<Anchor on:click={goToParent}>View Parent</Anchor>
|
||||||
{/if}
|
</small>
|
||||||
<NoteActions
|
{/if}
|
||||||
bind:this={actions}
|
{#if findRootId(note) && findRootId(note) !== findReplyId(note) && showParent}
|
||||||
{note}
|
<small class="text-gray-1">
|
||||||
{author}
|
<i class="fa fa-code-pull-request" />
|
||||||
{reply}
|
<Anchor on:click={goToRoot}>View Thread</Anchor>
|
||||||
{muted}
|
</small>
|
||||||
{setFeedRelay}
|
{/if}
|
||||||
{showEntire} />
|
</div>
|
||||||
|
{#if muted}
|
||||||
|
<p class="border-l-2 border-solid border-gray-6 pl-4 text-gray-1">
|
||||||
|
You have muted this note.
|
||||||
|
</p>
|
||||||
|
{:else}
|
||||||
|
<NoteContent {note} {showEntire} />
|
||||||
|
{/if}
|
||||||
|
<NoteActions
|
||||||
|
bind:this={actions}
|
||||||
|
{note}
|
||||||
|
{reply}
|
||||||
|
{author}
|
||||||
|
{muted}
|
||||||
|
{setFeedRelay}
|
||||||
|
{showEntire} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#if !replyIsActive && visibleNotes.length > 0 && !showEntire && depth > 0 && !muted}
|
||||||
|
<div class="relative">
|
||||||
|
<div
|
||||||
|
class="absolute top-0 right-0 z-10 -mt-4 -mr-2 flex h-6 w-6 cursor-pointer items-center
|
||||||
|
justify-center rounded-full border border-solid border-gray-7 bg-gray-8 text-gray-3"
|
||||||
|
on:click={() => {
|
||||||
|
collapsed = !collapsed
|
||||||
|
}}>
|
||||||
|
<Popover triggerType="mouseenter">
|
||||||
|
<div slot="trigger">
|
||||||
|
{#if collapsed}
|
||||||
|
<i class="fa fa-xs fa-up-right-and-down-left-from-center" />
|
||||||
|
{:else}
|
||||||
|
<i class="fa fa-xs fa-down-left-and-up-right-to-center" />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div slot="tooltip">
|
||||||
|
{collapsed ? "Show replies" : "Hide replies"}
|
||||||
|
</div>
|
||||||
|
</Popover>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
{/if}
|
||||||
|
|
||||||
|
<NoteReply
|
||||||
|
bind:this={reply}
|
||||||
|
on:start={() => {
|
||||||
|
replyIsActive = true
|
||||||
|
}}
|
||||||
|
on:reset={() => {
|
||||||
|
replyIsActive = false
|
||||||
|
}}
|
||||||
|
{note}
|
||||||
|
{borderColor} />
|
||||||
|
|
||||||
|
{#if !collapsed && visibleNotes.length > 0 && depth > 0 && !muted}
|
||||||
|
<div class="relative mt-4">
|
||||||
|
<div class={`absolute w-px bg-${borderColor} z-10 -mt-4 ml-4 h-0`} bind:this={border} />
|
||||||
|
<div class="note-children relative ml-8 flex flex-col gap-4" bind:this={childrenContainer}>
|
||||||
|
{#if !showEntire && note.replies.length > visibleNotes.length}
|
||||||
|
<button class="ml-5 cursor-pointer py-2 text-gray-1 outline-0" on:click={onClick}>
|
||||||
|
<i class="fa fa-up-down pr-2 text-sm" />
|
||||||
|
Show {quantify(
|
||||||
|
note.replies.length - visibleNotes.length,
|
||||||
|
"other reply",
|
||||||
|
"more replies"
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
{#each visibleNotes as r (r.id)}
|
||||||
|
<svelte:self
|
||||||
|
showParent={false}
|
||||||
|
note={r}
|
||||||
|
depth={depth - 1}
|
||||||
|
{feedRelay}
|
||||||
|
{setFeedRelay}
|
||||||
|
{invertColors}
|
||||||
|
{anchorId}
|
||||||
|
{showContext} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<NoteReply bind:this={reply} {note} {borderColor} />
|
|
||||||
|
|
||||||
{#if !reply?.isActive() && visibleNotes.length > 0 && !showEntire && depth > 0 && !muted}
|
|
||||||
<div class="relative -mt-4">
|
|
||||||
<div
|
|
||||||
class="absolute top-0 right-0 z-10 -mt-4 -mr-2 flex h-6 w-6 cursor-pointer items-center
|
|
||||||
justify-center rounded-full border border-solid border-gray-7 bg-gray-8 text-gray-3"
|
|
||||||
on:click={() => {
|
|
||||||
collapsed = !collapsed
|
|
||||||
}}>
|
|
||||||
<Popover triggerType="mouseenter">
|
|
||||||
<div slot="trigger">
|
|
||||||
{#if collapsed}
|
|
||||||
<i class="fa fa-xs fa-up-right-and-down-left-from-center" />
|
|
||||||
{:else}
|
|
||||||
<i class="fa fa-xs fa-down-left-and-up-right-to-center" />
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
<div slot="tooltip">
|
|
||||||
{collapsed ? "Show replies" : "Hide replies"}
|
|
||||||
</div>
|
|
||||||
</Popover>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if !collapsed && visibleNotes.length > 0 && depth > 0 && !muted}
|
|
||||||
<div class="relative">
|
|
||||||
<div class={`absolute w-px bg-${borderColor} z-10 -mt-4 ml-4 h-0`} bind:this={border} />
|
|
||||||
<div class="note-children relative ml-8 flex flex-col gap-4" bind:this={childrenContainer}>
|
|
||||||
{#if !showEntire && note.replies.length > visibleNotes.length}
|
|
||||||
<button class="ml-5 cursor-pointer py-2 text-gray-1" on:click={onClick}>
|
|
||||||
<i class="fa fa-up-down pr-2 text-sm" />
|
|
||||||
Show {quantify(note.replies.length - visibleNotes.length, "other reply", "more replies")}
|
|
||||||
</button>
|
|
||||||
{/if}
|
|
||||||
{#each visibleNotes as r (r.id)}
|
|
||||||
<svelte:self
|
|
||||||
showParent={false}
|
|
||||||
note={r}
|
|
||||||
depth={depth - 1}
|
|
||||||
{feedRelay}
|
|
||||||
{setFeedRelay}
|
|
||||||
{invertColors}
|
|
||||||
{anchorId}
|
|
||||||
{showContext} />
|
|
||||||
{/each}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import {objOf, reverse} from "ramda"
|
import {objOf, reverse} from "ramda"
|
||||||
import {navigate} from "svelte-routing"
|
import {navigate} from "svelte-routing"
|
||||||
import {fly} from "svelte/transition"
|
import {fly} from "svelte/transition"
|
||||||
import {splice} from 'hurdak/lib/hurdak'
|
import {splice} from "hurdak/lib/hurdak"
|
||||||
import {warn} from "src/util/logger"
|
import {warn} from "src/util/logger"
|
||||||
import {displayPerson, parseContent, Tags} from "src/util/nostr"
|
import {displayPerson, parseContent, Tags} from "src/util/nostr"
|
||||||
import MediaSet from "src/partials/MediaSet.svelte"
|
import MediaSet from "src/partials/MediaSet.svelte"
|
||||||
@ -38,7 +38,7 @@
|
|||||||
(type === "link" && !value.startsWith("ws")) ||
|
(type === "link" && !value.startsWith("ws")) ||
|
||||||
["nostr:note", "nostr:nevent"].includes(type)
|
["nostr:note", "nostr:nevent"].includes(type)
|
||||||
) {
|
) {
|
||||||
if (type === 'link') {
|
if (type === "link") {
|
||||||
links.push(value)
|
links.push(value)
|
||||||
} else {
|
} else {
|
||||||
entities.push({type, value})
|
entities.push({type, value})
|
||||||
@ -72,11 +72,11 @@
|
|||||||
// Truncate content if needed
|
// Truncate content if needed
|
||||||
let l = 0
|
let l = 0
|
||||||
if (shouldTruncate) {
|
if (shouldTruncate) {
|
||||||
for (const i in content) {
|
for (let i = 0; i < content.length; i++) {
|
||||||
const prev = content[i - 1]
|
const prev = content[i - 1]
|
||||||
|
|
||||||
// Avoid adding an ellipsis right after a newline
|
// Avoid adding an ellipsis right after a newline
|
||||||
if (l > truncateAt && prev?.type != 'newline') {
|
if (l > truncateAt && prev?.type != "newline") {
|
||||||
content = content.slice(0, i).concat({type: "text", value: "..."})
|
content = content.slice(0, i).concat({type: "text", value: "..."})
|
||||||
|
|
||||||
break
|
break
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {nip19} from "nostr-tools"
|
import {nip19} from "nostr-tools"
|
||||||
|
import {createEventDispatcher} from "svelte"
|
||||||
import {without, pluck, uniq} from "ramda"
|
import {without, pluck, uniq} from "ramda"
|
||||||
import {slide} from "svelte/transition"
|
import {slide} from "svelte/transition"
|
||||||
import {Tags, displayPerson} from "src/util/nostr"
|
import {Tags, displayPerson} from "src/util/nostr"
|
||||||
@ -16,13 +17,15 @@
|
|||||||
export let note
|
export let note
|
||||||
export let borderColor
|
export let borderColor
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
let data = null
|
let data = null
|
||||||
let reply = null
|
let reply = null
|
||||||
let container = null
|
let container = null
|
||||||
|
|
||||||
export const isActive = () => Boolean(reply)
|
|
||||||
|
|
||||||
export const start = () => {
|
export const start = () => {
|
||||||
|
dispatch("start")
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
image: null,
|
image: null,
|
||||||
mentions: without(
|
mentions: without(
|
||||||
@ -33,6 +36,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const reset = () => {
|
const reset = () => {
|
||||||
|
dispatch("reset")
|
||||||
|
|
||||||
data = null
|
data = null
|
||||||
reply = null
|
reply = null
|
||||||
}
|
}
|
||||||
@ -90,7 +95,7 @@
|
|||||||
{#if data}
|
{#if data}
|
||||||
<div
|
<div
|
||||||
transition:slide
|
transition:slide
|
||||||
class="note-reply relative z-10 flex flex-col gap-1"
|
class="note-reply relative z-10 my-2 flex flex-col gap-1"
|
||||||
bind:this={container}
|
bind:this={container}
|
||||||
on:click|stopPropagation>
|
on:click|stopPropagation>
|
||||||
<div class={`border border-${borderColor} rounded border-solid`}>
|
<div class={`border border-${borderColor} rounded border-solid`}>
|
||||||
|
Loading…
Reference in New Issue
Block a user