mirror of
https://github.com/PrimalHQ/primal-web-app.git
synced 2024-10-01 17:31:13 +00:00
Top zap transitions
This commit is contained in:
parent
9455df93ab
commit
7423100823
29
package-lock.json
generated
29
package-lock.json
generated
@ -9,7 +9,7 @@
|
|||||||
"version": "0.105.5",
|
"version": "0.105.5",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cashu/cashu-ts": "^0.9.0",
|
"@cashu/cashu-ts": "0.9.0",
|
||||||
"@cookbook/solid-intl": "0.1.2",
|
"@cookbook/solid-intl": "0.1.2",
|
||||||
"@jukben/emoji-search": "3.0.0",
|
"@jukben/emoji-search": "3.0.0",
|
||||||
"@kobalte/core": "0.11.0",
|
"@kobalte/core": "0.11.0",
|
||||||
@ -25,7 +25,8 @@
|
|||||||
"photoswipe": "5.4.3",
|
"photoswipe": "5.4.3",
|
||||||
"qr-code-styling": "^1.6.0-rc.1",
|
"qr-code-styling": "^1.6.0-rc.1",
|
||||||
"sass": "1.67.0",
|
"sass": "1.67.0",
|
||||||
"solid-js": "1.7.11"
|
"solid-js": "1.7.11",
|
||||||
|
"solid-transition-group": "^0.2.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@formatjs/cli": "^6.0.4",
|
"@formatjs/cli": "^6.0.4",
|
||||||
@ -961,6 +962,14 @@
|
|||||||
"solid-js": "^1.6.12"
|
"solid-js": "^1.6.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@solid-primitives/transition-group": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@solid-primitives/transition-group/-/transition-group-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-G3FuqvL13kQ55WzWPX2ewiXdZ/1iboiX53195sq7bbkDbXqP6TYKiadwEdsaDogW5rPnPYAym3+xnsNplQJRKQ==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"solid-js": "^1.6.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@solid-primitives/trigger": {
|
"node_modules/@solid-primitives/trigger": {
|
||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/@solid-primitives/trigger/-/trigger-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/@solid-primitives/trigger/-/trigger-1.0.8.tgz",
|
||||||
@ -2150,6 +2159,22 @@
|
|||||||
"solid-js": "^1.3"
|
"solid-js": "^1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/solid-transition-group": {
|
||||||
|
"version": "0.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/solid-transition-group/-/solid-transition-group-0.2.3.tgz",
|
||||||
|
"integrity": "sha512-iB72c9N5Kz9ykRqIXl0lQohOau4t0dhel9kjwFvx81UZJbVwaChMuBuyhiZmK24b8aKEK0w3uFM96ZxzcyZGdg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@solid-primitives/refs": "^1.0.5",
|
||||||
|
"@solid-primitives/transition-group": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0",
|
||||||
|
"pnpm": ">=8.6.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"solid-js": "^1.6.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/source-map-js": {
|
"node_modules/source-map-js": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
"photoswipe": "5.4.3",
|
"photoswipe": "5.4.3",
|
||||||
"qr-code-styling": "^1.6.0-rc.1",
|
"qr-code-styling": "^1.6.0-rc.1",
|
||||||
"sass": "1.67.0",
|
"sass": "1.67.0",
|
||||||
"solid-js": "1.7.11"
|
"solid-js": "1.7.11",
|
||||||
|
"solid-transition-group": "0.2.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,7 +351,7 @@
|
|||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.firstZap {
|
.topZap {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
@ -387,13 +387,52 @@
|
|||||||
&:hover {
|
&:hover {
|
||||||
background: var(--subtile-devider);
|
background: var(--subtile-devider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
transition: all 0.6s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.topZapEnterTransition {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(300px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.topZapExitTransition {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate7(30px);
|
||||||
|
}
|
||||||
|
|
||||||
.noteNotificationLink {
|
.noteNotificationLink {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: unset;
|
color: unset;
|
||||||
|
@ -97,6 +97,8 @@ const Note: Component<{
|
|||||||
|
|
||||||
let noteContextMenu: HTMLDivElement | undefined;
|
let noteContextMenu: HTMLDivElement | undefined;
|
||||||
|
|
||||||
|
let latestTopZap: string = '';
|
||||||
|
|
||||||
const onConfirmZap = (zapOption: ZapOption) => {
|
const onConfirmZap = (zapOption: ZapOption) => {
|
||||||
app?.actions.closeCustomZapModal();
|
app?.actions.closeCustomZapModal();
|
||||||
batch(() => {
|
batch(() => {
|
||||||
@ -106,6 +108,40 @@ const Note: Component<{
|
|||||||
updateReactionsState('zapped', () => true);
|
updateReactionsState('zapped', () => true);
|
||||||
updateReactionsState('showZapAnim', () => true)
|
updateReactionsState('showZapAnim', () => true)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
addTopZap(zapOption)
|
||||||
|
};
|
||||||
|
|
||||||
|
const addTopZap = (zapOption: ZapOption) => {
|
||||||
|
console.log('AADD')
|
||||||
|
|
||||||
|
const pubkey = account?.publicKey;
|
||||||
|
|
||||||
|
if (!pubkey) return;
|
||||||
|
|
||||||
|
const oldZaps = [ ...reactionsState.topZaps ];
|
||||||
|
|
||||||
|
latestTopZap = uuidv4() as string;
|
||||||
|
|
||||||
|
const newZap = {
|
||||||
|
amount: zapOption.amount || 0,
|
||||||
|
message: zapOption.message || '',
|
||||||
|
pubkey,
|
||||||
|
eventId: props.note.post.id,
|
||||||
|
id: latestTopZap,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!threadContext?.users.find((u) => u.pubkey === pubkey)) {
|
||||||
|
threadContext?.actions.fetchUsers([pubkey])
|
||||||
|
}
|
||||||
|
|
||||||
|
const zaps = [ ...oldZaps, { ...newZap }].sort((a, b) => b.amount - a.amount);
|
||||||
|
updateReactionsState('topZaps', () => [...zaps]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeTopZap = (zapOption: ZapOption) => {
|
||||||
|
const zaps = reactionsState.topZaps.filter(z => z.id !== latestTopZap);
|
||||||
|
updateReactionsState('topZaps', () => [...zaps]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSuccessZap = (zapOption: ZapOption) => {
|
const onSuccessZap = (zapOption: ZapOption) => {
|
||||||
@ -116,21 +152,21 @@ const Note: Component<{
|
|||||||
|
|
||||||
if (!pubkey) return;
|
if (!pubkey) return;
|
||||||
|
|
||||||
const oldZaps = [ ...reactionsState.topZaps ];
|
// const oldZaps = [ ...reactionsState.topZaps ];
|
||||||
|
|
||||||
const newZap = {
|
// const newZap = {
|
||||||
amount: zapOption.amount || 0,
|
// amount: zapOption.amount || 0,
|
||||||
message: zapOption.message || '',
|
// message: zapOption.message || '',
|
||||||
pubkey,
|
// pubkey,
|
||||||
eventId: props.note.post.id,
|
// eventId: props.note.post.id,
|
||||||
id: uuidv4() as string,
|
// id: uuidv4() as string,
|
||||||
};
|
// };
|
||||||
|
|
||||||
if (!threadContext?.users.find((u) => u.pubkey === pubkey)) {
|
// if (!threadContext?.users.find((u) => u.pubkey === pubkey)) {
|
||||||
threadContext?.actions.fetchUsers([pubkey])
|
// threadContext?.actions.fetchUsers([pubkey])
|
||||||
}
|
// }
|
||||||
|
|
||||||
const zaps = [ ...oldZaps, { ...newZap }].sort((a, b) => b.amount - a.amount);
|
// const zaps = [ ...oldZaps, { ...newZap }].sort((a, b) => b.amount - a.amount);
|
||||||
|
|
||||||
batch(() => {
|
batch(() => {
|
||||||
updateReactionsState('zapCount', (z) => z + 1);
|
updateReactionsState('zapCount', (z) => z + 1);
|
||||||
@ -140,7 +176,7 @@ const Note: Component<{
|
|||||||
updateReactionsState('showZapAnim', () => false);
|
updateReactionsState('showZapAnim', () => false);
|
||||||
updateReactionsState('hideZapIcon', () => false);
|
updateReactionsState('hideZapIcon', () => false);
|
||||||
updateReactionsState('zapped', () => true);
|
updateReactionsState('zapped', () => true);
|
||||||
updateReactionsState('topZaps', () => [...zaps]);
|
// updateReactionsState('topZaps', () => [...zaps]);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -156,6 +192,8 @@ const Note: Component<{
|
|||||||
updateReactionsState('hideZapIcon', () => false);
|
updateReactionsState('hideZapIcon', () => false);
|
||||||
updateReactionsState('zapped', () => props.note.post.noteActions.zapped);
|
updateReactionsState('zapped', () => props.note.post.noteActions.zapped);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
removeTopZap(zapOption);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCancelZap = (zapOption: ZapOption) => {
|
const onCancelZap = (zapOption: ZapOption) => {
|
||||||
@ -170,6 +208,8 @@ const Note: Component<{
|
|||||||
updateReactionsState('hideZapIcon', () => false);
|
updateReactionsState('hideZapIcon', () => false);
|
||||||
updateReactionsState('zapped', () => props.note.post.noteActions.zapped);
|
updateReactionsState('zapped', () => props.note.post.noteActions.zapped);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
removeTopZap(zapOption);
|
||||||
};
|
};
|
||||||
|
|
||||||
const customZapInfo: () => CustomZapInfo = () => ({
|
const customZapInfo: () => CustomZapInfo = () => ({
|
||||||
@ -293,6 +333,7 @@ const Note: Component<{
|
|||||||
customZapInfo={customZapInfo()}
|
customZapInfo={customZapInfo()}
|
||||||
wide={true}
|
wide={true}
|
||||||
large={true}
|
large={true}
|
||||||
|
onZapAnim={addTopZap}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { batch, Component, createEffect, Show } from 'solid-js';
|
import { batch, Component, createEffect, Show } from 'solid-js';
|
||||||
import { MenuItem, PrimalNote } from '../../../types/primal';
|
import { MenuItem, PrimalNote, ZapOption } from '../../../types/primal';
|
||||||
import { sendRepost, triggerImportEvents } from '../../../lib/notes';
|
import { sendRepost, triggerImportEvents } from '../../../lib/notes';
|
||||||
|
|
||||||
import styles from './NoteFooter.module.scss';
|
import styles from './NoteFooter.module.scss';
|
||||||
@ -22,7 +22,6 @@ import NoteFooterActionButton from './NoteFooterActionButton';
|
|||||||
import { NoteReactionsState } from '../Note';
|
import { NoteReactionsState } from '../Note';
|
||||||
import { SetStoreFunction } from 'solid-js/store';
|
import { SetStoreFunction } from 'solid-js/store';
|
||||||
import BookmarkNote from '../../BookmarkNote/BookmarkNote';
|
import BookmarkNote from '../../BookmarkNote/BookmarkNote';
|
||||||
import { APP_ID } from '../../../App';
|
|
||||||
|
|
||||||
export const lottieDuration = () => zapMD.op * 1_000 / zapMD.fr;
|
export const lottieDuration = () => zapMD.op * 1_000 / zapMD.fr;
|
||||||
|
|
||||||
@ -34,6 +33,7 @@ const NoteFooter: Component<{
|
|||||||
updateState: SetStoreFunction<NoteReactionsState>,
|
updateState: SetStoreFunction<NoteReactionsState>,
|
||||||
customZapInfo: CustomZapInfo,
|
customZapInfo: CustomZapInfo,
|
||||||
large?: boolean,
|
large?: boolean,
|
||||||
|
onZapAnim?: (zapOption: ZapOption) => void,
|
||||||
}> = (props) => {
|
}> = (props) => {
|
||||||
|
|
||||||
const account = useAccountContext();
|
const account = useAccountContext();
|
||||||
@ -268,10 +268,12 @@ const NoteFooter: Component<{
|
|||||||
|
|
||||||
batch(() => {
|
batch(() => {
|
||||||
props.updateState('isZapping', () => true);
|
props.updateState('isZapping', () => true);
|
||||||
props.updateState('showZapAnim', () => true);
|
|
||||||
props.updateState('satsZapped', (z) => z + amount);
|
props.updateState('satsZapped', (z) => z + amount);
|
||||||
|
props.updateState('showZapAnim', () => true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log('QUICK ZAP: ', props.onZapAnim)
|
||||||
|
props.onZapAnim && props.onZapAnim({ amount, message, emoji })
|
||||||
|
|
||||||
setTimeout(async () => {
|
setTimeout(async () => {
|
||||||
const success = await zapNote(props.note, account.publicKey, amount, message, account.relays);
|
const success = await zapNote(props.note, account.publicKey, amount, message, account.relays);
|
||||||
|
@ -2,6 +2,7 @@ import { Component, createMemo, createSignal, For, Show } from "solid-js";
|
|||||||
import { hookForDev } from "../../lib/devTools";
|
import { hookForDev } from "../../lib/devTools";
|
||||||
import { TopZap, useThreadContext } from "../../contexts/ThreadContext";
|
import { TopZap, useThreadContext } from "../../contexts/ThreadContext";
|
||||||
import Avatar from "../Avatar/Avatar";
|
import Avatar from "../Avatar/Avatar";
|
||||||
|
import { TransitionGroup } from 'solid-transition-group';
|
||||||
import styles from "./Note.module.scss";
|
import styles from "./Note.module.scss";
|
||||||
|
|
||||||
const NoteTopZaps: Component<{
|
const NoteTopZaps: Component<{
|
||||||
@ -62,39 +63,45 @@ const NoteTopZaps: Component<{
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div class={`${styles.zapHighlights}`}>
|
<div class={`${styles.zapHighlights}`}>
|
||||||
<For each={topZaps()}>
|
<TransitionGroup
|
||||||
{(zap, index) => (
|
name="top-zaps"
|
||||||
<>
|
enterClass={styles.topZapEnterTransition}
|
||||||
<button
|
exitClass={styles.topZapExitTransition}
|
||||||
class={styles.firstZap}
|
>
|
||||||
onClick={() => props.action()}
|
<For each={topZaps()}>
|
||||||
>
|
{(zap, index) => (
|
||||||
<Avatar user={zapSender(zap)} size="micro" />
|
<>
|
||||||
<div class={styles.amount}>
|
<button
|
||||||
{zap.amount.toLocaleString()}
|
class={`${styles.topZap}`}
|
||||||
</div>
|
onClick={() => props.action()}
|
||||||
<Show when={index() === 0}>
|
>
|
||||||
<div class={styles.description}>
|
<Avatar user={zapSender(zap)} size="micro" />
|
||||||
{zap.message}
|
<div class={styles.amount}>
|
||||||
|
{zap.amount.toLocaleString()}
|
||||||
</div>
|
</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>
|
</Show>
|
||||||
</button>
|
</>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
|
||||||
<Show when={index() === 0 && props.topZaps.length > 3}>
|
<Show when={hasMoreZaps()}>
|
||||||
<div class={styles.break}></div>
|
<button
|
||||||
</Show>
|
class={styles.moreZaps}
|
||||||
</>
|
onClick={() => props.action()}
|
||||||
)}
|
>
|
||||||
</For>
|
<div class={styles.contextIcon}></div>
|
||||||
|
</button>
|
||||||
<Show when={hasMoreZaps()}>
|
</Show>
|
||||||
<button
|
</TransitionGroup>
|
||||||
class={styles.moreZaps}
|
|
||||||
onClick={() => props.action()}
|
|
||||||
>
|
|
||||||
<div class={styles.contextIcon}></div>
|
|
||||||
</button>
|
|
||||||
</Show>
|
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user