Skip to content

Commit

Permalink
feat(ui): enhance context menu with hover effects, disable option, an…
Browse files Browse the repository at this point in the history
…d quick list creation (#787)

* feat: disabled when exceed invite limitation

* feat: add item hover

* fix: create list minimum value is 0

* feat: add actions settings loading

* feat: hide menu when enabled is false

* feat: change opacity when menu is disabled

* feat: add quick access for add feed to list

* fix: unify list item hover style

Signed-off-by: Innei <[email protected]>

* refactor: create list modal

Signed-off-by: Innei <[email protected]>

* update

Signed-off-by: Innei <[email protected]>

* unify style

Signed-off-by: Innei <[email protected]>

* native app style

Signed-off-by: Innei <[email protected]>

---------

Signed-off-by: Innei <[email protected]>
Co-authored-by: Innei <[email protected]>
  • Loading branch information
ischanx and Innei authored Oct 7, 2024
1 parent ce72b7a commit d2b5cc3
Show file tree
Hide file tree
Showing 23 changed files with 304 additions and 222 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const ContextMenuSubTrigger = React.forwardRef<
inset && "pl-8",
"center gap-2",
className,
props.disabled && "cursor-not-allowed opacity-30",
)}
{...props}
>
Expand Down
55 changes: 35 additions & 20 deletions apps/renderer/src/hooks/biz/useFeedActions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useFeedClaimModal } from "~/modules/claim"
import { FeedForm } from "~/modules/discover/feed-form"
import { InboxForm } from "~/modules/discover/inbox-form"
import { ListForm } from "~/modules/discover/list-form"
import { ListCreationModalContent } from "~/modules/settings/tabs/lists/modals"
import {
getFeedById,
useAddFeedToFeedList,
Expand All @@ -37,7 +38,6 @@ export const useFeedActions = ({
const { t } = useTranslation()
const feed = useFeedById(feedId)
const subscription = useSubscriptionByFeedId(feedId)

const { present } = useModalStack()
const deleteSubscription = useDeleteSubscription({})
const claimFeed = useFeedClaimModal({
Expand Down Expand Up @@ -92,28 +92,43 @@ export const useFeedActions = ({
{
type: "text" as const,
label: t("sidebar.feed_column.context_menu.add_feeds_to_list"),
enabled: !!listByView?.length,
submenu: listByView?.map((list) => {
const isIncluded = list.feedIds.includes(feedId)
return {
label: list.title || "",
submenu: [
...listByView.map((list) => {
const isIncluded = list.feedIds.includes(feedId)
return {
label: list.title || "",
type: "text" as const,
checked: isIncluded,
click() {
if (!isIncluded) {
addFeedToListMutation({
feedId,
listId: list.id,
})
} else {
removeFeedFromListMutation({
feedId,
listId: list.id,
})
}
},
}
}),
{
type: "separator",
},
{
label: t("sidebar.feed_actions.create_list"),
type: "text" as const,
checked: isIncluded,
icon: <i className="i-mgc-add-cute-re" />,
click() {
if (!isIncluded) {
addFeedToListMutation({
feedId,
listId: list.id,
})
} else {
removeFeedFromListMutation({
feedId,
listId: list.id,
})
}
present({
title: t("sidebar.feed_actions.create_list"),
content: () => <ListCreationModalContent />,
})
},
}
}),
},
],
},
{
type: "separator" as const,
Expand Down
3 changes: 1 addition & 2 deletions apps/renderer/src/lib/native-menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ export type NativeMenuItem = (
type: "text"
label: string
click?: () => void
enabled?: boolean
/** only work in web app */
icon?: React.ReactNode
shortcut?: string
Expand Down Expand Up @@ -130,7 +129,7 @@ export const showNativeMenu = async (
return {
...item,
icon: undefined,
enabled: item.enabled ?? (item.click !== undefined || !!item.submenu),
enabled: item.click !== undefined || (!!item.submenu && item.submenu.length > 0),
click: undefined,
submenu: item.submenu ? transformMenuItems(item.submenu) : undefined,
shortcut: item.shortcut?.replace("Meta", "CmdOrCtrl"),
Expand Down
11 changes: 1 addition & 10 deletions apps/renderer/src/modules/entry-column/item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { LoadingCircle } from "~/components/ui/loading"
import { views } from "~/constants"
import { useAuthQuery } from "~/hooks/common"
import type { FeedViewType } from "~/lib/enum"
import { FeedViewType as FeedViewTypeEnum } from "~/lib/enum"
import { cn } from "~/lib/utils"
import { Queries } from "~/queries"
import type { FlatEntryModel } from "~/store/entry"
Expand Down Expand Up @@ -39,17 +38,9 @@ function EntryItemImpl({ entry, view }: { entry: FlatEntryModel; view?: number }
)

const Item: EntryListItemFC = getItemComponentByView(view as FeedViewType)
const overlayItemClassName =
view === FeedViewTypeEnum.Pictures || view === FeedViewTypeEnum.Videos ? "top-0" : ""

return (
<EntryItemWrapper
itemClassName={Item.wrapperClassName}
entry={entry}
view={view}
overlay
overlayItemClassName={overlayItemClassName}
>
<EntryItemWrapper itemClassName={Item.wrapperClassName} entry={entry} view={view}>
<Item entryId={entry.entries.id} translation={translation.data} />
</EntryItemWrapper>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { useTranslation } from "react-i18next"
import { useDebounceCallback } from "usehooks-ts"

import { useGeneralSettingKey } from "~/atoms/settings/general"
import { ListItemHoverOverlay } from "~/components/ui/list-item-hover-overlay"
import { views } from "~/constants/tabs"
import { useAsRead } from "~/hooks/biz/useAsRead"
import { useEntryActions } from "~/hooks/biz/useEntryActions"
import { useFeedActions } from "~/hooks/biz/useFeedActions"
import { useNavigateEntry } from "~/hooks/biz/useNavigateEntry"
import { useRouteParamsSelector } from "~/hooks/biz/useRouteParams"
import { useAnyPointDown } from "~/hooks/common"
import type { FeedViewType } from "~/lib/enum"
import { showNativeMenu } from "~/lib/native-menu"
import { cn } from "~/lib/utils"
import type { FlatEntryModel } from "~/store/entry"
Expand All @@ -21,11 +22,9 @@ export const EntryItemWrapper: FC<
entry: FlatEntryModel
view?: number
itemClassName?: string
overlayItemClassName?: string
overlay?: boolean
style?: React.CSSProperties
} & PropsWithChildren
> = ({ entry, view, overlay, children, itemClassName, overlayItemClassName, style }) => {
> = ({ entry, view, children, itemClassName, style }) => {
const { items } = useEntryActions({
view,
entry,
Expand Down Expand Up @@ -118,7 +117,9 @@ export const EntryItemWrapper: FC<
className={cn(
"relative",
asRead ? "text-zinc-700 dark:text-neutral-400" : "text-zinc-900 dark:text-neutral-300",

views[view as FeedViewType]?.wideMode ? "rounded-md" : "-mx-2 px-2",
"duration-200 hover:bg-theme-item-hover",
(isActive || isContextMenuOpen) && "!bg-theme-item-active",
itemClassName,
)}
onClick={handleClick}
Expand All @@ -127,16 +128,7 @@ export const EntryItemWrapper: FC<
onDoubleClick={handleDoubleClick}
onContextMenu={handleContextMenu}
>
{overlay ? (
<ListItemHoverOverlay
isActive={isActive || isContextMenuOpen}
className={overlayItemClassName}
>
{children}
</ListItemHoverOverlay>
) : (
children
)}
{children}
</div>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ const WideModeButton = () => {
: t("entry_list_header.switch_to_normalmode")
}
>
<i className={cn(isWideMode ? "i-mgc-align-justify-cute-re" : "i-mgc-layout-4-cute-re")} />
<i className={cn(!isWideMode ? "i-mgc-align-justify-cute-re" : "i-mgc-layout-4-cute-re")} />
</ActionButton>
</ImpressionView>
)
Expand Down
46 changes: 32 additions & 14 deletions apps/renderer/src/modules/feed-column/category.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import { subscriptionActions, useSubscriptionByFeedId } from "~/store/subscripti
import { useFeedUnreadStore } from "~/store/unread"

import { useModalStack } from "../../components/ui/modal/stacked/hooks"
import { ListCreationModalContent } from "../settings/tabs/lists/modals"
import { useFeedListSortSelector } from "./atom"
import { CategoryRemoveDialogContent } from "./category-remove-dialog"
import { FeedItem } from "./item"
import { feedColumnStyles } from "./styles"
import { UnreadNumber } from "./unread-number"

type FeedId = string
Expand Down Expand Up @@ -135,9 +137,10 @@ function FeedCategoryImpl({ data: ids, view, categoryOpenStateData }: FeedCatego
<div tabIndex={-1} onClick={stopPropagation}>
{!!showCollapse && (
<div
data-active={isActive || isContextMenuOpen}
className={cn(
"flex w-full cursor-menu items-center justify-between rounded-md px-2.5 transition-colors",
(isActive || isContextMenuOpen) && "bg-native-active",
"flex w-full cursor-menu items-center justify-between rounded-md px-2.5",
feedColumnStyles.item,
)}
onClick={(e) => {
e.stopPropagation()
Expand All @@ -162,22 +165,37 @@ function FeedCategoryImpl({ data: ids, view, categoryOpenStateData }: FeedCatego
{
type: "text",
label: t("sidebar.feed_column.context_menu.add_feeds_to_list"),
enabled: !!listList?.length,
submenu: listList?.map((list) => ({
label: list.title || "",
type: "text",
click() {
return addMutation.mutate({
feedIds: ids,
listId: list.id,
})
},
})),
// @ts-expect-error
submenu: listList
?.map((list) => ({
label: list.title || "",
type: "text",
click() {
return addMutation.mutate({
feedIds: ids,
listId: list.id,
})
},
}))
.concat([
// @ts-expect-error
{ type: "separator" as const },
{
label: t("sidebar.feed_actions.create_list"),
type: "text" as const,

click() {
present({
title: t("sidebar.feed_actions.create_list"),
content: () => <ListCreationModalContent />,
})
},
},
]),
},
{ 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)
Expand Down
4 changes: 2 additions & 2 deletions apps/renderer/src/modules/feed-column/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,8 @@ export function FeedColumn({ children, className }: PropsWithChildren<{ classNam
className={cn(
active === index && item.className,
"flex h-11 flex-col items-center gap-1 text-xl",
ELECTRON ? "hover:!bg-theme-vibrancyBg" : "",
active === index && useHotkeysSwitch ? "bg-zinc-500/30" : "",
ELECTRON ? "hover:!bg-theme-item-hover" : "",
active === index && useHotkeysSwitch ? "bg-theme-item-active" : "",
)}
onClick={(e) => {
setActive(index)
Expand Down
10 changes: 7 additions & 3 deletions apps/renderer/src/modules/feed-column/item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { useListById } from "~/store/list"
import { subscriptionActions, useSubscriptionByFeedId } from "~/store/subscription"
import { useFeedUnreadStore } from "~/store/unread"

import { feedColumnStyles } from "./styles"
import { UnreadNumber } from "./unread-number"

interface FeedItemProps {
Expand Down Expand Up @@ -72,9 +73,10 @@ const FeedItemImpl = ({ view, feedId, className }: FeedItemProps) => {
<>
<div
data-feed-id={feedId}
data-active={isActive || isContextMenuOpen}
className={cn(
"flex w-full cursor-menu items-center justify-between rounded-md py-[2px] pr-2.5 text-sm font-medium leading-loose",
(isActive || isContextMenuOpen) && "bg-native-active",
feedColumnStyles.item,
isFeed ? "py-[2px]" : "py-1.5",
className,
)}
Expand Down Expand Up @@ -204,9 +206,10 @@ const ListItemImpl: Component<{
return (
<div
data-list-id={listId}
data-active={isActive || isContextMenuOpen}
className={cn(
"flex w-full cursor-menu items-center justify-between rounded-md pr-2.5 text-sm font-medium leading-loose",
(isActive || isContextMenuOpen) && "bg-native-active",
feedColumnStyles.item,
"py-1.5 pl-2.5",
className,
)}
Expand Down Expand Up @@ -275,10 +278,11 @@ const InboxItemImpl: Component<{
if (!inbox) return null
return (
<div
data-active={isActive || isContextMenuOpen}
data-inbox-id={inboxId}
className={cn(
"flex w-full cursor-menu items-center justify-between rounded-md pr-2.5 text-sm font-medium leading-loose",
(isActive || isContextMenuOpen) && "bg-native-active",
feedColumnStyles.item,
"py-[2px] pl-2.5",
className,
)}
Expand Down
6 changes: 4 additions & 2 deletions apps/renderer/src/modules/feed-column/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { useFeedUnreadStore } from "~/store/unread"

import { getFeedListSort, setFeedListSortBy, setFeedListSortOrder, useFeedListSort } from "./atom"
import { SortableFeedList, SortByAlphabeticalInbox, SortByAlphabeticalList } from "./sort-by"
import { feedColumnStyles } from "./styles"
import { UnreadNumber } from "./unread-number"

const useFeedsGroupedData = (view: FeedViewType) => {
Expand Down Expand Up @@ -167,9 +168,10 @@ function FeedListImpl({ className, view }: { className?: string; view: number })

<ScrollArea.ScrollArea mask={false} flex viewportClassName="!px-3" rootClassName="h-full">
<div
data-active={feedId === FEED_COLLECTION_LIST}
className={cn(
"mt-1 flex h-8 w-full shrink-0 cursor-menu items-center gap-2 rounded-md px-2.5 transition-colors",
feedId === FEED_COLLECTION_LIST && "bg-native-active",
"mt-1 flex h-8 w-full shrink-0 cursor-menu items-center gap-2 rounded-md px-2.5",
feedColumnStyles.item,
)}
onClick={(e) => {
e.stopPropagation()
Expand Down
8 changes: 8 additions & 0 deletions apps/renderer/src/modules/feed-column/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import clsx from "clsx"

export const feedColumnStyles = {
item: clsx(
!window.electron && tw`duration-200 hover:bg-theme-item-hover`,
tw`data-[active=true]:!bg-theme-item-active`,
),
}
4 changes: 2 additions & 2 deletions apps/renderer/src/modules/settings/modal/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ export function SettingModalLayout(
{settings.map((t) => (
<button
key={t.path}
className={`my-0.5 flex w-full items-center rounded-lg px-2.5 py-0.5 leading-loose text-theme-foreground/70 transition-colors ${
tab === t.path ? "bg-theme-item-active text-theme-foreground/90" : ""
className={`my-0.5 flex w-full items-center rounded-lg px-2.5 py-0.5 leading-loose text-theme-foreground/70 duration-200 hover:bg-theme-item-hover ${
tab === t.path ? "!bg-theme-item-active !text-theme-foreground/90" : ""
}`}
type="button"
onClick={() => setTab(t.path)}
Expand Down
3 changes: 3 additions & 0 deletions apps/renderer/src/modules/settings/tabs/invitations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ export const SettingInvitations = () => {
</p>
</div>
<Button
disabled={
!limitation.data || (invitations?.data && invitations?.data?.length >= limitation.data)
}
onClick={() => {
present({
title: t("invitation.confirmModal.title"),
Expand Down
Loading

0 comments on commit d2b5cc3

Please sign in to comment.