mirror of
https://github.com/RSSNext/Folo.git
synced 2026-10-18 13:51:00 +08:00
feat: enhance AI timeline functionality and improve settings integration
This commit is contained in:
@@ -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 />}
|
||||
|
||||
+7
-4
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user