Refactor columns

environments/review-refactor-c-r60qq9/deployments/1614
Alex Gleason 2022-11-30 11:19:16 -06:00
rodzic 0c16ffeb02
commit 7675860429
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
36 zmienionych plików z 122 dodań i 487 usunięć

Wyświetl plik

@ -1,129 +0,0 @@
'use strict';
import PropTypes from 'prop-types';
import React from 'react';
import { withRouter } from 'react-router-dom';
// import classNames from 'clsx';
// import { injectIntl, defineMessages } from 'react-intl';
// import Icon from 'soapbox/components/icon';
import SubNavigation from 'soapbox/components/sub-navigation';
// const messages = defineMessages({
// show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
// hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' },
// });
class ColumnHeader extends React.PureComponent {
static propTypes = {
// intl: PropTypes.object.isRequired,
title: PropTypes.node,
icon: PropTypes.string,
active: PropTypes.bool,
extraButton: PropTypes.node,
children: PropTypes.node,
history: PropTypes.object,
};
state = {
collapsed: true,
animating: false,
};
historyBack = () => {
if (window.history?.length === 1) {
this.props.history.push('/');
} else {
this.props.history.goBack();
}
}
handleToggleClick = (e) => {
e.stopPropagation();
this.setState({ collapsed: !this.state.collapsed, animating: true });
}
handleBackClick = () => {
this.historyBack();
}
handleTransitionEnd = () => {
this.setState({ animating: false });
}
render() {
const { title } = this.props;
return <SubNavigation message={title} />;
}
// render() {
// const { title, icon, active, children, extraButton, intl: { formatMessage } } = this.props;
// const { collapsed, animating } = this.state;
//
// const wrapperClassName = classNames('column-header__wrapper', {
// 'active': active,
// });
//
// const buttonClassName = classNames('column-header', {
// 'active': active,
// });
//
// const collapsibleClassName = classNames('column-header__collapsible', {
// 'collapsed': collapsed,
// 'animating': animating,
// });
//
// const collapsibleButtonClassName = classNames('column-header__button', {
// 'active': !collapsed,
// });
//
// let extraContent, collapseButton;
//
// if (children) {
// extraContent = (
// <div key='extra-content' className='column-header__collapsible__extra'>
// {children}
// </div>
// );
// }
//
// const collapsedContent = [
// extraContent,
// ];
//
// if (children) {
// collapseButton = <button className={collapsibleButtonClassName} title={formatMessage(collapsed ? messages.show : messages.hide)} aria-label={formatMessage(collapsed ? messages.show : messages.hide)} aria-pressed={collapsed ? 'false' : 'true'} onClick={this.handleToggleClick}><Icon id='cog' /></button>;
// }
//
// const hasTitle = icon && title;
//
// return (
// <div className={wrapperClassName}>
// <h1 className={buttonClassName}>
// {hasTitle && (
// <button>
// <Icon id={icon} fixedWidth className='column-header__icon' />
// {title}
// </button>
// )}
//
// <div className='column-header__buttons'>
// {extraButton}
// {collapseButton}
// </div>
// </h1>
//
// <div className={collapsibleClassName} tabIndex={collapsed ? -1 : null} onTransitionEnd={this.handleTransitionEnd}>
// <div className='column-header__collapsible-inner'>
// {(!collapsed || animating) && collapsedContent}
// </div>
// </div>
// </div>
// );
// }
}
export default withRouter(ColumnHeader);

Wyświetl plik

@ -1,41 +0,0 @@
// import throttle from 'lodash/throttle';
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
// import { connect } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { CardHeader, CardTitle } from './ui';
const messages = defineMessages({
back: { id: 'column_back_button.label', defaultMessage: 'Back' },
});
interface ISubNavigation {
message: React.ReactNode,
/** @deprecated Unused. */
settings?: React.ComponentType,
}
const SubNavigation: React.FC<ISubNavigation> = ({ message }) => {
const intl = useIntl();
const history = useHistory();
const handleBackClick = () => {
if (window.history && window.history.length === 1) {
history.push('/');
} else {
history.goBack();
}
};
return (
<CardHeader
aria-label={intl.formatMessage(messages.back)}
onBackClick={handleBackClick}
>
<CardTitle title={message} />
</CardHeader>
);
};
export default SubNavigation;

Wyświetl plik

