Handle sensitive and spoiler separately when writing a post
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
d33589d103
commit
604ebdd24a
9 changed files with 38 additions and 102 deletions
|
@ -188,7 +188,7 @@ const StatusContent: React.FC<IStatusContent> = React.memo(({
|
|||
|
||||
if (spoilerText) {
|
||||
output.push(
|
||||
<Text className='mb-2' size='2xl' weight='medium'>
|
||||
<Text size='2xl' weight='medium'>
|
||||
<span dangerouslySetInnerHTML={{ __html: spoilerText }} />
|
||||
{expandable && (
|
||||
<Button
|
||||
|
|
|
@ -92,7 +92,6 @@ const ChatMessage = (props: IChatMessage) => {
|
|||
})}
|
||||
media={[chatMessage.attachment]}
|
||||
onOpenMedia={onOpenMedia}
|
||||
visible
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -12,11 +12,10 @@ import {
|
|||
selectComposeSuggestion,
|
||||
uploadCompose,
|
||||
} from 'soapbox/actions/compose';
|
||||
import AutosuggestInput, { AutoSuggestion } from 'soapbox/components/autosuggest-input';
|
||||
import { Button, HStack, Stack } from 'soapbox/components/ui';
|
||||
import EmojiPickerDropdown from 'soapbox/features/emoji/containers/emoji-picker-dropdown-container';
|
||||
import { ComposeEditor } from 'soapbox/features/ui/util/async-components';
|
||||
import { useAppDispatch, useAppSelector, useCompose, useDraggedFiles, useFeatures, useInstance, usePrevious } from 'soapbox/hooks';
|
||||
import { useAppDispatch, useAppSelector, useCompose, useDraggedFiles, useFeatures, useInstance } from 'soapbox/hooks';
|
||||
|
||||
import QuotedStatusContainer from '../containers/quoted-status-container';
|
||||
import ReplyIndicatorContainer from '../containers/reply-indicator-container';
|
||||
|
@ -41,6 +40,7 @@ import UploadForm from './upload-form';
|
|||
import VisualCharacterCounter from './visual-character-counter';
|
||||
import Warning from './warning';
|
||||
|
||||
import type { AutoSuggestion } from 'soapbox/components/autosuggest-input';
|
||||
import type { Emoji } from 'soapbox/features/emoji';
|
||||
|
||||
const messages = defineMessages({
|
||||
|
@ -77,7 +77,6 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
|||
const features = useFeatures();
|
||||
|
||||
const {
|
||||
spoiler,
|
||||
spoiler_text: spoilerText,
|
||||
privacy,
|
||||
is_submitting: isSubmitting,
|
||||
|
@ -90,17 +89,13 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
|||
modified_language: modifiedLanguage,
|
||||
} = compose;
|
||||
|
||||
const prevSpoiler = usePrevious(spoiler);
|
||||
|
||||
const hasPoll = !!compose.poll;
|
||||
const isEditing = compose.id !== null;
|
||||
const anyMedia = compose.media_attachments.size > 0;
|
||||
|
||||
const [composeFocused, setComposeFocused] = useState(false);
|
||||
|
||||
const firstRender = useRef(true);
|
||||
const formRef = useRef<HTMLDivElement>(null);
|
||||
const spoilerTextRef = useRef<AutosuggestInput>(null);
|
||||
const editorRef = useRef<LexicalEditor>(null);
|
||||
|
||||
const { isDraggedOver } = useDraggedFiles(formRef);
|
||||
|
@ -171,10 +166,6 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
|||
dispatch(uploadCompose(id, files, intl));
|
||||
};
|
||||
|
||||
const focusSpoilerInput = () => {
|
||||
spoilerTextRef.current?.input?.focus();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('click', handleClick, true);
|
||||
|
||||
|
@ -183,16 +174,6 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
|||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (spoiler && firstRender.current) {
|
||||
firstRender.current = false;
|
||||
} else if (!spoiler && prevSpoiler) {
|
||||
//
|
||||
} else if (spoiler && !prevSpoiler) {
|
||||
focusSpoilerInput();
|
||||
}
|
||||
}, [spoiler]);
|
||||
|
||||
const renderButtons = useCallback(() => (
|
||||
<HStack alignItems='center' space={2}>
|
||||
<UploadButtonContainer composeId={id} />
|
||||
|
@ -208,14 +189,6 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
|||
<UploadForm composeId={id} onSubmit={handleSubmit} />
|
||||
<PollForm composeId={id} />
|
||||
|
||||
<SpoilerInput
|
||||
composeId={id}
|
||||
onSuggestionsFetchRequested={onSuggestionsFetchRequested}
|
||||
onSuggestionsClearRequested={onSuggestionsClearRequested}
|
||||
onSuggestionSelected={onSpoilerSuggestionSelected}
|
||||
ref={spoilerTextRef}
|
||||
/>
|
||||
|
||||
<ScheduleForm composeId={id} />
|
||||
</Stack>
|
||||
);
|
||||
|
@ -280,6 +253,13 @@ const ComposeForm = <ID extends string>({ id, shouldCondense, autoFocus, clickab
|
|||
</HStack>
|
||||
)}
|
||||
|
||||
<SpoilerInput
|
||||
composeId={id}
|
||||
onSuggestionsFetchRequested={onSuggestionsFetchRequested}
|
||||
onSuggestionsClearRequested={onSuggestionsClearRequested}
|
||||
onSuggestionSelected={onSpoilerSuggestionSelected}
|
||||
/>
|
||||
|
||||
<div>
|
||||
<Suspense>
|
||||
<ComposeEditor
|
||||
|
|
|
@ -7,8 +7,8 @@ import { useAppDispatch, useCompose } from 'soapbox/hooks';
|
|||
import ComposeFormButton from './compose-form-button';
|
||||
|
||||
const messages = defineMessages({
|
||||
marked: { id: 'compose_form.spoiler.marked', defaultMessage: 'Text is hidden behind warning' },
|
||||
unmarked: { id: 'compose_form.spoiler.unmarked', defaultMessage: 'Text is not hidden' },
|
||||
marked: { id: 'compose_form.spoiler.marked', defaultMessage: 'Media is marked as sensitive' },
|
||||
unmarked: { id: 'compose_form.spoiler.unmarked', defaultMessage: 'Media is not marked as sensitive' },
|
||||
});
|
||||
|
||||
interface ISpoilerButton {
|
||||
|
@ -19,7 +19,7 @@ const SpoilerButton: React.FC<ISpoilerButton> = ({ composeId }) => {
|
|||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const active = useCompose(composeId).spoiler;
|
||||
const active = useCompose(composeId).sensitive;
|
||||
|
||||
const onClick = () =>
|
||||
dispatch(changeComposeSpoilerness(composeId));
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { changeComposeSpoilerness, changeComposeSpoilerText } from 'soapbox/actions/compose';
|
||||
import { changeComposeSpoilerText } from 'soapbox/actions/compose';
|
||||
import AutosuggestInput, { IAutosuggestInput } from 'soapbox/components/autosuggest-input';
|
||||
import { Divider, Stack, Text } from 'soapbox/components/ui';
|
||||
import { useAppDispatch, useCompose } from 'soapbox/hooks';
|
||||
|
||||
const messages = defineMessages({
|
||||
title: { id: 'compose_form.spoiler_title', defaultMessage: 'Sensitive content' },
|
||||
placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here (optional)' },
|
||||
remove: { id: 'compose_form.spoiler_remove', defaultMessage: 'Remove sensitive' },
|
||||
placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Subject (optional)' },
|
||||
|
||||
});
|
||||
|
||||
interface ISpoilerInput extends Pick<IAutosuggestInput, 'onSuggestionsFetchRequested' | 'onSuggestionsClearRequested' | 'onSuggestionSelected'> {
|
||||
|
@ -26,56 +23,28 @@ const SpoilerInput = React.forwardRef<AutosuggestInput, ISpoilerInput>(({
|
|||
}, ref) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
const { language, modified_language, spoiler, spoiler_text: spoilerText, spoilerTextMap, suggestions } = useCompose(composeId);
|
||||
const { language, modified_language, spoiler_text: spoilerText, spoilerTextMap, suggestions } = useCompose(composeId);
|
||||
|
||||
const handleChangeSpoilerText: React.ChangeEventHandler<HTMLInputElement> = (e) => {
|
||||
dispatch(changeComposeSpoilerText(composeId, e.target.value));
|
||||
};
|
||||
|
||||
const handleRemove = () => {
|
||||
dispatch(changeComposeSpoilerness(composeId));
|
||||
};
|
||||
|
||||
const value = !modified_language || modified_language === language ? spoilerText : spoilerTextMap.get(modified_language, '');
|
||||
|
||||
return (
|
||||
<Stack
|
||||
space={4}
|
||||
className={clsx({
|
||||
'relative transition-height': true,
|
||||
'hidden': !spoiler,
|
||||
})}
|
||||
>
|
||||
<Divider />
|
||||
|
||||
<Stack space={2}>
|
||||
<Text weight='medium'>
|
||||
{intl.formatMessage(messages.title)}
|
||||
</Text>
|
||||
|
||||
<AutosuggestInput
|
||||
placeholder={intl.formatMessage(messages.placeholder)}
|
||||
value={value}
|
||||
onChange={handleChangeSpoilerText}
|
||||
disabled={!spoiler}
|
||||
suggestions={suggestions}
|
||||
onSuggestionsFetchRequested={onSuggestionsFetchRequested}
|
||||
onSuggestionsClearRequested={onSuggestionsClearRequested}
|
||||
onSuggestionSelected={onSuggestionSelected}
|
||||
searchTokens={[':']}
|
||||
id='cw-spoiler-input'
|
||||
className='rounded-md !bg-transparent dark:!bg-transparent'
|
||||
ref={ref}
|
||||
autoFocus
|
||||
/>
|
||||
|
||||
<div className='text-center'>
|
||||
<button type='button' className='text-danger-500' onClick={handleRemove}>
|
||||
{intl.formatMessage(messages.remove)}
|
||||
</button>
|
||||
</div>
|
||||
</Stack>
|
||||
</Stack>
|
||||
<AutosuggestInput
|
||||
placeholder={intl.formatMessage(messages.placeholder)}
|
||||
value={value}
|
||||
onChange={handleChangeSpoilerText}
|
||||
suggestions={suggestions}
|
||||
onSuggestionsFetchRequested={onSuggestionsFetchRequested}
|
||||
onSuggestionsClearRequested={onSuggestionsClearRequested}
|
||||
onSuggestionSelected={onSuggestionSelected}
|
||||
searchTokens={[':']}
|
||||
id='cw-spoiler-input'
|
||||
className='rounded-md !bg-transparent dark:!bg-transparent'
|
||||
ref={ref}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
@ -63,7 +63,6 @@ const StatusCheckBox: React.FC<IStatusCheckBox> = ({ id, disabled }) => {
|
|||
media={status.media_attachments}
|
||||
height={110}
|
||||
onOpenMedia={noop}
|
||||
visible
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -485,11 +485,9 @@
|
|||
"compose_form.schedule": "Schedule",
|
||||
"compose_form.scheduled_statuses.click_here": "Click here",
|
||||
"compose_form.scheduled_statuses.message": "You have scheduled posts. {click_here} to see them.",
|
||||
"compose_form.spoiler.marked": "Text is hidden behind warning",
|
||||
"compose_form.spoiler.unmarked": "Text is not hidden",
|
||||
"compose_form.spoiler_placeholder": "Write your warning here (optional)",
|
||||
"compose_form.spoiler_remove": "Remove sensitive",
|
||||
"compose_form.spoiler_title": "Sensitive content",
|
||||
"compose_form.spoiler.marked": "Media is marked as sensitive",
|
||||
"compose_form.spoiler.unmarked": "Media is not marked as sensitive",
|
||||
"compose_form.spoiler_placeholder": "Subject (optional)",
|
||||
"confirmation_modal.cancel": "Cancel",
|
||||
"confirmations.admin.deactivate_user.confirm": "Deactivate @{name}",
|
||||
"confirmations.admin.deactivate_user.heading": "Deactivate @{acct}",
|
||||
|
|
|
@ -485,11 +485,9 @@
|
|||
"compose_form.schedule": "Zaplanuj",
|
||||
"compose_form.scheduled_statuses.click_here": "Naciśnij tutaj",
|
||||
"compose_form.scheduled_statuses.message": "Masz zaplanowane wpisy. {click_here}, aby je zobaczyć.",
|
||||
"compose_form.spoiler.marked": "Tekst jest ukryty za ostrzeżeniem",
|
||||
"compose_form.spoiler.unmarked": "Tekst nie jest ukryty",
|
||||
"compose_form.spoiler_placeholder": "Wprowadź swoje ostrzeżenie o zawartości",
|
||||
"compose_form.spoiler_remove": "Usuń zaznaczenie jako wrażliwe",
|
||||
"compose_form.spoiler_title": "Treści wrażliwe",
|
||||
"compose_form.spoiler.marked": "Media są oznaczone jako wrażliwe",
|
||||
"compose_form.spoiler.unmarked": "Media nie są oznaczone jako wrażliwe",
|
||||
"compose_form.spoiler_placeholder": "Temat (nieobowiązkowy)",
|
||||
"confirmation_modal.cancel": "Anuluj",
|
||||
"confirmations.admin.deactivate_user.confirm": "Dezaktywuj @{name}",
|
||||
"confirmations.admin.deactivate_user.heading": "Dezaktywuj @{acct}",
|
||||
|
|
|
@ -105,7 +105,6 @@ const ReducerCompose = ImmutableRecord({
|
|||
resetFileKey: null as number | null,
|
||||
schedule: null as Date | null,
|
||||
sensitive: false,
|
||||
spoiler: false,
|
||||
spoiler_text: '',
|
||||
spoilerTextMap: ImmutableMap<Language, string>(),
|
||||
suggestions: ImmutableList<string>(),
|
||||
|
@ -165,7 +164,7 @@ const appendMedia = (compose: Compose, media: MediaAttachment, defaultSensitive?
|
|||
map.set('resetFileKey', Math.floor((Math.random() * 0x10000)));
|
||||
map.set('idempotencyKey', uuid());
|
||||
|
||||
if (prevSize === 0 && (defaultSensitive || compose.spoiler)) {
|
||||
if (prevSize === 0 && (defaultSensitive || compose.sensitive)) {
|
||||
map.set('sensitive', true);
|
||||
}
|
||||
});
|
||||
|
@ -293,9 +292,7 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | Me
|
|||
}));
|
||||
case COMPOSE_SPOILERNESS_CHANGE:
|
||||
return updateCompose(state, action.composeId, compose => compose.withMutations(map => {
|
||||
map.set('spoiler_text', '');
|
||||
map.set('spoiler', !compose.spoiler);
|
||||
map.set('sensitive', !compose.spoiler);
|
||||
map.set('sensitive', !compose.sensitive);
|
||||
map.set('idempotencyKey', uuid());
|
||||
}));
|
||||
case COMPOSE_SPOILER_TEXT_CHANGE:
|
||||
|
@ -342,7 +339,6 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | Me
|
|||
map.set('idempotencyKey', uuid());
|
||||
map.set('content_type', defaultCompose.content_type);
|
||||
if (action.preserveSpoilers && action.status.spoiler_text) {
|
||||
map.set('spoiler', true);
|
||||
map.set('sensitive', true);
|
||||
map.set('spoiler_text', action.status.spoiler_text);
|
||||
}
|
||||
|
@ -367,7 +363,6 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | Me
|
|||
map.set('caretPosition', null);
|
||||
map.set('idempotencyKey', uuid());
|
||||
map.set('content_type', defaultCompose.content_type);
|
||||
map.set('spoiler', false);
|
||||
map.set('spoiler_text', '');
|
||||
|
||||
if (action.status.visibility === 'group') {
|
||||
|
@ -484,10 +479,8 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | Me
|
|||
}
|
||||
|
||||
if (action.status.spoiler_text.length > 0) {
|
||||
map.set('spoiler', true);
|
||||
map.set('spoiler_text', action.status.spoiler_text);
|
||||
} else {
|
||||
map.set('spoiler', false);
|
||||
map.set('spoiler_text', '');
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue