Fix some layout stuff with replies

This commit is contained in:
Jonathan Staab 2023-04-12 12:59:37 -05:00
parent d9ab565b5f
commit b9b669af7c
4 changed files with 144 additions and 124 deletions

View File

@ -1,12 +1,9 @@
# Current
- [ ] Refactor
- Split out Note pieces
- Move global modals to child components?
- Combine app/agent, rename app2
- Some elements bleed through reply image modal
- DM view pushes user back to the bottom
- note.replies might be empty in note detail pre-load
- [ ] Improve topic suggestions and rendering
- [ ] Add topic search
- [ ] Relays bounty

View File

@ -31,6 +31,7 @@
export let invertColors = false
let reply = null
let replyIsActive = false
let actions = null
let visibleNotes = []
let collapsed = false
@ -106,123 +107,140 @@
})
</script>
<div bind:this={noteContainer} class="note group relative">
<Card class="relative flex gap-4" on:click={onClick} {interactive} {invertColors}>
{#if !showParent}
<div class={`absolute -ml-4 h-px w-4 bg-${borderColor} z-10`} style="left: 0px; top: 27px;" />
{/if}
<div>
<Anchor class="text-lg font-bold" href={routes.person($author.pubkey)}>
<PersonCircle size={10} person={$author} />
</Anchor>
</div>
<div class="flex min-w-0 flex-grow flex-col gap-2">
<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}
<div class="note">
<div bind:this={noteContainer} class="group relative">
<Card class="relative flex gap-4" on:click={onClick} {interactive} {invertColors}>
{#if !showParent}
<div
class={`absolute -ml-4 h-px w-4 bg-${borderColor} z-10`}
style="left: 0px; top: 27px;" />
{/if}
<div>
<Anchor class="text-lg font-bold" href={routes.person($author.pubkey)}>
<PersonCircle size={10} person={$author} />
</Anchor>
</div>
<div class="flex flex-col gap-2">
<div class="flex gap-2">
{#if findReplyId(note) && showParent}
<small class="text-gray-1">
<i class="fa fa-code-merge" />
<Anchor on:click={goToParent}>View Parent</Anchor>
</small>
{/if}
{#if findRootId(note) && findRootId(note) !== findReplyId(note) && showParent}
<small class="text-gray-1">
<i class="fa fa-code-pull-request" />
<Anchor on:click={goToRoot}>View Thread</Anchor>
</small>
{/if}
<div class="flex min-w-0 flex-grow flex-col gap-2">
<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>
</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}
{author}
{reply}
{muted}
{setFeedRelay}
{showEntire} />
<div class="flex flex-col gap-2">
<div class="flex gap-2">
{#if findReplyId(note) && showParent}
<small class="text-gray-1">
<i class="fa fa-code-merge" />
<Anchor on:click={goToParent}>View Parent</Anchor>
</small>
{/if}
{#if findRootId(note) && findRootId(note) !== findReplyId(note) && showParent}
<small class="text-gray-1">
<i class="fa fa-code-pull-request" />
<Anchor on:click={goToRoot}>View Thread</Anchor>
</small>
{/if}
</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>
</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>
<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}

View File

@ -2,7 +2,7 @@
import {objOf, reverse} from "ramda"
import {navigate} from "svelte-routing"
import {fly} from "svelte/transition"
import {splice} from 'hurdak/lib/hurdak'
import {splice} from "hurdak/lib/hurdak"
import {warn} from "src/util/logger"
import {displayPerson, parseContent, Tags} from "src/util/nostr"
import MediaSet from "src/partials/MediaSet.svelte"
@ -38,7 +38,7 @@
(type === "link" && !value.startsWith("ws")) ||
["nostr:note", "nostr:nevent"].includes(type)
) {
if (type === 'link') {
if (type === "link") {
links.push(value)
} else {
entities.push({type, value})
@ -72,11 +72,11 @@
// Truncate content if needed
let l = 0
if (shouldTruncate) {
for (const i in content) {
for (let i = 0; i < content.length; i++) {
const prev = content[i - 1]
// 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: "..."})
break

View File

@ -1,5 +1,6 @@
<script lang="ts">
import {nip19} from "nostr-tools"
import {createEventDispatcher} from "svelte"
import {without, pluck, uniq} from "ramda"
import {slide} from "svelte/transition"
import {Tags, displayPerson} from "src/util/nostr"
@ -16,13 +17,15 @@
export let note
export let borderColor
const dispatch = createEventDispatcher()
let data = null
let reply = null
let container = null
export const isActive = () => Boolean(reply)
export const start = () => {
dispatch("start")
data = {
image: null,
mentions: without(
@ -33,6 +36,8 @@
}
const reset = () => {
dispatch("reset")
data = null
reply = null
}
@ -90,7 +95,7 @@
{#if data}
<div
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}
on:click|stopPropagation>
<div class={`border border-${borderColor} rounded border-solid`}>