From a61bd173a9310fd4c9a27b08fcd057dd4231a9e3 Mon Sep 17 00:00:00 2001 From: Innei Date: Tue, 24 Sep 2024 21:32:49 +0800 Subject: [PATCH] feat(lottie): star lottie Signed-off-by: Innei --- apps/renderer/global.d.ts | 7 ++ .../components/ui/lottie-container/index.tsx | 99 ++++++++++++++++++ .../src/hooks/biz/useEntryActions.tsx | 15 ++- apps/renderer/src/lottie/star.lottie | Bin 0 -> 2326 bytes .../entry-column/layouts/EntryItemWrapper.tsx | 2 +- .../(with-layout)/profile/[id]/index.tsx | 5 +- .../renderer/src/providers/root-providers.tsx | 2 + 7 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 apps/renderer/src/components/ui/lottie-container/index.tsx create mode 100644 apps/renderer/src/lottie/star.lottie diff --git a/apps/renderer/global.d.ts b/apps/renderer/global.d.ts index 5553b75556..fbd50a0b90 100644 --- a/apps/renderer/global.d.ts +++ b/apps/renderer/global.d.ts @@ -9,4 +9,11 @@ declare global { platform: NodeJS.Platform } } + +declare module "react" { + export interface AriaAttributes { + "data-testid"?: string + } +} + export {} diff --git a/apps/renderer/src/components/ui/lottie-container/index.tsx b/apps/renderer/src/components/ui/lottie-container/index.tsx new file mode 100644 index 0000000000..0e51bb05ac --- /dev/null +++ b/apps/renderer/src/components/ui/lottie-container/index.tsx @@ -0,0 +1,99 @@ +import type { DotLottie } from "@lottiefiles/dotlottie-react" +import { DotLottieReact } from "@lottiefiles/dotlottie-react" +import { atom, useAtomValue } from "jotai" +import type { FC, ReactNode, RefCallback } from "react" +import { useEffect, useState } from "react" + +import { jotaiStore } from "~/lib/jotai" + +import { RootPortal } from "../portal" + +const portalElementsAtom = atom([] as ReactNode[]) + +export function LottieRenderContainer() { + const elements = useAtomValue(portalElementsAtom, { store: jotaiStore }) + + return ( + +
+ {elements.map((element) => element)} +
+
+ ) +} + +type LottieOptions = { + once?: boolean + + x: number + y: number + + height?: number + width?: number + className?: string + + onComplete?: () => void + + speed?: number +} +export const mountLottie = (url: string, options: LottieOptions) => { + const { once = true, height, width, x, y, className, speed } = options + + const Lottie: FC = () => { + const [dotLottie, setDotLottie] = useState(null) + + useEffect(() => { + function onComplete() { + if (once) { + unmount() + } + + options.onComplete?.() + } + + if (dotLottie) { + dotLottie.addEventListener("complete", onComplete) + } + + return () => { + if (dotLottie) { + dotLottie.removeEventListener("complete", onComplete) + } + } + }, [dotLottie]) + + const dotLottieRefCallback: RefCallback = (dotLottie) => { + setDotLottie(dotLottie) + } + + return ( + + ) + } + + const element = + const unmount = () => { + jotaiStore.set(portalElementsAtom, (prev) => prev.filter((e) => e !== element)) + } + + jotaiStore.set(portalElementsAtom, (prev) => [...prev, element]) + return unmount +} diff --git a/apps/renderer/src/hooks/biz/useEntryActions.tsx b/apps/renderer/src/hooks/biz/useEntryActions.tsx index 6ed9db3e66..a76015dd0f 100644 --- a/apps/renderer/src/hooks/biz/useEntryActions.tsx +++ b/apps/renderer/src/hooks/biz/useEntryActions.tsx @@ -14,6 +14,7 @@ import { } from "~/atoms/readability" import { useIntegrationSettingKey } from "~/atoms/settings/integration" import { whoami } from "~/atoms/user" +import { mountLottie } from "~/components/ui/lottie-container" import { SimpleIconsEagle, SimpleIconsInstapaper, @@ -23,12 +24,15 @@ import { shortcuts } from "~/constants/shortcuts" import { tipcClient } from "~/lib/client" import { nextFrame } from "~/lib/dom" import { getOS } from "~/lib/utils" +import StarAnimationUri from "~/lottie/star.lottie?url" import type { CombinedEntryModel } from "~/models" import { useTipModal } from "~/modules/wallet/hooks" import type { FlatEntryModel } from "~/store/entry" import { entryActions } from "~/store/entry" import { useFeedById } from "~/store/feed" +const absoluteStarAnimationUri = new URL(StarAnimationUri, import.meta.url).href + export const useEntryReadabilityToggle = ({ id, url }: { id: string; url: string }) => useCallback(async () => { const status = getReadabilityStatus()[id] @@ -165,7 +169,7 @@ export const useEntryActions = ({ hide?: boolean active?: boolean disabled?: boolean - onClick: () => void + onClick: (e: React.MouseEvent) => void }[] = [ { name: t("entry_actions.save_media_to_eagle"), @@ -295,7 +299,14 @@ export const useEntryActions = ({ name: t("entry_actions.star"), className: "i-mgc-star-cute-re", hide: !!populatedEntry.collections, - onClick: () => { + onClick: (e) => { + mountLottie(absoluteStarAnimationUri, { + x: e.clientX - 90, + y: e.clientY - 70, + height: 126, + width: 252, + }) + collect.mutate() }, }, diff --git a/apps/renderer/src/lottie/star.lottie b/apps/renderer/src/lottie/star.lottie new file mode 100644 index 0000000000000000000000000000000000000000..da36007d688715f52eecfc2f1f14590d24fd8d86 GIT binary patch literal 2326 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 literal 0 HcmV?d00001 diff --git a/apps/renderer/src/modules/entry-column/layouts/EntryItemWrapper.tsx b/apps/renderer/src/modules/entry-column/layouts/EntryItemWrapper.tsx index 60572a57df..53f25d616f 100644 --- a/apps/renderer/src/modules/entry-column/layouts/EntryItemWrapper.tsx +++ b/apps/renderer/src/modules/entry-column/layouts/EntryItemWrapper.tsx @@ -86,7 +86,7 @@ export const EntryItemWrapper: FC< .map((item) => ({ type: "text" as const, label: item.name, - click: item.onClick, + click: () => item.onClick(e), shortcut: item.shortcut, })), { diff --git a/apps/renderer/src/pages/(external)/(with-layout)/profile/[id]/index.tsx b/apps/renderer/src/pages/(external)/(with-layout)/profile/[id]/index.tsx index fbc6196e60..d60e8a788e 100644 --- a/apps/renderer/src/pages/(external)/(with-layout)/profile/[id]/index.tsx +++ b/apps/renderer/src/pages/(external)/(with-layout)/profile/[id]/index.tsx @@ -60,7 +60,10 @@ export function Component() {
{user.data?.handle}
-
+
{subscriptions.isLoading ? ( ) : ( diff --git a/apps/renderer/src/providers/root-providers.tsx b/apps/renderer/src/providers/root-providers.tsx index c14d309e2c..16715f979b 100644 --- a/apps/renderer/src/providers/root-providers.tsx +++ b/apps/renderer/src/providers/root-providers.tsx @@ -5,6 +5,7 @@ import { Provider } from "jotai" import type { FC, PropsWithChildren } from "react" import { HotkeysProvider } from "react-hotkeys-hook" +import { LottieRenderContainer } from "~/components/ui/lottie-container" import { ModalStackProvider } from "~/components/ui/modal" import { Toaster } from "~/components/ui/sonner" import { HotKeyScopeMap } from "~/constants" @@ -39,6 +40,7 @@ export const RootProviders: FC = ({ children }) => ( + {import.meta.env.DEV && }