Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: initial MEOW UI #2246

Merged
merged 15 commits into from
Sep 5, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const MeowIcon = () => {
return (
<svg width='18' height='16' viewBox='0 0 18 16' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path
d='M14.7736 9.58895C13.063 12.4503 9.54849 12.0278 9.54849 12.0278C9.54849 6.8438 14.0989 6.8438 14.0989 6.8438H15.6272C15.5026 7.99174 15.1925 8.88857 14.7736 9.58895ZM3.22642 9.58895C2.80755 8.88857 2.49736 7.99174 2.37283 6.8438H3.90113C3.90113 6.8438 8.45151 6.8438 8.45151 12.0278C8.45151 12.0278 4.93698 12.4503 3.22642 9.58895ZM16.5832 0L11.7272 3.81508H6.27283L1.41679 0L0 9.052L5.96094 15.6549C6.05887 15.7637 6.17887 15.8508 6.31245 15.91C6.44604 15.9693 6.59038 16 6.73642 16H11.2636C11.4096 16 11.554 15.9693 11.6875 15.91C11.8211 15.8508 11.9406 15.7637 12.0391 15.6549L18 9.052L16.5832 0Z'
fill='#01F4CB'
/>
</svg>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './meow-action';
21 changes: 21 additions & 0 deletions src/components/messenger/feed/components/post/actions/meow/lib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const INCREMENTS = 10;
const MS_BETWEEN_INCREMENTS = 1000;
const OPTIONS = 3;

interface MeowActionConfig {
increments: number;
msBetweenIncrements: number;
options: number;
max: number;
}

export const CONFIG: MeowActionConfig = {
increments: INCREMENTS,
msBetweenIncrements: MS_BETWEEN_INCREMENTS,
options: OPTIONS,
max: INCREMENTS * OPTIONS,
};

export const getScale = (amount: number, increments: number, max: number): number => {
return 1 + (Math.min(amount, max) / increments) * 0.05;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.Container > *:active {
background: none !important;
}

.Wash {
background: var(--color-secondary-5);
height: 100%;
left: 0;
position: absolute;
top: 0;
width: 100%;
z-index: -1;
}

.Amount {
font-size: 8px !important;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { AnimatePresence, motion } from 'framer-motion';
import { Action } from '@zero-tech/zui/components/Post';

import { MeowIcon } from './icon';
import { useMeowAction } from './useMeow';

import styles from './meow-action.module.scss';

export interface MeowActionProps {
meows?: number;
}

export const MeowAction = ({ meows = 0 }: MeowActionProps) => {
const { amount, backgroundOpacity, cancel, isActive, scale, start, stop, totalMeows } = useMeowAction(meows);

return (
<motion.div style={{ scale }} onTapStart={start} onTap={stop} onTapCancel={cancel} className={styles.Container}>
<Action>
<AnimatePresence>
{amount && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: backgroundOpacity }}
exit={{ opacity: 0 }}
className={styles.Wash}
/>
)}
</AnimatePresence>
<MeowIcon />
<span>{totalMeows}</span>
<AnimatePresence>
{amount && isActive && (
<motion.b
initial={{ opacity: 0, y: '100%', width: 0 }}
animate={{ opacity: 1, y: 0, width: 'auto' }}
exit={{ opacity: 0, y: '-200%', width: 0 }}
className={styles.Amount}
>
+{amount}
</motion.b>
)}
</AnimatePresence>
</Action>
</motion.div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { useRef, useState } from 'react';
import { useSpring } from 'framer-motion';
import { CONFIG, getScale } from './lib';

export const useMeowAction = (meows?: number) => {
const intervalRef = useRef(null);
const scale = useSpring(1, { stiffness: 300, damping: 7 });

const [amount, setAmount] = useState<number | null>(null);
const [isActive, setIsActive] = useState(false);
const [userAmount, setUserAmount] = useState<number>(0);

/**
* Starts the MEOW action
* Creates a timer which increments the amount at a set interval
* Stops when the amount reaches the maximum
* Also stops when cancel is called
*/
const start = () => {
setIsActive(true);

if (amount === null) {
setAmount(CONFIG.increments);
scale.set(getScale(CONFIG.increments, CONFIG.increments, CONFIG.max));
}

intervalRef.current = setInterval(() => {
setAmount((prevAmount) => {
const newAmount = (prevAmount ?? 0) + CONFIG.increments;

if (newAmount > CONFIG.max) {
return prevAmount;
}

scale.set(getScale(newAmount, CONFIG.increments, CONFIG.max));
return newAmount;
});
}, CONFIG.msBetweenIncrements);
};

/**
* Successfully trigger MEOW
*/
const stop = () => {
// Send data to matrix, then reset
setUserAmount(amount);
resetValues();
};

/**
* Cancel the MEOW action
*/
const cancel = () => {
resetValues();
};

const resetValues = () => {
setIsActive(false);
intervalRef.current && clearInterval(intervalRef.current);
setAmount(null);
scale.set(1);
};

return {
amount,
backgroundOpacity: (1 / CONFIG.max) * amount,
cancel,
isActive,
scale,
start,
stop,
totalMeows: meows + (amount ?? userAmount),
userAmount,
};
};
7 changes: 7 additions & 0 deletions src/components/messenger/feed/components/post/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
import { Name, Post as ZUIPost } from '@zero-tech/zui/components/Post';
import { Timestamp } from '@zero-tech/zui/components/Post/components/Timestamp';
import { Avatar } from '@zero-tech/zui/components';
import { MeowAction } from './actions/meow';
import { featureFlags } from '../../../../../lib/feature-flags';
import { Media, MediaType } from '../../../../../store/messages';

import styles from './styles.module.scss';

export interface PostProps {
Expand All @@ -28,6 +31,8 @@
}: PostProps) => {
const [isImageLoaded, setIsImageLoaded] = useState(false);

const isMeowsEnabled = featureFlags.enableMeows;

const multilineText = useMemo(
() =>
text?.split('\n').map((line, index) => (
Expand Down Expand Up @@ -100,7 +105,7 @@

return null;
},
[isImageLoaded, loadAttachmentDetails]

Check warning on line 108 in src/components/messenger/feed/components/post/index.tsx

View workflow job for this annotation

GitHub Actions / run-lint

React Hook useCallback has missing dependencies: 'getPlaceholderDimensions', 'handleImageLoad', and 'messageId'. Either include them or remove the dependency array
);

return (
Expand Down Expand Up @@ -133,6 +138,8 @@
</>
}
options={<Timestamp className={styles.Date} timestamp={timestamp} />}
// @note: This has no backend, so we're mocking MEOWs
actions={isMeowsEnabled && <MeowAction meows={text.length * 10} />}
/>
</div>
);
Expand Down
8 changes: 8 additions & 0 deletions src/lib/feature-flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,14 @@ export class FeatureFlags {
set enableAddWallets(value: boolean) {
this._setBoolean('enableAddWallets', value);
}

get enableMeows() {
return this._getBoolean('enableMeows', false);
}

set enableMeows(value: boolean) {
this._setBoolean('enableMeows', value);
}
}

export const featureFlags = new FeatureFlags();
Expand Down