pl-fe: add 'expand all posts' button
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -93,7 +93,7 @@ const StatusContent: React.FC<IStatusContent> = React.memo(({
|
||||
const node = useRef<HTMLDivElement>(null);
|
||||
const spoilerNode = useRef<HTMLSpanElement>(null);
|
||||
|
||||
const { statuses: statusesMeta, collapseStatus, expandStatus } = useStatusMetaStore();
|
||||
const { statuses: statusesMeta, collapseStatuses, expandStatuses } = useStatusMetaStore();
|
||||
const statusMeta = statusesMeta[status.id] || {};
|
||||
const { data: translation } = useStatusTranslation(status.id, statusMeta.targetLanguage);
|
||||
|
||||
@ -123,9 +123,9 @@ const StatusContent: React.FC<IStatusContent> = React.memo(({
|
||||
e.stopPropagation();
|
||||
|
||||
if (expanded) {
|
||||
collapseStatus(status.id);
|
||||
collapseStatuses([status.id]);
|
||||
setCollapsed(null);
|
||||
} else expandStatus(status.id);
|
||||
} else expandStatuses([status.id]);
|
||||
};
|
||||
|
||||
useLayoutEffect(() => {
|
||||
|
||||
@ -79,7 +79,7 @@ const Status: React.FC<IStatus> = (props) => {
|
||||
const history = useHistory();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { toggleStatusMediaHidden } = useStatusMetaStore();
|
||||
const { toggleStatusesMediaHidden } = useStatusMetaStore();
|
||||
const { openModal } = useModalsStore();
|
||||
const { boostModal } = useSettings();
|
||||
const didShowCard = useRef(false);
|
||||
@ -188,7 +188,7 @@ const Status: React.FC<IStatus> = (props) => {
|
||||
};
|
||||
|
||||
const handleHotkeyToggleSensitive = () => {
|
||||
toggleStatusMediaHidden(actualStatus.id);
|
||||
toggleStatusesMediaHidden([actualStatus.id]);
|
||||
};
|
||||
|
||||
const handleHotkeyReact = () => {
|
||||
|
||||
@ -64,13 +64,13 @@ const SensitiveContentOverlay = React.forwardRef<HTMLDivElement, ISensitiveConte
|
||||
|
||||
const matchedFilters = useMemo(() => filters.map(({ filter }) => filter.title), [filters]);
|
||||
|
||||
const { hideStatusMedia, revealStatusMedia } = useStatusMetaStore();
|
||||
const { hideStatusesMedia, revealStatusesMedia } = useStatusMetaStore();
|
||||
|
||||
const toggleVisibility = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
event.stopPropagation();
|
||||
|
||||
if (visible) hideStatusMedia(status.id);
|
||||
else revealStatusMedia(status.id);
|
||||
if (visible) hideStatusesMedia([status.id]);
|
||||
else revealStatusesMedia([status.id]);
|
||||
};
|
||||
|
||||
if (!useShowOverlay(status, displayMedia)) return null;
|
||||
|
||||
@ -204,7 +204,7 @@ const Notification: React.FC<INotification> = (props) => {
|
||||
const getNotification = useCallback(makeGetNotification(), []);
|
||||
|
||||
const { me } = useLoggedIn();
|
||||
const { toggleStatusMediaHidden } = useStatusMetaStore();
|
||||
const { toggleStatusesMediaHidden } = useStatusMetaStore();
|
||||
const { openModal } = useModalsStore();
|
||||
const { settings } = useSettingsStore();
|
||||
|
||||
@ -288,7 +288,7 @@ const Notification: React.FC<INotification> = (props) => {
|
||||
|
||||
const handleHotkeyToggleSensitive = useCallback(() => {
|
||||
if (status && typeof status === 'object') {
|
||||
toggleStatusMediaHidden(status.id);
|
||||
toggleStatusesMediaHidden([status.id]);
|
||||
}
|
||||
}, [status]);
|
||||
|
||||
|
||||
@ -125,19 +125,21 @@ interface IThread {
|
||||
withMedia?: boolean;
|
||||
isModal?: boolean;
|
||||
itemClassName?: string;
|
||||
setExpandAllStatuses?: (fn: () => void) => void;
|
||||
}
|
||||
|
||||
const Thread: React.FC<IThread> = ({
|
||||
const Thread = ({
|
||||
itemClassName,
|
||||
status,
|
||||
isModal,
|
||||
withMedia = true,
|
||||
}) => {
|
||||
setExpandAllStatuses,
|
||||
}: IThread) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const history = useHistory();
|
||||
const intl = useIntl();
|
||||
|
||||
const { toggleStatusMediaHidden } = useStatusMetaStore();
|
||||
const { expandStatuses, revealStatusesMedia, toggleStatusesMediaHidden } = useStatusMetaStore();
|
||||
const { openModal } = useModalsStore();
|
||||
const { settings: { boostModal, threads: { displayMode } } } = useSettingsStore();
|
||||
|
||||
@ -235,7 +237,7 @@ const Thread: React.FC<IThread> = ({
|
||||
};
|
||||
|
||||
const handleHotkeyToggleSensitive = () => {
|
||||
toggleStatusMediaHidden(status.id);
|
||||
toggleStatusesMediaHidden([status.id]);
|
||||
};
|
||||
|
||||
const handleMoveUp = (id: string) => {
|
||||
@ -413,6 +415,12 @@ const Thread: React.FC<IThread> = ({
|
||||
const children = useMemo(() => renderChildren(thread), [thread, linear]);
|
||||
if (isModal) children.unshift(<div key='padding' className='h-4' />);
|
||||
|
||||
useEffect(() => {
|
||||
setExpandAllStatuses?.(() => {
|
||||
expandStatuses(thread);
|
||||
revealStatusesMedia(thread);
|
||||
});
|
||||
}, [thread]);
|
||||
|
||||
return (
|
||||
<Stack
|
||||
|
||||
@ -1716,6 +1716,7 @@
|
||||
"status.show_original": "Show original",
|
||||
"status.spoiler.collapse": "Collapse",
|
||||
"status.spoiler.expand": "Expand",
|
||||
"status.thread.expand_all": "Expand all posts",
|
||||
"status.thread.linear_view": "Linear view",
|
||||
"status.thread.tree_view": "Tree view",
|
||||
"status.title": "Post details",
|
||||
|
||||
@ -36,6 +36,7 @@ const messages = defineMessages({
|
||||
blockAndReport: { id: 'confirmations.block.block_and_report', defaultMessage: 'Block and report' },
|
||||
treeView: { id: 'status.thread.tree_view', defaultMessage: 'Tree view' },
|
||||
linearView: { id: 'status.thread.linear_view', defaultMessage: 'Linear view' },
|
||||
expandAll: { id: 'status.thread.expand_all', defaultMessage: 'Expand all posts' },
|
||||
});
|
||||
|
||||
type RouteParams = {
|
||||
@ -55,9 +56,10 @@ const StatusPage: React.FC<IStatusDetails> = (props) => {
|
||||
const getStatus = useCallback(makeGetStatus(), []);
|
||||
const status = useAppSelector((state) => getStatus(state, { id: props.params.statusId }));
|
||||
|
||||
const [expandAllStatuses, setExpandAllStatuses] = useState<() => void>();
|
||||
const [isLoaded, setIsLoaded] = useState<boolean>(!!status);
|
||||
|
||||
const { settings: { threads: { displayMode } } } = useSettingsStore();
|
||||
const { settings: { displaySpoilers, threads: { displayMode } } } = useSettingsStore();
|
||||
|
||||
/** Fetch the status (and context) from the API. */
|
||||
const fetchData = () => {
|
||||
@ -77,22 +79,36 @@ const StatusPage: React.FC<IStatusDetails> = (props) => {
|
||||
|
||||
const handleRefresh = () => fetchData();
|
||||
|
||||
const items: Menu = useMemo(() => [
|
||||
{
|
||||
text: intl.formatMessage(messages.treeView),
|
||||
action: () => dispatch(changeSetting(['threads', 'displayMode'], 'tree')),
|
||||
icon: require('@tabler/icons/outline/list-tree.svg'),
|
||||
type: 'radio',
|
||||
checked: displayMode === 'tree',
|
||||
},
|
||||
{
|
||||
text: intl.formatMessage(messages.linearView),
|
||||
action: () => dispatch(changeSetting(['threads', 'displayMode'], 'linear')),
|
||||
icon: require('@tabler/icons/outline/list.svg'),
|
||||
type: 'radio',
|
||||
checked: displayMode === 'linear',
|
||||
},
|
||||
], [displayMode]);
|
||||
const items = useMemo(() => {
|
||||
const menu: Menu = [
|
||||
{
|
||||
text: intl.formatMessage(messages.treeView),
|
||||
action: () => dispatch(changeSetting(['threads', 'displayMode'], 'tree')),
|
||||
icon: require('@tabler/icons/outline/list-tree.svg'),
|
||||
type: 'radio',
|
||||
checked: displayMode === 'tree',
|
||||
},
|
||||
{
|
||||
text: intl.formatMessage(messages.linearView),
|
||||
action: () => dispatch(changeSetting(['threads', 'displayMode'], 'linear')),
|
||||
icon: require('@tabler/icons/outline/list.svg'),
|
||||
type: 'radio',
|
||||
checked: displayMode === 'linear',
|
||||
},
|
||||
];
|
||||
|
||||
if (!displaySpoilers && expandAllStatuses) {
|
||||
menu.push(
|
||||
null,
|
||||
{
|
||||
text: intl.formatMessage(messages.expandAll),
|
||||
action: expandAllStatuses,
|
||||
icon: require('@tabler/icons/outline/chevron-down.svg'),
|
||||
},
|
||||
);
|
||||
}
|
||||
return menu;
|
||||
}, [displayMode, expandAllStatuses]);
|
||||
|
||||
if (status?.event) {
|
||||
return (
|
||||
@ -130,7 +146,7 @@ const StatusPage: React.FC<IStatusDetails> = (props) => {
|
||||
action={<DropdownMenu items={items} src={require('@tabler/icons/outline/dots-vertical.svg')} />}
|
||||
>
|
||||
<PullToRefresh onRefresh={handleRefresh}>
|
||||
<Thread key={status.id} status={status} />
|
||||
<Thread key={status.id} status={status} setExpandAllStatuses={(fn) => setExpandAllStatuses(() => fn)} />
|
||||
</PullToRefresh>
|
||||
</Column>
|
||||
|
||||
|
||||
@ -3,11 +3,11 @@ import { mutative } from 'zustand-mutative';
|
||||
|
||||
type State = {
|
||||
statuses: Record<string, { expanded?: boolean; mediaVisible?: boolean; currentLanguage?: string; targetLanguage?: string }>;
|
||||
expandStatus: (statusId: string) => void;
|
||||
collapseStatus: (statusId: string) => void;
|
||||
revealStatusMedia: (statusId: string) => void;
|
||||
hideStatusMedia: (statusId: string) => void;
|
||||
toggleStatusMediaHidden: (statusId: string) => void;
|
||||
expandStatuses: (statusIds: Array<string>) => void;
|
||||
collapseStatuses: (statusIds: Array<string>) => void;
|
||||
revealStatusesMedia: (statusIds: Array<string>) => void;
|
||||
hideStatusesMedia: (statusIds: Array<string>) => void;
|
||||
toggleStatusesMediaHidden: (statusIds: Array<string>) => void;
|
||||
fetchTranslation: (statusId: string, targetLanguage: string) => void;
|
||||
hideTranslation: (statusId: string) => void;
|
||||
setStatusLanguage: (statusId: string, language: string) => void;
|
||||
@ -15,27 +15,41 @@ type State = {
|
||||
|
||||
const useStatusMetaStore = create<State>()(mutative((set) => ({
|
||||
statuses: {},
|
||||
expandStatus: (statusId) => set((state: State) => {
|
||||
if (!state.statuses[statusId]) state.statuses[statusId] = {};
|
||||
expandStatuses: (statusIds) => set((state: State) => {
|
||||
for (const statusId of statusIds) {
|
||||
if (!state.statuses[statusId]) state.statuses[statusId] = {};
|
||||
|
||||
state.statuses[statusId].expanded = true;
|
||||
state.statuses[statusId].expanded = true;
|
||||
}
|
||||
}),
|
||||
collapseStatus: (statusId) => set((state: State) => {
|
||||
if (!state.statuses[statusId]) state.statuses[statusId] = {};
|
||||
collapseStatuses: (statusIds) => set((state: State) => {
|
||||
for (const statusId of statusIds) {
|
||||
if (!state.statuses[statusId]) state.statuses[statusId] = {};
|
||||
|
||||
state.statuses[statusId].expanded = false;
|
||||
state.statuses[statusId].expanded = false;
|
||||
}
|
||||
}),
|
||||
revealStatusMedia: (statusId) => set((state: State) => {
|
||||
if (!state.statuses[statusId]) state.statuses[statusId] = {};
|
||||
revealStatusesMedia: (statusIds) => set((state: State) => {
|
||||
for (const statusId of statusIds) {
|
||||
if (!state.statuses[statusId]) state.statuses[statusId] = {};
|
||||
|
||||
state.statuses[statusId].mediaVisible = true;
|
||||
state.statuses[statusId].mediaVisible = true;
|
||||
}
|
||||
}),
|
||||
hideStatusMedia: (statusId) => set((state: State) => {
|
||||
if (!state.statuses[statusId]) state.statuses[statusId] = {};
|
||||
hideStatusesMedia: (statusIds) => set((state: State) => {
|
||||
for (const statusId of statusIds) {
|
||||
if (!state.statuses[statusId]) state.statuses[statusId] = {};
|
||||
|
||||
state.statuses[statusId].mediaVisible = false;
|
||||
state.statuses[statusId].mediaVisible = false;
|
||||
}
|
||||
}),
|
||||
toggleStatusMediaHidden: (statusId) => (state: State) => state[state.statuses[statusId].mediaVisible ? 'hideStatusMedia' : 'revealStatusMedia'](statusId),
|
||||
toggleStatusesMediaHidden: (statusIds) => (state: State) => {
|
||||
for (const statusId of statusIds) {
|
||||
if (!state.statuses[statusId]) state.statuses[statusId] = {};
|
||||
|
||||
state.statuses[statusId].mediaVisible = !state.statuses[statusId].mediaVisible;
|
||||
}
|
||||
},
|
||||
fetchTranslation: (statusId, targetLanguage) => set((state: State) => {
|
||||
if (!state.statuses[statusId]) state.statuses[statusId] = {};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user