Add ProgressBar and dark mode support
This commit is contained in:
parent
6baec89484
commit
86fb9bf704
|
@ -1,13 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
interface IProgressBar {
|
|
||||||
progress: number,
|
|
||||||
}
|
|
||||||
|
|
||||||
const ProgressBar: React.FC<IProgressBar> = ({ progress }) => (
|
|
||||||
<div className='h-2 w-full rounded-md bg-gray-300 dark:bg-slate-700 overflow-hidden'>
|
|
||||||
<div className='h-full bg-primary-500' style={{ width: `${Math.floor(progress*100)}%` }} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default ProgressBar;
|
|
|
@ -56,7 +56,6 @@ const StatusActionButton = React.forwardRef((props: IStatusActionButton, ref: Re
|
||||||
<Icon
|
<Icon
|
||||||
src={icon}
|
src={icon}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'rounded-full',
|
|
||||||
{
|
{
|
||||||
'fill-accent-300 hover:fill-accent-300': active && filled && color === COLORS.accent,
|
'fill-accent-300 hover:fill-accent-300': active && filled && color === COLORS.accent,
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,6 +23,7 @@ export {
|
||||||
MenuList,
|
MenuList,
|
||||||
} from './menu/menu';
|
} from './menu/menu';
|
||||||
export { default as Modal } from './modal/modal';
|
export { default as Modal } from './modal/modal';
|
||||||
|
export { default as ProgressBar } from './progress-bar/progress-bar';
|
||||||
export { default as Select } from './select/select';
|
export { default as Select } from './select/select';
|
||||||
export { default as Spinner } from './spinner/spinner';
|
export { default as Spinner } from './spinner/spinner';
|
||||||
export { default as Stack } from './stack/stack';
|
export { default as Stack } from './stack/stack';
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface IProgressBar {
|
||||||
|
progress: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProgressBar: React.FC<IProgressBar> = ({ progress }) => (
|
||||||
|
<div className='h-2.5 w-full rounded-full bg-gray-100 dark:bg-slate-900/50 overflow-hidden'>
|
||||||
|
<div className='h-full bg-accent-500' style={{ width: `${Math.floor(progress * 100)}%` }} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default ProgressBar;
|
|
@ -2,11 +2,9 @@ import React, { useEffect } from 'react';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import { fetchPatronInstance } from 'soapbox/actions/patron';
|
import { fetchPatronInstance } from 'soapbox/actions/patron';
|
||||||
import { Widget, Button, Text } from 'soapbox/components/ui';
|
import { Widget, Button, ProgressBar, Text } from 'soapbox/components/ui';
|
||||||
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
|
import { useAppSelector, useAppDispatch } from 'soapbox/hooks';
|
||||||
|
|
||||||
import ProgressBar from '../../../components/progress_bar';
|
|
||||||
|
|
||||||
/** Open link in a new tab. */
|
/** Open link in a new tab. */
|
||||||
// https://stackoverflow.com/a/28374344/8811886
|
// https://stackoverflow.com/a/28374344/8811886
|
||||||
const openInNewTab = (href: string): void => {
|
const openInNewTab = (href: string): void => {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import { Set as ImmutableSet } from 'immutable';
|
import { Set as ImmutableSet } from 'immutable';
|
||||||
import React, { useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { blockAccount } from 'soapbox/actions/accounts';
|
import { blockAccount } from 'soapbox/actions/accounts';
|
||||||
import { submitReport, cancelReport, submitReportSuccess, submitReportFail } from 'soapbox/actions/reports';
|
import { submitReport, cancelReport, submitReportSuccess, submitReportFail } from 'soapbox/actions/reports';
|
||||||
import { expandAccountTimeline } from 'soapbox/actions/timelines';
|
import { expandAccountTimeline } from 'soapbox/actions/timelines';
|
||||||
import { Modal } from 'soapbox/components/ui';
|
import { Modal, ProgressBar, Stack } from 'soapbox/components/ui';
|
||||||
import { useAccount, useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
import { useAccount, useAppDispatch, useAppSelector } from 'soapbox/hooks';
|
||||||
|
|
||||||
import ConfirmationStep from './steps/confirmation-step';
|
import ConfirmationStep from './steps/confirmation-step';
|
||||||
|
@ -103,6 +103,19 @@ const ReportModal = ({ onClose }: IReportModal) => {
|
||||||
return isSubmitting || (shouldRequireRule && !ruleId) || selectedStatusIds.size === 0;
|
return isSubmitting || (shouldRequireRule && !ruleId) || selectedStatusIds.size === 0;
|
||||||
}, [currentStep, isSubmitting, shouldRequireRule, ruleId, selectedStatusIds.size]);
|
}, [currentStep, isSubmitting, shouldRequireRule, ruleId, selectedStatusIds.size]);
|
||||||
|
|
||||||
|
const calculateProgress = useCallback(() => {
|
||||||
|
switch (currentStep) {
|
||||||
|
case Steps.ONE:
|
||||||
|
return 0.33;
|
||||||
|
case Steps.TWO:
|
||||||
|
return 0.66;
|
||||||
|
case Steps.THREE:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}, [currentStep]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (account) {
|
if (account) {
|
||||||
dispatch(expandAccountTimeline(account.id, { withReplies: true, maxId: null }));
|
dispatch(expandAccountTimeline(account.id, { withReplies: true, maxId: null }));
|
||||||
|
@ -119,13 +132,17 @@ const ReportModal = ({ onClose }: IReportModal) => {
|
||||||
<Modal
|
<Modal
|
||||||
title={<FormattedMessage id='report.target' defaultMessage='Reporting {target}' values={{ target: <strong>@{account.acct}</strong> }} />}
|
title={<FormattedMessage id='report.target' defaultMessage='Reporting {target}' values={{ target: <strong>@{account.acct}</strong> }} />}
|
||||||
onClose={handleClose}
|
onClose={handleClose}
|
||||||
cancelAction={onClose}
|
cancelAction={currentStep === Steps.THREE ? undefined : onClose}
|
||||||
confirmationAction={handleNextStep}
|
confirmationAction={handleNextStep}
|
||||||
confirmationText={confirmationText}
|
confirmationText={confirmationText}
|
||||||
confirmationDisabled={isConfirmationButtonDisabled}
|
confirmationDisabled={isConfirmationButtonDisabled}
|
||||||
skipFocus
|
skipFocus
|
||||||
>
|
>
|
||||||
|
<Stack space={4}>
|
||||||
|
<ProgressBar progress={calculateProgress()} />
|
||||||
|
|
||||||
<StepToRender account={account} />
|
<StepToRender account={account} />
|
||||||
|
</Stack>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,7 +11,7 @@ interface IOtherActionsStep {
|
||||||
const ConfirmationStep = ({ account }: IOtherActionsStep) => {
|
const ConfirmationStep = ({ account }: IOtherActionsStep) => {
|
||||||
return (
|
return (
|
||||||
<Stack space={1}>
|
<Stack space={1}>
|
||||||
<Text weight='medium'>
|
<Text weight='semibold' tag='h1' size='xl'>
|
||||||
Thanks for submitting your report.
|
Thanks for submitting your report.
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ const OtherActionsStep = ({ account }: IOtherActionsStep) => {
|
||||||
|
|
||||||
{features.reportMultipleStatuses && (
|
{features.reportMultipleStatuses && (
|
||||||
<Stack space={2}>
|
<Stack space={2}>
|
||||||
<Text size='xl' weight='semibold'>Include other statuses?</Text>
|
<Text tag='h1' size='xl' weight='semibold'>Include other statuses?</Text>
|
||||||
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
labelText='Would you like to add additional statuses to this report?'
|
labelText='Would you like to add additional statuses to this report?'
|
||||||
|
@ -134,7 +134,7 @@ const OtherActionsStep = ({ account }: IOtherActionsStep) => {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Stack space={2}>
|
<Stack space={2}>
|
||||||
<Text size='xl' weight='semibold'>Further actions:</Text>
|
<Text tag='h1' size='xl' weight='semibold'>Further actions:</Text>
|
||||||
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
labelText={<FormattedMessage id='report.block_hint' defaultMessage='Do you also want to block this account?' />}
|
labelText={<FormattedMessage id='report.block_hint' defaultMessage='Do you also want to block this account?' />}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { changeReportComment, changeReportRule } from 'soapbox/actions/reports';
|
||||||
import { fetchRules } from 'soapbox/actions/rules';
|
import { fetchRules } from 'soapbox/actions/rules';
|
||||||
import AttachmentThumbs from 'soapbox/components/attachment_thumbs';
|
import AttachmentThumbs from 'soapbox/components/attachment_thumbs';
|
||||||
import StatusContent from 'soapbox/components/status_content';
|
import StatusContent from 'soapbox/components/status_content';
|
||||||
import { FormGroup, Stack, Text, Textarea } from 'soapbox/components/ui';
|
import { FormGroup, HStack, Stack, Text, Textarea } from 'soapbox/components/ui';
|
||||||
import AccountContainer from 'soapbox/containers/account_container';
|
import AccountContainer from 'soapbox/containers/account_container';
|
||||||
import { useAppSelector } from 'soapbox/hooks';
|
import { useAppSelector } from 'soapbox/hooks';
|
||||||
|
|
||||||
|
@ -115,11 +115,11 @@ const ReasonStep = (_props: IReasonStep) => {
|
||||||
|
|
||||||
{shouldRequireRule && (
|
{shouldRequireRule && (
|
||||||
<Stack space={2}>
|
<Stack space={2}>
|
||||||
<Text size='xl' weight='semibold'>Reason for reporting</Text>
|
<Text size='xl' weight='semibold' tag='h1'>Reason for reporting</Text>
|
||||||
|
|
||||||
<div className='relative'>
|
<div className='relative'>
|
||||||
<div
|
<div
|
||||||
className='bg-white rounded-lg -space-y-px max-h-96 overflow-y-auto'
|
className='rounded-lg -space-y-px max-h-96 overflow-y-auto'
|
||||||
onScroll={handleRulesScrolling}
|
onScroll={handleRulesScrolling}
|
||||||
ref={rulesListRef}
|
ref={rulesListRef}
|
||||||
>
|
>
|
||||||
|
@ -132,21 +132,20 @@ const ReasonStep = (_props: IReasonStep) => {
|
||||||
data-testid={`rule-${rule.id}`}
|
data-testid={`rule-${rule.id}`}
|
||||||
onClick={() => dispatch(changeReportRule(rule.id))}
|
onClick={() => dispatch(changeReportRule(rule.id))}
|
||||||
className={classNames({
|
className={classNames({
|
||||||
'relative border border-solid border-gray-200 hover:bg-gray-50 text-left w-full p-4 flex justify-between items-center cursor-pointer': true,
|
'relative border border-solid border-gray-200 dark:border-slate-900/75 hover:bg-gray-50 dark:hover:bg-slate-900/50 text-left w-full p-4 flex justify-between items-center cursor-pointer': true,
|
||||||
'rounded-tl-lg rounded-tr-lg': idx === 0,
|
'rounded-tl-lg rounded-tr-lg': idx === 0,
|
||||||
'rounded-bl-lg rounded-br-lg': idx === rules.length - 1,
|
'rounded-bl-lg rounded-br-lg': idx === rules.length - 1,
|
||||||
'bg-gray-50': isSelected,
|
'bg-gray-50 dark:bg-slate-900': isSelected,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div className='mr-3 flex flex-col'>
|
<div className='mr-3 flex flex-col'>
|
||||||
<span
|
<Text
|
||||||
className={classNames('block text-sm font-medium', {
|
size='sm'
|
||||||
'text-primary-800': isSelected,
|
weight='medium'
|
||||||
'text-gray-800': !isSelected,
|
theme={isSelected ? 'primary' : 'default'}
|
||||||
})}
|
|
||||||
>
|
>
|
||||||
{rule.text}
|
{rule.text}
|
||||||
</span>
|
</Text>
|
||||||
<Text theme='muted' size='sm'>{rule.subtext}</Text>
|
<Text theme='muted' size='sm'>{rule.subtext}</Text>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -164,13 +163,13 @@ const ReasonStep = (_props: IReasonStep) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={classNames('inset-x-0 top-0 flex justify-center bg-gradient-to-b from-white pb-12 pt-8 pointer-events-none dark:from-slate-900 absolute transition-opacity duration-500', {
|
className={classNames('inset-x-0 top-0 flex rounded-t-lg justify-center bg-gradient-to-b from-white pb-12 pt-8 pointer-events-none dark:from-slate-900 absolute transition-opacity duration-500', {
|
||||||
'opacity-0': isNearTop,
|
'opacity-0': isNearTop,
|
||||||
'opacity-100': !isNearTop,
|
'opacity-100': !isNearTop,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
className={classNames('inset-x-0 bottom-0 flex justify-center bg-gradient-to-t from-white pt-12 pb-8 pointer-events-none dark:from-slate-900 absolute transition-opacity duration-500', {
|
className={classNames('inset-x-0 bottom-0 flex rounded-b-lg justify-center bg-gradient-to-t from-white pt-12 pb-8 pointer-events-none dark:from-slate-900 absolute transition-opacity duration-500', {
|
||||||
'opacity-0': isNearBottom,
|
'opacity-0': isNearBottom,
|
||||||
'opacity-100': !isNearBottom,
|
'opacity-100': !isNearBottom,
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -66,6 +66,8 @@ export default function reports(state = initialState, action) {
|
||||||
map.setIn(['new', 'status_ids'], ImmutableSet());
|
map.setIn(['new', 'status_ids'], ImmutableSet());
|
||||||
map.setIn(['new', 'comment'], '');
|
map.setIn(['new', 'comment'], '');
|
||||||
map.setIn(['new', 'isSubmitting'], false);
|
map.setIn(['new', 'isSubmitting'], false);
|
||||||
|
map.setIn(['new', 'rule_id'], null);
|
||||||
|
map.setIn(['new', 'block'], false);
|
||||||
});
|
});
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
|
|
Loading…
Reference in New Issue