feat: context menu of adding feeds to lists
This commit is contained in:
parent
eb20dfd705
commit
afb79a27fb
|
|
@ -7,9 +7,11 @@ import { useModalStack } from "~/components/ui/modal"
|
|||
import type { NativeMenuItem } from "~/lib/native-menu"
|
||||
import { useFeedClaimModal } from "~/modules/claim"
|
||||
import { FeedForm } from "~/modules/discover/feed-form"
|
||||
import { getFeedById, useFeedById } from "~/store/feed"
|
||||
import { Queries } from "~/queries"
|
||||
import { getFeedById, useAddFeedToFeedList, useFeedById } from "~/store/feed"
|
||||
import { subscriptionActions, useSubscriptionByFeedId } from "~/store/subscription"
|
||||
|
||||
import { useAuthQuery } from "../common"
|
||||
import { useNavigateEntry } from "./useNavigateEntry"
|
||||
import { getRouteParams } from "./useRouteParams"
|
||||
import { useDeleteSubscription } from "./useSubscriptionActions"
|
||||
|
|
@ -36,50 +38,13 @@ export const useFeedActions = ({
|
|||
const navigateEntry = useNavigateEntry()
|
||||
const isEntryList = type === "entryList"
|
||||
|
||||
const listList = useAuthQuery(Queries.lists.list())
|
||||
const addMutation = useAddFeedToFeedList()
|
||||
|
||||
const items = useMemo(() => {
|
||||
if (!feed) return []
|
||||
const isList = feed?.type === "list"
|
||||
const items: NativeMenuItem[] = [
|
||||
{
|
||||
type: "text" as const,
|
||||
label: isEntryList ? t("sidebar.feed_actions.edit_feed") : t("sidebar.feed_actions.edit"),
|
||||
shortcut: "E",
|
||||
click: () => {
|
||||
present({
|
||||
title: isList
|
||||
? t("sidebar.feed_actions.edit_list")
|
||||
: t("sidebar.feed_actions.edit_feed"),
|
||||
content: ({ dismiss }) => (
|
||||
<FeedForm asWidget id={feedId} onSuccess={dismiss} isList={isList} />
|
||||
),
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "text" as const,
|
||||
label: isEntryList
|
||||
? t("sidebar.feed_actions.unfollow_feed")
|
||||
: t("sidebar.feed_actions.unfollow"),
|
||||
shortcut: "Meta+Backspace",
|
||||
click: () => deleteSubscription.mutate(subscription),
|
||||
},
|
||||
{
|
||||
type: "text" as const,
|
||||
label: t(
|
||||
isList
|
||||
? "sidebar.feed_actions.navigate_to_list"
|
||||
: "sidebar.feed_actions.navigate_to_feed",
|
||||
),
|
||||
shortcut: "Meta+G",
|
||||
disabled: !isEntryList || getRouteParams().feedId === feedId,
|
||||
click: () => {
|
||||
navigateEntry({ feedId })
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "separator" as const,
|
||||
disabled: isEntryList,
|
||||
},
|
||||
...(!isList
|
||||
? [
|
||||
{
|
||||
|
|
@ -121,6 +86,66 @@ export const useFeedActions = ({
|
|||
type: "separator" as const,
|
||||
disabled: isEntryList,
|
||||
},
|
||||
{
|
||||
type: "text" as const,
|
||||
label: t("sidebar.feed_column.context_menu.add_feeds_to_list"),
|
||||
enabled: !!listList.data?.length,
|
||||
submenu: listList.data?.map((list) => ({
|
||||
label: list.title || "",
|
||||
type: "text",
|
||||
icon: list.image,
|
||||
click() {
|
||||
return addMutation.mutate({
|
||||
feedId,
|
||||
listId: list.id,
|
||||
})
|
||||
},
|
||||
})),
|
||||
},
|
||||
{
|
||||
type: "separator" as const,
|
||||
disabled: isEntryList,
|
||||
},
|
||||
{
|
||||
type: "text" as const,
|
||||
label: isEntryList ? t("sidebar.feed_actions.edit_feed") : t("sidebar.feed_actions.edit"),
|
||||
shortcut: "E",
|
||||
click: () => {
|
||||
present({
|
||||
title: isList
|
||||
? t("sidebar.feed_actions.edit_list")
|
||||
: t("sidebar.feed_actions.edit_feed"),
|
||||
content: ({ dismiss }) => (
|
||||
<FeedForm asWidget id={feedId} onSuccess={dismiss} isList={isList} />
|
||||
),
|
||||
})
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "text" as const,
|
||||
label: isEntryList
|
||||
? t("sidebar.feed_actions.unfollow_feed")
|
||||
: t("sidebar.feed_actions.unfollow"),
|
||||
shortcut: "Meta+Backspace",
|
||||
click: () => deleteSubscription.mutate(subscription),
|
||||
},
|
||||
{
|
||||
type: "text" as const,
|
||||
label: t(
|
||||
isList
|
||||
? "sidebar.feed_actions.navigate_to_list"
|
||||
: "sidebar.feed_actions.navigate_to_feed",
|
||||
),
|
||||
shortcut: "Meta+G",
|
||||
disabled: !isEntryList || getRouteParams().feedId === feedId,
|
||||
click: () => {
|
||||
navigateEntry({ feedId })
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "separator" as const,
|
||||
disabled: isEntryList,
|
||||
},
|
||||
{
|
||||
type: "text" as const,
|
||||
label: t(
|
||||
|
|
|
|||
|
|
@ -10,12 +10,13 @@ import { LoadingCircle } from "~/components/ui/loading"
|
|||
import { ROUTE_FEED_IN_FOLDER, views } from "~/constants"
|
||||
import { useNavigateEntry } from "~/hooks/biz/useNavigateEntry"
|
||||
import { getRouteParams, useRouteParamsSelector } from "~/hooks/biz/useRouteParams"
|
||||
import { useAnyPointDown, useInputComposition } from "~/hooks/common"
|
||||
import { useAnyPointDown, useAuthQuery, useInputComposition } from "~/hooks/common"
|
||||
import { stopPropagation } from "~/lib/dom"
|
||||
import type { FeedViewType } from "~/lib/enum"
|
||||
import { showNativeMenu } from "~/lib/native-menu"
|
||||
import { cn, sortByAlphabet } from "~/lib/utils"
|
||||
import { getPreferredTitle, useFeedStore } from "~/store/feed"
|
||||
import { Queries } from "~/queries"
|
||||
import { getPreferredTitle, useAddFeedToFeedList, useFeedStore } from "~/store/feed"
|
||||
import { subscriptionActions, useSubscriptionByFeedId } from "~/store/subscription"
|
||||
import { useFeedUnreadStore } from "~/store/unread"
|
||||
|
||||
|
|
@ -115,6 +116,9 @@ function FeedCategoryImpl({
|
|||
})
|
||||
const isCategoryIsWaiting = isChangePending
|
||||
|
||||
const listList = useAuthQuery(Queries.lists.list())
|
||||
const addMutation = useAddFeedToFeedList()
|
||||
|
||||
return (
|
||||
<div tabIndex={-1} onClick={stopPropagation}>
|
||||
{!!showCollapse && (
|
||||
|
|
@ -133,24 +137,6 @@ function FeedCategoryImpl({
|
|||
setIsContextMenuOpen(true)
|
||||
showNativeMenu(
|
||||
[
|
||||
{
|
||||
type: "text",
|
||||
enabled: !!(folderName && typeof view === "number"),
|
||||
label: t("sidebar.feed_column.context_menu.change_to_other_view"),
|
||||
submenu: views
|
||||
.filter((v) => v.view !== view)
|
||||
.map((v) => ({
|
||||
// TODO: fix this type error
|
||||
label: t(v.name),
|
||||
enabled: true,
|
||||
type: "text",
|
||||
shortcut: (v.view + 1).toString(),
|
||||
icon: v.icon,
|
||||
click() {
|
||||
return changeCategoryView(v.view)
|
||||
},
|
||||
})),
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
label: t("sidebar.feed_column.context_menu.mark_as_read"),
|
||||
|
|
@ -161,6 +147,39 @@ function FeedCategoryImpl({
|
|||
},
|
||||
},
|
||||
{ type: "separator" },
|
||||
{
|
||||
type: "text",
|
||||
label: t("sidebar.feed_column.context_menu.add_feeds_to_list"),
|
||||
enabled: !!listList.data?.length,
|
||||
submenu: listList.data?.map((list) => ({
|
||||
label: list.title || "",
|
||||
type: "text",
|
||||
icon: list.image,
|
||||
click() {
|
||||
return addMutation.mutate({
|
||||
feedIds: ids,
|
||||
listId: list.id,
|
||||
})
|
||||
},
|
||||
})),
|
||||
},
|
||||
{ type: "separator" },
|
||||
{
|
||||
type: "text",
|
||||
enabled: !!(folderName && typeof view === "number"),
|
||||
label: t("sidebar.feed_column.context_menu.change_to_other_view"),
|
||||
submenu: views
|
||||
.filter((v) => v.view !== view)
|
||||
.map((v) => ({
|
||||
label: t(v.name),
|
||||
type: "text",
|
||||
shortcut: (v.view + 1).toString(),
|
||||
icon: v.icon,
|
||||
click() {
|
||||
return changeCategoryView(v.view)
|
||||
},
|
||||
})),
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
label: t("sidebar.feed_column.context_menu.rename_category"),
|
||||
|
|
|
|||
|
|
@ -65,15 +65,14 @@ export const useFeedHeaderTitle = () => {
|
|||
export const useAddFeedToFeedList = (options?: { onSuccess: () => void; onError: () => void }) => {
|
||||
const { t } = useTranslation("settings")
|
||||
return useMutation({
|
||||
mutationFn: async (payload: { feedId: string; listId: string }) => {
|
||||
const feed = await apiClient.lists.feeds.$post({
|
||||
json: {
|
||||
listId: payload.listId,
|
||||
feedId: payload.feedId,
|
||||
},
|
||||
mutationFn: async (
|
||||
payload: { feedId: string; listId: string } | { feedIds: string[]; listId: string },
|
||||
) => {
|
||||
const feeds = await apiClient.lists.feeds.$post({
|
||||
json: payload,
|
||||
})
|
||||
|
||||
feedActions.addFeedToFeedList(payload.listId, feed.data)
|
||||
feeds.data.forEach((feed) => feedActions.addFeedToFeedList(payload.listId, feed))
|
||||
},
|
||||
onSuccess: () => {
|
||||
toast.success(t("lists.feeds.add.success"))
|
||||
|
|
|
|||
|
|
@ -182,7 +182,8 @@
|
|||
"sidebar.feed_actions.open_site_in_browser": "Open site in browser",
|
||||
"sidebar.feed_actions.unfollow": "Unfollow",
|
||||
"sidebar.feed_actions.unfollow_feed": "Unfollow feed",
|
||||
"sidebar.feed_column.context_menu.change_to_other_view": "Change to other view",
|
||||
"sidebar.feed_column.context_menu.add_feeds_to_list": "Add feeds to list",
|
||||
"sidebar.feed_column.context_menu.change_to_other_view": "Switch to another view",
|
||||
"sidebar.feed_column.context_menu.delete_category": "Delete category",
|
||||
"sidebar.feed_column.context_menu.delete_category_confirmation": "Delete category {{folderName}}?",
|
||||
"sidebar.feed_column.context_menu.mark_as_read": "Mark as read",
|
||||
|
|
|
|||
|
|
@ -3440,6 +3440,9 @@ declare const _routes: hono_hono_base.HonoBase<Env, {
|
|||
json: {
|
||||
feedId: string;
|
||||
listId: string;
|
||||
} | {
|
||||
feedIds: string[];
|
||||
listId: string;
|
||||
};
|
||||
};
|
||||
output: {
|
||||
|
|
@ -3471,7 +3474,7 @@ declare const _routes: hono_hono_base.HonoBase<Env, {
|
|||
handle: string | null;
|
||||
createdAt: string;
|
||||
}[] | null | undefined;
|
||||
};
|
||||
}[];
|
||||
};
|
||||
outputFormat: "json" | "text";
|
||||
status: 200;
|
||||
|
|
|
|||
Loading…
Reference in New Issue