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 {
|
.zapHighlights {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-wrap: wrap;
|
||||||
gap: 8px;
|
gap: 6px;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
|
||||||
&.onlyFew {
|
&.onlyFew {
|
||||||
@ -346,6 +346,11 @@
|
|||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.break {
|
||||||
|
flex-basis: 100%;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.firstZap {
|
.firstZap {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -383,93 +388,6 @@
|
|||||||
background: var(--subtile-devider);
|
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 { thread, zapCustomOption } from '../../translations';
|
||||||
import { useAccountContext } from '../../contexts/AccountContext';
|
import { useAccountContext } from '../../contexts/AccountContext';
|
||||||
import { uuidv4 } from '../../utils';
|
import { uuidv4 } from '../../utils';
|
||||||
|
import NoteTopZaps from './NoteTopZaps';
|
||||||
|
|
||||||
export type NoteReactionsState = {
|
export type NoteReactionsState = {
|
||||||
likes: number,
|
likes: number,
|
||||||
@ -206,41 +207,6 @@ const Note: Component<{
|
|||||||
return (likes || 0) + (zapCount || 0) + (reposts || 0) + (quoteCount || 0);
|
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(() => {
|
createEffect(() => {
|
||||||
updateReactionsState('topZaps', () => [ ...(threadContext?.topZaps[props.note.post.id] || []) ]);
|
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)} />
|
<ParsedNote note={props.note} width={Math.min(574, window.innerWidth)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Show
|
<NoteTopZaps
|
||||||
when={!threadContext?.isFetchingTopZaps}
|
topZaps={reactionsState.topZaps}
|
||||||
fallback={
|
zapCount={reactionsState.zapCount}
|
||||||
<div class={styles.topZapsLoading}>
|
action={() => openReactionModal('zaps')}
|
||||||
<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>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class={styles.time}
|
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