@ -44,13 +44,14 @@ const Card = React.forwardRef<HTMLDivElement, ICard>(({ children, variant = 'def
interface ICardHeader {
backHref?: string,
onBackClick?: (event: React.MouseEvent) => void
className?: string
}
/**
* Card header container with back button.
* Typically holds a CardTitle.
*/
const CardHeader: React.FC<ICardHeader> = ({ children, backHref, onBackClick }): JSX.Element => {
const CardHeader: React.FC<ICardHeader> = ({ className, children, backHref, onBackClick }): JSX.Element => {
const intl = useIntl();
const renderBackButton = () => {
@ -70,7 +71,7 @@ const CardHeader: React.FC<ICardHeader> = ({ children, backHref, onBackClick }):
};
return (
<HStack alignItems='center' space={2} className='mb-4'>
<HStack alignItems='center' space={2} className={classNames('mb-4', className)}>
{renderBackButton()}
{children}

Wyświetl plik

@ -1,7 +1,7 @@
import React from 'react';
import { render, screen } from '../../../../jest/test-helpers';
import Column from '../column';
import { Column } from '../column';
describe('<Column />', () => {
it('renders correctly with minimal props', () => {

Wyświetl plik

@ -1,3 +1,4 @@
import classNames from 'clsx';
import React from 'react';
import { useHistory } from 'react-router-dom';
@ -6,6 +7,38 @@ import { useSoapboxConfig } from 'soapbox/hooks';
import { Card, CardBody, CardHeader, CardTitle } from '../card/card';
interface IColumnHeader extends Pick<IColumn, 'label' | 'backHref' |'transparent'> {
children?: React.ReactNode
}
/** Contains the column title with optional back button. */
const ColumnHeader: React.FC<IColumnHeader> = ({ label, backHref, transparent, children }) => {
const history = useHistory();
const handleBackClick = () => {
if (backHref) {
history.push(backHref);
return;
}
if (history.length === 1) {
history.push('/');
} else {
history.goBack();
}
};
return (
<CardHeader
className={classNames({ 'px-4 pt-4 sm:p-0': transparent })}
onBackClick={handleBackClick}
>
<CardTitle title={label} />
{children}
</CardHeader>
);
};
export interface IColumn {
/** Route the back button goes to. */
backHref?: string,
@ -24,37 +57,8 @@ export interface IColumn {
/** A backdrop for the main section of the UI. */
const Column: React.FC<IColumn> = React.forwardRef((props, ref: React.ForwardedRef<HTMLDivElement>): JSX.Element => {
const { backHref, children, label, transparent = false, withHeader = true, className } = props;
const history = useHistory();
const soapboxConfig = useSoapboxConfig();
const handleBackClick = () => {
if (backHref) {
history.push(backHref);
return;
}
if (history.length === 1) {
history.push('/');
} else {
history.goBack();
}
};
const renderChildren = () => (
<Card variant={transparent ? undefined : 'rounded'} className={className}>
{withHeader ? (
<CardHeader onBackClick={handleBackClick}>
<CardTitle title={label} />
</CardHeader>
) : null}
<CardBody>
{children}
</CardBody>
</Card>
);
return (
<div role='region' className='relative' ref={ref} aria-label={label} column-type={transparent ? 'transparent' : 'filled'}>
<Helmet>
@ -69,9 +73,20 @@ const Column: React.FC<IColumn> = React.forwardRef((props, ref: React.ForwardedR
)}
</Helmet>
{renderChildren()}
<Card variant={transparent ? undefined : 'rounded'} className={className}>
{withHeader && (
<ColumnHeader label={label} backHref={backHref} transparent={transparent} />
)}
<CardBody>
{children}
</CardBody>
</Card>
</div>
);
});
export default Column;
export {
Column,
ColumnHeader,
};

Wyświetl plik

@ -4,7 +4,7 @@ export { default as Banner } from './banner/banner';
export { default as Button } from './button/button';
export { Card, CardBody, CardHeader, CardTitle } from './card/card';
export { default as Checkbox } from './checkbox/checkbox';
export { default as Column } from './column/column';
export { Column, ColumnHeader } from './column/column';
export { default as Counter } from './counter/counter';
export { default as Datepicker } from './datepicker/datepicker';
export { default as Divider } from './divider/divider';

Wyświetl plik

@ -3,10 +3,9 @@ import { defineMessages, FormattedDate, useIntl } from 'react-intl';
import { fetchModerationLog } from 'soapbox/actions/admin';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Column } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import Column from '../ui/components/column';
const messages = defineMessages({
heading: { id: 'column.admin.moderation_log', defaultMessage: 'Moderation Log' },
emptyMessage: { id: 'admin.moderation_log.empty_message', defaultMessage: 'You have not performed any moderation actions yet. When you do, a history will be shown here.' },
@ -47,7 +46,7 @@ const ModerationLog = () => {
};
return (
<Column icon='balance-scale' label={intl.formatMessage(messages.heading)}>
<Column label={intl.formatMessage(messages.heading)}>
<ScrollableList
isLoading={isLoading}
showLoading={showLoading}

Wyświetl plik

@ -8,9 +8,9 @@ import { connect } from 'react-redux';
import { fetchUsers } from 'soapbox/actions/admin';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Column } from 'soapbox/components/ui';
import AccountContainer from 'soapbox/containers/account-container';
import { SimpleForm, TextInput } from 'soapbox/features/forms';
import Column from 'soapbox/features/ui/components/column';
const messages = defineMessages({
heading: { id: 'column.admin.users', defaultMessage: 'Users' },

Wyświetl plik

@ -4,10 +4,9 @@ import { defineMessages, useIntl } from 'react-intl';
import { fetchBackups, createBackup } from 'soapbox/actions/backups';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Column } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import Column from '../ui/components/better-column';
const messages = defineMessages({
heading: { id: 'column.backups', defaultMessage: 'Backups' },
create: { id: 'backups.actions.create', defaultMessage: 'Create backup' },
@ -52,7 +51,11 @@ const Backups = () => {
);
return (
<Column icon='cloud-download' label={intl.formatMessage(messages.heading)} menu={makeColumnMenu()}>
<Column
label={intl.formatMessage(messages.heading)}
// @ts-ignore FIXME: make this menu available.
menu={makeColumnMenu()}
>
<ScrollableList
isLoading={isLoading}
showLoading={showLoading}

Wyświetl plik

@ -5,7 +5,6 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { fetchBookmarkedStatuses, expandBookmarkedStatuses } from 'soapbox/actions/bookmarks';
import PullToRefresh from 'soapbox/components/pull-to-refresh';
import StatusList from 'soapbox/components/status-list';
import SubNavigation from 'soapbox/components/sub-navigation';
import { Column } from 'soapbox/components/ui';
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
@ -36,10 +35,7 @@ const Bookmarks: React.FC = () => {
const emptyMessage = <FormattedMessage id='empty_column.bookmarks' defaultMessage="You don't have any bookmarks yet. When you add one, it will show up here." />;
return (
<Column transparent withHeader={false}>
<div className='px-4 pt-4 sm:p-0'>
<SubNavigation message={intl.formatMessage(messages.heading)} />
</div>
<Column label={intl.formatMessage(messages.heading)} transparent>
<PullToRefresh onRefresh={handleRefresh}>
<StatusList
statusIds={statusIds}

Wyświetl plik

@ -4,7 +4,6 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { connectCommunityStream } from 'soapbox/actions/streaming';
import { expandCommunityTimeline } from 'soapbox/actions/timelines';
import PullToRefresh from 'soapbox/components/pull-to-refresh';
import SubNavigation from 'soapbox/components/sub-navigation';
import { Column } from 'soapbox/components/ui';
import { useAppDispatch, useSettings } from 'soapbox/hooks';
@ -41,11 +40,7 @@ const CommunityTimeline = () => {
}, [onlyMedia]);
return (
<Column label={intl.formatMessage(messages.title)} transparent withHeader={false}>
<div className='px-4 sm:p-0'>
<SubNavigation message={intl.formatMessage(messages.title)} />
</div>
<Column label={intl.formatMessage(messages.title)} transparent>
<PullToRefresh onRefresh={handleRefresh}>
<Timeline
scrollKey={`${timelineId}_timeline`}

Wyświetl plik

@ -3,8 +3,7 @@ import { useIntl, FormattedMessage, defineMessages } from 'react-intl';
import { createApp } from 'soapbox/actions/apps';
import { obtainOAuthToken } from 'soapbox/actions/oauth';
import { Button, Form, FormActions, FormGroup, Input, Stack, Text, Textarea } from 'soapbox/components/ui';
import Column from 'soapbox/features/ui/components/column';
import { Column, Button, Form, FormActions, FormGroup, Input, Stack, Text, Textarea } from 'soapbox/components/ui';
import { useAppDispatch, useOwnAccount } from 'soapbox/hooks';
import { getBaseURL } from 'soapbox/utils/accounts';

Wyświetl plik

@ -4,9 +4,7 @@ import { useDispatch } from 'react-redux';
import { changeSettingImmediate } from 'soapbox/actions/settings';
import snackbar from 'soapbox/actions/snackbar';
import { Button, Form, FormActions, FormGroup, Input, Text } from 'soapbox/components/ui';
import Column from '../ui/components/column';
import { Column, Button, Form, FormActions, FormGroup, Input, Text } from 'soapbox/components/ui';
const messages = defineMessages({
heading: { id: 'column.developers', defaultMessage: 'Developers' },

Wyświetl plik

@ -5,12 +5,10 @@ import { Link, useHistory } from 'react-router-dom';
import { changeSettingImmediate } from 'soapbox/actions/settings';
import snackbar from 'soapbox/actions/snackbar';
import { Text } from 'soapbox/components/ui';
import { Column, Text } from 'soapbox/components/ui';
import SvgIcon from 'soapbox/components/ui/icon/svg-icon';
import sourceCode from 'soapbox/utils/code';
import Column from '../ui/components/column';
const messages = defineMessages({
heading: { id: 'column.developers', defaultMessage: 'Developers' },
leave: { id: 'developers.leave', defaultMessage: 'You have left developers' },

Wyświetl plik

@ -6,11 +6,9 @@ import { useDispatch } from 'react-redux';
import { fetchDomainBlocks, expandDomainBlocks } from 'soapbox/actions/domain-blocks';
import Domain from 'soapbox/components/domain';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Spinner } from 'soapbox/components/ui';
import { Column, Spinner } from 'soapbox/components/ui';
import { useAppSelector } from 'soapbox/hooks';
import Column from '../ui/components/column';
const messages = defineMessages({
heading: { id: 'column.domain_blocks', defaultMessage: 'Hidden domains' },
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
@ -42,7 +40,7 @@ const DomainBlocks: React.FC = () => {
const emptyMessage = <FormattedMessage id='empty_column.domain_blocks' defaultMessage='There are no hidden domains yet.' />;
return (
<Column icon='minus-circle' label={intl.formatMessage(messages.heading)}>
<Column label={intl.formatMessage(messages.heading)}>
<ScrollableList
scrollKey='domain_blocks'
onLoadMore={() => handleLoadMore(dispatch)}

Wyświetl plik

@ -6,8 +6,7 @@ import {
exportBlocks,
exportMutes,
} from 'soapbox/actions/export-data';
import Column from '../ui/components/column';
import { Column } from 'soapbox/components/ui';
import CSVExporter from './components/csv-exporter';
@ -38,7 +37,7 @@ const ExportData = () => {
const intl = useIntl();
return (
<Column icon='cloud-download-alt' label={intl.formatMessage(messages.heading)}>
<Column label={intl.formatMessage(messages.heading)}>
<CSVExporter action={exportFollows} messages={followMessages} />
<CSVExporter action={exportBlocks} messages={blockMessages} />
<CSVExporter action={exportMutes} messages={muteMessages} />

Wyświetl plik

@ -7,11 +7,10 @@ import { fetchAccount, fetchAccountByUsername } from 'soapbox/actions/accounts';
import { fetchFavouritedStatuses, expandFavouritedStatuses, fetchAccountFavouritedStatuses, expandAccountFavouritedStatuses } from 'soapbox/actions/favourites';
import MissingIndicator from 'soapbox/components/missing-indicator';
import StatusList from 'soapbox/components/status-list';
import { Column } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
import { findAccountByUsername } from 'soapbox/selectors';
import Column from '../ui/components/column';
const messages = defineMessages({
heading: { id: 'column.favourited_statuses', defaultMessage: 'Liked posts' },
});

Wyświetl plik

@ -2,13 +2,11 @@ import React, { useState, useCallback } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Accordion } from 'soapbox/components/ui';
import { Column, Accordion } from 'soapbox/components/ui';
import { useAppSelector, useInstance } from 'soapbox/hooks';
import { makeGetHosts } from 'soapbox/selectors';
import { federationRestrictionsDisclosed } from 'soapbox/utils/state';
import Column from '../ui/components/column';
import RestrictedInstance from './components/restricted-instance';
import type { OrderedSet as ImmutableOrderedSet } from 'immutable';
@ -39,7 +37,7 @@ const FederationRestrictions = () => {
const emptyMessage = disclosed ? messages.emptyMessage : messages.notDisclosed;
return (
<Column icon='gavel' label={intl.formatMessage(messages.heading)}>
<Column label={intl.formatMessage(messages.heading)}>
<Accordion
headline={intl.formatMessage(messages.boxTitle)}
expanded={explanationBoxExpanded}

Wyświetl plik

@ -4,9 +4,8 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { fetchSuggestions } from 'soapbox/actions/suggestions';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Stack, Text } from 'soapbox/components/ui';
import { Column, Stack, Text } from 'soapbox/components/ui';
import AccountContainer from 'soapbox/containers/account-container';
import Column from 'soapbox/features/ui/components/column';
import { useAppDispatch, useAppSelector, useFeatures } from 'soapbox/hooks';
const messages = defineMessages({

Wyświetl plik

@ -5,11 +5,9 @@ import { useDispatch } from 'react-redux';
import { fetchFollowRequests, expandFollowRequests } from 'soapbox/actions/accounts';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Spinner } from 'soapbox/components/ui';
import { Column, Spinner } from 'soapbox/components/ui';
import { useAppSelector } from 'soapbox/hooks';
import Column from '../ui/components/column';
import AccountAuthorize from './components/account-authorize';
const messages = defineMessages({
@ -42,7 +40,7 @@ const FollowRequests: React.FC = () => {
const emptyMessage = <FormattedMessage id='empty_column.follow_requests' defaultMessage="You don't have any follow requests yet. When you receive one, it will show up here." />;
return (
<Column icon='user-plus' label={intl.formatMessage(messages.heading)}>
<Column label={intl.formatMessage(messages.heading)}>
<ScrollableList
scrollKey='follow_requests'
onLoadMore={() => handleLoadMore(dispatch)}

Wyświetl plik

@ -11,13 +11,11 @@ import {
} from 'soapbox/actions/accounts';
import MissingIndicator from 'soapbox/components/missing-indicator';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Spinner } from 'soapbox/components/ui';
import { Column, Spinner } from 'soapbox/components/ui';
import AccountContainer from 'soapbox/containers/account-container';
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
import { findAccountByUsername } from 'soapbox/selectors';
import Column from '../ui/components/column';
const messages = defineMessages({
heading: { id: 'column.followers', defaultMessage: 'Followers' },
});

Wyświetl plik

@ -11,13 +11,11 @@ import {
} from 'soapbox/actions/accounts';
import MissingIndicator from 'soapbox/components/missing-indicator';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Spinner } from 'soapbox/components/ui';
import { Column, Spinner } from 'soapbox/components/ui';
import AccountContainer from 'soapbox/containers/account-container';
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
import { findAccountByUsername } from 'soapbox/selectors';
import Column from '../ui/components/column';
const messages = defineMessages({
heading: { id: 'column.following', defaultMessage: 'Following' },
});

Wyświetl plik

@ -1,9 +1,8 @@
import React, { useEffect, useRef } from 'react';
import { FormattedMessage } from 'react-intl';
import { useIntl, defineMessages } from 'react-intl';
import { connectHashtagStream } from 'soapbox/actions/streaming';
import { expandHashtagTimeline, clearTimeline } from 'soapbox/actions/timelines';
import SubNavigation from 'soapbox/components/sub-navigation';
import { Column } from 'soapbox/components/ui';
import Timeline from 'soapbox/features/ui/components/timeline';
import { useAppDispatch } from 'soapbox/hooks';
@ -15,6 +14,13 @@ type Mode = 'any' | 'all' | 'none';
type Tag = { value: string };
type Tags = { [k in Mode]: Tag[] };
const messages = defineMessages({
any: { id: 'hashtag.column_header.tag_mode.any', defaultMessage: 'or {additional}' },
all: { id: 'hashtag.column_header.tag_mode.all', defaultMessage: 'and {additional}' },
none: { id: 'hashtag.column_header.tag_mode.none', defaultMessage: 'without {additional}' },
empty: { id: 'empty_column.hashtag', defaultMessage: 'There is nothing in this hashtag yet.' },
});
interface IHashtagTimeline {
params?: {
id?: string,
@ -23,6 +29,7 @@ interface IHashtagTimeline {
}
export const HashtagTimeline: React.FC<IHashtagTimeline> = ({ params }) => {
const intl = useIntl();
const id = params?.id || '';
const tags = params?.tags || { any: [], all: [], none: [] };
@ -31,22 +38,22 @@ export const HashtagTimeline: React.FC<IHashtagTimeline> = ({ params }) => {
// Mastodon supports displaying results from multiple hashtags.
// https://github.com/mastodon/mastodon/issues/6359
const title = () => {
const title: React.ReactNode[] = [`#${id}`];
const title = (): string => {
const title: string[] = [`#${id}`];
if (additionalFor('any')) {
title.push(' ', <FormattedMessage key='any' id='hashtag.column_header.tag_mode.any' values={{ additional: additionalFor('any') }} defaultMessage='or {additional}' />);
title.push(' ', intl.formatMessage(messages.any, { additional: additionalFor('any') }));
}
if (additionalFor('all')) {
title.push(' ', <FormattedMessage key='all' id='hashtag.column_header.tag_mode.all' values={{ additional: additionalFor('all') }} defaultMessage='and {additional}' />);
title.push(' ', intl.formatMessage(messages.any, { additional: additionalFor('all') }));
}
if (additionalFor('none')) {
title.push(' ', <FormattedMessage key='none' id='hashtag.column_header.tag_mode.none' values={{ additional: additionalFor('none') }} defaultMessage='without {additional}' />);
title.push(' ', intl.formatMessage(messages.any, { additional: additionalFor('none') }));
}
return title;
return title.join('');
};
const additionalFor = (mode: Mode) => {
@ -98,16 +105,12 @@ export const HashtagTimeline: React.FC<IHashtagTimeline> = ({ params }) => {
}, [id]);
return (
<Column label={`#${id}`} transparent withHeader={false}>
<div className='px-4 pt-4 sm:p-0'>
<SubNavigation message={title()} />
</div>
<Column label={title()} transparent>
<Timeline
scrollKey='hashtag_timeline'
timelineId={`hashtag:${id}`}
onLoadMore={handleLoadMore}
emptyMessage={<FormattedMessage id='empty_column.hashtag' defaultMessage='There is nothing in this hashtag yet.' />}
emptyMessage={intl.formatMessage(messages.empty)}
divideType='space'
/>
</Column>

Wyświetl plik

@ -6,8 +6,7 @@ import {
importBlocks,
importMutes,
} from 'soapbox/actions/import-data';
import Column from '../ui/components/column';
import { Column } from 'soapbox/components/ui';
import CSVImporter from './components/csv-importer';
@ -38,7 +37,7 @@ const ImportData = () => {
const intl = useIntl();
return (
<Column icon='cloud-upload-alt' label={intl.formatMessage(messages.heading)}>
<Column label={intl.formatMessage(messages.heading)}>
<CSVImporter action={importFollows} messages={followMessages} />
<CSVImporter action={importBlocks} messages={blockMessages} />
<CSVImporter action={importMutes} messages={muteMessages} />

Wyświetl plik

@ -7,26 +7,16 @@ import { openModal } from 'soapbox/actions/modals';
import { connectListStream } from 'soapbox/actions/streaming';
import { expandListTimeline } from 'soapbox/actions/timelines';
import MissingIndicator from 'soapbox/components/missing-indicator';
import { Button, Spinner } from 'soapbox/components/ui';
import Column from 'soapbox/features/ui/components/column';
import { Column, Button, Spinner } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import Timeline from '../ui/components/timeline';
// const messages = defineMessages({
// deleteHeading: { id: 'confirmations.delete_list.heading', defaultMessage: 'Delete list' },
// deleteMessage: { id: 'confirmations.delete_list.message', defaultMessage: 'Are you sure you want to permanently delete this list?' },
// deleteConfirm: { id: 'confirmations.delete_list.confirm', defaultMessage: 'Delete' },
// });
const ListTimeline: React.FC = () => {
const dispatch = useAppDispatch();
const { id } = useParams<{ id: string }>();
// const intl = useIntl();
// const history = useHistory();
const list = useAppSelector((state) => state.lists.get(id));
// const hasUnread = useAppSelector((state) => state.timelines.get(`list:${props.params.id}`)?.unread > 0);
useEffect(() => {
dispatch(fetchList(id));
@ -47,19 +37,6 @@ const ListTimeline: React.FC = () => {
dispatch(openModal('LIST_EDITOR', { listId: id }));
};
// const handleDeleteClick = () => {
// dispatch(openModal('CONFIRM', {
// icon: require('@tabler/icons/trash.svg'),
// heading: intl.formatMessage(messages.deleteHeading),
// message: intl.formatMessage(messages.deleteMessage),
// confirm: intl.formatMessage(messages.deleteConfirm),
// onConfirm: () => {
// dispatch(deleteList(id));
// history.push('/lists');
// },
// }));
// };
const title = list ? list.title : id;
if (typeof list === 'undefined') {
@ -85,26 +62,7 @@ const ListTimeline: React.FC = () => {
);
return (
<Column label={title} heading={title} transparent withHeader={false}>
{/* <HomeColumnHeader activeItem='lists' activeSubItem={id} active={hasUnread}>
<div className='column-header__links'>
<button className='text-btn column-header__setting-btn' tabIndex='0' onClick={handleEditClick}>
<Icon id='pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' />
</button>
<button className='text-btn column-header__setting-btn' tabIndex='0' onClick={handleDeleteClick}>
<Icon id='trash' /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' />
</button>
<hr />
<Link to='/lists' className='text-btn column-header__setting-btn column-header__setting-btn--link'>
<FormattedMessage id='lists.view_all' defaultMessage='View all lists' />
<Icon id='arrow-right' />
</Link>
</div>
</HomeColumnHeader> */}
<Column label={title} transparent>
<Timeline
scrollKey='list_timeline'
timelineId={`list:${id}`}

Wyświetl plik

@ -5,10 +5,9 @@ import { useParams } from 'react-router-dom';
import { fetchPinnedStatuses } from 'soapbox/actions/pin-statuses';
import MissingIndicator from 'soapbox/components/missing-indicator';
import StatusList from 'soapbox/components/status-list';
import { Column } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import Column from '../ui/components/column';
const messages = defineMessages({
heading: { id: 'column.pins', defaultMessage: 'Pinned posts' },
});
@ -36,7 +35,7 @@ const PinnedStatuses = () => {
}
return (
<Column label={intl.formatMessage(messages.heading)} transparent withHeader={false}>
<Column label={intl.formatMessage(messages.heading)} transparent>
<StatusList
statusIds={statusIds}
scrollKey='pinned_statuses'

Wyświetl plik

@ -6,7 +6,6 @@ import { changeSetting } from 'soapbox/actions/settings';
import { connectPublicStream } from 'soapbox/actions/streaming';
import { expandPublicTimeline } from 'soapbox/actions/timelines';
import PullToRefresh from 'soapbox/components/pull-to-refresh';
import SubNavigation from 'soapbox/components/sub-navigation';
import { Accordion, Column } from 'soapbox/components/ui';
import { useAppDispatch, useInstance, useSettings } from 'soapbox/hooks';
@ -61,11 +60,7 @@ const CommunityTimeline = () => {
}, [onlyMedia]);
return (
<Column label={intl.formatMessage(messages.title)} transparent withHeader={false}>
<div className='px-4 sm:p-0'>
<SubNavigation message={intl.formatMessage(messages.title)} />
</div>
<Column label={intl.formatMessage(messages.title)} transparent>
<PinnedHostsPicker />
{showExplanationBox && <div className='mb-4'>

Wyświetl plik

@ -1,11 +1,10 @@
import React, { useEffect, useRef } from 'react';
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
import { FormattedMessage } from 'react-intl';
import { useHistory } from 'react-router-dom';
import { connectRemoteStream } from 'soapbox/actions/streaming';
import { expandRemoteTimeline } from 'soapbox/actions/timelines';
import IconButton from 'soapbox/components/icon-button';
import SubNavigation from 'soapbox/components/sub-navigation';
import { Column, HStack, Text } from 'soapbox/components/ui';
import { useAppDispatch, useSettings } from 'soapbox/hooks';
@ -13,10 +12,6 @@ import Timeline from '../ui/components/timeline';
import PinnedHostsPicker from './components/pinned-hosts-picker';
const messages = defineMessages({
heading: { id: 'column.remote', defaultMessage: 'Federated timeline' },
});
interface IRemoteTimeline {
params?: {
instance?: string,
@ -25,7 +20,6 @@ interface IRemoteTimeline {
/** View statuses from a remote instance. */
const RemoteTimeline: React.FC<IRemoteTimeline> = ({ params }) => {
const intl = useIntl();
const history = useHistory();
const dispatch = useAppDispatch();
@ -65,25 +59,21 @@ const RemoteTimeline: React.FC<IRemoteTimeline> = ({ params }) => {
}, [onlyMedia]);
return (
<Column label={intl.formatMessage(messages.heading)} transparent withHeader={false}>
<div className='px-4 pt-4 sm:p-0'>
<SubNavigation message={instance} />
<Column label={instance} transparent>
{instance && <PinnedHostsPicker host={instance} />}
{instance && <PinnedHostsPicker host={instance} />}
{!pinned && (
<HStack className='mb-4 px-2' space={2}>
<IconButton iconClassName='h-5 w-5' src={require('@tabler/icons/x.svg')} onClick={handleCloseClick} />
<Text>
<FormattedMessage
id='remote_timeline.filter_message'
defaultMessage='You are viewing the timeline of {instance}.'
values={{ instance }}
/>
</Text>
</HStack>
)}
</div>
{!pinned && (
<HStack className='mb-4 px-2' space={2}>
<IconButton iconClassName='h-5 w-5' src={require('@tabler/icons/x.svg')} onClick={handleCloseClick} />
<Text>
<FormattedMessage
id='remote_timeline.filter_message'
defaultMessage='You are viewing the timeline of {instance}.'
values={{ instance }}
/>
</Text>
</HStack>
)}
<Timeline
scrollKey={`${timelineId}_${instance}_timeline`}

Wyświetl plik

@ -4,10 +4,9 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { fetchScheduledStatuses, expandScheduledStatuses } from 'soapbox/actions/scheduled-statuses';
import ScrollableList from 'soapbox/components/scrollable-list';
import { Column } from 'soapbox/components/ui';
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
import Column from '../ui/components/column';
import ScheduledStatus from './components/scheduled-status';
const messages = defineMessages({
@ -33,7 +32,7 @@ const ScheduledStatuses = () => {
const emptyMessage = <FormattedMessage id='empty_column.scheduled_statuses' defaultMessage="You don't have any scheduled statuses yet. When you add one, it will show up here." />;
return (
<Column icon='calendar' label={intl.formatMessage(messages.heading)}>
<Column label={intl.formatMessage(messages.heading)}>
<ScrollableList
scrollKey='scheduled_statuses'
hasMore={hasMore}

Wyświetl plik

@ -29,7 +29,6 @@ import MissingIndicator from 'soapbox/components/missing-indicator';
import PullToRefresh from 'soapbox/components/pull-to-refresh';
import ScrollableList from 'soapbox/components/scrollable-list';
import StatusActionBar from 'soapbox/components/status-action-bar';
import SubNavigation from 'soapbox/components/sub-navigation';
import Tombstone from 'soapbox/components/tombstone';
import { Column, Stack } from 'soapbox/components/ui';
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder-status';
@ -510,11 +509,7 @@ const Thread: React.FC<IThread> = (props) => {
}
return (
<Column label={intl.formatMessage(titleMessage, { username })} transparent withHeader={false}>
<div className='px-4 pt-4 sm:p-0'>
<SubNavigation message={intl.formatMessage(titleMessage, { username })} />
</div>
<Column label={intl.formatMessage(titleMessage, { username })} transparent>
<PullToRefresh onRefresh={handleRefresh}>
<Stack space={2}>
<div ref={node} className='thread'>

Wyświetl plik

@ -4,7 +4,6 @@ import { useDispatch } from 'react-redux';
import { importFetchedStatuses } from 'soapbox/actions/importer';
import { expandTimelineSuccess } from 'soapbox/actions/timelines';
import SubNavigation from 'soapbox/components/sub-navigation';
import { Column } from '../../components/ui';
import Timeline from '../ui/components/timeline';
@ -40,8 +39,7 @@ const TestTimeline: React.FC = () => {
}, []);
return (
<Column label={intl.formatMessage(messages.title)} transparent withHeader={false}>
<SubNavigation message={intl.formatMessage(messages.title)} />
<Column label={intl.formatMessage(messages.title)} transparent>
<Timeline
scrollKey={`${timelineId}_timeline`}
timelineId={`${timelineId}${onlyMedia ? ':media' : ''}`}

Wyświetl plik

@ -1,39 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import { Column } from 'soapbox/components/ui';
import DropdownMenu from 'soapbox/containers/dropdown-menu-container';
import ColumnHeader from './column-header';
// Yes, there are 3 types of columns at this point, but this one is better, I swear
export default class BetterColumn extends React.PureComponent {
static propTypes = {
heading: PropTypes.string,
icon: PropTypes.string,
children: PropTypes.node,
active: PropTypes.bool,
menu: PropTypes.array,
};
render() {
const { heading, icon, children, active, menu, ...rest } = this.props;
const columnHeaderId = heading && heading.replace(/ /g, '-');
return (
<Column aria-labelledby={columnHeaderId} className='column--better' {...rest}>
<div className='column__top'>
{heading && <ColumnHeader icon={icon} active={active} type={heading} columnHeaderId={columnHeaderId} />}
{menu && (
<div className='column__menu'>
<DropdownMenu items={menu} icon='ellipsis-v' size={18} direction='right' />
</div>
)}
</div>
{children}
</Column>
);
}
}

Wyświetl plik

@ -1,7 +1,7 @@
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import Column from './column';
import { Column } from 'soapbox/components/ui';
const messages = defineMessages({
title: { id: 'column_forbidden.title', defaultMessage: 'Forbidden' },

Wyświetl plik

@ -1,47 +0,0 @@
import React from 'react';
// import classNames from 'clsx';
// import Icon from 'soapbox/components/icon';
import SubNavigation from 'soapbox/components/sub-navigation';
interface IColumnHeader {
icon?: string,
type: string
active?: boolean,
columnHeaderId?: string,
}
const ColumnHeader: React.FC<IColumnHeader> = ({ type }) => {
return <SubNavigation message={type} />;
};
export default ColumnHeader;
// export default class ColumnHeader extends React.PureComponent {
// static propTypes = {
// icon: PropTypes.string,
// type: PropTypes.string,
// active: PropTypes.bool,
// onClick: PropTypes.func,
// columnHeaderId: PropTypes.string,
// };
// handleClick = () => {
// this.props.onClick();
// }
// render() {
// const { icon, type, active, columnHeaderId } = this.props;
// return (
// <h1 className={classNames('column-header', { active })} id={columnHeaderId || null}>
// <button onClick={this.handleClick}>
// {icon && <Icon id={icon} fixedWidth className='column-header__icon' />}
// {type}
// </button>
// </h1>
// );
// }
// }

Wyświetl plik

@ -1,36 +0,0 @@
import React from 'react';
import Pullable from 'soapbox/components/pullable';
import { Column } from 'soapbox/components/ui';
import ColumnHeader from './column-header';
import type { IColumn } from 'soapbox/components/ui/column/column';
interface IUIColumn extends IColumn {
heading?: string,
icon?: string,
active?: boolean,
}
const UIColumn: React.FC<IUIColumn> = ({
heading,
icon,
children,
active,
...rest
}) => {
const columnHeaderId = heading && heading.replace(/ /g, '-');
return (
<Column aria-labelledby={columnHeaderId} {...rest}>
{heading && <ColumnHeader icon={icon} active={active} type={heading} columnHeaderId={columnHeaderId} />}
<Pullable>
{children}
</Pullable>
</Column>
);
};
export default UIColumn;

Wyświetl plik

@ -240,7 +240,7 @@ const SwitchingColumnsArea: React.FC = ({ children }) => {
<WrappedRoute path='/tags/:id' publicRoute page={DefaultPage} component={HashtagTimeline} content={children} />
{features.lists && <WrappedRoute path='/lists' page={DefaultPage} component={Lists} content={children} />}
{features.lists && <WrappedRoute path='/list/:id' page={HomePage} component={ListTimeline} content={children} />}
{features.lists && <WrappedRoute path='/list/:id' page={DefaultPage} component={ListTimeline} content={children} />}
{features.bookmarks && <WrappedRoute path='/bookmarks' page={DefaultPage} component={Bookmarks} content={children} />}
<WrappedRoute path='/notifications' page={DefaultPage} component={Notifications} content={children} />