Merge remote-tracking branch 'origin/develop' into oauth-consumer-strategies
This commit is contained in:
commit
5b2894cd8d
23 changed files with 96 additions and 102 deletions
|
@ -37,7 +37,7 @@ if (!HTMLCanvasElement.prototype.toBlob) {
|
|||
const dataURL = this.toDataURL(type, quality);
|
||||
let data;
|
||||
|
||||
if (dataURL.indexOf(BASE64_MARKER) >= 0) {
|
||||
if (dataURL.includes(BASE64_MARKER)) {
|
||||
const [, base64] = dataURL.split(BASE64_MARKER);
|
||||
data = decodeBase64(base64);
|
||||
} else {
|
||||
|
|
|
@ -30,7 +30,7 @@ const textAtCursorMatchesToken = (str: string, caretPosition: number, searchToke
|
|||
word = str.slice(left, right + caretPosition);
|
||||
}
|
||||
|
||||
if (!word || word.trim().length < 3 || searchTokens.indexOf(word[0]) === -1) {
|
||||
if (!word || word.trim().length < 3 || !searchTokens.includes(word[0])) {
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ const textAtCursorMatchesToken = (str: string, caretPosition: number) => {
|
|||
word = str.slice(left, right + caretPosition);
|
||||
}
|
||||
|
||||
if (!word || word.trim().length < 3 || ['@', ':', '#'].indexOf(word[0]) === -1) {
|
||||
if (!word || word.trim().length < 3 || !['@', ':', '#'].includes(word[0])) {
|
||||
return [null, null];
|
||||
}
|
||||
|
||||
|
|
|
@ -12,12 +12,14 @@ interface IIconButton extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|||
/** Text to display next ot the button. */
|
||||
text?: string,
|
||||
/** Don't render a background behind the icon. */
|
||||
transparent?: boolean
|
||||
transparent?: boolean,
|
||||
/** Predefined styles to display for the button. */
|
||||
theme?: 'seamless' | 'outlined',
|
||||
}
|
||||
|
||||
/** A clickable icon. */
|
||||
const IconButton = React.forwardRef((props: IIconButton, ref: React.ForwardedRef<HTMLButtonElement>): JSX.Element => {
|
||||
const { src, className, iconClassName, text, transparent = false, ...filteredProps } = props;
|
||||
const { src, className, iconClassName, text, transparent = false, theme = 'seamless', ...filteredProps } = props;
|
||||
|
||||
return (
|
||||
<button
|
||||
|
@ -25,6 +27,7 @@ const IconButton = React.forwardRef((props: IIconButton, ref: React.ForwardedRef
|
|||
type='button'
|
||||
className={classNames('flex items-center space-x-2 p-1 rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 dark:ring-offset-0 focus:ring-primary-500', {
|
||||
'bg-white dark:bg-transparent': !transparent,
|
||||
'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': theme === 'outlined',
|
||||
'opacity-50': filteredProps.disabled,
|
||||
}, className)}
|
||||
{...filteredProps}
|
||||
|
|
|
@ -24,11 +24,11 @@ const getStatus = makeGetStatus();
|
|||
* Legacy Status wrapper accepting a status ID instead of the full entity.
|
||||
* @deprecated Use the Status component directly.
|
||||
*/
|
||||
const StatusContainer: React.FC<IStatusContainer> = ({ id }) => {
|
||||
const StatusContainer: React.FC<IStatusContainer> = ({ id, onMoveUp, onMoveDown }) => {
|
||||
const status = useAppSelector(state => getStatus(state, { id }));
|
||||
|
||||
if (status) {
|
||||
return <Status status={status} />;
|
||||
return <Status status={status} onMoveUp={onMoveUp} onMoveDown={onMoveDown} />;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -696,7 +696,8 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
// src={require('@tabler/icons/mail.svg')}
|
||||
// onClick={onDirect}
|
||||
// title={intl.formatMessage(messages.direct, { name: account.username })}
|
||||
// className='px-2 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'
|
||||
// theme='outlined'
|
||||
// className='px-2'
|
||||
// iconClassName='w-4 h-4'
|
||||
// />
|
||||
// );
|
||||
|
@ -715,7 +716,8 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
src={require('@tabler/icons/upload.svg')}
|
||||
onClick={handleShare}
|
||||
title={intl.formatMessage(messages.share, { name: account.username })}
|
||||
className='px-2 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'
|
||||
theme='outlined'
|
||||
className='px-2'
|
||||
iconClassName='w-4 h-4'
|
||||
/>
|
||||
);
|
||||
|
@ -770,7 +772,8 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
<MenuButton
|
||||
as={IconButton}
|
||||
src={require('@tabler/icons/dots.svg')}
|
||||
className='px-2 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'
|
||||
theme='outlined'
|
||||
className='px-2'
|
||||
iconClassName='w-4 h-4'
|
||||
children={null}
|
||||
/>
|
||||
|
|
|
@ -38,7 +38,7 @@ const MediaItem: React.FC<IMediaItem> = ({ attachment, displayWidth, onOpenMedia
|
|||
};
|
||||
|
||||
const hoverToPlay = () => {
|
||||
return !autoPlayGif && ['gifv', 'video'].indexOf(attachment.type) !== -1;
|
||||
return !autoPlayGif && ['gifv', 'video'].includes(attachment.type);
|
||||
};
|
||||
|
||||
const handleClick: React.MouseEventHandler = e => {
|
||||
|
|
|
@ -85,8 +85,8 @@ export function search(value, { emojisToShowFilter, maxResults, include, exclude
|
|||
pool = {};
|
||||
|
||||
data.categories.forEach(category => {
|
||||
const isIncluded = include && include.length ? include.indexOf(category.name.toLowerCase()) > -1 : true;
|
||||
const isExcluded = exclude && exclude.length ? exclude.indexOf(category.name.toLowerCase()) > -1 : false;
|
||||
const isIncluded = include && include.length ? include.includes(category.name.toLowerCase()) : true;
|
||||
const isExcluded = exclude && exclude.length ? exclude.includes(category.name.toLowerCase()) : false;
|
||||
if (!isIncluded || isExcluded) {
|
||||
return;
|
||||
}
|
||||
|
@ -95,8 +95,8 @@ export function search(value, { emojisToShowFilter, maxResults, include, exclude
|
|||
});
|
||||
|
||||
if (custom.length) {
|
||||
const customIsIncluded = include && include.length ? include.indexOf('custom') > -1 : true;
|
||||
const customIsExcluded = exclude && exclude.length ? exclude.indexOf('custom') > -1 : false;
|
||||
const customIsIncluded = include && include.length ? include.includes('custom') : true;
|
||||
const customIsExcluded = exclude && exclude.length ? exclude.includes('custom') : false;
|
||||
if (customIsIncluded && !customIsExcluded) {
|
||||
addCustomToPool(custom, pool);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ const buildSearch = (data) => {
|
|||
(split ? string.split(/[-|_|\s]+/) : [string]).forEach((s) => {
|
||||
s = s.toLowerCase();
|
||||
|
||||
if (search.indexOf(s) === -1) {
|
||||
if (!search.includes(s)) {
|
||||
search.push(s);
|
||||
}
|
||||
});
|
||||
|
@ -190,7 +190,7 @@ function getData(emoji, skin, set) {
|
|||
|
||||
function uniq(arr) {
|
||||
return arr.reduce((acc, item) => {
|
||||
if (acc.indexOf(item) === -1) {
|
||||
if (!acc.includes(item)) {
|
||||
acc.push(item);
|
||||
}
|
||||
return acc;
|
||||
|
@ -201,7 +201,7 @@ function intersect(a, b) {
|
|||
const uniqA = uniq(a);
|
||||
const uniqB = uniq(b);
|
||||
|
||||
return uniqA.filter(item => uniqB.indexOf(item) >= 0);
|
||||
return uniqA.filter(item => uniqB.includes(item));
|
||||
}
|
||||
|
||||
function deepMerge(a, b) {
|
||||
|
|
|
@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { replaceHomeTimeline } from 'soapbox/actions/timelines';
|
||||
import { useAppDispatch, useAppSelector, useDimensions, useFeatures } from 'soapbox/hooks';
|
||||
import { useAppDispatch, useAppSelector, useDimensions } from 'soapbox/hooks';
|
||||
import useCarouselAvatars from 'soapbox/queries/carousels';
|
||||
|
||||
import { Card, HStack, Icon, Stack, Text } from '../../components/ui';
|
||||
|
@ -59,8 +59,6 @@ const CarouselItem = ({ avatar }: { avatar: any }) => {
|
|||
};
|
||||
|
||||
const FeedCarousel = () => {
|
||||
const features = useFeatures();
|
||||
|
||||
const { data: avatars, isFetching, isError } = useCarouselAvatars();
|
||||
|
||||
const [cardRef, setCardRef, { width }] = useDimensions();
|
||||
|
@ -83,10 +81,6 @@ const FeedCarousel = () => {
|
|||
}
|
||||
}, [width, widthPerAvatar]);
|
||||
|
||||
if (!features.feedUserFiltering) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<Card variant='rounded' size='lg' data-testid='feed-carousel-error'>
|
||||
|
|
|
@ -104,7 +104,7 @@ const messages: Record<NotificationType, MessageDescriptor> = defineMessages({
|
|||
},
|
||||
update: {
|
||||
id: 'notification.update',
|
||||
defaultMessage: '{name} edited a post',
|
||||
defaultMessage: '{name} edited a post you interacted with',
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ const addAutoPlay = (html: string): string => {
|
|||
const iframe = document.querySelector('iframe');
|
||||
|
||||
if (iframe) {
|
||||
if (iframe.src.indexOf('?') !== -1) {
|
||||
if (iframe.src.includes('?')) {
|
||||
iframe.src += '&';
|
||||
} else {
|
||||
iframe.src += '?';
|
||||
|
|
|
@ -9,6 +9,8 @@ import { useAppSelector } from 'soapbox/hooks';
|
|||
interface IThreadStatus {
|
||||
id: string,
|
||||
focusedStatusId: string,
|
||||
onMoveUp: (id: string) => void,
|
||||
onMoveDown: (id: string) => void,
|
||||
}
|
||||
|
||||
/** Status with reply-connector in threads. */
|
||||
|
|
|
@ -369,6 +369,8 @@ const Thread: React.FC<IThread> = (props) => {
|
|||
key={id}
|
||||
id={id}
|
||||
focusedStatusId={status!.id}
|
||||
onMoveUp={handleMoveUp}
|
||||
onMoveDown={handleMoveDown}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -92,7 +92,7 @@ export default class ModalRoot extends React.PureComponent {
|
|||
}
|
||||
|
||||
renderLoading = modalId => () => {
|
||||
return ['MEDIA', 'VIDEO', 'BOOST', 'CONFIRM', 'ACTIONS'].indexOf(modalId) === -1 ? <ModalLoading /> : null;
|
||||
return !['MEDIA', 'VIDEO', 'BOOST', 'CONFIRM', 'ACTIONS'].includes(modalId) ? <ModalLoading /> : null;
|
||||
}
|
||||
|
||||
renderError = (props) => {
|
||||
|
|
|
@ -93,7 +93,8 @@ const SubscriptionButton = ({ account }: ISubscriptionButton) => {
|
|||
src={isSubscribed ? require('@tabler/icons/bell-ringing.svg') : require('@tabler/icons/bell.svg')}
|
||||
onClick={handleToggle}
|
||||
title={title}
|
||||
className='px-2 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'
|
||||
theme='outlined'
|
||||
className='px-2'
|
||||
iconClassName='w-4 h-4'
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -28,7 +28,7 @@ const UserPanel: React.FC<IUserPanel> = ({ accountId, action, badges, domain })
|
|||
|
||||
if (!account) return null;
|
||||
const displayNameHtml = { __html: account.get('display_name_html') };
|
||||
const acct = account.get('acct').indexOf('@') === -1 && domain ? `${account.get('acct')}@${domain}` : account.get('acct');
|
||||
const acct = !account.get('acct').includes('@') && domain ? `${account.get('acct')}@${domain}` : account.get('acct');
|
||||
const header = account.get('header');
|
||||
const verified = account.get('verified');
|
||||
|
||||
|
|
|
@ -352,7 +352,7 @@ const UI: React.FC = ({ children }) => {
|
|||
const handleDragEnter = (e: DragEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
if (e.target && dragTargets.current.indexOf(e.target) === -1) {
|
||||
if (e.target && !dragTargets.current.includes(e.target)) {
|
||||
dragTargets.current.push(e.target);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import BundleContainer from '../containers/bundle_container';
|
|||
type PageProps = {
|
||||
params?: MatchType['params'],
|
||||
layout?: any,
|
||||
children: React.ReactNode,
|
||||
};
|
||||
|
||||
interface IWrappedRoute extends RouteProps {
|
||||
|
|
|
@ -58,7 +58,7 @@ const HomePage: React.FC = ({ children }) => {
|
|||
</Card>
|
||||
)}
|
||||
|
||||
<FeedCarousel />
|
||||
{features.feedUserFiltering && <FeedCarousel />}
|
||||
|
||||
{children}
|
||||
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
import React from 'react';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import LinkFooter from 'soapbox/features/ui/components/link_footer';
|
||||
import {
|
||||
WhoToFollowPanel,
|
||||
TrendsPanel,
|
||||
SignUpPanel,
|
||||
CtaBanner,
|
||||
} from 'soapbox/features/ui/util/async-components';
|
||||
// import GroupSidebarPanel from '../features/groups/sidebar_panel';
|
||||
import { getFeatures } from 'soapbox/utils/features';
|
||||
|
||||
import { Layout } from '../components/ui';
|
||||
import BundleContainer from '../features/ui/containers/bundle_container';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const me = state.get('me');
|
||||
const features = getFeatures(state.get('instance'));
|
||||
|
||||
return {
|
||||
me,
|
||||
showTrendsPanel: features.trends,
|
||||
showWhoToFollowPanel: features.suggestions,
|
||||
};
|
||||
};
|
||||
|
||||
export default @connect(mapStateToProps)
|
||||
class StatusPage extends ImmutablePureComponent {
|
||||
|
||||
render() {
|
||||
const { me, children, showTrendsPanel, showWhoToFollowPanel } = this.props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Layout.Main>
|
||||
{children}
|
||||
|
||||
{!me && (
|
||||
<BundleContainer fetchComponent={CtaBanner}>
|
||||
{Component => <Component key='cta-banner' />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
</Layout.Main>
|
||||
|
||||
<Layout.Aside>
|
||||
{!me && (
|
||||
<BundleContainer fetchComponent={SignUpPanel}>
|
||||
{Component => <Component key='sign-up-panel' />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
{showTrendsPanel && (
|
||||
<BundleContainer fetchComponent={TrendsPanel}>
|
||||
{Component => <Component limit={3} key='trends-panel' />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
{showWhoToFollowPanel && (
|
||||
<BundleContainer fetchComponent={WhoToFollowPanel}>
|
||||
{Component => <Component limit={5} key='wtf-panel' />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
<LinkFooter key='link-footer' />
|
||||
</Layout.Aside>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
57
app/soapbox/pages/status_page.tsx
Normal file
57
app/soapbox/pages/status_page.tsx
Normal file
|
@ -0,0 +1,57 @@
|
|||
import React from 'react';
|
||||
|
||||
import LinkFooter from 'soapbox/features/ui/components/link_footer';
|
||||
import {
|
||||
WhoToFollowPanel,
|
||||
TrendsPanel,
|
||||
SignUpPanel,
|
||||
CtaBanner,
|
||||
} from 'soapbox/features/ui/util/async-components';
|
||||
import { useAppSelector, useFeatures } from 'soapbox/hooks';
|
||||
|
||||
import { Layout } from '../components/ui';
|
||||
import BundleContainer from '../features/ui/containers/bundle_container';
|
||||
|
||||
interface IStatusPage {
|
||||
children: React.ReactNode,
|
||||
}
|
||||
|
||||
const StatusPage: React.FC<IStatusPage> = ({ children }) => {
|
||||
const me = useAppSelector(state => state.me);
|
||||
const features = useFeatures();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Layout.Main>
|
||||
{children}
|
||||
|
||||
{!me && (
|
||||
<BundleContainer fetchComponent={CtaBanner}>
|
||||
{Component => <Component key='cta-banner' />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
</Layout.Main>
|
||||
|
||||
<Layout.Aside>
|
||||
{!me && (
|
||||
<BundleContainer fetchComponent={SignUpPanel}>
|
||||
{Component => <Component key='sign-up-panel' />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
{features.trends && (
|
||||
<BundleContainer fetchComponent={TrendsPanel}>
|
||||
{Component => <Component limit={3} key='trends-panel' />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
{features.suggestions && (
|
||||
<BundleContainer fetchComponent={WhoToFollowPanel}>
|
||||
{Component => <Component limit={5} key='wtf-panel' />}
|
||||
</BundleContainer>
|
||||
)}
|
||||
<LinkFooter key='link-footer' />
|
||||
</Layout.Aside>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatusPage;
|
|
@ -93,7 +93,7 @@ const toServerSideType = (columnType: string): string => {
|
|||
case 'thread':
|
||||
return columnType;
|
||||
default:
|
||||
if (columnType.indexOf('list:') > -1) {
|
||||
if (columnType.includes('list:')) {
|
||||
return 'home';
|
||||
} else {
|
||||
return 'public'; // community, account, hashtag
|
||||
|
|
Loading…
Reference in a new issue