Top zap transitions

This commit is contained in:
Bojan Mojsilovic 2024-04-29 14:06:49 +02:00
parent 9455df93ab
commit 7423100823
6 changed files with 166 additions and 51 deletions

29
package-lock.json generated
View File

@ -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",

View File

@ -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"
} }
} }

View File

@ -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;

View File

@ -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>

View File

@ -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);

View File

@ -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,11 +63,16 @@ const NoteTopZaps: Component<{
} }
> >
<div class={`${styles.zapHighlights}`}> <div class={`${styles.zapHighlights}`}>
<TransitionGroup
name="top-zaps"
enterClass={styles.topZapEnterTransition}
exitClass={styles.topZapExitTransition}
>
<For each={topZaps()}> <For each={topZaps()}>
{(zap, index) => ( {(zap, index) => (
<> <>
<button <button
class={styles.firstZap} class={`${styles.topZap}`}
onClick={() => props.action()} onClick={() => props.action()}
> >
<Avatar user={zapSender(zap)} size="micro" /> <Avatar user={zapSender(zap)} size="micro" />
@ -95,6 +101,7 @@ const NoteTopZaps: Component<{
<div class={styles.contextIcon}></div> <div class={styles.contextIcon}></div>
</button> </button>
</Show> </Show>
</TransitionGroup>
</div> </div>
</Show> </Show>
); );