Improve compose page styles, propagate compose toast to other tabs
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
b820781eff
commit
4c9201e8b4
6 changed files with 35 additions and 20 deletions
|
@ -274,15 +274,18 @@ const directComposeById = (accountId: string) =>
|
||||||
dispatch(openModal('COMPOSE'));
|
dispatch(openModal('COMPOSE'));
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleComposeSubmit = (dispatch: AppDispatch, getState: () => RootState, composeId: string, data: APIEntity, status: string, edit?: boolean) => {
|
const handleComposeSubmit = (dispatch: AppDispatch, getState: () => RootState, composeId: string, data: APIEntity, status: string, edit?: boolean, propagate?: boolean) => {
|
||||||
if (!dispatch || !getState) return;
|
if (!dispatch || !getState) return;
|
||||||
|
|
||||||
dispatch(insertIntoTagHistory(composeId, data.tags || [], status));
|
dispatch(insertIntoTagHistory(composeId, data.tags || [], status));
|
||||||
dispatch(submitComposeSuccess(composeId, { ...data }));
|
dispatch(submitComposeSuccess(composeId, { ...data }));
|
||||||
toast.success(edit ? messages.editSuccess : messages.success, {
|
const toastMessage = edit ? messages.editSuccess : messages.success;
|
||||||
|
const toastOpts = {
|
||||||
actionLabel: messages.view,
|
actionLabel: messages.view,
|
||||||
actionLink: `/@${data.account.acct}/posts/${data.id}`,
|
actionLink: `/@${data.account.acct}/posts/${data.id}`,
|
||||||
});
|
};
|
||||||
|
if (propagate) toast.propagate('success', toastMessage, toastOpts);
|
||||||
|
else toast.success(toastMessage, toastOpts);
|
||||||
};
|
};
|
||||||
|
|
||||||
const needsDescriptions = (state: RootState, composeId: string) => {
|
const needsDescriptions = (state: RootState, composeId: string) => {
|
||||||
|
@ -303,7 +306,7 @@ const validateSchedule = (state: RootState, composeId: string) => {
|
||||||
return schedule.getTime() > fiveMinutesFromNow.getTime();
|
return schedule.getTime() > fiveMinutesFromNow.getTime();
|
||||||
};
|
};
|
||||||
|
|
||||||
const submitCompose = (composeId: string, routerHistory?: History, force = false, onSubmit?: () => void) =>
|
const submitCompose = (composeId: string, routerHistory?: History, force = false, onSubmit?: () => void, propagate?: boolean) =>
|
||||||
(dispatch: AppDispatch, getState: () => RootState) => {
|
(dispatch: AppDispatch, getState: () => RootState) => {
|
||||||
if (!isLoggedIn(getState)) return;
|
if (!isLoggedIn(getState)) return;
|
||||||
const state = getState();
|
const state = getState();
|
||||||
|
@ -368,7 +371,7 @@ const submitCompose = (composeId: string, routerHistory?: History, force = false
|
||||||
if (!statusId && data.visibility === 'direct' && getState().conversations.mounted <= 0 && routerHistory) {
|
if (!statusId && data.visibility === 'direct' && getState().conversations.mounted <= 0 && routerHistory) {
|
||||||
routerHistory.push('/messages');
|
routerHistory.push('/messages');
|
||||||
}
|
}
|
||||||
handleComposeSubmit(dispatch, getState, composeId, data, status, !!statusId);
|
handleComposeSubmit(dispatch, getState, composeId, data, status, !!statusId, propagate);
|
||||||
if (onSubmit) onSubmit();
|
if (onSubmit) onSubmit();
|
||||||
}).catch(function(error) {
|
}).catch(function(error) {
|
||||||
dispatch(submitComposeFail(composeId, error));
|
dispatch(submitComposeFail(composeId, error));
|
||||||
|
|
|
@ -30,6 +30,7 @@ interface IAutosuggesteTextarea {
|
||||||
onFocus: () => void
|
onFocus: () => void
|
||||||
onBlur?: () => void
|
onBlur?: () => void
|
||||||
condensed?: boolean
|
condensed?: boolean
|
||||||
|
fullScreen?: boolean
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +228,7 @@ class AutosuggestTextarea extends ImmutablePureComponent<IAutosuggesteTextarea>
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, children, condensed, id } = this.props;
|
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, children, condensed, id, fullScreen } = this.props;
|
||||||
const { suggestionsHidden } = this.state;
|
const { suggestionsHidden } = this.state;
|
||||||
const style = { direction: 'ltr', minRows: 10 };
|
const style = { direction: 'ltr', minRows: 10 };
|
||||||
|
|
||||||
|
@ -237,7 +238,7 @@ class AutosuggestTextarea extends ImmutablePureComponent<IAutosuggesteTextarea>
|
||||||
}
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
<div key='textarea'>
|
<div key='textarea' className={clsx(fullScreen && 'grow')}>
|
||||||
<div className='relative'>
|
<div className='relative'>
|
||||||
<label>
|
<label>
|
||||||
<span style={{ display: 'none' }}>{placeholder}</span>
|
<span style={{ display: 'none' }}>{placeholder}</span>
|
||||||
|
@ -247,6 +248,7 @@ class AutosuggestTextarea extends ImmutablePureComponent<IAutosuggesteTextarea>
|
||||||
className={clsx('w-full resize-none border-0 px-0 text-gray-800 transition-[min-height] placeholder:text-gray-600 focus:border-0 focus:shadow-none focus:ring-0 motion-reduce:transition-none dark:bg-transparent dark:text-white dark:placeholder:text-gray-600', {
|
className={clsx('w-full resize-none border-0 px-0 text-gray-800 transition-[min-height] placeholder:text-gray-600 focus:border-0 focus:shadow-none focus:ring-0 motion-reduce:transition-none dark:bg-transparent dark:text-white dark:placeholder:text-gray-600', {
|
||||||
'min-h-[40px]': condensed,
|
'min-h-[40px]': condensed,
|
||||||
'min-h-[100px]': !condensed,
|
'min-h-[100px]': !condensed,
|
||||||
|
'h-full': fullScreen,
|
||||||
})}
|
})}
|
||||||
id={id}
|
id={id}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|
|
@ -195,11 +195,7 @@ const SoapboxMount = () => {
|
||||||
<GdprBanner />
|
<GdprBanner />
|
||||||
|
|
||||||
<div id='toaster'>
|
<div id='toaster'>
|
||||||
<Toaster
|
<Toaster position='top-right' />
|
||||||
position='top-right'
|
|
||||||
containerClassName='top-10'
|
|
||||||
containerStyle={{ top: 75 }}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</Route>
|
</Route>
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|
|
@ -66,9 +66,10 @@ interface IComposeForm<ID extends string> {
|
||||||
group?: string
|
group?: string
|
||||||
extra?: React.ReactNode
|
extra?: React.ReactNode
|
||||||
onSubmit?: () => void
|
onSubmit?: () => void
|
||||||
|
fullScreen?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickableAreaRef, event, group, extra, onSubmit }: IComposeForm<ID>) => {
|
const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickableAreaRef, event, group, extra, onSubmit, fullScreen }: IComposeForm<ID>) => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
@ -158,7 +159,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(submitCompose(id, history, false, onSubmit));
|
dispatch(submitCompose(id, history, false, onSubmit, fullScreen));
|
||||||
};
|
};
|
||||||
|
|
||||||
const onSuggestionsClearRequested = () => {
|
const onSuggestionsClearRequested = () => {
|
||||||
|
@ -275,7 +276,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack className='w-full' space={4} ref={formRef} onClick={handleClick} element='form' onSubmit={handleSubmit}>
|
<Stack className='w-full' grow={fullScreen} space={4} ref={formRef} onClick={handleClick} element='form' onSubmit={handleSubmit}>
|
||||||
{scheduledStatusCount > 0 && !event && !group && (
|
{scheduledStatusCount > 0 && !event && !group && (
|
||||||
<Warning
|
<Warning
|
||||||
message={(
|
message={(
|
||||||
|
@ -319,6 +320,7 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
||||||
autoFocus={shouldAutoFocus}
|
autoFocus={shouldAutoFocus}
|
||||||
condensed={condensed}
|
condensed={condensed}
|
||||||
id='compose-textarea'
|
id='compose-textarea'
|
||||||
|
fullScreen
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
!condensed &&
|
!condensed &&
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { fetchStatus } from 'soapbox/actions/statuses';
|
||||||
import { Stack } from 'soapbox/components/ui';
|
import { Stack } from 'soapbox/components/ui';
|
||||||
import ComposeForm from 'soapbox/features/compose/components/compose-form';
|
import ComposeForm from 'soapbox/features/compose/components/compose-form';
|
||||||
import { useAppDispatch, useCompose } from 'soapbox/hooks';
|
import { useAppDispatch, useCompose } from 'soapbox/hooks';
|
||||||
import { makeGetStatus } from 'soapbox/selectors';
|
import { makeGetStatus, selectOwnAccount } from 'soapbox/selectors';
|
||||||
import { getFeatures } from 'soapbox/utils/features';
|
import { getFeatures } from 'soapbox/utils/features';
|
||||||
|
|
||||||
const getStatus = makeGetStatus();
|
const getStatus = makeGetStatus();
|
||||||
|
@ -56,7 +56,7 @@ const ComposePage = () => {
|
||||||
type: COMPOSE_REPLY,
|
type: COMPOSE_REPLY,
|
||||||
id: 'compose-modal',
|
id: 'compose-modal',
|
||||||
status: status,
|
status: status,
|
||||||
account: state.accounts.get(state.me)!,
|
account: selectOwnAccount(state),
|
||||||
explicitAddressing,
|
explicitAddressing,
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -72,7 +72,7 @@ const ComposePage = () => {
|
||||||
type: COMPOSE_QUOTE,
|
type: COMPOSE_QUOTE,
|
||||||
id: 'compose-modal',
|
id: 'compose-modal',
|
||||||
status: status,
|
status: status,
|
||||||
account: state.accounts.get(state.me)!,
|
account: selectOwnAccount(state),
|
||||||
explicitAddressing,
|
explicitAddressing,
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -83,7 +83,7 @@ const ComposePage = () => {
|
||||||
<h3 className='grow-0 truncate text-lg font-bold leading-6 text-gray-900 dark:text-white'>
|
<h3 className='grow-0 truncate text-lg font-bold leading-6 text-gray-900 dark:text-white'>
|
||||||
{heading}
|
{heading}
|
||||||
</h3>
|
</h3>
|
||||||
<ComposeForm id='compose-modal' onSubmit={() => window.close()} />
|
<ComposeForm id='compose-modal' onSubmit={() => window.close()} fullScreen />
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,6 +17,13 @@ interface IToastOptions {
|
||||||
summary?: string
|
summary?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let bc: BroadcastChannel;
|
||||||
|
if (BroadcastChannel) {
|
||||||
|
bc = new BroadcastChannel('toast');
|
||||||
|
bc.onmessage = ({ data }) => createToast(data.type, data.message, data.opts);
|
||||||
|
(window as any).bc = bc;
|
||||||
|
}
|
||||||
|
|
||||||
const DEFAULT_DURATION = 4000;
|
const DEFAULT_DURATION = 4000;
|
||||||
|
|
||||||
const createToast = (type: ToastType, message: ToastText, opts?: IToastOptions) => {
|
const createToast = (type: ToastType, message: ToastText, opts?: IToastOptions) => {
|
||||||
|
@ -39,6 +46,10 @@ function error(message: ToastText, opts?: IToastOptions) {
|
||||||
createToast('error', message, opts);
|
createToast('error', message, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const propagate = (type: ToastType, message: ToastText, opts?: IToastOptions) => {
|
||||||
|
bc?.postMessage({ type, message, opts });
|
||||||
|
};
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
unexpectedMessage: { id: 'alert.unexpected.message', defaultMessage: 'An unexpected error occurred.' },
|
unexpectedMessage: { id: 'alert.unexpected.message', defaultMessage: 'An unexpected error occurred.' },
|
||||||
});
|
});
|
||||||
|
@ -79,5 +90,6 @@ export default {
|
||||||
info,
|
info,
|
||||||
success,
|
success,
|
||||||
error,
|
error,
|
||||||
|
propagate,
|
||||||
showAlertForError,
|
showAlertForError,
|
||||||
};
|
};
|
Loading…
Reference in a new issue