diff --git a/apps/desktop/src/renderer/src/hooks/biz/useEntryActions.tsx b/apps/desktop/src/renderer/src/hooks/biz/useEntryActions.tsx index 44179cdfb..af72b34dd 100644 --- a/apps/desktop/src/renderer/src/hooks/biz/useEntryActions.tsx +++ b/apps/desktop/src/renderer/src/hooks/biz/useEntryActions.tsx @@ -141,6 +141,7 @@ export const useEntryActions = ({ type: feed.type, ownerUserId: feed.ownerUserId, id: feed.id, + siteUrl: feed.siteUrl, } }) const listId = useRouteParamsSelector((s) => s.listId) @@ -242,7 +243,9 @@ export const useEntryActions = ({ }), new EntryActionMenuItem({ id: COMMAND_ID.entry.viewSourceContent, - onClick: runCmdFn(COMMAND_ID.entry.viewSourceContent, [{ entryId }]), + onClick: runCmdFn(COMMAND_ID.entry.viewSourceContent, [ + { entryId, siteUrl: feed?.siteUrl }, + ]), hide: isMobile() || !entry?.entries.url, active: isShowSourceContent, entryId, @@ -343,6 +346,7 @@ export const useEntryActions = ({ isEntryInReadability, feed?.id, feed?.ownerUserId, + feed?.siteUrl, hasEntry, imageLength, inList, diff --git a/apps/desktop/src/renderer/src/hooks/common/useFeedSafeUrl.ts b/apps/desktop/src/renderer/src/hooks/common/useFeedSafeUrl.ts new file mode 100644 index 000000000..098ea52b5 --- /dev/null +++ b/apps/desktop/src/renderer/src/hooks/common/useFeedSafeUrl.ts @@ -0,0 +1,28 @@ +import { resolveUrlWithBase } from "@follow/utils/utils" +import { useMemo } from "react" + +import { useEntry } from "~/store/entry" +import { useFeedById } from "~/store/feed" +import { useInboxById } from "~/store/inbox" + +export const useFeedSafeUrl = (entryId: string) => { + const entry = useEntry(entryId) + const feed = useFeedById(entry?.feedId) + const inbox = useInboxById(entry?.inboxId, (inbox) => inbox !== null) + + return useMemo(() => { + if (inbox) return entry?.entries.authorUrl + const href = entry?.entries.url + if (!href) return "#" + + if (href.startsWith("http")) { + const domain = new URL(href).hostname + if (domain === "localhost") return "#" + + return href + } + const feedSiteUrl = feed?.type === "feed" ? feed.siteUrl : null + if (feedSiteUrl) return resolveUrlWithBase(href, feedSiteUrl) + return href + }, [entry?.entries.authorUrl, entry?.entries.url, feed?.type, inbox]) +} diff --git a/apps/desktop/src/renderer/src/modules/command/commands/entry.tsx b/apps/desktop/src/renderer/src/modules/command/commands/entry.tsx index f9e526dac..cf2e9ce03 100644 --- a/apps/desktop/src/renderer/src/modules/command/commands/entry.tsx +++ b/apps/desktop/src/renderer/src/modules/command/commands/entry.tsx @@ -1,6 +1,6 @@ import { FeedViewType, UserRole } from "@follow/constants" import { IN_ELECTRON } from "@follow/shared/constants" -import { cn } from "@follow/utils/utils" +import { cn, resolveUrlWithBase } from "@follow/utils/utils" import { useMutation } from "@tanstack/react-query" import { useTranslation } from "react-i18next" import { toast } from "sonner" @@ -234,7 +234,7 @@ export const useRegisterEntryCommands = () => { id: COMMAND_ID.entry.viewSourceContent, label: t("entry_actions.view_source_content"), icon: , - run: ({ entryId }) => { + run: ({ entryId, siteUrl }) => { if (!getShowSourceContent()) { const entry = useEntryStore.getState().flatMapEntries[entryId] if (!entry || !entry.entries.url) { @@ -250,7 +250,7 @@ export const useRegisterEntryCommands = () => { if (viewPreviewInModal) { showSourceContentModal({ title: entry.entries.title ?? undefined, - src: entry.entries.url, + src: siteUrl ? resolveUrlWithBase(entry?.entries.url, siteUrl) : entry?.entries.url, }) return } diff --git a/apps/desktop/src/renderer/src/modules/command/commands/types.ts b/apps/desktop/src/renderer/src/modules/command/commands/types.ts index 81bc3cf8d..07e7eb88a 100644 --- a/apps/desktop/src/renderer/src/modules/command/commands/types.ts +++ b/apps/desktop/src/renderer/src/modules/command/commands/types.ts @@ -42,7 +42,7 @@ export type OpenInBrowserCommand = Command<{ export type ViewSourceContentCommand = Command<{ id: typeof COMMAND_ID.entry.viewSourceContent - fn: (data: { entryId: string }) => void + fn: (data: { entryId: string; siteUrl?: string | null | undefined }) => void }> export type ShareCommand = Command<{ diff --git a/apps/desktop/src/renderer/src/modules/discover/form.tsx b/apps/desktop/src/renderer/src/modules/discover/form.tsx index 1cb82bf51..f5131e1f3 100644 --- a/apps/desktop/src/renderer/src/modules/discover/form.tsx +++ b/apps/desktop/src/renderer/src/modules/discover/form.tsx @@ -30,6 +30,7 @@ import { Media } from "~/components/ui/media" import { useModalStack } from "~/components/ui/modal/stacked/hooks" import { useFollow } from "~/hooks/biz/useFollow" import { getRouteParams } from "~/hooks/biz/useRouteParams" +import { useFeedSafeUrl } from "~/hooks/common/useFeedSafeUrl" import { apiClient } from "~/lib/api-fetch" import { UrlBuilder } from "~/lib/url-builder" @@ -365,42 +366,9 @@ const SearchCard: FC<{