mirror of
https://github.com/mastodon/mastodon.git
synced 2026-09-13 13:38:15 -05:00
Refactors column component (#40112)
This commit is contained in:
@@ -1,60 +0,0 @@
|
||||
import { forwardRef, useRef, useImperativeHandle } from 'react';
|
||||
import type { Ref } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { scrollTop } from 'mastodon/scroll';
|
||||
|
||||
export interface ColumnRef {
|
||||
scrollTop: () => void;
|
||||
node: HTMLDivElement | null;
|
||||
}
|
||||
|
||||
interface ColumnProps {
|
||||
children?: React.ReactNode;
|
||||
label?: string;
|
||||
bindToDocument?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const Column = forwardRef<ColumnRef, ColumnProps>(
|
||||
({ children, label, bindToDocument, className }, ref: Ref<ColumnRef>) => {
|
||||
const nodeRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
node: nodeRef.current,
|
||||
|
||||
scrollTop() {
|
||||
let scrollable = null;
|
||||
|
||||
if (bindToDocument) {
|
||||
scrollable = document.scrollingElement;
|
||||
} else {
|
||||
scrollable = nodeRef.current?.querySelector('.scrollable');
|
||||
}
|
||||
|
||||
if (!scrollable) {
|
||||
return;
|
||||
}
|
||||
|
||||
scrollTop(scrollable);
|
||||
},
|
||||
}));
|
||||
|
||||
return (
|
||||
<div
|
||||
role='region'
|
||||
aria-label={label}
|
||||
className={classNames('column', className)}
|
||||
ref={nodeRef}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Column.displayName = 'Column';
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default Column;
|
||||
@@ -7,9 +7,9 @@ import { Icon } from 'mastodon/components/icon';
|
||||
import { getColumnSkipLinkId } from 'mastodon/features/ui/components/skip_links';
|
||||
import { ButtonInTabsBar } from 'mastodon/features/ui/util/columns_context';
|
||||
|
||||
import { useColumnIndexContext } from '../features/ui/components/columns_area';
|
||||
import { useAppHistory } from '../router';
|
||||
|
||||
import { useAppHistory } from './router';
|
||||
import { useColumnIndexContext } from './context';
|
||||
|
||||
type OnClickCallback = () => void;
|
||||
|
||||
12
app/javascript/mastodon/components/column/context.ts
Normal file
12
app/javascript/mastodon/components/column/context.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
export const ColumnIndexContext = createContext(1);
|
||||
export const useColumnIndexContext = () => useContext(ColumnIndexContext);
|
||||
|
||||
export const ColumnContext = createContext({
|
||||
scrollTop: () => {
|
||||
// Implemented in index.tsx
|
||||
},
|
||||
});
|
||||
|
||||
export const useColumn = () => useContext(ColumnContext);
|
||||
@@ -16,11 +16,11 @@ import { Icon } from 'mastodon/components/icon';
|
||||
import { ButtonInTabsBar } from 'mastodon/features/ui/util/columns_context';
|
||||
import { useIdentity } from 'mastodon/identity_context';
|
||||
|
||||
import { useColumnIndexContext } from '../features/ui/components/columns_area';
|
||||
import { getColumnSkipLinkId } from '../features/ui/components/skip_links';
|
||||
import { getColumnSkipLinkId } from '../../features/ui/components/skip_links';
|
||||
import { NavigationFocusTarget } from '../navigation_focus_target';
|
||||
import { useAppHistory } from '../router';
|
||||
|
||||
import { NavigationFocusTarget } from './navigation_focus_target';
|
||||
import { useAppHistory } from './router';
|
||||
import { useColumn, useColumnIndexContext } from './context';
|
||||
|
||||
export const messages = defineMessages({
|
||||
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
|
||||
@@ -73,7 +73,7 @@ const BackButton: React.FC<{
|
||||
);
|
||||
};
|
||||
|
||||
export interface Props {
|
||||
export interface ColumnHeaderProps {
|
||||
title?: React.ReactNode;
|
||||
icon?: string;
|
||||
iconComponent?: IconProp;
|
||||
@@ -87,12 +87,13 @@ export interface Props {
|
||||
placeholder?: boolean;
|
||||
appendContent?: React.ReactNode;
|
||||
collapseIssues?: boolean;
|
||||
scrollTopOnClick?: boolean;
|
||||
onClick?: () => void;
|
||||
onMove?: (arg0: number) => void;
|
||||
onPin?: () => void;
|
||||
}
|
||||
|
||||
export const ColumnHeader: React.FC<Props> = ({
|
||||
export const ColumnHeader: React.FC<ColumnHeaderProps> = ({
|
||||
title,
|
||||
icon,
|
||||
iconComponent,
|
||||
@@ -106,6 +107,7 @@ export const ColumnHeader: React.FC<Props> = ({
|
||||
placeholder,
|
||||
appendContent,
|
||||
collapseIssues,
|
||||
scrollTopOnClick,
|
||||
onClick,
|
||||
onMove,
|
||||
onPin,
|
||||
@@ -125,9 +127,13 @@ export const ColumnHeader: React.FC<Props> = ({
|
||||
[setCollapsed, setAnimating],
|
||||
);
|
||||
|
||||
const { scrollTop } = useColumn();
|
||||
const handleTitleClick = useCallback(() => {
|
||||
onClick?.();
|
||||
}, [onClick]);
|
||||
if (scrollTopOnClick) {
|
||||
scrollTop();
|
||||
}
|
||||
}, [onClick, scrollTop, scrollTopOnClick]);
|
||||
|
||||
const handleMoveLeft = useCallback(() => {
|
||||
onMove?.(-1);
|
||||
@@ -290,7 +296,7 @@ export const ColumnHeader: React.FC<Props> = ({
|
||||
as='h1'
|
||||
className='column-header__title-wrapper'
|
||||
>
|
||||
{onClick ? (
|
||||
{onClick || scrollTopOnClick ? (
|
||||
<button
|
||||
onClick={handleTitleClick}
|
||||
className={titleClassNames}
|
||||
@@ -337,6 +343,3 @@ export const ColumnHeader: React.FC<Props> = ({
|
||||
return <ButtonInTabsBar>{component}</ButtonInTabsBar>;
|
||||
}
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default ColumnHeader;
|
||||
80
app/javascript/mastodon/components/column/index.tsx
Normal file
80
app/javascript/mastodon/components/column/index.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import { useRef, useMemo } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
|
||||
import { getColumnSkipLinkId } from '@/mastodon/features/ui/components/skip_links';
|
||||
import { scrollTop } from 'mastodon/scroll';
|
||||
|
||||
import { ColumnContext, useColumnIndexContext } from './context';
|
||||
|
||||
interface ColumnProps {
|
||||
children?: React.ReactNode;
|
||||
label?: string;
|
||||
bindToDocument?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const TIMEOUT = 200;
|
||||
|
||||
export const Column: React.FC<ColumnProps> = ({
|
||||
children,
|
||||
label,
|
||||
bindToDocument,
|
||||
className,
|
||||
}) => {
|
||||
const nodeRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const idleCallbackId = useRef<number>(null);
|
||||
const contextValue = useMemo(
|
||||
() => ({
|
||||
scrollTop() {
|
||||
let scrollable = null;
|
||||
|
||||
if (bindToDocument) {
|
||||
scrollable = document.scrollingElement;
|
||||
} else {
|
||||
scrollable = nodeRef.current?.querySelector('.scrollable');
|
||||
}
|
||||
|
||||
if (!scrollable) {
|
||||
return;
|
||||
}
|
||||
|
||||
idleCallbackId.current = scrollTop(scrollable, {
|
||||
timeout: TIMEOUT,
|
||||
callback() {
|
||||
idleCallbackId.current = null;
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
[bindToDocument],
|
||||
);
|
||||
|
||||
const handleScroll = useDebouncedCallback(() => {
|
||||
if (typeof idleCallbackId.current === 'number') {
|
||||
cancelIdleCallback(idleCallbackId.current);
|
||||
}
|
||||
}, TIMEOUT);
|
||||
|
||||
const columnIndex = useColumnIndexContext();
|
||||
|
||||
return (
|
||||
<div
|
||||
role='region'
|
||||
ref={nodeRef}
|
||||
onScroll={handleScroll}
|
||||
className={classNames('column', className)}
|
||||
aria-label={label}
|
||||
aria-labelledby={
|
||||
label === undefined ? getColumnSkipLinkId(columnIndex) : undefined
|
||||
}
|
||||
>
|
||||
<ColumnContext.Provider value={contextValue}>
|
||||
{children}
|
||||
</ColumnContext.Provider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -13,7 +13,7 @@ import { domain } from 'mastodon/initial_state';
|
||||
import { injectIntl } from '@/mastodon/components/intl';
|
||||
import { fetchServer, fetchExtendedDescription, fetchDomainBlocks } from 'mastodon/actions/server';
|
||||
import { Account } from 'mastodon/components/account';
|
||||
import Column from 'mastodon/components/column';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { NavigationFocusTarget } from 'mastodon/components/navigation_focus_target';
|
||||
import { ServerHeroImage } from 'mastodon/components/server_hero_image';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Link } from 'react-router-dom';
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column_header';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
||||
import { BundleColumnError } from '@/mastodon/features/ui/components/bundle_column_error';
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ import { List as ImmutableList } from 'immutable';
|
||||
import { fetchEndorsedAccounts } from '@/mastodon/actions/accounts';
|
||||
import { AccountHeader } from '@/mastodon/components/account_header';
|
||||
import { AccountListItem } from '@/mastodon/components/account_list_item';
|
||||
import { ColumnBackButton } from '@/mastodon/components/column_back_button';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnBackButton } from '@/mastodon/components/column/back_button';
|
||||
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
||||
import { RemoteHint } from '@/mastodon/components/remote_hint';
|
||||
import {
|
||||
@@ -20,7 +21,6 @@ import {
|
||||
import type { TruncatedListItemInfo } from '@/mastodon/components/truncated_list';
|
||||
import { TruncatedListItems } from '@/mastodon/components/truncated_list';
|
||||
import { BundleColumnError } from '@/mastodon/features/ui/components/bundle_column_error';
|
||||
import Column from '@/mastodon/features/ui/components/column';
|
||||
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||
import { useAccountId } from '@/mastodon/hooks/useAccountId';
|
||||
import { useAccountVisibility } from '@/mastodon/hooks/useAccountVisibility';
|
||||
|
||||
@@ -7,12 +7,12 @@ import { List as ImmutableList, isList } from 'immutable';
|
||||
import { openModal } from '@/mastodon/actions/modal';
|
||||
import { expandAccountMediaTimeline } from '@/mastodon/actions/timelines';
|
||||
import { AccountHeader } from '@/mastodon/components/account_header';
|
||||
import { ColumnBackButton } from '@/mastodon/components/column_back_button';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnBackButton } from '@/mastodon/components/column/back_button';
|
||||
import { LimitedAccountHint } from '@/mastodon/components/limited_account_hint';
|
||||
import { RemoteHint } from '@/mastodon/components/remote_hint';
|
||||
import ScrollableList from '@/mastodon/components/scrollable_list';
|
||||
import { BundleColumnError } from '@/mastodon/features/ui/components/bundle_column_error';
|
||||
import Column from '@/mastodon/features/ui/components/column';
|
||||
import { useAccountId } from '@/mastodon/hooks/useAccountId';
|
||||
import { useAccountVisibility } from '@/mastodon/hooks/useAccountVisibility';
|
||||
import type { MediaAttachment } from '@/mastodon/models/media_attachment';
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
} from '@/mastodon/actions/timelines_typed';
|
||||
import { AccountHeader } from '@/mastodon/components/account_header';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnBackButton } from '@/mastodon/components/column_back_button';
|
||||
import { ColumnBackButton } from '@/mastodon/components/column/back_button';
|
||||
import { LimitedAccountHint } from '@/mastodon/components/limited_account_hint';
|
||||
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
||||
import { RemoteHint } from '@/mastodon/components/remote_hint';
|
||||
|
||||
@@ -10,12 +10,12 @@ import { debounce } from 'lodash';
|
||||
|
||||
import { injectIntl } from '@/mastodon/components/intl';
|
||||
import BlockIcon from '@/material-icons/400-24px/block-fill.svg?react';
|
||||
import { Account } from 'mastodon/components/account';
|
||||
|
||||
import { fetchBlocks, expandBlocks } from '../../actions/blocks';
|
||||
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import Column from '../ui/components/column';
|
||||
import { fetchBlocks, expandBlocks } from '@/mastodon/actions/blocks';
|
||||
import { Account } from '@/mastodon/components/account';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
||||
import ScrollableList from '@/mastodon/components/scrollable_list';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.blocks', defaultMessage: 'Blocked users' },
|
||||
@@ -61,7 +61,8 @@ class Blocks extends ImmutablePureComponent {
|
||||
const emptyMessage = <FormattedMessage id='empty_column.blocks' defaultMessage="You haven't blocked any users yet." />;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} icon='ban' iconComponent={BlockIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
|
||||
<Column bindToDocument={!multiColumn}>
|
||||
<ColumnHeader icon='ban' iconComponent={BlockIcon} title={intl.formatMessage(messages.heading)} showBackButton />
|
||||
<ScrollableList
|
||||
scrollKey='blocks'
|
||||
onLoadMore={this.handleLoadMore}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { useEffect, useRef, useCallback } from 'react';
|
||||
import { useEffect, useCallback } from 'react';
|
||||
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import BookmarksIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react';
|
||||
import {
|
||||
fetchBookmarkedStatuses,
|
||||
expandBookmarkedStatuses,
|
||||
} from 'mastodon/actions/bookmarks';
|
||||
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import type { ColumnRef } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import StatusList from 'mastodon/components/status_list';
|
||||
import { getStatusList } from 'mastodon/selectors';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
@@ -27,7 +26,6 @@ const Bookmarks: React.FC<{
|
||||
}> = ({ columnId, multiColumn }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
const columnRef = useRef<ColumnRef>(null);
|
||||
const statusIds = useAppSelector((state) =>
|
||||
getStatusList(state, 'bookmarks'),
|
||||
);
|
||||
@@ -58,10 +56,6 @@ const Bookmarks: React.FC<{
|
||||
[dispatch, columnId],
|
||||
);
|
||||
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
columnRef.current?.scrollTop();
|
||||
}, []);
|
||||
|
||||
const handleLoadMore = useCallback(() => {
|
||||
dispatch(expandBookmarkedStatuses());
|
||||
}, [dispatch]);
|
||||
@@ -78,7 +72,6 @@ const Bookmarks: React.FC<{
|
||||
return (
|
||||
<Column
|
||||
bindToDocument={!multiColumn}
|
||||
ref={columnRef}
|
||||
label={intl.formatMessage(messages.heading)}
|
||||
>
|
||||
<ColumnHeader
|
||||
@@ -87,9 +80,9 @@ const Bookmarks: React.FC<{
|
||||
title={intl.formatMessage(messages.heading)}
|
||||
onPin={handlePin}
|
||||
onMove={handleMove}
|
||||
onClick={handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
/>
|
||||
|
||||
<StatusList
|
||||
|
||||
@@ -7,6 +7,8 @@ import { Link } from 'react-router-dom';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import HelpIcon from '@/material-icons/400-24px/help.svg?react';
|
||||
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
|
||||
import ShareIcon from '@/material-icons/400-24px/share.svg?react';
|
||||
@@ -18,8 +20,6 @@ import type {
|
||||
} from 'mastodon/api_types/collections';
|
||||
import { Badge } from 'mastodon/components/badge';
|
||||
import { Callout } from 'mastodon/components/callout';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { DisplayName } from 'mastodon/components/display_name';
|
||||
import { useAccountHandle } from 'mastodon/components/display_name/default';
|
||||
import { FormattedDateWrapper } from 'mastodon/components/formatted_date';
|
||||
|
||||
@@ -13,10 +13,10 @@ import {
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
|
||||
import { Callout } from 'mastodon/components/callout';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
|
||||
import { useIdentity } from 'mastodon/identity_context';
|
||||
|
||||
@@ -4,9 +4,9 @@ import { Route, Switch, useRouteMatch } from 'react-router-dom';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { NavigationFocusTarget } from '@/mastodon/components/navigation_focus_target';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { DisplayNameSimple } from 'mastodon/components/display_name/simple';
|
||||
import { Scrollable } from 'mastodon/components/scrollable_list/components';
|
||||
import { TabLink, TabList } from 'mastodon/components/tab_list';
|
||||
|
||||
@@ -8,6 +8,8 @@ import { Helmet } from '@unhead/react/helmet';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import PeopleIcon from '@/material-icons/400-24px/group.svg?react';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { injectIntl } from '@/mastodon/components/intl';
|
||||
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
@@ -17,8 +19,6 @@ import { canViewFeed } from 'mastodon/permissions';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { connectCommunityStream } from '../../actions/streaming';
|
||||
import { expandCommunityTimeline } from '../../actions/timelines';
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
@@ -70,10 +70,6 @@ class CommunityTimeline extends PureComponent {
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
};
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
const { signedIn } = this.props.identity;
|
||||
@@ -110,10 +106,6 @@ class CommunityTimeline extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
};
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
const { dispatch, onlyMedia } = this.props;
|
||||
|
||||
@@ -138,7 +130,7 @@ class CommunityTimeline extends PureComponent {
|
||||
);
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
|
||||
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
|
||||
<ColumnHeader
|
||||
icon='users'
|
||||
iconComponent={PeopleIcon}
|
||||
@@ -146,9 +138,9 @@ class CommunityTimeline extends PureComponent {
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
onClick={this.handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
>
|
||||
<ColumnSettingsContainer columnId={columnId} />
|
||||
</ColumnHeader>
|
||||
|
||||
@@ -9,6 +9,8 @@ import type { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import elephantUIPlane from '@/images/elephant_ui_plane.svg';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import EditIcon from '@/material-icons/400-24px/edit_square.svg?react';
|
||||
import PeopleIcon from '@/material-icons/400-24px/group.svg?react';
|
||||
import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react';
|
||||
@@ -19,8 +21,6 @@ import PublicIcon from '@/material-icons/400-24px/public.svg?react';
|
||||
import SettingsIcon from '@/material-icons/400-24px/settings.svg?react';
|
||||
import { mountCompose, unmountCompose } from 'mastodon/actions/compose';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { mascot, reduceMotion } from 'mastodon/initial_state';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useRef, useCallback, useEffect } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
@@ -11,8 +11,8 @@ import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?re
|
||||
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
|
||||
import { mountConversations, unmountConversations, expandConversations } from 'mastodon/actions/conversations';
|
||||
import { connectDirectStream } from 'mastodon/actions/streaming';
|
||||
import Column from 'mastodon/components/column';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
|
||||
import { ConversationsList } from './components/conversations_list';
|
||||
|
||||
@@ -21,7 +21,6 @@ const messages = defineMessages({
|
||||
});
|
||||
|
||||
const DirectTimeline = ({ columnId, multiColumn }) => {
|
||||
const columnRef = useRef();
|
||||
const intl = useIntl();
|
||||
const dispatch = useDispatch();
|
||||
const pinned = !!columnId;
|
||||
@@ -38,10 +37,6 @@ const DirectTimeline = ({ columnId, multiColumn }) => {
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
}, [dispatch, columnId]);
|
||||
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
columnRef.current.scrollTop();
|
||||
}, [columnRef]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(mountConversations());
|
||||
dispatch(expandConversations());
|
||||
@@ -55,16 +50,16 @@ const DirectTimeline = ({ columnId, multiColumn }) => {
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={columnRef} label={intl.formatMessage(messages.title)}>
|
||||
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
|
||||
<ColumnHeader
|
||||
icon='at'
|
||||
iconComponent={AlternateEmailIcon}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={handlePin}
|
||||
onMove={handleMove}
|
||||
onClick={handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
/>
|
||||
|
||||
<ConversationsList
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { ChangeEventHandler } from 'react';
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
@@ -7,6 +7,8 @@ import { List as ImmutableList } from 'immutable';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import PeopleIcon from '@/material-icons/400-24px/group.svg?react';
|
||||
import {
|
||||
addColumn,
|
||||
@@ -15,9 +17,6 @@ import {
|
||||
changeColumnParams,
|
||||
} from 'mastodon/actions/columns';
|
||||
import { fetchDirectory, expandDirectory } from 'mastodon/actions/directory';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import type { ColumnRef } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { LoadMore } from 'mastodon/components/load_more';
|
||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||
import { RadioButton } from 'mastodon/components/radio_button';
|
||||
@@ -49,8 +48,6 @@ export const Directory: React.FC<{
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const column = useRef<ColumnRef>(null);
|
||||
|
||||
const [orderParam, setOrderParam] = useSearchParam('order');
|
||||
const [localParam, setLocalParam] = useSearchParam('local');
|
||||
|
||||
@@ -98,10 +95,6 @@ export const Directory: React.FC<{
|
||||
[dispatch, columnId],
|
||||
);
|
||||
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
column.current?.scrollTop();
|
||||
}, []);
|
||||
|
||||
const handleChangeOrder = useCallback<ChangeEventHandler<HTMLInputElement>>(
|
||||
(e) => {
|
||||
if (columnId) {
|
||||
@@ -194,7 +187,6 @@ export const Directory: React.FC<{
|
||||
return (
|
||||
<Column
|
||||
bindToDocument={!multiColumn}
|
||||
ref={column}
|
||||
label={intl.formatMessage(messages.title)}
|
||||
>
|
||||
<ColumnHeader
|
||||
@@ -203,9 +195,9 @@ export const Directory: React.FC<{
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={handlePin}
|
||||
onMove={handleMove}
|
||||
onClick={handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
/>
|
||||
|
||||
{multiColumn && !pinned ? (
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { useEffect, useRef, useCallback, useState } from 'react';
|
||||
import { useEffect, useCallback, useState } from 'react';
|
||||
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import BlockIcon from '@/material-icons/400-24px/block-fill.svg?react';
|
||||
import { apiGetDomainBlocks } from 'mastodon/api/domain_blocks';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import type { ColumnRef } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { Domain } from 'mastodon/components/domain';
|
||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||
|
||||
@@ -22,7 +21,6 @@ const Blocks: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [next, setNext] = useState<string | undefined>();
|
||||
const hasMore = !!next;
|
||||
const columnRef = useRef<ColumnRef>(null);
|
||||
|
||||
useEffect(() => {
|
||||
void apiGetDomainBlocks()
|
||||
@@ -58,10 +56,6 @@ const Blocks: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
||||
});
|
||||
}, [setLoading, setDomains, setNext, next]);
|
||||
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
columnRef.current?.scrollTop();
|
||||
}, []);
|
||||
|
||||
const handleUnblock = useCallback((domain: string) => {
|
||||
setDomains((prev) => prev.filter((d) => d !== domain));
|
||||
}, []);
|
||||
@@ -76,16 +70,15 @@ const Blocks: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
||||
return (
|
||||
<Column
|
||||
bindToDocument={!multiColumn}
|
||||
ref={columnRef}
|
||||
label={intl.formatMessage(messages.heading)}
|
||||
>
|
||||
<ColumnHeader
|
||||
icon='ban'
|
||||
iconComponent={BlockIcon}
|
||||
title={intl.formatMessage(messages.heading)}
|
||||
onClick={handleHeaderClick}
|
||||
multiColumn={multiColumn}
|
||||
showBackButton
|
||||
scrollTopOnClick
|
||||
/>
|
||||
|
||||
<ScrollableList
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import { useCallback, useRef } from 'react';
|
||||
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
import { NavLink, Switch, Route } from 'react-router-dom';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import TrendingUpIcon from '@/material-icons/400-24px/trending_up.svg?react';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import type { ColumnRef } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { SymbolLogo } from 'mastodon/components/logo';
|
||||
import { Search } from 'mastodon/features/compose/components/search';
|
||||
import { useBreakpoint } from 'mastodon/features/ui/hooks/useBreakpoint';
|
||||
@@ -27,25 +24,19 @@ const messages = defineMessages({
|
||||
const Explore: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
||||
const { signedIn } = useIdentity();
|
||||
const intl = useIntl();
|
||||
const columnRef = useRef<ColumnRef>(null);
|
||||
const logoRequired = useBreakpoint('full');
|
||||
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
columnRef.current?.scrollTop();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Column
|
||||
bindToDocument={!multiColumn}
|
||||
ref={columnRef}
|
||||
label={intl.formatMessage(messages.title)}
|
||||
>
|
||||
<ColumnHeader
|
||||
icon={'explore'}
|
||||
iconComponent={logoRequired ? SymbolLogo : TrendingUpIcon}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onClick={handleHeaderClick}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
/>
|
||||
|
||||
<div className='explore__search-header'>
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { useEffect, useRef, useCallback } from 'react';
|
||||
import { useEffect, useCallback } from 'react';
|
||||
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import StarIcon from '@/material-icons/400-24px/star-fill.svg?react';
|
||||
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
|
||||
import {
|
||||
fetchFavouritedStatuses,
|
||||
expandFavouritedStatuses,
|
||||
} from 'mastodon/actions/favourites';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import type { ColumnRef } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import StatusList from 'mastodon/components/status_list';
|
||||
import { getStatusList } from 'mastodon/selectors';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
@@ -27,7 +26,6 @@ const Favourites: React.FC<{ columnId: string; multiColumn: boolean }> = ({
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
const columnRef = useRef<ColumnRef>(null);
|
||||
const statusIds = useAppSelector((state) =>
|
||||
getStatusList(state, 'favourites'),
|
||||
);
|
||||
@@ -58,10 +56,6 @@ const Favourites: React.FC<{ columnId: string; multiColumn: boolean }> = ({
|
||||
[dispatch, columnId],
|
||||
);
|
||||
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
columnRef.current?.scrollTop();
|
||||
}, []);
|
||||
|
||||
const handleLoadMore = useCallback(() => {
|
||||
dispatch(expandFavouritedStatuses());
|
||||
}, [dispatch]);
|
||||
@@ -78,7 +72,6 @@ const Favourites: React.FC<{ columnId: string; multiColumn: boolean }> = ({
|
||||
return (
|
||||
<Column
|
||||
bindToDocument={!multiColumn}
|
||||
ref={columnRef}
|
||||
label={intl.formatMessage(messages.heading)}
|
||||
>
|
||||
<ColumnHeader
|
||||
@@ -87,9 +80,9 @@ const Favourites: React.FC<{ columnId: string; multiColumn: boolean }> = ({
|
||||
title={intl.formatMessage(messages.heading)}
|
||||
onPin={handlePin}
|
||||
onMove={handleMove}
|
||||
onClick={handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
/>
|
||||
|
||||
<StatusList
|
||||
|
||||
@@ -13,12 +13,12 @@ import { debounce } from 'lodash';
|
||||
import RefreshIcon from '@/material-icons/400-24px/refresh.svg?react';
|
||||
import { fetchFavourites, expandFavourites } from 'mastodon/actions/interactions';
|
||||
import { Account } from 'mastodon/components/account';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { injectIntl } from '@/mastodon/components/intl';
|
||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||
import Column from 'mastodon/features/ui/components/column';
|
||||
|
||||
const messages = defineMessages({
|
||||
refresh: { id: 'refresh', defaultMessage: 'Refresh' },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useRef, useCallback, useEffect } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
|
||||
@@ -12,13 +12,13 @@ import { addColumn } from 'mastodon/actions/columns';
|
||||
import { changeSetting } from 'mastodon/actions/settings';
|
||||
import { connectPublicStream, connectCommunityStream } from 'mastodon/actions/streaming';
|
||||
import { expandPublicTimeline, expandCommunityTimeline } from 'mastodon/actions/timelines';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
|
||||
import { localLiveFeedAccess, remoteLiveFeedAccess, domain } from 'mastodon/initial_state';
|
||||
import { canViewFeed } from 'mastodon/permissions';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import SettingToggle from '../notifications/components/setting_toggle';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
|
||||
@@ -62,7 +62,6 @@ const Firehose = ({ feedType, multiColumn }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
const { signedIn, permissions } = useIdentity();
|
||||
const columnRef = useRef(null);
|
||||
|
||||
const onlyMedia = useAppSelector((state) => state.getIn(['settings', 'firehose', 'onlyMedia'], false));
|
||||
const hasUnread = useAppSelector((state) => state.getIn(['timelines', `${feedType}${onlyMedia ? ':media' : ''}`, 'unread'], 0) > 0);
|
||||
@@ -101,8 +100,6 @@ const Firehose = ({ feedType, multiColumn }) => {
|
||||
[dispatch, onlyMedia, feedType],
|
||||
);
|
||||
|
||||
const handleHeaderClick = useCallback(() => columnRef.current?.scrollTop(), []);
|
||||
|
||||
useEffect(() => {
|
||||
let disconnect;
|
||||
|
||||
@@ -180,15 +177,15 @@ const Firehose = ({ feedType, multiColumn }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={columnRef} label={intl.formatMessage(messages.title)}>
|
||||
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
|
||||
<ColumnHeader
|
||||
icon='globe'
|
||||
iconComponent={PublicIcon}
|
||||
active={hasUnread}
|
||||
title={intl.formatMessage(title)}
|
||||
onPin={handlePin}
|
||||
onClick={handleHeaderClick}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
>
|
||||
<ColumnSettings />
|
||||
</ColumnHeader>
|
||||
|
||||
@@ -11,14 +11,15 @@ import { connect } from 'react-redux';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
import PersonAddIcon from '@/material-icons/400-24px/person_add.svg?react';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { injectIntl } from '@/mastodon/components/intl';
|
||||
|
||||
import { fetchFollowRequests, expandFollowRequests } from '../../actions/accounts';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import { me } from '../../initial_state';
|
||||
import Column from '../ui/components/column';
|
||||
|
||||
import AccountAuthorizeContainer from './containers/account_authorize_container';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.follow_requests', defaultMessage: 'Follow requests' },
|
||||
@@ -69,7 +70,8 @@ class FollowRequests extends ImmutablePureComponent {
|
||||
);
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} icon='user-plus' iconComponent={PersonAddIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
|
||||
<Column bindToDocument={!multiColumn}>
|
||||
<ColumnHeader icon='user-plus' iconComponent={PersonAddIcon} title={intl.formatMessage(messages.heading)} showBackButton />
|
||||
<ScrollableList
|
||||
scrollKey='follow_requests'
|
||||
onLoadMore={this.handleLoadMore}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useCallback, useRef } from 'react';
|
||||
import { useEffect, useCallback } from 'react';
|
||||
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
@@ -6,6 +6,8 @@ import { isFulfilled } from '@reduxjs/toolkit';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import TagIcon from '@/material-icons/400-24px/tag.svg?react';
|
||||
import {
|
||||
fetchFollowedHashtags,
|
||||
@@ -13,9 +15,6 @@ import {
|
||||
} from 'mastodon/actions/tags_typed';
|
||||
import type { ApiHashtagJSON } from 'mastodon/api_types/tags';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import type { ColumnRef } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { Hashtag } from 'mastodon/components/hashtag';
|
||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
@@ -86,11 +85,6 @@ const FollowedTags: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const columnRef = useRef<ColumnRef>(null);
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
columnRef.current?.scrollTop();
|
||||
}, []);
|
||||
|
||||
const emptyMessage = (
|
||||
<FormattedMessage
|
||||
id='empty_column.followed_tags'
|
||||
@@ -101,16 +95,15 @@ const FollowedTags: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
||||
return (
|
||||
<Column
|
||||
bindToDocument={!multiColumn}
|
||||
ref={columnRef}
|
||||
label={intl.formatMessage(messages.heading)}
|
||||
>
|
||||
<ColumnHeader
|
||||
icon='hashtag'
|
||||
iconComponent={TagIcon}
|
||||
title={intl.formatMessage(messages.heading)}
|
||||
onClick={handleHeaderClick}
|
||||
multiColumn={multiColumn}
|
||||
showBackButton
|
||||
scrollTopOnClick
|
||||
/>
|
||||
|
||||
<ScrollableList
|
||||
|
||||
@@ -3,7 +3,7 @@ import type { FC, ReactNode } from 'react';
|
||||
|
||||
import { AccountListItem } from '@/mastodon/components/account_list_item';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnBackButton } from '@/mastodon/components/column_back_button';
|
||||
import { ColumnBackButton } from '@/mastodon/components/column/back_button';
|
||||
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
||||
import ScrollableList from '@/mastodon/components/scrollable_list';
|
||||
import { BundleColumnError } from '@/mastodon/features/ui/components/bundle_column_error';
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useIntl } from 'react-intl';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
|
||||
import { NavigationPanel } from '../navigation_panel';
|
||||
import { LinkFooter } from '../ui/components/link_footer';
|
||||
|
||||
@@ -13,8 +13,8 @@ import TagIcon from '@/material-icons/400-24px/tag.svg?react';
|
||||
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
|
||||
import { connectHashtagStream } from 'mastodon/actions/streaming';
|
||||
import { expandHashtagTimeline, clearTimeline } from 'mastodon/actions/timelines';
|
||||
import Column from 'mastodon/components/column';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { remoteTopicFeedAccess, me, localTopicFeedAccess } from 'mastodon/initial_state';
|
||||
|
||||
@@ -90,10 +90,6 @@ class HashtagTimeline extends PureComponent {
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
};
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
};
|
||||
|
||||
_subscribe (dispatch, id, tags = {}, local) {
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
@@ -156,10 +152,6 @@ class HashtagTimeline extends PureComponent {
|
||||
this._unsubscribe();
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
};
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
const { dispatch, params, local } = this.props;
|
||||
const { id, tags } = params;
|
||||
@@ -173,7 +165,7 @@ class HashtagTimeline extends PureComponent {
|
||||
const pinned = !!columnId;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={`#${id}`}>
|
||||
<Column bindToDocument={!multiColumn} label={`#${id}`}>
|
||||
<ColumnHeader
|
||||
icon='hashtag'
|
||||
iconComponent={TagIcon}
|
||||
@@ -181,10 +173,10 @@ class HashtagTimeline extends PureComponent {
|
||||
title={this.title()}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
onClick={this.handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
showBackButton
|
||||
scrollTopOnClick
|
||||
>
|
||||
{columnId && <ColumnSettingsContainer columnId={columnId} />}
|
||||
</ColumnHeader>
|
||||
|
||||
@@ -10,6 +10,8 @@ import { connect } from 'react-redux';
|
||||
|
||||
import CampaignIcon from '@/material-icons/400-24px/campaign.svg?react';
|
||||
import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { injectIntl } from '@/mastodon/components/intl';
|
||||
import { SymbolLogo } from 'mastodon/components/logo';
|
||||
import { fetchAnnouncements, toggleShowAnnouncements } from 'mastodon/actions/announcements';
|
||||
@@ -20,8 +22,6 @@ import { withBreakpoint } from 'mastodon/features/ui/hooks/useBreakpoint';
|
||||
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { expandHomeTimeline } from '../../actions/timelines';
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
|
||||
import { ColumnSettings } from './components/column_settings';
|
||||
@@ -73,14 +73,6 @@ class HomeTimeline extends PureComponent {
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
};
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
};
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
};
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
this.props.dispatch(expandHomeTimeline({ maxId }));
|
||||
};
|
||||
@@ -150,7 +142,7 @@ class HomeTimeline extends PureComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
|
||||
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
|
||||
<ColumnHeader
|
||||
icon='home'
|
||||
iconComponent={matchesBreakpoint ? SymbolLogo : HomeIcon}
|
||||
@@ -158,11 +150,11 @@ class HomeTimeline extends PureComponent {
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
onClick={this.handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
extraButton={announcementsButton}
|
||||
appendContent={hasAnnouncements && showAnnouncements && <Announcements />}
|
||||
scrollTopOnClick
|
||||
>
|
||||
<ColumnSettings />
|
||||
</ColumnHeader>
|
||||
|
||||
@@ -7,8 +7,8 @@ import { Helmet } from '@unhead/react/helmet';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
import InfoIcon from '@/material-icons/400-24px/info.svg?react';
|
||||
import Column from 'mastodon/components/column';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { injectIntl } from '@/mastodon/components/intl';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { useRef, useEffect, useCallback } from 'react';
|
||||
import { useEffect, useCallback } from 'react';
|
||||
|
||||
import { useParams } from 'react-router-dom';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import TrendingUpIcon from '@/material-icons/400-24px/trending_up.svg?react';
|
||||
import { expandLinkTimeline } from 'mastodon/actions/timelines';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import type { ColumnRef } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import StatusListContainer from 'mastodon/features/ui/containers/status_list_container';
|
||||
import type { Card } from 'mastodon/models/status';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
@@ -19,7 +18,6 @@ export const LinkTimeline: React.FC<{
|
||||
const { url } = useParams<{ url: string }>();
|
||||
const decodedUrl = url ? decodeURIComponent(url) : undefined;
|
||||
const dispatch = useAppDispatch();
|
||||
const columnRef = useRef<ColumnRef>(null);
|
||||
const firstStatusId = useAppSelector((state) =>
|
||||
decodedUrl
|
||||
? (state.timelines.getIn([`link:${decodedUrl}`, 'items', 0]) as string)
|
||||
@@ -31,10 +29,6 @@ export const LinkTimeline: React.FC<{
|
||||
: undefined,
|
||||
);
|
||||
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
columnRef.current?.scrollTop();
|
||||
}, []);
|
||||
|
||||
const handleLoadMore = useCallback(
|
||||
(maxId: string) => {
|
||||
void dispatch(expandLinkTimeline(decodedUrl, { maxId }));
|
||||
@@ -47,14 +41,14 @@ export const LinkTimeline: React.FC<{
|
||||
}, [dispatch, decodedUrl]);
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={columnRef} label={story?.title}>
|
||||
<Column bindToDocument={!multiColumn} label={story?.title}>
|
||||
<ColumnHeader
|
||||
icon='explore'
|
||||
iconComponent={TrendingUpIcon}
|
||||
title={story?.title}
|
||||
onClick={handleHeaderClick}
|
||||
multiColumn={multiColumn}
|
||||
showBackButton
|
||||
scrollTopOnClick
|
||||
/>
|
||||
|
||||
<StatusListContainer
|
||||
|
||||
@@ -17,8 +17,8 @@ import { fetchList } from 'mastodon/actions/lists';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { connectListStream } from 'mastodon/actions/streaming';
|
||||
import { expandListTimeline } from 'mastodon/actions/timelines';
|
||||
import Column from 'mastodon/components/column';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
||||
@@ -59,10 +59,6 @@ class ListTimeline extends PureComponent {
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
};
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch } = this.props;
|
||||
const { id } = this.props.params;
|
||||
@@ -96,10 +92,6 @@ class ListTimeline extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
};
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
const { id } = this.props.params;
|
||||
this.props.dispatch(expandListTimeline(id, { maxId }));
|
||||
@@ -133,7 +125,7 @@ class ListTimeline extends PureComponent {
|
||||
}
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={title}>
|
||||
<Column bindToDocument={!multiColumn} label={title}>
|
||||
<ColumnHeader
|
||||
icon='list-ul'
|
||||
iconComponent={ListAltIcon}
|
||||
@@ -141,9 +133,9 @@ class ListTimeline extends PureComponent {
|
||||
title={title}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
onClick={this.handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
>
|
||||
<div className='column-settings'>
|
||||
<section className='column-header__links'>
|
||||
|
||||
@@ -6,6 +6,8 @@ import { Link } from 'react-router-dom';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { NotSignedInIndicator } from '@/mastodon/components/not_signed_in_indicator';
|
||||
import { useIdentity } from '@/mastodon/identity_context';
|
||||
import AddIcon from '@/material-icons/400-24px/add.svg?react';
|
||||
@@ -14,8 +16,6 @@ import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
||||
import SquigglyArrow from '@/svg-icons/squiggly_arrow.svg?react';
|
||||
import { fetchLists } from 'mastodon/actions/lists';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { Dropdown } from 'mastodon/components/dropdown_menu';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||
|
||||
@@ -6,6 +6,9 @@ import { useParams, Link } from 'react-router-dom';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { ColumnSearchHeader } from '@/mastodon/components/column/search_header';
|
||||
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
|
||||
import SquigglyArrow from '@/svg-icons/squiggly_arrow.svg?react';
|
||||
import { fetchRelationships } from 'mastodon/actions/accounts';
|
||||
@@ -22,9 +25,6 @@ import {
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import { VerifiedBadge } from 'mastodon/components/badge';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { ColumnSearchHeader } from 'mastodon/components/column_search_header';
|
||||
import { FollowersCounter } from 'mastodon/components/counters';
|
||||
import { DisplayName } from 'mastodon/components/display_name';
|
||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||
|
||||
@@ -8,6 +8,8 @@ import { isFulfilled } from '@reduxjs/toolkit';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { NotSignedInIndicator } from '@/mastodon/components/not_signed_in_indicator';
|
||||
import { useIdentity } from '@/mastodon/identity_context';
|
||||
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
|
||||
@@ -19,8 +21,6 @@ import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
|
||||
import type { RepliesPolicyType } from 'mastodon/api_types/lists';
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import { AvatarGroup } from 'mastodon/components/avatar_group';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import {
|
||||
SelectField,
|
||||
TextInputField,
|
||||
|
||||
@@ -11,13 +11,14 @@ import { connect } from 'react-redux';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
import VolumeOffIcon from '@/material-icons/400-24px/volume_off.svg?react';
|
||||
import { Account } from 'mastodon/components/account';
|
||||
import { fetchMutes, expandMutes } from '@/mastodon/actions/mutes';
|
||||
import { Account } from '@/mastodon/components/account';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { injectIntl } from '@/mastodon/components/intl';
|
||||
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
||||
import ScrollableList from '@/mastodon/components/scrollable_list';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
|
||||
import { fetchMutes, expandMutes } from '../../actions/mutes';
|
||||
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import Column from '../ui/components/column';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.mutes', defaultMessage: 'Muted users' },
|
||||
@@ -63,7 +64,8 @@ class Mutes extends ImmutablePureComponent {
|
||||
const emptyMessage = <FormattedMessage id='empty_column.mutes' defaultMessage="You haven't muted any users yet." />;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} icon='volume-off' iconComponent={VolumeOffIcon} heading={intl.formatMessage(messages.heading)} alwaysShowBackButton>
|
||||
<Column bindToDocument={!multiColumn}>
|
||||
<ColumnHeader icon='volume-off' iconComponent={VolumeOffIcon} title={intl.formatMessage(messages.heading)} showBackButton />
|
||||
<ScrollableList
|
||||
scrollKey='mutes'
|
||||
onLoadMore={this.handleLoadMore}
|
||||
|
||||
@@ -2,13 +2,13 @@ import { useCallback } from 'react';
|
||||
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { messages as columnHeaderMessages } from '@/mastodon/components/column/header';
|
||||
import { useAppDispatch } from '@/mastodon/store';
|
||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||
import UnfoldMoreIcon from '@/material-icons/400-24px/unfold_more.svg?react';
|
||||
import { requestBrowserPermission } from 'mastodon/actions/notifications';
|
||||
import { changeSetting } from 'mastodon/actions/settings';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { messages as columnHeaderMessages } from 'mastodon/components/column_header';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { IconButton } from 'mastodon/components/icon_button';
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useRef, useCallback, useEffect } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
@@ -17,8 +17,8 @@ import {
|
||||
acceptNotificationRequest,
|
||||
dismissNotificationRequest,
|
||||
} from 'mastodon/actions/notification_requests';
|
||||
import Column from 'mastodon/components/column';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { IconButton } from 'mastodon/components/icon_button';
|
||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||
import { SensitiveMediaContextProvider } from 'mastodon/features/ui/util/sensitive_media_context';
|
||||
@@ -32,7 +32,6 @@ const messages = defineMessages({
|
||||
});
|
||||
|
||||
export const NotificationRequest = ({ multiColumn, params: { id } }) => {
|
||||
const columnRef = useRef();
|
||||
const intl = useIntl();
|
||||
const dispatch = useDispatch();
|
||||
const notificationRequest = useSelector(state => state.notificationRequests.current.item?.id === id ? state.notificationRequests.current.item : null);
|
||||
@@ -43,10 +42,6 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => {
|
||||
const hasMore = useSelector(state => !!state.notificationRequests.current.notifications.next);
|
||||
const removed = useSelector(state => state.notificationRequests.current.removed);
|
||||
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
columnRef.current?.scrollTop();
|
||||
}, [columnRef]);
|
||||
|
||||
const handleLoadMore = useCallback(() => {
|
||||
dispatch(expandNotificationsForRequest({ accountId }));
|
||||
}, [dispatch, accountId]);
|
||||
@@ -89,14 +84,14 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={columnRef} label={columnTitle}>
|
||||
<Column bindToDocument={!multiColumn} label={columnTitle}>
|
||||
<ColumnHeader
|
||||
icon='archive'
|
||||
iconComponent={InventoryIcon}
|
||||
title={columnTitle}
|
||||
onClick={handleHeaderClick}
|
||||
multiColumn={multiColumn}
|
||||
showBackButton
|
||||
scrollTopOnClick
|
||||
extraButton={!removed && (
|
||||
<>
|
||||
<IconButton className='column-header__button' iconComponent={DeleteIcon} onClick={handleDismiss} title={intl.formatMessage(messages.dismiss)} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useRef, useCallback, useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
@@ -19,8 +19,8 @@ import {
|
||||
} from 'mastodon/actions/notification_requests';
|
||||
import { changeSetting } from 'mastodon/actions/settings';
|
||||
import { CheckBox } from 'mastodon/components/check_box';
|
||||
import Column from 'mastodon/components/column';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||
import { Dropdown } from 'mastodon/components/dropdown_menu';
|
||||
@@ -163,7 +163,6 @@ SelectRow.propTypes = {
|
||||
};
|
||||
|
||||
export const NotificationRequests = ({ multiColumn }) => {
|
||||
const columnRef = useRef();
|
||||
const intl = useIntl();
|
||||
const dispatch = useDispatch();
|
||||
const isLoading = useSelector(state => state.notificationRequests.isLoading);
|
||||
@@ -174,10 +173,6 @@ export const NotificationRequests = ({ multiColumn }) => {
|
||||
const [checkedRequestIds, setCheckedRequestIds] = useState([]);
|
||||
const [selectAllChecked, setSelectAllChecked] = useState(false);
|
||||
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
columnRef.current?.scrollTop();
|
||||
}, [columnRef]);
|
||||
|
||||
const handleCheck = useCallback(id => {
|
||||
setCheckedRequestIds(ids => {
|
||||
const position = ids.indexOf(id);
|
||||
@@ -213,14 +208,14 @@ export const NotificationRequests = ({ multiColumn }) => {
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={columnRef} label={intl.formatMessage(messages.title)}>
|
||||
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
|
||||
<ColumnHeader
|
||||
icon='archive'
|
||||
iconComponent={InventoryIcon}
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onClick={handleHeaderClick}
|
||||
multiColumn={multiColumn}
|
||||
showBackButton
|
||||
scrollTopOnClick
|
||||
appendContent={
|
||||
notificationRequests.length > 0 && (
|
||||
<SelectRow selectionMode={selectionMode} setSelectionMode={setSelectionMode} selectAllChecked={selectAllChecked} toggleSelectAll={toggleSelectAll} selectedItems={checkedRequestIds} />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
@@ -6,6 +6,16 @@ import { Helmet } from '@unhead/react/helmet';
|
||||
import { isEqual } from 'lodash';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
|
||||
import {
|
||||
addColumn,
|
||||
removeColumn,
|
||||
moveColumn,
|
||||
} from '@/mastodon/actions/columns';
|
||||
import { submitMarkers } from '@/mastodon/actions/markers';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { LoadGap } from '@/mastodon/components/load_gap';
|
||||
import ScrollableList from '@/mastodon/components/scrollable_list';
|
||||
import DoneAllIcon from '@/material-icons/400-24px/done_all.svg?react';
|
||||
import NotificationsIcon from '@/material-icons/400-24px/notifications-fill.svg?react';
|
||||
import {
|
||||
@@ -33,13 +43,6 @@ import {
|
||||
} from 'mastodon/selectors/settings';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { submitMarkers } from '../../actions/markers';
|
||||
import { Column } from '../../components/column';
|
||||
import type { ColumnRef } from '../../components/column';
|
||||
import { ColumnHeader } from '../../components/column_header';
|
||||
import { LoadGap } from '../../components/load_gap';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import {
|
||||
FilteredNotificationsBanner,
|
||||
FilteredNotificationsIconButton,
|
||||
@@ -96,8 +99,6 @@ export const Notifications: React.FC<{
|
||||
selectNeedsNotificationPermission,
|
||||
);
|
||||
|
||||
const columnRef = useRef<ColumnRef>(null);
|
||||
|
||||
// Keep track of mounted components for unread notification handling
|
||||
useEffect(() => {
|
||||
void dispatch(mountNotifications());
|
||||
@@ -159,10 +160,6 @@ export const Notifications: React.FC<{
|
||||
[dispatch, columnId],
|
||||
);
|
||||
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
columnRef.current?.scrollTop();
|
||||
}, []);
|
||||
|
||||
const handleMarkAsRead = useCallback(() => {
|
||||
dispatch(markNotificationsAsRead());
|
||||
void dispatch(submitMarkers({ immediate: true }));
|
||||
@@ -255,7 +252,6 @@ export const Notifications: React.FC<{
|
||||
return (
|
||||
<Column
|
||||
bindToDocument={!multiColumn}
|
||||
ref={columnRef}
|
||||
label={intl.formatMessage(messages.title)}
|
||||
>
|
||||
<ColumnHeader
|
||||
@@ -265,10 +261,10 @@ export const Notifications: React.FC<{
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={handlePin}
|
||||
onMove={handleMove}
|
||||
onClick={handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
extraButton={extraButton}
|
||||
scrollTopOnClick
|
||||
>
|
||||
<ColumnSettingsContainer />
|
||||
</ColumnHeader>
|
||||
|
||||
@@ -7,6 +7,9 @@ import { Link } from 'react-router-dom';
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { ColumnSearchHeader } from '@/mastodon/components/column/search_header';
|
||||
import PersonIcon from '@/material-icons/400-24px/person.svg?react';
|
||||
import { fetchRelationships } from 'mastodon/actions/accounts';
|
||||
import { importFetchedAccounts } from 'mastodon/actions/importer';
|
||||
@@ -15,9 +18,6 @@ import { markAsPartial } from 'mastodon/actions/timelines';
|
||||
import { apiRequest } from 'mastodon/api';
|
||||
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
|
||||
import { Account } from 'mastodon/components/account';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { ColumnSearchHeader } from 'mastodon/components/column_search_header';
|
||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||
|
||||
|
||||
@@ -7,14 +7,14 @@ import { useHistory } from 'react-router-dom';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import AddPhotoAlternateIcon from '@/material-icons/400-24px/add_photo_alternate.svg?react';
|
||||
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
|
||||
import PersonIcon from '@/material-icons/400-24px/person.svg?react';
|
||||
import { updateAccount } from 'mastodon/actions/accounts';
|
||||
import { closeOnboarding } from 'mastodon/actions/onboarding';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import {
|
||||
TextAreaField,
|
||||
TextInputField,
|
||||
|
||||
@@ -9,12 +9,13 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import PushPinIcon from '@/material-icons/400-24px/push_pin.svg?react';
|
||||
import { fetchPinnedStatuses } from '@/mastodon/actions/pin_statuses';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { injectIntl } from '@/mastodon/components/intl';
|
||||
import { getStatusList } from 'mastodon/selectors';
|
||||
import StatusList from '@/mastodon/components/status_list';
|
||||
import { getStatusList } from '@/mastodon/selectors';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
|
||||
import { fetchPinnedStatuses } from '../../actions/pin_statuses';
|
||||
import StatusList from '../../components/status_list';
|
||||
import Column from '../ui/components/column';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.pins', defaultMessage: 'Pinned post' },
|
||||
@@ -39,19 +40,12 @@ class PinnedStatuses extends ImmutablePureComponent {
|
||||
this.props.dispatch(fetchPinnedStatuses());
|
||||
}
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
};
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
};
|
||||
|
||||
render () {
|
||||
const { intl, statusIds, hasMore, multiColumn } = this.props;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} icon='thumb-tack' iconComponent={PushPinIcon} heading={intl.formatMessage(messages.heading)} ref={this.setRef} alwaysShowBackButton>
|
||||
<Column bindToDocument={!multiColumn}>
|
||||
<ColumnHeader icon='thumb-tack' iconComponent={PushPinIcon} title={intl.formatMessage(messages.heading)} showBackButton />
|
||||
<StatusList
|
||||
statusIds={statusIds}
|
||||
scrollKey='pinned_statuses'
|
||||
|
||||
@@ -4,10 +4,10 @@ import { FormattedMessage, useIntl, defineMessages } from 'react-intl';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { NavigationFocusTarget } from '@/mastodon/components/navigation_focus_target';
|
||||
import { apiGetPrivacyPolicy } from 'mastodon/api/instance';
|
||||
import type { ApiPrivacyPolicyJSON } from 'mastodon/api_types/instance';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { FormattedDateWrapper } from 'mastodon/components/formatted_date';
|
||||
import { Skeleton } from 'mastodon/components/skeleton';
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import { Helmet } from '@unhead/react/helmet';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import PublicIcon from '@/material-icons/400-24px/public.svg?react';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
|
||||
import { injectIntl } from '@/mastodon/components/intl';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
@@ -17,8 +19,6 @@ import { canViewFeed } from 'mastodon/permissions';
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { connectPublicStream } from '../../actions/streaming';
|
||||
import { expandPublicTimeline } from '../../actions/timelines';
|
||||
import Column from '../../components/column';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
|
||||
import ColumnSettingsContainer from './containers/column_settings_container';
|
||||
@@ -73,10 +73,6 @@ class PublicTimeline extends PureComponent {
|
||||
dispatch(moveColumn(columnId, dir));
|
||||
};
|
||||
|
||||
handleHeaderClick = () => {
|
||||
this.column.scrollTop();
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch, onlyMedia, onlyRemote } = this.props;
|
||||
const { signedIn } = this.props.identity;
|
||||
@@ -113,10 +109,6 @@ class PublicTimeline extends PureComponent {
|
||||
}
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.column = c;
|
||||
};
|
||||
|
||||
handleLoadMore = maxId => {
|
||||
const { dispatch, onlyMedia, onlyRemote } = this.props;
|
||||
|
||||
@@ -141,7 +133,7 @@ class PublicTimeline extends PureComponent {
|
||||
);
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
|
||||
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
|
||||
<ColumnHeader
|
||||
icon='globe'
|
||||
iconComponent={PublicIcon}
|
||||
@@ -149,9 +141,9 @@ class PublicTimeline extends PureComponent {
|
||||
title={intl.formatMessage(messages.title)}
|
||||
onPin={this.handlePin}
|
||||
onMove={this.handleMove}
|
||||
onClick={this.handleHeaderClick}
|
||||
pinned={pinned}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
>
|
||||
<ColumnSettingsContainer columnId={columnId} />
|
||||
</ColumnHeader>
|
||||
|
||||
@@ -6,17 +6,16 @@ import { List as ImmutableList } from 'immutable';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { fetchQuotes } from '@/mastodon/actions/interactions_typed';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { Icon } from '@/mastodon/components/icon';
|
||||
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
||||
import StatusList from '@/mastodon/components/status_list';
|
||||
import { useIdentity } from '@/mastodon/identity_context';
|
||||
import { domain } from '@/mastodon/initial_state';
|
||||
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
|
||||
import RefreshIcon from '@/material-icons/400-24px/refresh.svg?react';
|
||||
import { fetchQuotes } from 'mastodon/actions/interactions_typed';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||
import StatusList from 'mastodon/components/status_list';
|
||||
import { useIdentity } from 'mastodon/identity_context';
|
||||
import { domain } from 'mastodon/initial_state';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
import Column from '../ui/components/column';
|
||||
|
||||
const messages = defineMessages({
|
||||
refresh: { id: 'refresh', defaultMessage: 'Refresh' },
|
||||
|
||||
@@ -11,15 +11,14 @@ import { connect } from 'react-redux';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
import RefreshIcon from '@/material-icons/400-24px/refresh.svg?react';
|
||||
import { Account } from 'mastodon/components/account';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { fetchReblogs, expandReblogs } from '@/mastodon/actions/interactions';
|
||||
import { Account } from '@/mastodon/components/account';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { Icon } from '@/mastodon/components/icon';
|
||||
import { injectIntl } from '@/mastodon/components/intl';
|
||||
|
||||
import { fetchReblogs, expandReblogs } from '../../actions/interactions';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import { LoadingIndicator } from '../../components/loading_indicator';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
import Column from '../ui/components/column';
|
||||
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
||||
import ScrollableList from '@/mastodon/components/scrollable_list';
|
||||
|
||||
const messages = defineMessages({
|
||||
refresh: { id: 'refresh', defaultMessage: 'Refresh' },
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { useCallback, useEffect, useRef } from 'react';
|
||||
import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import CollectionsIcon from '@/material-icons/400-24px/category.svg?react';
|
||||
import FindInPageIcon from '@/material-icons/400-24px/find_in_page.svg?react';
|
||||
import PeopleIcon from '@/material-icons/400-24px/group.svg?react';
|
||||
@@ -12,9 +14,6 @@ import TagIcon from '@/material-icons/400-24px/tag.svg?react';
|
||||
import { submitSearch, expandSearch } from 'mastodon/actions/search';
|
||||
import type { ApiSearchType } from 'mastodon/api_types/search';
|
||||
import { Account } from 'mastodon/components/account';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import type { ColumnRef } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import { CompatibilityHashtag as Hashtag } from 'mastodon/components/hashtag';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import ScrollableList from 'mastodon/components/scrollable_list';
|
||||
@@ -72,7 +71,6 @@ const typeFromParam = (param?: string): SearchType => {
|
||||
export const SearchResults: React.FC<{ multiColumn: boolean }> = ({
|
||||
multiColumn,
|
||||
}) => {
|
||||
const columnRef = useRef<ColumnRef>(null);
|
||||
const intl = useIntl();
|
||||
const [q] = useSearchParam('q');
|
||||
const [type, setType] = useSearchParam('type');
|
||||
@@ -93,10 +91,6 @@ export const SearchResults: React.FC<{ multiColumn: boolean }> = ({
|
||||
}
|
||||
}, [dispatch, trimmedValue, mappedType]);
|
||||
|
||||
const handleHeaderClick = useCallback(() => {
|
||||
columnRef.current?.scrollTop();
|
||||
}, []);
|
||||
|
||||
const handleSelectAll = useCallback(() => {
|
||||
setType(null);
|
||||
}, [setType]);
|
||||
@@ -243,15 +237,14 @@ export const SearchResults: React.FC<{ multiColumn: boolean }> = ({
|
||||
return (
|
||||
<Column
|
||||
bindToDocument={!multiColumn}
|
||||
ref={columnRef}
|
||||
label={intl.formatMessage(messages.title, { q })}
|
||||
>
|
||||
<ColumnHeader
|
||||
icon={'search'}
|
||||
iconComponent={SearchIcon}
|
||||
title={intl.formatMessage(messages.title, { q })}
|
||||
onClick={handleHeaderClick}
|
||||
multiColumn={multiColumn}
|
||||
scrollTopOnClick
|
||||
appendContent={
|
||||
<>
|
||||
<div className='explore__search-header'>
|
||||
|
||||
@@ -13,6 +13,8 @@ import { connect } from 'react-redux';
|
||||
|
||||
import VisibilityIcon from '@/material-icons/400-24px/visibility.svg?react';
|
||||
import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import { Hotkeys } from 'mastodon/components/hotkeys';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { injectIntl } from '@/mastodon/components/intl';
|
||||
@@ -59,13 +61,11 @@ import {
|
||||
undoStatusTranslation,
|
||||
} from '../../actions/statuses';
|
||||
import { setStatusQuotePolicy } from '../../actions/statuses_typed';
|
||||
import ColumnHeader from '../../components/column_header';
|
||||
import { textForScreenReader, defaultMediaVisibility } from '../../components/status';
|
||||
import { StatusQuoteManager } from '../../components/status_quoted';
|
||||
import { deleteModal } from '../../initial_state';
|
||||
import { makeGetStatus, makeGetPictureInPicture } from '../../selectors';
|
||||
import { getAncestorsIds, getDescendantsIds } from 'mastodon/selectors/contexts';
|
||||
import Column from '../ui/components/column';
|
||||
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from '../ui/util/fullscreen';
|
||||
|
||||
import ActionBar from './components/action_bar';
|
||||
|
||||
@@ -11,10 +11,10 @@ import { Link, useParams } from 'react-router-dom';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { NavigationFocusTarget } from '@/mastodon/components/navigation_focus_target';
|
||||
import { apiGetTermsOfService } from 'mastodon/api/instance';
|
||||
import type { ApiTermsOfServiceJSON } from 'mastodon/api_types/instance';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { BundleColumnError } from 'mastodon/features/ui/components/bundle_column_error';
|
||||
|
||||
import { getColumnSkipLinkId } from '../ui/components/skip_links';
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import { render, fireEvent, screen } from '@/testing/rendering';
|
||||
|
||||
import Column from '../column';
|
||||
import { FocusTargetProvider } from '@/mastodon/components/navigation_focus_target';
|
||||
|
||||
const fakeIcon = () => <span />;
|
||||
|
||||
describe('<Column />', () => {
|
||||
describe('<ColumnHeader /> click handler', () => {
|
||||
it('runs the scroll animation if the column contains scrollable content', () => {
|
||||
const scrollToMock = vi.fn();
|
||||
const { container } = render(
|
||||
<FocusTargetProvider>
|
||||
<Column heading='notifications' icon='notifications' iconComponent={fakeIcon}>
|
||||
<div className='scrollable' />
|
||||
</Column>
|
||||
</FocusTargetProvider>,
|
||||
);
|
||||
container.querySelector('.scrollable').scrollTo = scrollToMock;
|
||||
fireEvent.click(screen.getByText('notifications'));
|
||||
expect(scrollToMock).toHaveBeenCalledWith({ behavior: 'smooth', top: 0 });
|
||||
});
|
||||
|
||||
it('does not try to scroll if there is no scrollable content', () => {
|
||||
render(
|
||||
<FocusTargetProvider>
|
||||
<Column heading='notifications' icon='notifications' iconComponent={fakeIcon} />
|
||||
</FocusTargetProvider>
|
||||
);
|
||||
fireEvent.click(screen.getByText('notifications'));
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -5,10 +5,10 @@ import { Link } from 'react-router-dom';
|
||||
|
||||
import { Helmet } from '@unhead/react/helmet';
|
||||
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { CopyButton } from '@/mastodon/components/copy_button';
|
||||
import { EmptyState } from '@/mastodon/components/empty_state';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { Column } from 'mastodon/components/column';
|
||||
|
||||
import classes from './styles.module.scss';
|
||||
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
import ColumnHeader from '../../../components/column_header';
|
||||
import { isMobile } from '../../../is_mobile';
|
||||
import { scrollTop } from '../../../scroll';
|
||||
|
||||
export default class Column extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
heading: PropTypes.string,
|
||||
alwaysShowBackButton: PropTypes.bool,
|
||||
icon: PropTypes.string,
|
||||
iconComponent: PropTypes.func,
|
||||
children: PropTypes.node,
|
||||
active: PropTypes.bool,
|
||||
hideHeadingOnMobile: PropTypes.bool,
|
||||
};
|
||||
|
||||
handleHeaderClick = () => {
|
||||
const scrollable = this.node.querySelector('.scrollable');
|
||||
|
||||
if (!scrollable) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._interruptScrollAnimation = scrollTop(scrollable);
|
||||
};
|
||||
|
||||
scrollTop () {
|
||||
const scrollable = this.node.querySelector('.scrollable');
|
||||
|
||||
if (!scrollable) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._interruptScrollAnimation = scrollTop(scrollable);
|
||||
}
|
||||
|
||||
|
||||
handleScroll = debounce(() => {
|
||||
if (typeof this._interruptScrollAnimation !== 'undefined') {
|
||||
this._interruptScrollAnimation();
|
||||
}
|
||||
}, 200);
|
||||
|
||||
setRef = (c) => {
|
||||
this.node = c;
|
||||
};
|
||||
|
||||
render () {
|
||||
const { heading, icon, iconComponent, children, active, hideHeadingOnMobile, alwaysShowBackButton } = this.props;
|
||||
|
||||
const showHeading = heading && (!hideHeadingOnMobile || (hideHeadingOnMobile && !isMobile(window.innerWidth)));
|
||||
|
||||
const columnHeaderId = showHeading && heading.replace(/ /g, '-');
|
||||
|
||||
const header = showHeading && (
|
||||
<ColumnHeader icon={icon} iconComponent={iconComponent} active={active} title={heading} onClick={this.handleHeaderClick} columnHeaderId={columnHeaderId} showBackButton={alwaysShowBackButton} />
|
||||
);
|
||||
return (
|
||||
<div
|
||||
ref={this.setRef}
|
||||
role='region'
|
||||
aria-labelledby={columnHeaderId}
|
||||
className='column'
|
||||
onScroll={this.handleScroll}
|
||||
>
|
||||
{header}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Column } from 'mastodon/components/column';
|
||||
import { ColumnHeader } from 'mastodon/components/column_header';
|
||||
import type { Props as ColumnHeaderProps } from 'mastodon/components/column_header';
|
||||
import { Column } from '@/mastodon/components/column';
|
||||
import { ColumnHeader } from '@/mastodon/components/column/header';
|
||||
import type { ColumnHeaderProps } from '@/mastodon/components/column/header';
|
||||
|
||||
export const ColumnLoading: React.FC<ColumnHeaderProps> = (otherProps) => (
|
||||
<Column>
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import {
|
||||
Children,
|
||||
cloneElement,
|
||||
createContext,
|
||||
forwardRef,
|
||||
isValidElement,
|
||||
useCallback,
|
||||
useContext,
|
||||
} from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import type { List, Record } from 'immutable';
|
||||
|
||||
import { ColumnIndexContext } from '@/mastodon/components/column/context';
|
||||
import { useAppSelector } from '@/mastodon/store';
|
||||
import { Footer } from 'mastodon/features/custom_homepage/components/footer';
|
||||
import { Header } from 'mastodon/features/custom_homepage/components/header';
|
||||
@@ -69,9 +68,6 @@ const TabsBarPortal = () => {
|
||||
return <div id='tabs-bar__portal' ref={setRef} />;
|
||||
};
|
||||
|
||||
export const ColumnIndexContext = createContext(1);
|
||||
export const useColumnIndexContext = () => useContext(ColumnIndexContext);
|
||||
|
||||
interface Column {
|
||||
uuid: string;
|
||||
id: keyof typeof componentMap;
|
||||
|
||||
@@ -47,11 +47,15 @@ export const scrollRight = (node: Element, position: number) =>
|
||||
}
|
||||
});
|
||||
|
||||
export const scrollTop = (node: Element) =>
|
||||
export const scrollTop = (
|
||||
node: Element,
|
||||
{ callback, ...rest }: IdleRequestOptions & { callback?: () => void } = {},
|
||||
) =>
|
||||
requestIdleCallback(() => {
|
||||
if (isScrollBehaviorSupported) {
|
||||
node.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
} else {
|
||||
scroll(node, 'scrollTop', 0);
|
||||
}
|
||||
});
|
||||
callback?.();
|
||||
}, rest);
|
||||
|
||||
Reference in New Issue
Block a user