diff --git a/apps/desktop/layer/renderer/src/modules/power/ranking/index.tsx b/apps/desktop/layer/renderer/src/modules/power/ranking/index.tsx
deleted file mode 100644
index 217d477322..0000000000
--- a/apps/desktop/layer/renderer/src/modules/power/ranking/index.tsx
+++ /dev/null
@@ -1,146 +0,0 @@
-import { useMobile } from "@follow/components/hooks/useMobile.js"
-import { MotionButtonBase } from "@follow/components/ui/button/index.js"
-import {
- Table,
- TableBody,
- TableCell,
- TableHead,
- TableHeader,
- TableRow,
-} from "@follow/components/ui/table/index.jsx"
-import { EllipsisHorizontalTextWithTooltip } from "@follow/components/ui/typography/index.js"
-import { cn } from "@follow/utils/utils"
-import { Fragment } from "react"
-import { useTranslation } from "react-i18next"
-
-import { useWhoami } from "~/atoms/user"
-import { usePresentUserProfileModal } from "~/modules/profile/hooks"
-import { SettingSectionTitle } from "~/modules/settings/section"
-import { UserAvatar } from "~/modules/user/UserAvatar"
-import { Balance } from "~/modules/wallet/balance"
-import { Level } from "~/modules/wallet/level"
-import type { useWalletTransactions } from "~/queries/wallet"
-import { useWalletRanking } from "~/queries/wallet"
-
-const medals = ["", "🥇", "🥈", "🥉"]
-const rankNumber = (index: number) => {
- if (index < medals.length) {
- return
{medals[index]}
- }
- return
{index}
-}
-
-export const PowerRanking: Component = ({ className }) => {
- const { t } = useTranslation("settings")
- const ranking = useWalletRanking()
-
- const isMobile = useMobile()
- return (
-
-
-
-
-
-
- #
- {t("wallet.ranking.name")}
- {t("wallet.ranking.power")}
- {t("wallet.ranking.level")}
-
-
-
- {ranking.data?.map((row, index) => {
- const lastRow = ranking.data?.[index - 1]
- const hasGap = lastRow?.rank && row.rank && row.rank - lastRow.rank !== 1
-
- return (
-
- {!!hasGap && (
- <>
-
- ...
-
-
-
-
-
-
- >
- )}
-
- {!!row.rank && rankNumber(row.rank)}
-
-
-
-
-
-
- {row.powerToken}
-
-
-
- {!!row.level && }
-
-
- )
- })}
-
- ...
-
-
-
-
-
- )
-}
-
-const UserRenderer = ({
- user,
- avatarClassName,
-}: {
- user?: NonNullable
["data"]>[number][
- | "fromUser"
- | "toUser"]
- avatarClassName?: string
-}) => {
- const { t } = useTranslation("settings")
- const me = useWhoami()
- const isMe = user?.id === me?.id
-
- const name = isMe ? t("wallet.transactions.you") : user?.name || APP_NAME
-
- const presentUserModal = usePresentUserProfileModal("drawer")
- return (
- {
- if (user?.id) presentUserModal(user.id)
- }}
- className="cursor-button flex w-full min-w-0 items-center gap-2"
- >
-
-
-
-
- {isMe ? (
- {t("wallet.transactions.you")}
- ) : (
- {name}
- )}
-
-
-
- )
-}
diff --git a/apps/desktop/layer/renderer/src/modules/power/transaction-section/index.tsx b/apps/desktop/layer/renderer/src/modules/power/transaction-section/index.tsx
index 53369561e2..9bc417e8cc 100644
--- a/apps/desktop/layer/renderer/src/modules/power/transaction-section/index.tsx
+++ b/apps/desktop/layer/renderer/src/modules/power/transaction-section/index.tsx
@@ -4,7 +4,6 @@ import { TransactionTypes } from "@follow/models/types"
import { useState } from "react"
import { useTranslation } from "react-i18next"
-import { useServerConfigs } from "~/atoms/server-configs"
import { useWhoami } from "~/atoms/user"
import { getBlockchainExplorerUrl } from "~/lib/utils"
import { SettingSectionTitle } from "~/modules/settings/section"
@@ -27,18 +26,11 @@ export const TransactionsSection: Component = ({ className }) => {
type: type === "all" ? undefined : (type as (typeof TransactionTypes)[number]),
})
- const serverConfigs = useServerConfigs()
-
if (!myWallet) return null
return (
-
- {t("wallet.transactions.description", {
- percentage: Number.parseInt(serverConfigs?.TAX_POINT || "0") / 100,
- })}
-
setType(val)}>
{tabs.map((tab) => (
diff --git a/apps/desktop/layer/renderer/src/modules/profile/two-factor.tsx b/apps/desktop/layer/renderer/src/modules/profile/two-factor.tsx
index 5ac0eb1522..55c0e309f8 100644
--- a/apps/desktop/layer/renderer/src/modules/profile/two-factor.tsx
+++ b/apps/desktop/layer/renderer/src/modules/profile/two-factor.tsx
@@ -208,7 +208,7 @@ export const TwoFactorForm = () => {
return totpURI ? (
-
+
{
const { entryId } = use(EntryInfoContext)
- const entry = useEntry(entryId)
- const mediaDuration = formatTimeToSeconds(entry?.entries.attachments?.[0]?.duration_in_seconds)
+ const entry = useEntry(entryId, (state) => {
+ const attachments = state.entries.attachments || []
+ const firstAttachment = attachments[0]
+ const { duration_in_seconds, url: firstAttachmentUrl } = firstAttachment || {}
+ const seconds = duration_in_seconds ? (formatTimeToSeconds(duration_in_seconds) ?? 0) : 0
+
+ return {
+ firstAttachmentUrl,
+ seconds,
+ }
+ })
+ const src = entry?.firstAttachmentUrl
+ const mediaDuration = entry?.seconds
- const src = entry?.entries?.attachments?.[0]?.url
if (!src) return {props.time}
const seekTo = timeStringToSeconds(props.time)
diff --git a/apps/desktop/layer/renderer/src/modules/renderer/html.tsx b/apps/desktop/layer/renderer/src/modules/renderer/html.tsx
index 247c3048c6..4b2501cf10 100644
--- a/apps/desktop/layer/renderer/src/modules/renderer/html.tsx
+++ b/apps/desktop/layer/renderer/src/modules/renderer/html.tsx
@@ -1,5 +1,6 @@
import { FeedViewType } from "@follow/constants"
import { useMemo } from "react"
+import type { JSX } from "react/jsx-runtime"
import {
MarkdownImageRecordContext,
@@ -26,11 +27,9 @@ export function EntryContentHTMLRenderer
} & HTMLProps) {
- const entry = useEntry(entryId)
-
- const images: Record = useMemo(() => {
- return (
- entry?.entries.media?.reduce(
+ const entry = useEntry(entryId, (state) => {
+ const images =
+ state.entries.media?.reduce(
(acc, media) => {
if (media.height && media.width) {
acc[media.url] = media
@@ -39,8 +38,13 @@ export function EntryContentHTMLRenderer,
) ?? {}
- )
- }, [entry])
+
+ return {
+ images,
+ }
+ })
+
+ const images: Record = useMemo(() => entry?.images ?? {}, [entry])
const actions: MarkdownRenderActions = useMemo(() => {
return {
isAudio() {
diff --git a/apps/desktop/layer/renderer/src/modules/settings/control.tsx b/apps/desktop/layer/renderer/src/modules/settings/control.tsx
index f73836f99d..0fe7ef9426 100644
--- a/apps/desktop/layer/renderer/src/modules/settings/control.tsx
+++ b/apps/desktop/layer/renderer/src/modules/settings/control.tsx
@@ -121,7 +121,7 @@ export const SettingActionItem = ({
}) => (
diff --git a/apps/desktop/layer/renderer/src/modules/settings/helper/EnhancedIndicator.tsx b/apps/desktop/layer/renderer/src/modules/settings/helper/EnhancedIndicator.tsx
index 129a200020..c316f6fc69 100644
--- a/apps/desktop/layer/renderer/src/modules/settings/helper/EnhancedIndicator.tsx
+++ b/apps/desktop/layer/renderer/src/modules/settings/helper/EnhancedIndicator.tsx
@@ -8,6 +8,8 @@ import { IconTransition } from "~/components/ux/transition/icon"
export const EnhancedSettingsIndicator = () => {
const enhancedSettings = useGeneralSettingKey("enhancedSettings")
const { t } = useTranslation("settings")
+
+ if (!enhancedSettings) return null
return (
diff --git a/apps/desktop/layer/renderer/src/modules/settings/helper/builder.ts b/apps/desktop/layer/renderer/src/modules/settings/helper/builder.ts
index bbe99c7f0d..6b1c2983b6 100644
--- a/apps/desktop/layer/renderer/src/modules/settings/helper/builder.ts
+++ b/apps/desktop/layer/renderer/src/modules/settings/helper/builder.ts
@@ -1,3 +1,5 @@
+import type { JSX } from "react/jsx-runtime"
+
import type { SettingItem } from "./setting-builder"
import { createSettingBuilder } from "./setting-builder"
diff --git a/apps/desktop/layer/renderer/src/modules/settings/helper/withSettingEnable.tsx b/apps/desktop/layer/renderer/src/modules/settings/helper/withSettingEnable.tsx
index 74a12c1071..31d6f553ce 100644
--- a/apps/desktop/layer/renderer/src/modules/settings/helper/withSettingEnable.tsx
+++ b/apps/desktop/layer/renderer/src/modules/settings/helper/withSettingEnable.tsx
@@ -1,5 +1,6 @@
import type { FC } from "react"
import { createElement } from "react"
+import type { JSX } from "react/jsx-runtime"
type WithSelect = T & {
select: (_s: any) => any
diff --git a/apps/desktop/layer/renderer/src/modules/settings/modal/content.mobile.tsx b/apps/desktop/layer/renderer/src/modules/settings/modal/content.mobile.tsx
index aa5320e51e..1ea6f16ee5 100644
--- a/apps/desktop/layer/renderer/src/modules/settings/modal/content.mobile.tsx
+++ b/apps/desktop/layer/renderer/src/modules/settings/modal/content.mobile.tsx
@@ -1,3 +1,4 @@
+import { useTypeScriptHappyCallback } from "@follow/hooks"
import PKG from "@pkg"
import { createElement, Suspense } from "react"
import { Trans, useTranslation } from "react-i18next"
@@ -21,12 +22,15 @@ export const MobileSettingModalContent = () => {
{
- present({
- title: "",
- content: () => ,
- })
- }}
+ onChange={useTypeScriptHappyCallback(
+ (tab) => {
+ present({
+ title: "",
+ content: () => ,
+ })
+ },
+ [present],
+ )}
/>
diff --git a/apps/desktop/layer/renderer/src/modules/settings/modal/content.tsx b/apps/desktop/layer/renderer/src/modules/settings/modal/content.tsx
index 1acb7afe40..25c16d50a3 100644
--- a/apps/desktop/layer/renderer/src/modules/settings/modal/content.tsx
+++ b/apps/desktop/layer/renderer/src/modules/settings/modal/content.tsx
@@ -1,13 +1,16 @@
import { ScrollArea } from "@follow/components/ui/scroll-area/index.js"
+import { cn } from "@follow/utils"
import { repository } from "@pkg"
import type { FC } from "react"
import { Suspense, useDeferredValue, useLayoutEffect, useState } from "react"
import { Trans } from "react-i18next"
+import { useLoaderData } from "react-router"
import { ModalClose } from "~/components/ui/modal/stacked/components"
import { SettingsTitle } from "~/modules/settings/title"
import { getSettingPages } from "../settings-glob"
+import type { SettingPageConfig } from "../utils"
import { SettingTabProvider, useSettingTab } from "./context"
import { SettingModalLayout } from "./layout"
@@ -39,6 +42,7 @@ const Content = () => {
}
}, [key])
+ const config = (useLoaderData() || loader || {}) as SettingPageConfig
if (!Component) return null
return (
@@ -49,12 +53,15 @@ const Content = () => {
mask={false}
ref={setScroller}
rootClassName="h-full grow flex-1 shrink-0 overflow-auto pl-8 pr-7"
- viewportClassName="px-1 min-h-full [&>div]:min-h-full [&>div]:relative pb-8"
+ viewportClassName={cn(
+ "px-1 min-h-full [&>div]:min-h-full [&>div]:relative",
+ config.viewportClassName,
+ )}
>
-
-
+
+
void
item: SettingPageConfig
path: string
-
+ isActive: boolean
onChange?: (tab: string) => void
}) => {
- const { tab, setTab, item, path, onChange } = props
+ const { setTab, item, path, onChange, isActive } = props
const { disableIf } = item
const ctx = useSettingPageContext()
@@ -174,7 +173,7 @@ const SettingItemButtonImpl = (props: {
diff --git a/apps/desktop/layer/renderer/src/modules/user/ProfileButton.shared.tsx b/apps/desktop/layer/renderer/src/modules/user/ProfileButton.shared.tsx
deleted file mode 100644
index 7a7b6b46f1..0000000000
--- a/apps/desktop/layer/renderer/src/modules/user/ProfileButton.shared.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import type { WalletModel } from "@follow/models"
-import { cn } from "@follow/utils/utils"
-
-import { Balance } from "../wallet/balance"
-
-export const PowerButton: Component<{
- isLoading: boolean
- myWallet?: WalletModel
- className?: string
-}> = ({ isLoading, myWallet, className }) => {
- return (
-
-
- {isLoading ? (
-
- ) : (
- {BigInt(myWallet?.powerToken || 0n)}
- )}
-
- )
-}
diff --git a/apps/desktop/layer/renderer/src/pages/(main)/(layer)/(subview)/discover/category/[category].tsx b/apps/desktop/layer/renderer/src/pages/(main)/(layer)/(subview)/discover/category/[category].tsx
index 52cf0235c9..c427a7ad3e 100644
--- a/apps/desktop/layer/renderer/src/pages/(main)/(layer)/(subview)/discover/category/[category].tsx
+++ b/apps/desktop/layer/renderer/src/pages/(main)/(layer)/(subview)/discover/category/[category].tsx
@@ -4,7 +4,7 @@ import { Input } from "@follow/components/ui/input/Input.js"
import { LoadingCircle } from "@follow/components/ui/loading/index.js"
import { EllipsisHorizontalTextWithTooltip } from "@follow/components/ui/typography/EllipsisWithTooltip.js"
import { CategoryMap, RSSHubCategories } from "@follow/constants"
-import { cn } from "@follow/utils/utils"
+import { cn, formatNumber } from "@follow/utils/utils"
import { keepPreviousData } from "@tanstack/react-query"
import { useMemo, useState } from "react"
import { useTranslation } from "react-i18next"
@@ -49,7 +49,7 @@ export const Component = () => {
const data: RouteData = rsshubPopular.data as any
- const rsshubAnalytics = useAuthQuery(Queries.discover.rsshubAnalytics(), {
+ const rsshubAnalytics = useAuthQuery(Queries.discover.rsshubAnalytics({ lang }), {
staleTime: 1000 * 60 * 60 * 24, // 1 day
placeholderData: keepPreviousData,
})
@@ -281,7 +281,7 @@ const RecommendationListItem = ({
{analytics?.subscriptionCount && (
- {analytics?.subscriptionCount}
+ {formatNumber(analytics?.subscriptionCount || 0)}
)}
diff --git a/apps/desktop/layer/renderer/src/pages/(main)/(layer)/(subview)/power/index.tsx b/apps/desktop/layer/renderer/src/pages/(main)/(layer)/(subview)/power/index.tsx
index c968349429..5f5bcae171 100644
--- a/apps/desktop/layer/renderer/src/pages/(main)/(layer)/(subview)/power/index.tsx
+++ b/apps/desktop/layer/renderer/src/pages/(main)/(layer)/(subview)/power/index.tsx
@@ -4,7 +4,6 @@ import { useTranslation } from "react-i18next"
import { useSubViewTitle } from "~/modules/app-layout/subview/hooks"
import { MyWalletSection } from "~/modules/power/my-wallet-section"
-import { PowerRanking } from "~/modules/power/ranking"
import { TransactionsSection } from "~/modules/power/transaction-section"
export function Component() {
@@ -25,9 +24,6 @@ export function Component() {