diff --git a/app/soapbox/components/dropdown_menu.tsx b/app/soapbox/components/dropdown_menu.tsx index 7d13d6829f..d3efa6865d 100644 --- a/app/soapbox/components/dropdown_menu.tsx +++ b/app/soapbox/components/dropdown_menu.tsx @@ -223,12 +223,12 @@ const RouterDropdownMenu = withRouter(DropdownMenu); export interface IDropdown extends RouteComponentProps { icon?: string, - src: string, + src?: string, items: Menu, size?: number, active?: boolean, pressed?: boolean, - title: string, + title?: string, disabled?: boolean, status?: Status, isUserTouching?: () => boolean, @@ -245,6 +245,7 @@ export interface IDropdown extends RouteComponentProps { openedViaKeyboard?: boolean, text?: string, onShiftClick?: React.EventHandler, + children?: JSX.Element, } interface IDropdownState { @@ -355,27 +356,38 @@ class Dropdown extends React.PureComponent { } render() { - const { src, items, title, disabled, dropdownPlacement, openDropdownId, openedViaKeyboard = false, pressed, text } = this.props; + const { src = require('@tabler/icons/icons/dots.svg'), items, title, disabled, dropdownPlacement, openDropdownId, openedViaKeyboard = false, pressed, text, children } = this.props; const open = this.state.id === openDropdownId; return ( <> - + {children ? ( + React.cloneElement(children, { + disabled, + onClick: this.handleClick, + onMouseDown: this.handleMouseDown, + onKeyDown: this.handleButtonKeyDown, + onKeyPress: this.handleKeyPress, + ref: this.setTargetRef, + }) + ) : ( + + )} diff --git a/app/soapbox/components/ui/hoverable/hoverable.tsx b/app/soapbox/components/hoverable.tsx similarity index 97% rename from app/soapbox/components/ui/hoverable/hoverable.tsx rename to app/soapbox/components/hoverable.tsx index c7d884dc73..751c413c10 100644 --- a/app/soapbox/components/ui/hoverable/hoverable.tsx +++ b/app/soapbox/components/hoverable.tsx @@ -3,7 +3,7 @@ import React, { useState, useRef } from 'react'; import { usePopper } from 'react-popper'; interface IHoverable { - component: React.Component, + component: JSX.Element, } /** Wrapper to render a given component when hovered */ diff --git a/app/soapbox/components/status-action-button.tsx b/app/soapbox/components/status-action-button.tsx new file mode 100644 index 0000000000..0a07feb66a --- /dev/null +++ b/app/soapbox/components/status-action-button.tsx @@ -0,0 +1,81 @@ +import classNames from 'classnames'; +import React from 'react'; +import InlineSVG from 'react-inlinesvg'; + +import { Text } from 'soapbox/components/ui'; +import { shortNumberFormat } from 'soapbox/utils/numbers'; + +const COLORS = { + accent: 'text-accent-300 hover:text-accent-300 dark:hover:text-accent-300', + success: 'text-success-600 hover:text-success-600 dark:hover:text-success-600', + '': '', +}; + +const FILL_COLORS = { + accent: 'fill-accent-300 hover:fill-accent-300', + '': '', +}; + +type Color = keyof typeof COLORS; +type FillColor = keyof typeof FILL_COLORS; + +interface IStatusActionCounter { + count: number, +} + +/** Action button numerical counter, eg "5" likes */ +const StatusActionCounter: React.FC = ({ count = 0 }): JSX.Element => { + return ( + + {shortNumberFormat(count)} + + ); +}; + +interface IStatusActionButton extends React.ButtonHTMLAttributes { + iconClassName?: string, + icon: string, + count?: number, + active?: boolean, + color?: Color, + fill?: FillColor, +} + +const StatusActionButton = React.forwardRef((props: IStatusActionButton, ref: React.ForwardedRef): JSX.Element => { + const { icon, className, iconClassName, active, color = '', fill = '', count = 0, ...filteredProps } = props; + + return ( + + ); +}); + +export default StatusActionButton; diff --git a/app/soapbox/components/status_action_bar.tsx b/app/soapbox/components/status_action_bar.tsx index 3900118e93..013ba980ef 100644 --- a/app/soapbox/components/status_action_bar.tsx +++ b/app/soapbox/components/status_action_bar.tsx @@ -1,4 +1,3 @@ -import classNames from 'classnames'; import { List as ImmutableList } from 'immutable'; import React from 'react'; import ImmutablePureComponent from 'react-immutable-pure-component'; @@ -8,11 +7,8 @@ import { withRouter } from 'react-router-dom'; import { simpleEmojiReact } from 'soapbox/actions/emoji_reacts'; import EmojiSelector from 'soapbox/components/emoji_selector'; -import { - StatusAction, - StatusActionButton, - StatusActionCounter, -} from 'soapbox/components/ui/status/status-action-button'; +import Hoverable from 'soapbox/components/hoverable'; +import StatusActionButton from 'soapbox/components/status-action-button'; import DropdownMenuContainer from 'soapbox/containers/dropdown_menu_container'; import { isUserTouching } from 'soapbox/is_mobile'; import { getReactForStatus, reduceEmoji } from 'soapbox/utils/emoji_reacts'; @@ -20,8 +16,6 @@ import { getFeatures } from 'soapbox/utils/features'; import { openModal } from '../actions/modals'; -import { IconButton, Hoverable } from './ui'; - import type { History } from 'history'; import type { AnyAction, Dispatch } from 'redux'; import type { Menu } from 'soapbox/components/dropdown_menu'; @@ -171,7 +165,7 @@ class StatusActionBar extends ImmutablePureComponent { + handleLikeButtonClick: React.EventHandler = (e) => { const { features } = this.props; const reactForStatus = getReactForStatus(this.props.status, this.props.allowedEmoji); @@ -186,6 +180,8 @@ class StatusActionBar extends ImmutablePureComponent { @@ -204,13 +200,15 @@ class StatusActionBar extends ImmutablePureComponent = () => { + handleFavouriteClick: React.EventHandler = (e) => { const { me, onFavourite, onOpenUnauthorizedModal, status } = this.props; if (me) { onFavourite(status); } else { onOpenUnauthorizedModal('FAVOURITE'); } + + e.stopPropagation(); } handleBookmarkClick: React.EventHandler = (e) => { @@ -589,47 +587,30 @@ class StatusActionBar extends ImmutablePureComponent - ); - } else { - reblogButton = ( - - ); - } + const reblogButton = ( + + ); if (!status.in_reply_to_id) { replyTitle = intl.formatMessage(messages.reply); @@ -648,55 +629,40 @@ class StatusActionBar extends ImmutablePureComponent - - {reblogButton} - {reblogCount > 0 && ( - - )} - + {features.quotePosts && me ? ( + + {reblogButton} + + ) : ( + reblogButton + )} {features.emojiReacts ? ( -
- as any - )} - > - - - - {emojiReactCount > 0 && ( - (features.exposableReactions && !features.emojiReacts) ? ( - - ) : ( - - ) )} -
+ > + + ): ( @@ -710,14 +676,12 @@ class StatusActionBar extends ImmutablePureComponent )} - - + - + ); } diff --git a/app/soapbox/components/ui/index.ts b/app/soapbox/components/ui/index.ts index 3aa272def9..fa60595f5a 100644 --- a/app/soapbox/components/ui/index.ts +++ b/app/soapbox/components/ui/index.ts @@ -7,7 +7,6 @@ export { default as EmojiSelector } from './emoji-selector/emoji-selector'; export { default as Form } from './form/form'; export { default as FormActions } from './form-actions/form-actions'; export { default as FormGroup } from './form-group/form-group'; -export { default as Hoverable } from './hoverable/hoverable'; export { default as HStack } from './hstack/hstack'; export { default as Icon } from './icon/icon'; export { default as IconButton } from './icon-button/icon-button'; diff --git a/app/soapbox/components/ui/status/status-action-button.tsx b/app/soapbox/components/ui/status/status-action-button.tsx deleted file mode 100644 index 635e0dbe90..0000000000 --- a/app/soapbox/components/ui/status/status-action-button.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import classNames from 'classnames'; -import React from 'react'; - -import { IconButton } from 'soapbox/components/ui'; -import { shortNumberFormat } from 'soapbox/utils/numbers'; - -interface IStatusActionCounter { - count: number, - className?: string, -} - -/** Action button numerical counter, eg "5" likes */ -const StatusActionCounter: React.FC = ({ count = 0, className }): JSX.Element => { - return ( - - {shortNumberFormat(count)} - - ); -}; - -interface IStatusAction { - title?: string, -} - -/** Status action container element */ -const StatusAction: React.FC = ({ title, children }) => { - return ( -
- {children} -
- ); -}; - -interface IStatusActionButton { - icon: string, - onClick: () => void, - count?: number, - active?: boolean, - title?: string, -} - -/** Action button (eg "Like") for a Status */ -const StatusActionButton: React.FC = ({ icon, title, active = false, onClick, count = 0 }): JSX.Element => { - - const handleClick: React.EventHandler = (e) => { - onClick(); - e.stopPropagation(); - e.preventDefault(); - }; - - return ( - - - - {(count || null) && ( - - )} - - ); -}; - -export { StatusAction, StatusActionButton, StatusActionCounter };