feat: enhance AI timeline functionality and improve settings integration

This commit is contained in:
DIYgod
2025-11-20 15:01:16 +08:00
parent 7797b7b8fd
commit 6913079254
4 changed files with 12 additions and 32 deletions
@@ -15,10 +15,8 @@ import type { FC } from "react"
import { useCallback } from "react"
import { useTranslation } from "react-i18next"
import { useNavigate } from "react-router"
import { toast } from "sonner"
import { previewBackPath } from "~/atoms/preview"
import { useAISettingKey } from "~/atoms/settings/ai"
import { useGeneralSettingKey } from "~/atoms/settings/general"
import { useSubscriptionColumnShow } from "~/atoms/sidebar"
import { ROUTE_ENTRY_PENDING } from "~/constants"
@@ -32,8 +30,6 @@ import { useRunCommandFn } from "~/modules/command/hooks/use-command"
import { useCommandShortcut } from "~/modules/command/hooks/use-command-binding"
import { EntryHeader } from "~/modules/entry-content/components/entry-header"
import { FeedIcon } from "~/modules/feed/feed-icon"
import { useSettingModal } from "~/modules/settings/modal/useSettingModal"
import { AI_SETTING_SECTION_IDS } from "~/modules/settings/tabs/ai"
import { useRefreshFeedMutation } from "~/queries/feed"
import { useFeedHeaderIcon, useFeedHeaderTitle } from "~/store/feed/hooks"
@@ -55,8 +51,6 @@ export const EntryListHeader: FC<{
const unreadOnly = useGeneralSettingKey("unreadOnly")
const [aiTimelineEnabled, setAiTimelineEnabled] = useAtom(aiTimelineEnabledAtom)
const aiEnabled = useFeature("ai")
const aiTimelinePrompt = useAISettingKey("aiTimelinePrompt")
const showSettings = useSettingModal()
const { feedId, entryId, view, isCollection } = routerParams
const isPreview = useIsPreviewFeed()
@@ -113,16 +107,8 @@ export const EntryListHeader: FC<{
const showAiTimelineToggle = aiEnabled
const handleAiTimelineButtonClick = useCallback(() => {
const hasTimelinePrompt = !!aiTimelinePrompt?.trim()
if (!aiTimelineEnabled && !hasTimelinePrompt) {
toast.info(t("entry_list_header.ai_timeline_prompt_required"))
showSettings({ tab: "ai", section: AI_SETTING_SECTION_IDS.timelinePrompt })
return
}
setAiTimelineEnabled((prev) => !prev)
}, [aiTimelineEnabled, aiTimelinePrompt, setAiTimelineEnabled, showSettings, t])
}, [setAiTimelineEnabled])
const renderAiTimelineButton = () => {
if (!showAiTimelineToggle) return null
@@ -182,7 +168,7 @@ export const EntryListHeader: FC<{
{showEntryHeader && <EntryHeader entryId={entryId} />}
{(showAiTimelineToggle || showTimelineSummaryButton) && (
<div className="flex items-center gap-2">
{renderAiTimelineButton()}
{aiTimelineEnabled && renderAiTimelineButton()}
{renderTimelineSummaryButton()}
</div>
)}
@@ -190,7 +176,7 @@ export const EntryListHeader: FC<{
</>
)}
{!isWideMode && renderAiTimelineButton()}
{!isWideMode && aiTimelineEnabled && renderAiTimelineButton()}
<AppendTaildingDivider>
{view === FeedViewType.Pictures && <SwitchToMasonryButton />}
@@ -4,14 +4,16 @@ import {
DEFAULT_SUMMARIZE_TIMELINE_SHORTCUT_ID,
} from "@follow/shared/settings/defaults"
import { stopPropagation } from "@follow/utils/dom"
import { useSetAtom } from "jotai"
import { useCallback } from "react"
import { toast } from "sonner"
import { useSendAIShortcut } from "~/modules/ai-chat/hooks/useSendAIShortcut"
import { aiTimelineEnabledAtom } from "~/modules/entry-column/atoms/ai-timeline"
import { useSettingModal } from "~/modules/settings/modal/use-setting-modal-hack"
export const EntryPlaceholderLogo = () => {
const { sendAIShortcut } = useSendAIShortcut()
const setAiTimelineEnabled = useSetAtom(aiTimelineEnabledAtom)
const settingModalPresent = useSettingModal()
const handleSummarizeTimeline = useCallback(() => {
void sendAIShortcut({
@@ -25,6 +27,9 @@ export const EntryPlaceholderLogo = () => {
ensureNewChat: true,
})
}, [sendAIShortcut])
const handleToggleAiTimeline = useCallback(() => {
setAiTimelineEnabled((prev) => !prev)
}, [setAiTimelineEnabled])
const buttons = [
{
@@ -39,9 +44,7 @@ export const EntryPlaceholderLogo = () => {
},
{
label: "Sort the timeline by importance",
onClick: () => {
toast.success("Coming soon!")
},
onClick: handleToggleAiTimeline,
icon: <i className="i-mgc-refresh-4-ai-cute-re text-base" />,
},
{
@@ -9,10 +9,8 @@ import { ByokSection } from "./ai/byok"
import { MCPServicesSection } from "./ai/mcp/MCPServicesSection"
import { UserMemorySection } from "./ai/memory"
import { PanelStyleSection } from "./ai/PanelStyleSection"
import { PersonalizePromptSection } from "./ai/PersonalizePromptSection"
import { AIShortcutsSection } from "./ai/shortcuts/AIShortcutsSection"
import { TaskSchedulingSection } from "./ai/tasks"
import { TimelinePromptSection } from "./ai/TimelinePromptSection"
import { UsageAnalysisSection } from "./ai/usage"
const SettingBuilder = createSettingBuilder(useAISettingValue)
@@ -51,14 +49,6 @@ export const SettingAI = () => {
value: t("personalize.title"),
},
PersonalizePromptSection,
{
type: "title",
value: t("timeline_prompt.title"),
id: AI_SETTING_SECTION_IDS.timelinePrompt,
},
TimelinePromptSection,
{
type: "title",
value: t("shortcuts.title"),
@@ -104,12 +104,13 @@ export const useEntriesQuery = (
queryFn: ({ pageParam }) =>
entrySyncServices.fetchEntries({
...props,
limit: aiSort ? 100 : limit,
pageParam,
read: unreadOnly ? false : undefined,
excludePrivate: hidePrivateSubscriptionsInTimeline,
}),
getNextPageParam: (lastPage) => lastPage.data?.at(-1)?.entries.publishedAt,
getNextPageParam: (lastPage) => (aiSort ? null : lastPage.data?.at(-1)?.entries.publishedAt),
initialPageParam: undefined as undefined | string,
refetchOnWindowFocus: false,
refetchOnReconnect: false,