From 39ef8c9f0eada2dd7606e901491468577a4bb85a Mon Sep 17 00:00:00 2001 From: Whitewater Date: Fri, 27 Sep 2024 01:48:01 +0800 Subject: [PATCH] refactor: extract component from EntryContent (#617) * refactor: extract EntryTitle component from EntryContent * refactor: extract SupportCreator component from EntryContent --- .../entry-content/components/EntryTitle.tsx | 85 ++++++++++++ .../components/SupportCreator.tsx | 62 +++++++++ .../src/modules/entry-content/index.tsx | 124 +----------------- 3 files changed, 153 insertions(+), 118 deletions(-) create mode 100644 apps/renderer/src/modules/entry-content/components/EntryTitle.tsx create mode 100644 apps/renderer/src/modules/entry-content/components/SupportCreator.tsx diff --git a/apps/renderer/src/modules/entry-content/components/EntryTitle.tsx b/apps/renderer/src/modules/entry-content/components/EntryTitle.tsx new file mode 100644 index 000000000..b8ee7d0a8 --- /dev/null +++ b/apps/renderer/src/modules/entry-content/components/EntryTitle.tsx @@ -0,0 +1,85 @@ +import { useMemo } from "react" + +import { useWhoami } from "~/atoms/user" +import { useAuthQuery } from "~/hooks/common" +import type { FeedModel } from "~/models" +import { Queries } from "~/queries" +import { useEntry, useEntryReadHistory } from "~/store/entry" +import { getPreferredTitle, useFeedById } from "~/store/feed" + +import { EntryTranslation } from "../../entry-column/translation" + +interface EntryLinkProps { + entryId: string +} + +const safeUrl = (url: string, baseUrl: string) => { + try { + return new URL(url, baseUrl).href + } catch { + return url + } +} + +export const EntryTitle = ({ entryId }: EntryLinkProps) => { + const user = useWhoami() + const entry = useEntry(entryId) + const feed = useFeedById(entry?.feedId) as FeedModel + const entryHistory = useEntryReadHistory(entryId) + + const populatedFullHref = useMemo(() => { + const href = entry?.entries.url + if (!href) return "#" + + if (href.startsWith("http")) return href + const feedSiteUrl = feed?.siteUrl + if (href.startsWith("/") && feedSiteUrl) return safeUrl(href, feedSiteUrl) + return href + }, [entry?.entries.url, feed?.siteUrl]) + + const translation = useAuthQuery( + Queries.ai.translation({ + entry: entry!, + language: entry?.settings?.translation, + extraFields: ["title"], + }), + { + enabled: !!entry?.settings?.translation, + refetchOnMount: false, + refetchOnWindowFocus: false, + meta: { + persist: true, + }, + }, + ) + + if (!entry) return null + + return ( + +
+ +
+
{getPreferredTitle(feed)}
+
+ {entry.entries.publishedAt && new Date(entry.entries.publishedAt).toLocaleString()} + +
+ + + {( + (entryHistory?.readCount ?? 0) + + (entryHistory?.userIds?.every((id) => id !== user?.id) ? 1 : 0) + ) // if no me, +1 + .toLocaleString()} + +
+
+
+ ) +} diff --git a/apps/renderer/src/modules/entry-content/components/SupportCreator.tsx b/apps/renderer/src/modules/entry-content/components/SupportCreator.tsx new file mode 100644 index 000000000..55cd337f9 --- /dev/null +++ b/apps/renderer/src/modules/entry-content/components/SupportCreator.tsx @@ -0,0 +1,62 @@ +import { useTranslation } from "react-i18next" + +import { Button } from "~/components/ui/button" +import { Divider } from "~/components/ui/divider" +import { UserAvatar } from "~/components/user-button" +import { useEntry } from "~/store/entry" +import { useFeedById } from "~/store/feed" + +import { useTipModal } from "../../wallet/hooks" + +export const SupportCreator = ({ entryId }: { entryId: string }) => { + const { t } = useTranslation() + const entry = useEntry(entryId) + const feed = useFeedById(entry?.feedId) + + const openTipModal = useTipModal({ + userId: feed?.ownerUserId ?? undefined, + feedId: entry?.feedId, + entryId, + }) + + if (!feed || !feed.ownerUserId || feed.type !== "feed") return null + + return ( + <> + + +
+ + + {!!feed.tipUsers?.length && ( + <> +
+ {t("entry_content.support_amount", { amount: feed.tipUsers.length })} +
+
+ {feed.tipUsers?.map((user) => ( +
+ +
+ ))} +
+ + )} +
+ + ) +} diff --git a/apps/renderer/src/modules/entry-content/index.tsx b/apps/renderer/src/modules/entry-content/index.tsx index 6f4ebfff5..783f4e777 100644 --- a/apps/renderer/src/modules/entry-content/index.tsx +++ b/apps/renderer/src/modules/entry-content/index.tsx @@ -13,18 +13,14 @@ import { useEntryReadabilityContent, } from "~/atoms/readability" import { useUISettingKey } from "~/atoms/settings/ui" -import { useWhoami } from "~/atoms/user" import { m } from "~/components/common/Motion" import { ShadowDOM } from "~/components/common/ShadowDOM" import { AutoResizeHeight } from "~/components/ui/auto-resize-height" -import { Button } from "~/components/ui/button" -import { Divider } from "~/components/ui/divider" import { HTML } from "~/components/ui/markdown" import { Toc } from "~/components/ui/markdown/components/Toc" import { useInPeekModal } from "~/components/ui/modal/inspire/PeekModal" import { RootPortal } from "~/components/ui/portal" import { ScrollArea } from "~/components/ui/scroll-area" -import { UserAvatar } from "~/components/user-button" import { isWebBuild, ROUTE_FEED_PENDING } from "~/constants" import { shortcuts } from "~/constants/shortcuts" import { useEntryReadabilityToggle } from "~/hooks/biz/useEntryActions" @@ -41,27 +37,19 @@ import { WrappedElementProvider, } from "~/providers/wrapped-element-provider" import { Queries } from "~/queries" -import { useEntry, useEntryReadHistory } from "~/store/entry" -import { getPreferredTitle, useFeedById, useFeedHeaderTitle } from "~/store/feed" +import { useEntry } from "~/store/entry" +import { useFeedById, useFeedHeaderTitle } from "~/store/feed" import { LoadingWithIcon } from "../../components/ui/loading" import { EntryPlaceholderDaily } from "../ai/ai-daily/EntryPlaceholderDaily" -import { EntryTranslation } from "../entry-column/translation" -import { useTipModal } from "../wallet/hooks" import { setEntryContentScrollToTop, setEntryTitleMeta } from "./atoms" import { EntryPlaceholderLogo } from "./components/EntryPlaceholderLogo" +import { EntryTitle } from "./components/EntryTitle" +import { SupportCreator } from "./components/SupportCreator" import { EntryHeader } from "./header" import { EntryContentLoading } from "./loading" import { EntryContentProvider } from "./provider" -const safeUrl = (url: string, baseUrl: string) => { - try { - return new URL(url, baseUrl).href - } catch { - return url - } -} - export const EntryContent = ({ entryId }: { entryId: ActiveEntryId }) => { const title = useFeedHeaderTitle() const { feedId, view } = useRouteParams() @@ -87,7 +75,6 @@ export const EntryContent = ({ entryId }: { entryId: ActiveEntryId }) => { export const EntryContentRender: Component<{ entryId: string }> = ({ entryId, className }) => { const { t } = useTranslation() - const user = useWhoami() const { error, data, isPending } = useAuthQuery(Queries.entries.byId(entryId), { staleTime: 300_000, @@ -97,27 +84,7 @@ export const EntryContentRender: Component<{ entryId: string }> = ({ entryId, cl useTitle(entry?.entries.title) const feed = useFeedById(entry?.feedId) as FeedModel - - const entryHistory = useEntryReadHistory(entryId) - const readerRenderInlineStyle = useUISettingKey("readerRenderInlineStyle") - - const translation = useAuthQuery( - Queries.ai.translation({ - entry: entry!, - language: entry?.settings?.translation, - extraFields: ["title"], - }), - { - enabled: !!entry?.settings?.translation, - refetchOnMount: false, - refetchOnWindowFocus: false, - meta: { - persist: true, - }, - }, - ) - const summary = useAuthQuery( Queries.ai.summary({ entryId, @@ -166,22 +133,6 @@ export const EntryContentRender: Component<{ entryId: string }> = ({ entryId, cl [readerFontFamily], ) - const populatedFullHref = useMemo(() => { - const href = entry?.entries.url - if (!href) return "#" - - if (href.startsWith("http")) return href - const feedSiteUrl = feed?.siteUrl - if (href.startsWith("/") && feedSiteUrl) return safeUrl(href, feedSiteUrl) - return href - }, [entry?.entries.url, feed?.siteUrl]) - - const openTipModal = useTipModal({ - userId: feed?.ownerUserId ?? undefined, - feedId: entry?.feedId, - entryId, - }) - if (!entry) return null const content = entry?.entries.content ?? data?.entries.content @@ -216,33 +167,7 @@ export const EntryContentRender: Component<{ entryId: string }> = ({ entryId, cl onContextMenu={stopPropagation} className="relative m-auto min-w-0 max-w-[550px] @3xl:max-w-[70ch]" > - -
- -
-
- {getPreferredTitle(feed)} -
-
- {entry.entries.publishedAt && new Date(entry.entries.publishedAt).toLocaleString()} - -
- - - {( - (entryHistory?.readCount ?? 0) + - (entryHistory?.userIds?.every((id) => id !== user?.id) ? 1 : 0) - ) // if no me, +1 - .toLocaleString()} - -
-
-
+
@@ -301,44 +226,7 @@ export const EntryContentRender: Component<{ entryId: string }> = ({ entryId, cl
)} - {feed?.ownerUserId && ( - <> - - -
- - - {!!feed.tipUsers?.length && ( - <> -
- {t("entry_content.support_amount", { amount: feed.tipUsers.length })} -
-
- {feed.tipUsers?.map((user) => ( -
- -
- ))} -
- - )} -
- - )} + {feed?.ownerUserId && }