refactor: enhance mobile settings modal and layout components

- Introduced `useTypeScriptHappyCallback` for improved tab change handling in the mobile settings modal.
- Updated the `Content` component to utilize `useLoaderData` for better data management and added a dynamic `viewportClassName`.
- Simplified the `SettingItemButtonImpl` by removing the `tab` prop and using an `isActive` flag for better clarity in active state management.

Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
Innei 2025-05-27 23:29:11 +08:00
parent 00342e7a7d
commit de00a1864e
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
3 changed files with 35 additions and 25 deletions

View File

@ -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 = () => {
</div>
<SidebarItems
onChange={(tab) => {
present({
title: "",
content: () => <Content tab={tab} />,
})
}}
onChange={useTypeScriptHappyCallback(
(tab) => {
present({
title: "",
content: () => <Content tab={tab} />,
})
},
[present],
)}
/>
</div>
</div>

View File

@ -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,
)}
>
<Component />
<div className="h-12" />
<p className="absolute inset-x-0 bottom-0 flex items-center justify-center gap-1 text-xs opacity-80">
<div className="h-16" />
<p className="absolute inset-x-0 bottom-4 flex items-center justify-center gap-1 text-xs opacity-80">
<Trans
ns="settings"
i18nKey="common.give_star"

View File

@ -155,14 +155,13 @@ export function SettingModalLayout(
}
const SettingItemButtonImpl = (props: {
tab: string
setTab: (tab: string) => 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: {
<button
className={cn(
"text-text my-0.5 flex w-full items-center rounded-lg px-2.5 py-0.5 leading-loose",
tab === path && "!bg-theme-item-active !text-text",
isActive && "!bg-theme-item-active !text-text",
!IN_ELECTRON && "hover:bg-theme-item-hover duration-200",
disabled && "cursor-not-allowed opacity-50",
)}
@ -202,22 +201,22 @@ const SettingItemButtonImpl = (props: {
const SettingItemButton = memo(SettingItemButtonImpl)
export const SidebarItems = memo(
(props: { onChange?: (tab: string) => void }) => {
const { onChange } = props
const setTab = useSetSettingTab()
const tab = useSettingTab()
const availableSettings = useAvailableSettings()
return availableSettings.map((t) => (
export const SidebarItems = memo((props: { onChange?: (tab: string) => void }) => {
const { onChange } = props
const setTab = useSetSettingTab()
const tab = useSettingTab()
const availableSettings = useAvailableSettings()
return availableSettings.map((t) => {
const isActive = tab === t.path
return (
<SettingItemButton
key={t.path}
tab={tab}
isActive={isActive}
setTab={setTab}
item={t}
path={t.path}
onChange={onChange}
/>
))
},
() => true,
)
)
})
})