Skip to content

Commit

Permalink
add button in the header to star entry (#1025)
Browse files Browse the repository at this point in the history
  • Loading branch information
Athou committed Apr 14, 2024
1 parent 5d75885 commit 0d081bc
Show file tree
Hide file tree
Showing 19 changed files with 229 additions and 39 deletions.
3 changes: 3 additions & 0 deletions commafeed-client/src/app/constants.ts
Expand Up @@ -104,6 +104,9 @@ export const Constants = {
entryId: (entry: Entry) => `entry-id-${entry.id}`,
entryContextMenuId: (entry: Entry) => entry.id,
},
tooltip: {
delay: 500,
},
browserExtensionUrl: "https://github.com/Athou/commafeed-browser-extension",
bitcoinWalletAddress: "1dymfUxqCWpyD7a6rQSqNy4rLVDBsAr5e",
}
20 changes: 13 additions & 7 deletions commafeed-client/src/app/entries/thunks.ts
Expand Up @@ -113,13 +113,19 @@ export const markAllEntries = createAppAsyncThunk(
thunkApi.dispatch(reloadTree())
}
)
export const starEntry = createAppAsyncThunk("entries/entry/star", (arg: { entry: Entry; starred: boolean }) => {
client.entry.star({
id: arg.entry.id,
feedId: +arg.entry.feedId,
starred: arg.starred,
})
})
export const starEntry = createAppAsyncThunk(
"entries/entry/star",
(arg: { entry: Entry; starred: boolean }) => {
client.entry.star({
id: arg.entry.id,
feedId: +arg.entry.feedId,
starred: arg.starred,
})
},
{
condition: arg => arg.entry.markable && arg.entry.starred !== arg.starred,
}
)
export const selectEntry = createAppAsyncThunk(
"entries/entry/select",
(
Expand Down
4 changes: 4 additions & 0 deletions commafeed-client/src/app/types.ts
Expand Up @@ -6,6 +6,8 @@ export type ViewMode = "title" | "cozy" | "detailed" | "expanded"

export type ScrollMode = "always" | "never" | "if_needed"

export type IconDisplayMode = "always" | "never" | "on_desktop" | "on_mobile"

export interface AddCategoryRequest {
name: string
parentId?: string
Expand Down Expand Up @@ -242,6 +244,8 @@ export interface Settings {
customJs?: string
scrollSpeed: number
scrollMode: ScrollMode
starIconDisplayMode: IconDisplayMode
externalLinkIconDisplayMode: IconDisplayMode
markAllAsReadConfirmation: boolean
customContextMenu: boolean
mobileFooter: boolean
Expand Down
12 changes: 12 additions & 0 deletions commafeed-client/src/app/user/slice.ts
Expand Up @@ -4,6 +4,7 @@ import { createSlice, isAnyOf } from "@reduxjs/toolkit"
import { type Settings, type UserModel } from "app/types"
import {
changeCustomContextMenu,
changeExternalLinkIconDisplayMode,
changeLanguage,
changeMarkAllAsReadConfirmation,
changeMobileFooter,
Expand All @@ -14,6 +15,7 @@ import {
changeScrollSpeed,
changeSharingSetting,
changeShowRead,
changeStarIconDisplayMode,
reloadProfile,
reloadSettings,
reloadTags,
Expand Down Expand Up @@ -69,6 +71,14 @@ export const userSlice = createSlice({
if (!state.settings) return
state.settings.scrollMode = action.meta.arg
})
builder.addCase(changeStarIconDisplayMode.pending, (state, action) => {
if (!state.settings) return
state.settings.starIconDisplayMode = action.meta.arg
})
builder.addCase(changeExternalLinkIconDisplayMode.pending, (state, action) => {
if (!state.settings) return
state.settings.externalLinkIconDisplayMode = action.meta.arg
})
builder.addCase(changeMarkAllAsReadConfirmation.pending, (state, action) => {
if (!state.settings) return
state.settings.markAllAsReadConfirmation = action.meta.arg
Expand All @@ -92,6 +102,8 @@ export const userSlice = createSlice({
changeShowRead.fulfilled,
changeScrollMarks.fulfilled,
changeScrollMode.fulfilled,
changeStarIconDisplayMode.fulfilled,
changeExternalLinkIconDisplayMode.fulfilled,
changeMarkAllAsReadConfirmation.fulfilled,
changeCustomContextMenu.fulfilled,
changeMobileFooter.fulfilled,
Expand Down
18 changes: 17 additions & 1 deletion commafeed-client/src/app/user/thunks.ts
@@ -1,7 +1,7 @@
import { createAppAsyncThunk } from "app/async-thunk"
import { client } from "app/client"
import { reloadEntries } from "app/entries/thunks"
import type { ReadingMode, ReadingOrder, ScrollMode, SharingSettings } from "app/types"
import type { IconDisplayMode, ReadingMode, ReadingOrder, ScrollMode, SharingSettings } from "app/types"

export const reloadSettings = createAppAsyncThunk("settings/reload", async () => await client.user.getSettings().then(r => r.data))
export const reloadProfile = createAppAsyncThunk("profile/reload", async () => await client.user.getProfile().then(r => r.data))
Expand Down Expand Up @@ -43,6 +43,22 @@ export const changeScrollMode = createAppAsyncThunk("settings/scrollMode", (scro
if (!settings) return
client.user.saveSettings({ ...settings, scrollMode })
})
export const changeStarIconDisplayMode = createAppAsyncThunk(
"settings/starIconDisplayMode",
(starIconDisplayMode: IconDisplayMode, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, starIconDisplayMode })
}
)
export const changeExternalLinkIconDisplayMode = createAppAsyncThunk(
"settings/externalLinkIconDisplayMode",
(externalLinkIconDisplayMode: IconDisplayMode, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, externalLinkIconDisplayMode })
}
)
export const changeMarkAllAsReadConfirmation = createAppAsyncThunk(
"settings/markAllAsReadConfirmation",
(markAllAsReadConfirmation: boolean, thunkApi) => {
Expand Down
3 changes: 2 additions & 1 deletion commafeed-client/src/components/ActionButton.tsx
@@ -1,5 +1,6 @@
import { ActionIcon, Button, type ButtonVariant, Tooltip, useMantineTheme } from "@mantine/core"
import { type ActionIconVariant } from "@mantine/core/lib/components/ActionIcon/ActionIcon"
import { Constants } from "app/constants"
import { useActionButton } from "hooks/useActionButton"
import { forwardRef, type MouseEventHandler, type ReactNode } from "react"

Expand All @@ -22,7 +23,7 @@ export const ActionButton = forwardRef<HTMLButtonElement, ActionButtonProps>((pr
const variant = props.variant ?? "subtle"
const iconOnly = (mobile && !props.showLabelOnMobile) || (!mobile && props.hideLabelOnDesktop)
return iconOnly ? (
<Tooltip label={props.label} openDelay={500}>
<Tooltip label={props.label} openDelay={Constants.tooltip.delay}>
<ActionIcon ref={ref} color={theme.primaryColor} variant={variant} className={props.className} onClick={props.onClick}>
{props.icon}
</ActionIcon>
Expand Down
3 changes: 2 additions & 1 deletion commafeed-client/src/components/RelativeDate.tsx
@@ -1,5 +1,6 @@
import { Trans } from "@lingui/macro"
import { Tooltip } from "@mantine/core"
import { Constants } from "app/constants"
import dayjs from "dayjs"
import { useEffect, useState } from "react"

Expand All @@ -13,7 +14,7 @@ export function RelativeDate(props: { date: Date | number | undefined }) {
if (!props.date) return <Trans>N/A</Trans>
const date = dayjs(props.date)
return (
<Tooltip label={date.toDate().toLocaleString()} openDelay={500}>
<Tooltip label={date.toDate().toLocaleString()} openDelay={Constants.tooltip.delay}>
<span>{date.from(dayjs(now))}</span>
</Tooltip>
)
Expand Down
28 changes: 26 additions & 2 deletions commafeed-client/src/components/content/FeedEntry.tsx
@@ -1,8 +1,10 @@
import { Box, Divider, type MantineRadius, type MantineSpacing, Paper } from "@mantine/core"
import { Constants } from "app/constants"
import { useAppSelector } from "app/store"
import { type Entry, type ViewMode } from "app/types"
import { FeedEntryCompactHeader } from "components/content/header/FeedEntryCompactHeader"
import { FeedEntryHeader } from "components/content/header/FeedEntryHeader"
import { useMobile } from "hooks/useMobile"
import { useViewMode } from "hooks/useViewMode"
import React from "react"
import { useSwipeable } from "react-swipeable"
Expand Down Expand Up @@ -103,6 +105,15 @@ export function FeedEntry(props: FeedEntryProps) {
maxWidth: props.maxWidth,
})

const externalLinkDisplayMode = useAppSelector(state => state.user.settings?.externalLinkIconDisplayMode)
const starIconDisplayMode = useAppSelector(state => state.user.settings?.starIconDisplayMode)
const mobile = useMobile()

const showExternalLinkIcon =
externalLinkDisplayMode && ["always", mobile ? "on_mobile" : "on_desktop"].includes(externalLinkDisplayMode)
const showStarIcon =
props.entry.markable && starIconDisplayMode && ["always", mobile ? "on_mobile" : "on_desktop"].includes(starIconDisplayMode)

const swipeHandlers = useSwipeable({
onSwipedLeft: props.onSwipedLeft,
})
Expand Down Expand Up @@ -147,8 +158,21 @@ export function FeedEntry(props: FeedEntryProps) {
onContextMenu={props.onHeaderRightClick}
>
<Box px={paddingX} py={paddingY} {...swipeHandlers}>
{compactHeader && <FeedEntryCompactHeader entry={props.entry} />}
{!compactHeader && <FeedEntryHeader entry={props.entry} expanded={props.expanded} />}
{compactHeader && (
<FeedEntryCompactHeader
entry={props.entry}
showStarIcon={showStarIcon}
showExternalLinkIcon={showExternalLinkIcon}
/>
)}
{!compactHeader && (
<FeedEntryHeader
entry={props.entry}
expanded={props.expanded}
showStarIcon={showStarIcon}
showExternalLinkIcon={showExternalLinkIcon}
/>
)}
</Box>
</a>
{props.expanded && (
Expand Down
Expand Up @@ -2,13 +2,16 @@ import { Box, Text } from "@mantine/core"
import { type Entry } from "app/types"
import { FeedFavicon } from "components/content/FeedFavicon"
import { OpenExternalLink } from "components/content/header/OpenExternalLink"
import { Star } from "components/content/header/Star"
import { RelativeDate } from "components/RelativeDate"
import { OnDesktop } from "components/responsive/OnDesktop"
import { tss } from "tss"
import { FeedEntryTitle } from "./FeedEntryTitle"

export interface FeedEntryHeaderProps {
entry: Entry
showStarIcon?: boolean
showExternalLinkIcon?: boolean
}

const useStyles = tss
Expand Down Expand Up @@ -46,6 +49,7 @@ export function FeedEntryCompactHeader(props: FeedEntryHeaderProps) {
})
return (
<Box className={classes.wrapper}>
{props.showStarIcon && <Star entry={props.entry} />}
<Box>
<FeedFavicon url={props.entry.iconUrl} />
</Box>
Expand All @@ -62,7 +66,7 @@ export function FeedEntryCompactHeader(props: FeedEntryHeaderProps) {
<RelativeDate date={props.entry.date} />
</Text>
</OnDesktop>
<OpenExternalLink entry={props.entry} />
{props.showExternalLinkIcon && <OpenExternalLink entry={props.entry} />}
</Box>
)
}
31 changes: 16 additions & 15 deletions commafeed-client/src/components/content/header/FeedEntryHeader.tsx
@@ -1,14 +1,17 @@
import { Box, Space, Text } from "@mantine/core"
import { Box, Flex, Space, Text } from "@mantine/core"
import { type Entry } from "app/types"
import { FeedFavicon } from "components/content/FeedFavicon"
import { OpenExternalLink } from "components/content/header/OpenExternalLink"
import { Star } from "components/content/header/Star"
import { RelativeDate } from "components/RelativeDate"
import { tss } from "tss"
import { FeedEntryTitle } from "./FeedEntryTitle"

export interface FeedEntryHeaderProps {
entry: Entry
expanded: boolean
showStarIcon?: boolean
showExternalLinkIcon?: boolean
}

const useStyles = tss
Expand All @@ -17,16 +20,9 @@ const useStyles = tss
}>()
.create(({ colorScheme, read }) => ({
main: {
display: "flex",
alignItems: "flex-start",
justifyContent: "space-between",
},
mainText: {
fontWeight: colorScheme === "light" && !read ? "bold" : "inherit",
},
details: {
display: "flex",
alignItems: "center",
fontSize: "90%",
},
}))
Expand All @@ -37,21 +33,26 @@ export function FeedEntryHeader(props: FeedEntryHeaderProps) {
})
return (
<Box>
<Box className={classes.main}>
<Box className={classes.mainText}>
<Flex align="flex-start" justify="space-between">
<Flex align="flex-start" className={classes.main}>
{props.showStarIcon && (
<Box ml={-6}>
<Star entry={props.entry} />
</Box>
)}
<FeedEntryTitle entry={props.entry} />
</Box>
<OpenExternalLink entry={props.entry} />
</Box>
<Box className={classes.details}>
</Flex>
{props.showExternalLinkIcon && <OpenExternalLink entry={props.entry} />}
</Flex>
<Flex align="center" className={classes.details}>
<FeedFavicon url={props.entry.iconUrl} />
<Space w={6} />
<Text c="dimmed">
{props.entry.feedName}
<span> · </span>
<RelativeDate date={props.entry.date} />
</Text>
</Box>
</Flex>
{props.expanded && (
<Box className={classes.details}>
<Text c="dimmed">
Expand Down
@@ -1,5 +1,6 @@
import { Trans } from "@lingui/macro"
import { ActionIcon, Anchor, Tooltip } from "@mantine/core"
import { Constants } from "app/constants"
import { markEntry } from "app/entries/thunks"
import { useAppDispatch } from "app/store"
import { type Entry } from "app/types"
Expand All @@ -19,9 +20,9 @@ export function OpenExternalLink(props: { entry: Entry }) {

return (
<Anchor href={props.entry.url} target="_blank" rel="noreferrer" onClick={onClick}>
<Tooltip label={<Trans>Open link</Trans>}>
<Tooltip label={<Trans>Open link</Trans>} openDelay={Constants.tooltip.delay}>
<ActionIcon variant="transparent" c="dimmed">
<TbExternalLink />
<TbExternalLink size={18} />
</ActionIcon>
</Tooltip>
</Anchor>
Expand Down
29 changes: 29 additions & 0 deletions commafeed-client/src/components/content/header/Star.tsx
@@ -0,0 +1,29 @@
import { Trans } from "@lingui/macro"
import { ActionIcon, Tooltip } from "@mantine/core"
import { Constants } from "app/constants"
import { starEntry } from "app/entries/thunks"
import { useAppDispatch } from "app/store"
import type { Entry } from "app/types"
import { TbStar, TbStarFilled } from "react-icons/tb"

export function Star(props: { entry: Entry }) {
const dispatch = useAppDispatch()
const onClick = (e: React.MouseEvent) => {
e.stopPropagation()
e.preventDefault()
dispatch(
starEntry({
entry: props.entry,
starred: !props.entry.starred,
})
)
}

return (
<Tooltip label={props.entry.starred ? <Trans>Unstar</Trans> : <Trans>Star</Trans>} openDelay={Constants.tooltip.delay}>
<ActionIcon variant="transparent" onClick={onClick}>
{props.entry.starred ? <TbStarFilled size={18} /> : <TbStar size={18} />}
</ActionIcon>
</Tooltip>
)
}

5 comments on commit 0d081bc

@canoine
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello,
Is this related to this commit ? And is this problem general, or only on my own instance ?
Capture d’écran_2024-04-14_17-32-40
Capture d’écran_2024-04-14_17-33-04

@Athou
Copy link
Owner Author

@Athou Athou commented on 0d081bc Apr 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to run lingui on the new labels, it was fixed in 6e0e692:)

@canoine
Copy link
Contributor

@canoine canoine commented on 0d081bc Apr 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh... So I suppose my browser's cache needs to be cleaned, as the problem persists after a new update (CommaFeed version 4.3.3 (e415d1d)).

@Athou
Copy link
Owner Author

@Athou Athou commented on 0d081bc Apr 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh indeed, I'm going to check what's wrong, thanks!

@canoine
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, 85ae70f fixes the problem. Thank you. :)

Please sign in to comment.