diff --git a/src/components/dropdown-menu/dropdown-menu-item.tsx b/src/components/dropdown-menu/dropdown-menu-item.tsx index 61cf054d5..e934d079d 100644 --- a/src/components/dropdown-menu/dropdown-menu-item.tsx +++ b/src/components/dropdown-menu/dropdown-menu-item.tsx @@ -22,9 +22,10 @@ interface IDropdownMenuItem { index: number; item: MenuItem | null; onClick?(): void; + autoFocus?: boolean; } -const DropdownMenuItem = ({ index, item, onClick }: IDropdownMenuItem) => { +const DropdownMenuItem = ({ index, item, onClick, autoFocus }: IDropdownMenuItem) => { const history = useHistory(); const itemRef = useRef(null); @@ -63,7 +64,7 @@ const DropdownMenuItem = ({ index, item, onClick }: IDropdownMenuItem) => { useEffect(() => { const firstItem = index === 0; - if (itemRef.current && firstItem) { + if (itemRef.current && (autoFocus ? firstItem : item?.active)) { itemRef.current.focus({ preventScroll: true }); } }, [itemRef.current, index]); diff --git a/src/components/dropdown-menu/dropdown-menu.tsx b/src/components/dropdown-menu/dropdown-menu.tsx index 3c888cf53..b751bdcde 100644 --- a/src/components/dropdown-menu/dropdown-menu.tsx +++ b/src/components/dropdown-menu/dropdown-menu.tsx @@ -262,6 +262,8 @@ const DropdownMenu = (props: IDropdownMenu) => { return null; } + const autoFocus = !items.some((item) => item?.active); + return ( <> {children ? ( @@ -309,6 +311,7 @@ const DropdownMenu = (props: IDropdownMenu) => { item={item} index={idx} onClick={handleClose} + autoFocus={autoFocus} /> ))} diff --git a/src/components/ui/button/button.tsx b/src/components/ui/button/button.tsx index 412717d3c..281709431 100644 --- a/src/components/ui/button/button.tsx +++ b/src/components/ui/button/button.tsx @@ -8,19 +8,16 @@ import { useButtonStyles } from './useButtonStyles'; import type { ButtonSizes, ButtonThemes } from './useButtonStyles'; -interface IButton { +interface IButton extends Pick< + React.ComponentProps<'button'>, + 'children' | 'className' | 'disabled' | 'onClick' | 'onMouseDown' | 'onKeyDown' | 'title' | 'type' +> { /** Whether this button expands the width of its container. */ block?: boolean; - /** Elements inside the ); diff --git a/src/components/ui/button/useButtonStyles.ts b/src/components/ui/button/useButtonStyles.ts index ed9c5cbe7..9acbb1c36 100644 --- a/src/components/ui/button/useButtonStyles.ts +++ b/src/components/ui/button/useButtonStyles.ts @@ -11,14 +11,14 @@ const themes = { danger: 'border-transparent bg-danger-100 dark:bg-danger-900 text-danger-600 dark:text-danger-200 hover:bg-danger-600 hover:text-gray-100 dark:hover:text-gray-100 dark:hover:bg-danger-500 focus:ring-danger-500', transparent: 'border-transparent bg-transparent text-primary-600 dark:text-accent-blue dark:bg-transparent hover:bg-gray-200 dark:hover:bg-gray-800/50', outline: 'border-gray-100 border-2 bg-transparent text-gray-100 hover:bg-white/10', - muted: 'border border-solid bg-transparent border-gray-400 dark:border-gray-800 hover:border-primary-300 dark:hover:border-primary-700 focus:border-primary-500 text-gray-900 dark:text-gray-100 focus:ring-primary-500', + muted: 'border border-solid bg-transparent border-gray-400 dark:border-gray-800 hover:border-primary-300 dark:hover:border-primary-700 focus:border-primary-500 text-gray-800 dark:text-gray-100 focus:ring-primary-500', }; const sizes = { - xs: 'px-3 py-1 text-xs', - sm: 'px-3 py-1.5 text-xs leading-4', - md: 'px-4 py-2 text-sm', - lg: 'px-6 py-3 text-base', + xs: 'gap-x-1.5 px-2 py-1 text-xs', + sm: 'gap-x-2 px-3 py-1.5 text-xs leading-4', + md: 'gap-x-2 px-4 py-2 text-sm', + lg: 'gap-x-2 px-6 py-3 text-base', }; type ButtonSizes = keyof typeof sizes diff --git a/src/features/compose/components/compose-form.tsx b/src/features/compose/components/compose-form.tsx index 4aa39a789..944adc84d 100644 --- a/src/features/compose/components/compose-form.tsx +++ b/src/features/compose/components/compose-form.tsx @@ -26,7 +26,7 @@ import WarningContainer from '../containers/warning-container'; import { $createEmojiNode } from '../editor/nodes/emoji-node'; import { countableText } from '../util/counter'; -import MarkdownButton from './markdown-button'; +import ContentTypeButton from './content-type-button'; import PollButton from './poll-button'; import PollForm from './polls/poll-form'; import PrivacyDropdown from './privacy-dropdown'; @@ -197,10 +197,8 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab {features.media && } {features.polls && } - {features.privacyScopes && !group && !groupId && } {features.scheduledStatuses && } {features.spoilers && } - {features.richText && } ), [features, id]); @@ -240,6 +238,11 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab publishText = intl.formatMessage(messages.schedule); } + const selectButtons = []; + + if (features.privacyScopes && !group && !groupId) selectButtons.push(); + if (features.richText) selectButtons.push(); + return ( {scheduledStatusCount > 0 && !event && !group && ( @@ -269,6 +272,12 @@ const ComposeForm = ({ id, shouldCondense, autoFocus, clickab {!shouldCondense && !event && !group && } + {!!selectButtons && ( + + {selectButtons} + + )} +
= ({ composeId }) => { - const intl = useIntl(); - const dispatch = useAppDispatch(); - - const active = useCompose(composeId).content_type === 'text/markdown'; - - const onClick = () => dispatch(changeComposeContentType(composeId, active ? 'text/plain' : 'text/markdown')); - - return ( - - ); - -}; - -export { MarkdownButton as default }; diff --git a/src/features/compose/components/privacy-dropdown.tsx b/src/features/compose/components/privacy-dropdown.tsx index fe1ba2a33..9a5a2ecd1 100644 --- a/src/features/compose/components/privacy-dropdown.tsx +++ b/src/features/compose/components/privacy-dropdown.tsx @@ -9,7 +9,7 @@ import Overlay from 'react-overlays/lib/Overlay'; import { changeComposeVisibility } from 'soapbox/actions/compose'; import { closeModal, openModal } from 'soapbox/actions/modals'; import Icon from 'soapbox/components/icon'; -import { IconButton } from 'soapbox/components/ui'; +import { Button } from 'soapbox/components/ui'; import { useAppDispatch, useCompose } from 'soapbox/hooks'; import { userTouching } from 'soapbox/is-mobile'; @@ -277,12 +277,12 @@ const PrivacyDropdown: React.FC = ({ active: valueOption && options.indexOf(valueOption) === 0, })} > - { @@ -116,6 +117,7 @@ const Preferences = () => { const defaultContentTypeOptions = React.useMemo(() => ({ 'text/plain': intl.formatMessage(messages.content_type_plaintext), 'text/markdown': intl.formatMessage(messages.content_type_markdown), + 'text/html': intl.formatMessage(messages.content_type_html), }), []); return ( diff --git a/src/locales/en.json b/src/locales/en.json index aafcd1bbf..6600651c6 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -440,13 +440,12 @@ "compose_event.tabs.pending": "Manage requests", "compose_event.update": "Update", "compose_event.upload_banner": "Upload event banner", + "compose_form.content_type.change": "Change content type", "compose_form.direct_message_warning": "This post will only be sent to the mentioned users.", "compose_form.event_placeholder": "Post to this event", "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", "compose_form.lock_disclaimer.lock": "locked", - "compose_form.markdown.marked": "Post markdown enabled", - "compose_form.markdown.unmarked": "Post markdown disabled", "compose_form.message": "Message", "compose_form.placeholder": "What's on your mind?", "compose_form.poll.add_option": "Add an answer", @@ -1162,6 +1161,7 @@ "preferences.fields.unfollow_modal_label": "Show confirmation dialog before unfollowing someone", "preferences.hints.demetricator": "Decrease social media anxiety by hiding all numbers from the site.", "preferences.notifications.advanced": "Show all notification categories", + "preferences.options.content_type_html": "HTML", "preferences.options.content_type_markdown": "Markdown", "preferences.options.content_type_plaintext": "Plain text", "preferences.options.privacy_followers_only": "Followers-only",