mirror of
https://github.com/PrimalHQ/primal-web-app.git
synced 2024-10-01 17:31:13 +00:00
Refactor top zaps into a single list
This commit is contained in:
parent
a55c5122f7
commit
9455df93ab
@ -336,8 +336,8 @@
|
||||
|
||||
.zapHighlights {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
gap: 6px;
|
||||
align-items: flex-start;
|
||||
|
||||
&.onlyFew {
|
||||
@ -346,6 +346,11 @@
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.break {
|
||||
flex-basis: 100%;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.firstZap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@ -383,93 +388,6 @@
|
||||
background: var(--subtile-devider);
|
||||
}
|
||||
}
|
||||
|
||||
.topZaps {
|
||||
display: flex;
|
||||
align-self: center;
|
||||
gap: 6px;
|
||||
width: 100%;
|
||||
|
||||
.zapList {
|
||||
display: flex;
|
||||
align-self: center;
|
||||
gap: 6px;
|
||||
max-width: calc(100% - 30px);
|
||||
overflow-x: scroll;
|
||||
overflow-y: hidden;
|
||||
|
||||
/* Hide scrollbar for Chrome, Safari and Opera */
|
||||
&::-webkit-scrollbar {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
/* Hide scrollbar for IE, Edge and Firefox */
|
||||
-ms-overflow-style: none !important; /* IE and Edge */
|
||||
scrollbar-width: none !important; /* Firefox */
|
||||
|
||||
.topZap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding-left: 2px;
|
||||
padding-right: 10px;
|
||||
padding-block: 2px;
|
||||
margin: 0;
|
||||
border-radius: 12px;
|
||||
background: var(--devider);
|
||||
width: fit-content;
|
||||
text-decoration: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
.amount {
|
||||
color: var(--text-primary);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.description {
|
||||
color: var(--text-secondary-2);
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: var(--subtile-devider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.moreZaps {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background: var(--devider);
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
.contextIcon {
|
||||
width: 16px;
|
||||
height: 14px;
|
||||
background-color: var(--text-secondary-2);
|
||||
-webkit-mask: url(../../assets/icons/context.svg) no-repeat 0 / 100%;
|
||||
mask: url(../../assets/icons/context.svg) no-repeat 0 / 100%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.contextIcon {
|
||||
background-color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,6 +21,7 @@ import { hexToNpub } from '../../lib/keys';
|
||||
import { thread, zapCustomOption } from '../../translations';
|
||||
import { useAccountContext } from '../../contexts/AccountContext';
|
||||
import { uuidv4 } from '../../utils';
|
||||
import NoteTopZaps from './NoteTopZaps';
|
||||
|
||||
export type NoteReactionsState = {
|
||||
likes: number,
|
||||
@ -206,41 +207,6 @@ const Note: Component<{
|
||||
return (likes || 0) + (zapCount || 0) + (reposts || 0) + (quoteCount || 0);
|
||||
};
|
||||
|
||||
const firstZap = createMemo(() => reactionsState.topZaps[0]);
|
||||
|
||||
const restZaps = createMemo(() => {
|
||||
const zaps = reactionsState.topZaps.slice(1);
|
||||
|
||||
let limit = 0;
|
||||
let digits = 0;
|
||||
|
||||
for (let i=0; i< zaps.length; i++) {
|
||||
const amount = zaps[i].amount || 0;
|
||||
const length = Math.log(amount) * Math.LOG10E + 1 | 0;
|
||||
|
||||
digits += length;
|
||||
|
||||
if (digits > 25 || limit > 6) break;
|
||||
|
||||
limit++;
|
||||
}
|
||||
|
||||
const rest = zaps.slice(0, limit);
|
||||
|
||||
if (rest.length < reactionsState.zapCount - 1) {
|
||||
updateReactionsState('moreZapsAvailable', () => true);
|
||||
}
|
||||
else {
|
||||
updateReactionsState('moreZapsAvailable', () => false);
|
||||
}
|
||||
|
||||
return rest;
|
||||
});
|
||||
|
||||
const zapSender = (zap: TopZap) => {
|
||||
return threadContext?.users.find(u => u.pubkey === zap.pubkey);
|
||||
};
|
||||
|
||||
createEffect(() => {
|
||||
updateReactionsState('topZaps', () => [ ...(threadContext?.topZaps[props.note.post.id] || []) ]);
|
||||
});
|
||||
@ -299,66 +265,11 @@ const Note: Component<{
|
||||
<ParsedNote note={props.note} width={Math.min(574, window.innerWidth)} />
|
||||
</div>
|
||||
|
||||
<Show
|
||||
when={!threadContext?.isFetchingTopZaps}
|
||||
fallback={
|
||||
<div class={styles.topZapsLoading}>
|
||||
<div class={styles.firstZap}></div>
|
||||
<div class={styles.topZaps}>
|
||||
<div class={styles.zapList}>
|
||||
<div class={styles.topZap}></div>
|
||||
<div class={styles.topZap}></div>
|
||||
<div class={styles.topZap}></div>
|
||||
<div class={styles.topZap}></div>
|
||||
<div class={styles.topZap}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div class={`${styles.zapHighlights} ${reactionsState.topZaps.length < 4 ? styles.onlyFew : ''}`}>
|
||||
<Show when={firstZap()}>
|
||||
<button
|
||||
class={styles.firstZap}
|
||||
onClick={() => openReactionModal('zaps')}
|
||||
>
|
||||
<Avatar user={zapSender(firstZap())} size="micro" />
|
||||
<div class={styles.amount}>
|
||||
{firstZap().amount.toLocaleString()}
|
||||
</div>
|
||||
<div class={styles.description}>
|
||||
{firstZap().message}
|
||||
</div>
|
||||
</button>
|
||||
</Show>
|
||||
<div class={styles.topZaps}>
|
||||
<div class={styles.zapList}>
|
||||
<For each={restZaps()}>
|
||||
{zap => (
|
||||
<button
|
||||
class={styles.topZap}
|
||||
onClick={() => openReactionModal('zaps')}
|
||||
>
|
||||
<Avatar user={zapSender(zap)} size="micro" />
|
||||
<div class={styles.amount}>
|
||||
{zap.amount.toLocaleString()}
|
||||
</div>
|
||||
</button>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
|
||||
<Show when={reactionsState.moreZapsAvailable}>
|
||||
<button
|
||||
class={styles.moreZaps}
|
||||
onClick={() => openReactionModal('zaps')}
|
||||
>
|
||||
<div class={styles.contextIcon}></div>
|
||||
</button>
|
||||
</Show>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
<NoteTopZaps
|
||||
topZaps={reactionsState.topZaps}
|
||||
zapCount={reactionsState.zapCount}
|
||||
action={() => openReactionModal('zaps')}
|
||||
/>
|
||||
|
||||
<div
|
||||
class={styles.time}
|
||||
|
103
src/components/Note/NoteTopZaps.tsx
Normal file
103
src/components/Note/NoteTopZaps.tsx
Normal file
@ -0,0 +1,103 @@
|
||||
import { Component, createMemo, createSignal, For, Show } from "solid-js";
|
||||
import { hookForDev } from "../../lib/devTools";
|
||||
import { TopZap, useThreadContext } from "../../contexts/ThreadContext";
|
||||
import Avatar from "../Avatar/Avatar";
|
||||
import styles from "./Note.module.scss";
|
||||
|
||||
const NoteTopZaps: Component<{
|
||||
topZaps: TopZap[],
|
||||
zapCount: number,
|
||||
action: () => void,
|
||||
id?: string,
|
||||
}> = (props) => {
|
||||
|
||||
const threadContext = useThreadContext();
|
||||
|
||||
const [hasMoreZaps, setHasMoreZaps] = createSignal(false);
|
||||
|
||||
const topZaps = () => {
|
||||
const zaps = [...props.topZaps];
|
||||
|
||||
let limit = 0;
|
||||
let digits = 0;
|
||||
|
||||
for (let i=0; i< zaps.length; i++) {
|
||||
const amount = zaps[i].amount || 0;
|
||||
const length = Math.log(amount) * Math.LOG10E + 1 | 0;
|
||||
|
||||
digits += length;
|
||||
|
||||
if (digits > 25 || limit > 7) break;
|
||||
|
||||
limit++;
|
||||
}
|
||||
|
||||
const highlights = zaps.slice(0, limit);
|
||||
|
||||
setHasMoreZaps(() => highlights.length < props.zapCount - 1);
|
||||
|
||||
return highlights;
|
||||
}
|
||||
|
||||
const zapSender = (zap: TopZap) => {
|
||||
return threadContext?.users.find(u => u.pubkey === zap.pubkey);
|
||||
};
|
||||
return (
|
||||
|
||||
<Show
|
||||
when={!threadContext?.isFetchingTopZaps}
|
||||
fallback={
|
||||
<div class={styles.topZapsLoading}>
|
||||
<div class={styles.firstZap}></div>
|
||||
<div class={styles.topZaps}>
|
||||
<div class={styles.zapList}>
|
||||
<div class={styles.topZap}></div>
|
||||
<div class={styles.topZap}></div>
|
||||
<div class={styles.topZap}></div>
|
||||
<div class={styles.topZap}></div>
|
||||
<div class={styles.topZap}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div class={`${styles.zapHighlights}`}>
|
||||
<For each={topZaps()}>
|
||||
{(zap, index) => (
|
||||
<>
|
||||
<button
|
||||
class={styles.firstZap}
|
||||
onClick={() => props.action()}
|
||||
>
|
||||
<Avatar user={zapSender(zap)} size="micro" />
|
||||
<div class={styles.amount}>
|
||||
{zap.amount.toLocaleString()}
|
||||
</div>
|
||||
<Show when={index() === 0}>
|
||||
<div class={styles.description}>
|
||||
{zap.message}
|
||||
</div>
|
||||
</Show>
|
||||
</button>
|
||||
|
||||
<Show when={index() === 0 && props.topZaps.length > 3}>
|
||||
<div class={styles.break}></div>
|
||||
</Show>
|
||||
</>
|
||||
)}
|
||||
</For>
|
||||
|
||||
<Show when={hasMoreZaps()}>
|
||||
<button
|
||||
class={styles.moreZaps}
|
||||
onClick={() => props.action()}
|
||||
>
|
||||
<div class={styles.contextIcon}></div>
|
||||
</button>
|
||||
</Show>
|
||||
</div>
|
||||
</Show>
|
||||
);
|
||||
}
|
||||
|
||||
export default hookForDev(NoteTopZaps);
|
Loading…
Reference in New Issue
Block a user