diff --git a/src/renderer/src/modules/discover/user-form.tsx b/src/renderer/src/modules/discover/user-form.tsx
new file mode 100644
index 000000000..36716f601
--- /dev/null
+++ b/src/renderer/src/modules/discover/user-form.tsx
@@ -0,0 +1,41 @@
+import { LoadingCircle } from "@renderer/components/ui/loading"
+import { useAuthQuery } from "@renderer/hooks/common"
+import { Queries } from "@renderer/queries"
+
+import { DiscoverFeedForm } from "./DiscoverFeedForm"
+
+export function DiscoverUser() {
+ const { data, isLoading } = useAuthQuery(
+ Queries.discover.rsshubNamespace({
+ namespace: "follow",
+ }),
+ {
+ meta: {
+ persist: true,
+ },
+ },
+ )
+
+ if (isLoading) {
+ return (
+
+
+
+ )
+ }
+
+ return (
+ <>
+ {data?.follow.routes && (
+
+
+
+ )}
+ >
+ )
+}
diff --git a/src/renderer/src/modules/entry-column/Items/notification-item.tsx b/src/renderer/src/modules/entry-column/Items/notification-item.tsx
index b2de946f4..b9e5ccb84 100644
--- a/src/renderer/src/modules/entry-column/Items/notification-item.tsx
+++ b/src/renderer/src/modules/entry-column/Items/notification-item.tsx
@@ -4,7 +4,9 @@ import { ListItem } from "@renderer/modules/entry-column/templates/list-item-tem
import type { UniversalItemProps } from "../types"
export function NotificationItem({ entryId, entryPreview, translation }: UniversalItemProps) {
- return
+ return (
+
+ )
}
export const NotificationItemSkeleton = (
diff --git a/src/renderer/src/modules/entry-column/templates/list-item-template.tsx b/src/renderer/src/modules/entry-column/templates/list-item-template.tsx
index bee8051a0..8255785f9 100644
--- a/src/renderer/src/modules/entry-column/templates/list-item-template.tsx
+++ b/src/renderer/src/modules/entry-column/templates/list-item-template.tsx
@@ -1,15 +1,21 @@
+import { env } from "@env"
import { AudioPlayer, useAudioPlayerAtomSelector } from "@renderer/atoms/player"
import { FeedIcon } from "@renderer/components/feed-icon"
+import { FollowIcon } from "@renderer/components/icons/follow"
+import { Button } from "@renderer/components/ui/button"
import { RelativeTime } from "@renderer/components/ui/datetime"
import { Media } from "@renderer/components/ui/media"
+import { useModalStack } from "@renderer/components/ui/modal"
import { FEED_COLLECTION_LIST } from "@renderer/constants"
import { useAsRead } from "@renderer/hooks/biz/useAsRead"
import { useRouteParamsSelector } from "@renderer/hooks/biz/useRouteParams"
import { cn, isSafari } from "@renderer/lib/utils"
+import { FeedForm } from "@renderer/modules/discover/feed-form"
import { EntryTranslation } from "@renderer/modules/entry-column/translation"
import { Queries } from "@renderer/queries"
import { useEntry } from "@renderer/store/entry/hooks"
import { getPreferredTitle, useFeedById } from "@renderer/store/feed"
+import { useSubscriptionStore } from "@renderer/store/subscription"
import { useDebounceCallback } from "usehooks-ts"
import { ReactVirtuosoItemPlaceholder } from "../../../components/ui/placeholder"
@@ -22,9 +28,11 @@ export function ListItem({
translation,
withDetails,
withAudio,
+ withFollow,
}: UniversalItemProps & {
withDetails?: boolean
withAudio?: boolean
+ withFollow?: boolean
}) {
const entry = useEntry(entryId) || entryPreview
@@ -42,6 +50,13 @@ export function ListItem({
{ leading: false },
)
+ const isSubscription = withFollow && entry?.entries.url?.startsWith(`${env.VITE_WEB_URL}/feed/`)
+ const feedId = isSubscription
+ ? entry?.entries.url?.replace(`${env.VITE_WEB_URL}/feed/`, "")
+ : undefined
+ const isFollowed = !!useSubscriptionStore((state) => feedId && state.data[feedId])
+ const { present } = useModalStack()
+
// NOTE: prevent 0 height element, react virtuoso will not stop render any more
if (!entry || !feed) return
@@ -122,6 +137,27 @@ export function ListItem({
)}
+ {feedId && !isFollowed && (
+
+ )}
+
{withAudio && entry.entries?.attachments?.[0].url && (