forked from Archives/Athou_commafeed
add aria-label to action buttons (#1507)
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
import type { MessageDescriptor } from "@lingui/core"
|
||||||
|
import { useLingui } from "@lingui/react"
|
||||||
import { ActionIcon, Button, type ButtonVariant, Tooltip, useMantineTheme } from "@mantine/core"
|
import { ActionIcon, Button, type ButtonVariant, Tooltip, useMantineTheme } from "@mantine/core"
|
||||||
import type { ActionIconVariant } from "@mantine/core/lib/components/ActionIcon/ActionIcon"
|
import type { ActionIconVariant } from "@mantine/core/lib/components/ActionIcon/ActionIcon"
|
||||||
import { Constants } from "app/constants"
|
import { Constants } from "app/constants"
|
||||||
@@ -7,7 +9,7 @@ import { type MouseEventHandler, type ReactNode, forwardRef } from "react"
|
|||||||
interface ActionButtonProps {
|
interface ActionButtonProps {
|
||||||
className?: string
|
className?: string
|
||||||
icon?: ReactNode
|
icon?: ReactNode
|
||||||
label: ReactNode
|
label?: string | MessageDescriptor
|
||||||
onClick?: MouseEventHandler
|
onClick?: MouseEventHandler
|
||||||
variant?: ActionIconVariant & ButtonVariant
|
variant?: ActionIconVariant & ButtonVariant
|
||||||
hideLabelOnDesktop?: boolean
|
hideLabelOnDesktop?: boolean
|
||||||
@@ -20,17 +22,35 @@ interface ActionButtonProps {
|
|||||||
export const ActionButton = forwardRef<HTMLButtonElement, ActionButtonProps>((props: ActionButtonProps, ref) => {
|
export const ActionButton = forwardRef<HTMLButtonElement, ActionButtonProps>((props: ActionButtonProps, ref) => {
|
||||||
const { mobile } = useActionButton()
|
const { mobile } = useActionButton()
|
||||||
const theme = useMantineTheme()
|
const theme = useMantineTheme()
|
||||||
|
const { _ } = useLingui()
|
||||||
|
|
||||||
|
const label = typeof props.label === "string" ? props.label : props.label && _(props.label)
|
||||||
const variant = props.variant ?? "subtle"
|
const variant = props.variant ?? "subtle"
|
||||||
const iconOnly = (mobile && !props.showLabelOnMobile) || (!mobile && props.hideLabelOnDesktop)
|
const iconOnly = (mobile && !props.showLabelOnMobile) || (!mobile && props.hideLabelOnDesktop)
|
||||||
return iconOnly ? (
|
return iconOnly ? (
|
||||||
<Tooltip label={props.label} openDelay={Constants.tooltip.delay}>
|
<Tooltip label={label} openDelay={Constants.tooltip.delay}>
|
||||||
<ActionIcon ref={ref} color={theme.primaryColor} variant={variant} className={props.className} onClick={props.onClick}>
|
<ActionIcon
|
||||||
|
ref={ref}
|
||||||
|
color={theme.primaryColor}
|
||||||
|
variant={variant}
|
||||||
|
className={props.className}
|
||||||
|
onClick={props.onClick}
|
||||||
|
aria-label={label}
|
||||||
|
>
|
||||||
{props.icon}
|
{props.icon}
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
) : (
|
) : (
|
||||||
<Button ref={ref} variant={variant} size="xs" className={props.className} leftSection={props.icon} onClick={props.onClick}>
|
<Button
|
||||||
{props.label}
|
ref={ref}
|
||||||
|
variant={variant}
|
||||||
|
size="xs"
|
||||||
|
className={props.className}
|
||||||
|
leftSection={props.icon}
|
||||||
|
onClick={props.onClick}
|
||||||
|
aria-label={label}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
</Button>
|
</Button>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Trans, t } from "@lingui/macro"
|
import { msg, t } from "@lingui/macro"
|
||||||
import { Group, Indicator, Popover, TagsInput } from "@mantine/core"
|
import { Group, Indicator, Popover, TagsInput } from "@mantine/core"
|
||||||
import { markEntriesUpToEntry, markEntry, starEntry, tagEntry } from "app/entries/thunks"
|
import { markEntriesUpToEntry, markEntry, starEntry, tagEntry } from "app/entries/thunks"
|
||||||
import { useAppDispatch, useAppSelector } from "app/store"
|
import { useAppDispatch, useAppSelector } from "app/store"
|
||||||
@@ -40,13 +40,13 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
|
|||||||
{props.entry.markable && (
|
{props.entry.markable && (
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={props.entry.read ? <TbMail size={18} /> : <TbMailOpened size={18} />}
|
icon={props.entry.read ? <TbMail size={18} /> : <TbMailOpened size={18} />}
|
||||||
label={props.entry.read ? <Trans>Keep unread</Trans> : <Trans>Mark as read</Trans>}
|
label={props.entry.read ? msg`Keep unread` : msg`Mark as read`}
|
||||||
onClick={readStatusButtonClicked}
|
onClick={readStatusButtonClicked}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={props.entry.starred ? <TbStarOff size={18} /> : <TbStar size={18} />}
|
icon={props.entry.starred ? <TbStarOff size={18} /> : <TbStar size={18} />}
|
||||||
label={props.entry.starred ? <Trans>Unstar</Trans> : <Trans>Star</Trans>}
|
label={props.entry.starred ? msg`Unstar` : msg`Star`}
|
||||||
onClick={async () =>
|
onClick={async () =>
|
||||||
await dispatch(
|
await dispatch(
|
||||||
starEntry({
|
starEntry({
|
||||||
@@ -59,7 +59,7 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
|
|||||||
|
|
||||||
<Popover withArrow withinPortal shadow="md" closeOnClickOutside={!mobile}>
|
<Popover withArrow withinPortal shadow="md" closeOnClickOutside={!mobile}>
|
||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
<ActionButton icon={<TbShare size={18} />} label={<Trans>Share</Trans>} />
|
<ActionButton icon={<TbShare size={18} />} label={msg`Share`} />
|
||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
<Popover.Dropdown>
|
<Popover.Dropdown>
|
||||||
<ShareButtons url={props.entry.url} description={props.entry.title} />
|
<ShareButtons url={props.entry.url} description={props.entry.title} />
|
||||||
@@ -70,7 +70,7 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
|
|||||||
<Popover withArrow shadow="md" closeOnClickOutside={!mobile}>
|
<Popover withArrow shadow="md" closeOnClickOutside={!mobile}>
|
||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
<Indicator label={props.entry.tags.length} disabled={props.entry.tags.length === 0} inline size={16}>
|
<Indicator label={props.entry.tags.length} disabled={props.entry.tags.length === 0} inline size={16}>
|
||||||
<ActionButton icon={<TbTag size={18} />} label={<Trans>Tags</Trans>} />
|
<ActionButton icon={<TbTag size={18} />} label={msg`Tags`} />
|
||||||
</Indicator>
|
</Indicator>
|
||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
<Popover.Dropdown>
|
<Popover.Dropdown>
|
||||||
@@ -88,13 +88,13 @@ export function FeedEntryFooter(props: FeedEntryFooterProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<a href={props.entry.url} target="_blank" rel="noreferrer">
|
<a href={props.entry.url} target="_blank" rel="noreferrer">
|
||||||
<ActionButton icon={<TbExternalLink size={18} />} label={<Trans>Open link</Trans>} />
|
<ActionButton icon={<TbExternalLink size={18} />} label={msg`Open link`} />
|
||||||
</a>
|
</a>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={<TbArrowBarToDown size={18} />}
|
icon={<TbArrowBarToDown size={18} />}
|
||||||
label={<Trans>Mark as read up to here</Trans>}
|
label={msg`Mark as read up to here`}
|
||||||
onClick={async () => await dispatch(markEntriesUpToEntry(props.entry))}
|
onClick={async () => await dispatch(markEntriesUpToEntry(props.entry))}
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Trans, t } from "@lingui/macro"
|
import { msg, t } from "@lingui/macro"
|
||||||
import { Box, Center, CloseButton, Divider, Group, Indicator, Popover, TextInput } from "@mantine/core"
|
import { Box, Center, CloseButton, Divider, Group, Indicator, Popover, TextInput } from "@mantine/core"
|
||||||
import { useForm } from "@mantine/form"
|
import { useForm } from "@mantine/form"
|
||||||
import { reloadEntries, search, selectNextEntry, selectPreviousEntry } from "app/entries/thunks"
|
import { reloadEntries, search, selectNextEntry, selectPreviousEntry } from "app/entries/thunks"
|
||||||
@@ -77,7 +77,7 @@ export function Header() {
|
|||||||
<HeaderToolbar>
|
<HeaderToolbar>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={<TbArrowUp size={iconSize} />}
|
icon={<TbArrowUp size={iconSize} />}
|
||||||
label={<Trans>Previous</Trans>}
|
label={msg`Previous`}
|
||||||
onClick={async () =>
|
onClick={async () =>
|
||||||
await dispatch(
|
await dispatch(
|
||||||
selectPreviousEntry({
|
selectPreviousEntry({
|
||||||
@@ -90,7 +90,7 @@ export function Header() {
|
|||||||
/>
|
/>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={<TbArrowDown size={iconSize} />}
|
icon={<TbArrowDown size={iconSize} />}
|
||||||
label={<Trans>Next</Trans>}
|
label={msg`Next`}
|
||||||
onClick={async () =>
|
onClick={async () =>
|
||||||
await dispatch(
|
await dispatch(
|
||||||
selectNextEntry({
|
selectNextEntry({
|
||||||
@@ -106,7 +106,7 @@ export function Header() {
|
|||||||
|
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={<TbRefresh size={iconSize} />}
|
icon={<TbRefresh size={iconSize} />}
|
||||||
label={<Trans>Refresh</Trans>}
|
label={msg`Refresh`}
|
||||||
onClick={async () => await dispatch(reloadEntries())}
|
onClick={async () => await dispatch(reloadEntries())}
|
||||||
/>
|
/>
|
||||||
<MarkAllAsReadButton iconSize={iconSize} />
|
<MarkAllAsReadButton iconSize={iconSize} />
|
||||||
@@ -115,19 +115,19 @@ export function Header() {
|
|||||||
|
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={settings.readingMode === "all" ? <TbEye size={iconSize} /> : <TbEyeOff size={iconSize} />}
|
icon={settings.readingMode === "all" ? <TbEye size={iconSize} /> : <TbEyeOff size={iconSize} />}
|
||||||
label={settings.readingMode === "all" ? <Trans>All</Trans> : <Trans>Unread</Trans>}
|
label={settings.readingMode === "all" ? msg`All` : msg`Unread`}
|
||||||
onClick={async () => await dispatch(changeReadingMode(settings.readingMode === "all" ? "unread" : "all"))}
|
onClick={async () => await dispatch(changeReadingMode(settings.readingMode === "all" ? "unread" : "all"))}
|
||||||
/>
|
/>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={settings.readingOrder === "asc" ? <TbSortAscending size={iconSize} /> : <TbSortDescending size={iconSize} />}
|
icon={settings.readingOrder === "asc" ? <TbSortAscending size={iconSize} /> : <TbSortDescending size={iconSize} />}
|
||||||
label={settings.readingOrder === "asc" ? <Trans>Asc</Trans> : <Trans>Desc</Trans>}
|
label={settings.readingOrder === "asc" ? msg`Asc` : msg`Desc`}
|
||||||
onClick={async () => await dispatch(changeReadingOrder(settings.readingOrder === "asc" ? "desc" : "asc"))}
|
onClick={async () => await dispatch(changeReadingOrder(settings.readingOrder === "asc" ? "desc" : "asc"))}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Popover>
|
<Popover>
|
||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
<Indicator disabled={!searchFromStore}>
|
<Indicator disabled={!searchFromStore}>
|
||||||
<ActionButton icon={<TbSearch size={iconSize} />} label={<Trans>Search</Trans>} />
|
<ActionButton icon={<TbSearch size={iconSize} />} label={msg`Search`} />
|
||||||
</Indicator>
|
</Indicator>
|
||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
<Popover.Dropdown>
|
<Popover.Dropdown>
|
||||||
@@ -153,12 +153,12 @@ export function Header() {
|
|||||||
|
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={<TbSettings size={iconSize} />}
|
icon={<TbSettings size={iconSize} />}
|
||||||
label={<Trans>Extension options</Trans>}
|
label={msg`Extension options`}
|
||||||
onClick={() => openSettingsPage()}
|
onClick={() => openSettingsPage()}
|
||||||
/>
|
/>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
icon={<TbExternalLink size={iconSize} />}
|
icon={<TbExternalLink size={iconSize} />}
|
||||||
label={<Trans>Open CommaFeed</Trans>}
|
label={msg`Open CommaFeed`}
|
||||||
onClick={() => openAppInNewTab()}
|
onClick={() => openAppInNewTab()}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Trans } from "@lingui/macro"
|
import { Trans, msg } from "@lingui/macro"
|
||||||
|
|
||||||
import { Button, Code, Group, Modal, Slider, Stack, Text } from "@mantine/core"
|
import { Button, Code, Group, Modal, Slider, Stack, Text } from "@mantine/core"
|
||||||
import { markAllEntries } from "app/entries/thunks"
|
import { markAllEntries } from "app/entries/thunks"
|
||||||
@@ -91,7 +91,7 @@ export function MarkAllAsReadButton(props: { iconSize: number }) {
|
|||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Modal>
|
</Modal>
|
||||||
<ActionButton icon={<TbChecks size={props.iconSize} />} label={<Trans>Mark all as read</Trans>} onClick={buttonClicked} />
|
<ActionButton icon={<TbChecks size={props.iconSize} />} label={msg`Mark all as read`} onClick={buttonClicked} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Trans } from "@lingui/macro"
|
import { msg } from "@lingui/macro"
|
||||||
import { Anchor, Box, Center, Container, Divider, Group, Image, Space, Title, useMantineColorScheme } from "@mantine/core"
|
import { Anchor, Box, Center, Container, Divider, Group, Image, Space, Title, useMantineColorScheme } from "@mantine/core"
|
||||||
import { client } from "app/client"
|
import { client } from "app/client"
|
||||||
import { redirectToApiDocumentation, redirectToLogin, redirectToRegistration, redirectToRootCategory } from "app/redirect/thunks"
|
import { redirectToApiDocumentation, redirectToLogin, redirectToRegistration, redirectToRootCategory } from "app/redirect/thunks"
|
||||||
@@ -38,7 +38,7 @@ export function WelcomePage() {
|
|||||||
{serverInfos?.demoAccountEnabled && (
|
{serverInfos?.demoAccountEnabled && (
|
||||||
<Center>
|
<Center>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
label={<Trans>Try the demo!</Trans>}
|
label={msg`Try the demo!`}
|
||||||
icon={<TbClock size={iconSize} />}
|
icon={<TbClock size={iconSize} />}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={async () => await login.execute({ name: "demo", password: "demo" })}
|
onClick={async () => await login.execute({ name: "demo", password: "demo" })}
|
||||||
@@ -96,7 +96,7 @@ function Buttons() {
|
|||||||
return (
|
return (
|
||||||
<Group gap={14}>
|
<Group gap={14}>
|
||||||
<ActionButton
|
<ActionButton
|
||||||
label={<Trans>Log in</Trans>}
|
label={msg`Log in`}
|
||||||
icon={<TbKey size={iconSize} />}
|
icon={<TbKey size={iconSize} />}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
onClick={async () => await dispatch(redirectToLogin())}
|
onClick={async () => await dispatch(redirectToLogin())}
|
||||||
@@ -104,7 +104,7 @@ function Buttons() {
|
|||||||
/>
|
/>
|
||||||
{serverInfos?.allowRegistrations && (
|
{serverInfos?.allowRegistrations && (
|
||||||
<ActionButton
|
<ActionButton
|
||||||
label={<Trans>Sign up</Trans>}
|
label={msg`Sign up`}
|
||||||
icon={<TbUserPlus size={iconSize} />}
|
icon={<TbUserPlus size={iconSize} />}
|
||||||
variant="filled"
|
variant="filled"
|
||||||
onClick={async () => await dispatch(redirectToRegistration())}
|
onClick={async () => await dispatch(redirectToRegistration())}
|
||||||
@@ -113,7 +113,7 @@ function Buttons() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<ActionButton
|
<ActionButton
|
||||||
label={dark ? <Trans>Switch to light theme</Trans> : <Trans>Switch to dark theme</Trans>}
|
label={dark ? msg`Switch to light theme` : msg`Switch to dark theme`}
|
||||||
icon={colorScheme === "dark" ? <TbSun size={18} /> : <TbMoon size={iconSize} />}
|
icon={colorScheme === "dark" ? <TbSun size={18} /> : <TbMoon size={iconSize} />}
|
||||||
onClick={() => toggleColorScheme()}
|
onClick={() => toggleColorScheme()}
|
||||||
hideLabelOnDesktop
|
hideLabelOnDesktop
|
||||||
@@ -121,7 +121,7 @@ function Buttons() {
|
|||||||
|
|
||||||
{isBrowserExtensionPopup && (
|
{isBrowserExtensionPopup && (
|
||||||
<ActionButton
|
<ActionButton
|
||||||
label={<Trans>Extension options</Trans>}
|
label={msg`Extension options`}
|
||||||
icon={<TbSettings size={iconSize} />}
|
icon={<TbSettings size={iconSize} />}
|
||||||
onClick={() => openSettingsPage()}
|
onClick={() => openSettingsPage()}
|
||||||
hideLabelOnDesktop
|
hideLabelOnDesktop
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Trans } from "@lingui/macro"
|
import { msg } from "@lingui/macro"
|
||||||
import { ActionIcon, AppShell, Box, Center, Group, ScrollArea, Title, useMantineTheme } from "@mantine/core"
|
import { ActionIcon, AppShell, Box, Center, Group, ScrollArea, Title, useMantineTheme } from "@mantine/core"
|
||||||
import { Constants } from "app/constants"
|
import { Constants } from "app/constants"
|
||||||
import { redirectToAdd, redirectToRootCategory } from "app/redirect/thunks"
|
import { redirectToAdd, redirectToRootCategory } from "app/redirect/thunks"
|
||||||
@@ -101,7 +101,7 @@ export default function Layout(props: LayoutProps) {
|
|||||||
|
|
||||||
const burger = (
|
const burger = (
|
||||||
<ActionButton
|
<ActionButton
|
||||||
label={mobileMenuOpen ? <Trans>Close menu</Trans> : <Trans>Open menu</Trans>}
|
label={mobileMenuOpen ? msg`Close menu` : msg`Open menu`}
|
||||||
icon={mobileMenuOpen ? <TbX size={18} /> : <TbMenu2 size={18} />}
|
icon={mobileMenuOpen ? <TbX size={18} /> : <TbMenu2 size={18} />}
|
||||||
onClick={() => dispatch(setMobileMenuOpen(!mobileMenuOpen))}
|
onClick={() => dispatch(setMobileMenuOpen(!mobileMenuOpen))}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user