Merge remote-tracking branch 'origin/develop' into chats

environments/review-chats-g56n7m/deployments/1581
Chewbacca 2 years ago
commit f7f40703cd

@ -28,6 +28,8 @@ busybox unzip soapbox.zip -o -d /opt/pleroma/instance
The change will take effect immediately, just refresh your browser tab.
It's not necessary to restart the Pleroma service.
***For OTP releases,*** *unpack to /var/lib/pleroma instead.*
To remove Soapbox and revert to the default pleroma-fe, simply `rm /opt/pleroma/instance/static/index.html` (you can delete other stuff in there too, but be careful not to delete your own HTML files).
## :elephant: Deploy on Mastodon

@ -1,12 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>Generated by IcoMoon</metadata>
<defs>
<font id="icomoon" horiz-adv-x="1024">
<font-face units-per-em="1024" ascent="960" descent="-64" />
<missing-glyph horiz-adv-x="1024" />
<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
<glyph unicode="&#xe900;" glyph-name="spinster" d="M512 857.6c-226.216 0-409.6-183.384-409.6-409.6v0c0-226.216 183.384-409.6 409.6-409.6v0c226.216 0 409.6 183.384 409.6 409.6v0c0 226.216-183.384 409.6-409.6 409.6v0zM525.84 706.224c32.633 0 64.793-3.777 96.48-11.344 31.687-7.095 59.576-17.748 83.696-31.936l-43.264-104.272c-47.294 25.539-93.176 38.304-137.632 38.304-27.903 0-48.239-4.255-61.008-12.768-12.769-8.040-19.152-18.677-19.152-31.92s7.57-23.171 22.704-29.792c15.134-6.621 39.493-13.482 73.072-20.576 37.835-8.040 69.039-16.797 93.632-26.256 25.066-8.986 46.588-23.648 64.56-43.984 18.445-19.863 27.664-47.059 27.664-81.584 0-29.795-8.279-56.744-24.832-80.864s-41.374-43.515-74.48-58.176c-33.106-14.188-73.314-21.28-120.608-21.28-40.2 0-79.205 4.964-117.040 14.896s-68.577 23.175-92.224 39.728l46.112 103.568c22.228-14.661 48.006-26.486 77.328-35.472s58.168-13.472 86.544-13.472c53.915 0 80.864 13.475 80.864 40.432 0 14.188-7.801 24.595-23.408 31.216-15.134 7.094-39.724 14.432-73.776 22-37.362 8.040-68.582 16.551-93.648 25.536-25.066 9.459-46.572 24.352-64.544 44.688s-26.96 47.763-26.96 82.288c0 30.268 8.279 57.464 24.832 81.584 16.553 24.592 41.143 43.988 73.776 58.176 33.106 14.188 73.545 21.28 121.312 21.28z" />
<glyph unicode="&#xe901;" glyph-name="fediverse" d="M553.99 908.789c-46.369-0.785-83.969-37.261-86.545-83.096l-0.010-0.231c-0.083-1.432-0.13-3.108-0.13-4.794 0-46.987 36.77-85.385 83.105-87.99l0.231-0.010c1.432-0.083 3.107-0.13 4.794-0.13 46.988 0 85.387 36.772 87.99 83.108l0.010 0.231c0.083 1.431 0.13 3.106 0.13 4.791 0 46.988-36.771 85.387-83.108 87.99l-0.231 0.010c-1.441 0.084-3.127 0.132-4.823 0.132-0.497 0-0.993-0.004-1.487-0.012l0.075 0.001zM459.882 805.031l-251.29-127.347c13.547-13.809 23-31.679 26.366-51.617l0.080-0.57 251.287 127.353c-13.545 13.808-22.997 31.675-26.363 51.611l-0.080 0.57zM641.318 775.903c-9.415-17.78-23.636-31.938-40.939-41.021l-0.532-0.254 198.787-199.554c9.415 17.78 23.634 31.938 40.936 41.021l0.532 0.254zM487.306 751.83l-147.023-287.024 43.408-43.576 155.667 303.891c-20.483 3.55-38.302 13.087-52.060 26.716l0.007-0.007zM599.388 734.397c-12.846-6.718-28.060-10.66-44.195-10.66-1.77 0-3.529 0.047-5.276 0.141l0.244-0.010c-3.232 0.199-6.15 0.516-9.026 0.959l0.542-0.069 22.259-142.535 60.737-9.746zM138.038 697.983c-46.37-0.783-83.972-37.26-86.548-83.095l-0.010-0.231c-0.083-1.432-0.13-3.107-0.13-4.794 0-46.988 36.772-85.387 83.108-87.99l0.231-0.010c1.432-0.083 3.107-0.13 4.794-0.13 46.988 0 85.387 36.772 87.99 83.108l0.010 0.231c0.083 1.432 0.13 3.107 0.13 4.794 0 46.988-36.772 85.387-83.108 87.99l-0.231 0.010c-1.43 0.083-3.103 0.13-4.787 0.13-0.51 0-1.018-0.004-1.526-0.013l0.076 0.001zM235.216 624.428c0.752-4.537 1.182-9.766 1.182-15.095 0-1.667-0.042-3.325-0.125-4.972l0.009 0.231c-0.796-13.969-4.43-26.918-10.33-38.52l0.254 0.551 142.645-22.911 28.036 54.751zM479.695 585.167l-28.039-54.757 337.040-54.13c-0.697 4.368-1.096 9.405-1.096 14.535 0 1.678 0.043 3.346 0.127 5.002l-0.009-0.232c0.815 14.158 4.546 27.272 10.597 38.992l-0.254-0.542zM883.076 578.43c-46.37-0.783-83.972-37.26-86.548-83.095l-0.010-0.231c-0.083-1.432-0.13-3.107-0.13-4.794 0-46.988 36.772-85.387 83.108-87.99l0.231-0.010c1.432-0.083 3.107-0.13 4.794-0.13 46.988 0 85.387 36.772 87.99 83.108l0.010 0.231c0.083 1.432 0.13 3.107 0.13 4.794 0 46.988-36.772 85.387-83.108 87.99l-0.231 0.010c-1.438 0.084-3.119 0.131-4.812 0.131-0.501 0-1-0.004-1.499-0.012l0.075 0.001zM225.366 565.098c-9.414-17.777-23.632-31.933-40.931-41.016l-0.532-0.254 227.623-228.511 54.877 27.811zM182.639 523.19c-12.642-6.466-27.577-10.256-43.397-10.256-1.77 0-3.529 0.047-5.276 0.141l0.244-0.010c-3.521 0.199-6.741 0.548-9.909 1.050l0.551-0.072 43.485-278.147c12.642 6.466 27.577 10.256 43.397 10.256 1.77 0 3.529-0.047 5.276-0.141l-0.244 0.010c3.519-0.2 6.737-0.548 9.903-1.050l-0.55 0.072zM576.873 499.359l52.629-336.996c12.457 6.245 27.143 9.902 42.682 9.902 1.773 0 3.535-0.048 5.285-0.142l-0.244 0.010c3.8-0.219 7.286-0.616 10.711-1.192l-0.569 0.079-49.754 318.595zM788.965 474.681l-128.865-65.308 9.501-60.776 145.806 73.896c-13.546 13.809-22.998 31.679-26.363 51.617l-0.080 0.57zM816.386 421.477l-128.362-250.594c20.486-3.55 38.307-13.087 52.065-26.719l-0.007 0.007 128.359 250.591c-20.485 3.551-38.305 13.090-52.062 26.722l0.007-0.007zM302.044 390.153l-74.471-145.382c20.481-3.55 38.298-13.086 52.054-26.714l-0.007 0.007 65.83 128.515zM585.292 371.462l-304.691-154.416c13.549-13.81 23.003-31.682 26.368-51.622l0.080-0.57 287.744 145.83zM525.607 263.696l-54.877-27.811 115.337-115.788c9.415 17.78 23.636 31.938 40.939 41.021l0.532 0.254zM210.049 237.339c-46.369-0.785-83.969-37.261-86.545-83.096l-0.010-0.231c-0.083-1.432-0.13-3.107-0.13-4.794 0-46.988 36.772-85.387 83.108-87.99l0.231-0.010c1.432-0.083 3.107-0.13 4.794-0.13 46.988 0 85.387 36.772 87.99 83.108l0.010 0.231c0.083 1.432 0.13 3.107 0.13 4.794 0 46.988-36.772 85.387-83.108 87.99l-0.231 0.010c-1.438 0.084-3.12 0.132-4.813 0.132-0.501 0-1.002-0.004-1.501-0.013l0.075 0.001zM307.279 163.476c0.72-4.438 1.131-9.554 1.131-14.766 0-1.675-0.042-3.34-0.126-4.993l0.009 0.232c-0.806-14.078-4.495-27.122-10.481-38.793l0.254 0.546 278.1-44.626c-0.721 4.442-1.133 9.563-1.133 14.779 0 1.671 0.042 3.332 0.126 4.983l-0.009-0.232c0.807 14.078 4.497 27.12 10.484 38.79l-0.254-0.546zM670.509 163.451c-46.37-0.783-83.972-37.26-86.548-83.095l-0.010-0.231c-0.083-1.432-0.13-3.107-0.13-4.794 0-46.988 36.772-85.387 83.108-87.99l0.231-0.010c1.432-0.083 3.107-0.13 4.794-0.13 46.988 0 85.387 36.772 87.99 83.108l0.010 0.231c0.083 1.432 0.13 3.107 0.13 4.794 0 46.988-36.772 85.387-83.108 87.99l-0.231 0.010c-1.438 0.084-3.119 0.131-4.812 0.131-0.501 0-1-0.004-1.499-0.012l0.075 0.001z" />
</font></defs></svg>

Before

Width:  |  Height:  |  Size: 6.0 KiB

@ -87,7 +87,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.type.hint": "Click to toggle poll type. Radio button (default) is single. Checkbox is multiple.",
"compose_form.publish": "Publish",
"compose_form.publish_loud": "{publish}!",
@ -566,7 +566,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.type.hint": "Click to toggle poll type. Radio button (default) is single. Checkbox is multiple.",
"compose_form.publish": "Publish",
"compose_form.publish_loud": "{publish}!",

@ -253,6 +253,10 @@ export const logOut = () =>
export const switchAccount = (accountId: string, background = false) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const account = getState().accounts.get(accountId);
// Clear all stored cache from React Query
queryClient.invalidateQueries();
queryClient.clear();
return dispatch({ type: SWITCH_ACCOUNT, account, background });
};

@ -4,7 +4,7 @@ import { useDispatch } from 'react-redux';
import { unblockDomain } from 'soapbox/actions/domain-blocks';
import IconButton from './icon-button';
import { HStack, IconButton, Text } from './ui';
const messages = defineMessages({
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
@ -34,17 +34,12 @@ const Domain: React.FC<IDomain> = ({ domain }) => {
};
return (
<div className='domain'>
<div className='domain__wrapper'>
<span className='domain__domain-name'>
<strong>{domain}</strong>
</span>
<div className='domain__buttons'>
<IconButton active src={require('@tabler/icons/lock-open.svg')} title={intl.formatMessage(messages.unblockDomain, { domain })} onClick={handleDomainUnblock} />
</div>
</div>
</div>
<HStack alignItems='center' justifyContent='between' space={1} className='p-2'>
<Text tag='span'>
{domain}
</Text>
<IconButton iconClassName='h-5 w-5' src={require('@tabler/icons/lock-open.svg')} title={intl.formatMessage(messages.unblockDomain, { domain })} onClick={handleDomainUnblock} />
</HStack>
);
};

@ -1,77 +1,77 @@
.status-content p {
[data-markup] p {
@apply mb-4 whitespace-pre-wrap;
}
.status-content p:last-child {
[data-markup] p:last-child {
@apply mb-0;
}
.status-content a {
[data-markup] a {
@apply text-primary-600 dark:text-accent-blue hover:underline;
}
.status-content strong {
[data-markup] strong {
@apply font-bold;
}
.status-content em {
[data-markup] em {
@apply italic;
}
.status-content ul,
.status-content ol {
[data-markup] ul,
[data-markup] ol {
@apply pl-10 mb-4;
}
.status-content ul {
[data-markup] ul {
@apply list-disc list-outside;
}
.status-content ol {
[data-markup] ol {
@apply list-decimal list-outside;
}
.status-content blockquote {
[data-markup] blockquote {
@apply py-1 pl-4 mb-4 border-l-4 border-solid border-gray-400 text-gray-500 dark:text-gray-400;
}
.status-content code {
[data-markup] code {
@apply cursor-text font-mono;
}
.status-content p > code,
.status-content pre {
[data-markup] p > code,
[data-markup] pre {
@apply bg-gray-100 dark:bg-primary-800;
}
/* Inline code */
.status-content p > code {
[data-markup] p > code {
@apply py-0.5 px-1 rounded-sm;
}
/* Code block */
.status-content pre {
[data-markup] pre {
@apply py-2 px-3 mb-4 leading-6 overflow-x-auto rounded-md break-all;
}
.status-content pre:last-child {
[data-markup] pre:last-child {
@apply mb-0;
}
/* Markdown images */
.status-content img:not(.emojione):not([width][height]) {
[data-markup] img:not(.emojione):not([width][height]) {
@apply w-full h-72 object-contain rounded-lg overflow-hidden my-4 block;
}
/* User setting to underline links */
body.underline-links .status-content a {
body.underline-links [data-markup] a {
@apply underline;
}
.status-content .big-emoji img.emojione {
[data-markup] .big-emoji img.emojione {
@apply inline w-9 h-9 p-1;
}
.status-content .status-link {
[data-markup] .status-link {
@apply hover:underline text-primary-600 dark:text-accent-blue hover:text-primary-800 dark:hover:text-accent-blue;
}

@ -0,0 +1,16 @@
import React from 'react';
import Text, { IText } from './ui/text/text';
import './markup.css';
interface IMarkup extends IText {
}
/** Styles HTML markup returned by the API, such as in account bios and statuses. */
const Markup = React.forwardRef<any, IMarkup>((props, ref) => {
return (
<Text ref={ref} {...props} data-markup />
);
});
export default Markup;

@ -1,5 +1,5 @@
import classNames from 'clsx';
import React, { MouseEventHandler, useState } from 'react';
import React, { MouseEventHandler, useEffect, useRef, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { useHistory } from 'react-router-dom';
@ -37,7 +37,16 @@ const QuotedStatus: React.FC<IQuotedStatus> = ({ status, onCancel, compose }) =>
const settings = useSettings();
const displayMedia = settings.get('displayMedia');
const overlay = useRef<HTMLDivElement>(null);
const [showMedia, setShowMedia] = useState<boolean>(defaultMediaVisibility(status, displayMedia));
const [minHeight, setMinHeight] = useState(208);
useEffect(() => {
if (overlay.current) {
setMinHeight(overlay.current.getBoundingClientRect().height);
}
}, [overlay.current]);
const handleExpandClick: MouseEventHandler<HTMLDivElement> = (e) => {
if (!status) return;
@ -103,15 +112,16 @@ const QuotedStatus: React.FC<IQuotedStatus> = ({ status, onCancel, compose }) =>
<StatusReplyMentions status={status} hoverable={false} />
<Stack className={classNames('relative z-0', {
'min-h-[220px]': status.hidden,
})}
<Stack
className='relative z-0'
style={{ minHeight: status.hidden ? Math.max(minHeight, 208) + 12 : undefined }}
>
{(status.hidden) && (
<SensitiveContentOverlay
status={status}
visible={showMedia}
onToggleVisibility={handleToggleMediaVisibility}
ref={overlay}
/>
)}

@ -1,4 +1,3 @@
import classNames from 'clsx';
import { List as ImmutableList } from 'immutable';
import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
@ -16,6 +15,7 @@ import { initReport } from 'soapbox/actions/reports';
import { deleteStatus, editStatus, toggleMuteStatus } from 'soapbox/actions/statuses';
import EmojiButtonWrapper from 'soapbox/components/emoji-button-wrapper';
import StatusActionButton from 'soapbox/components/status-action-button';
import { HStack } from 'soapbox/components/ui';
import DropdownMenuContainer from 'soapbox/containers/dropdown-menu-container';
import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount, useSettings, useSoapboxConfig } from 'soapbox/hooks';
import { isLocal } from 'soapbox/utils/accounts';
@ -127,8 +127,6 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
} else {
onOpenUnauthorizedModal('REPLY');
}
e.stopPropagation();
};
const handleShareClick = () => {
@ -146,18 +144,13 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
} else {
onOpenUnauthorizedModal('FAVOURITE');
}
e.stopPropagation();
};
const handleBookmarkClick: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
dispatch(toggleBookmark(status));
};
const handleReblogClick: React.EventHandler<React.MouseEvent> = e => {
e.stopPropagation();
if (me) {
const modalReblog = () => dispatch(toggleReblog(status));
const boostModal = settings.get('boostModal');
@ -172,8 +165,6 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
};
const handleQuoteClick: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
if (me) {
dispatch(quoteCompose(status));
} else {
@ -199,12 +190,10 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
};
const handleDeleteClick: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
doDeleteStatus();
};
const handleRedraftClick: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
doDeleteStatus(true);
};
@ -213,35 +202,29 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
};
const handlePinClick: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
dispatch(togglePin(status));
};
const handleMentionClick: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
dispatch(mentionCompose(status.account as Account));
};
const handleDirectClick: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
dispatch(directCompose(status.account as Account));
};
const handleChatClick: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
const account = status.account as Account;
dispatch(launchChat(account.id, history));
};
const handleMuteClick: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
dispatch(initMuteModal(status.account as Account));
};
const handleBlockClick: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
const account = status.get('account') as Account;
dispatch(openModal('CONFIRM', {
icon: require('@tabler/icons/ban.svg'),
heading: <FormattedMessage id='confirmations.block.heading' defaultMessage='Block @{name}' values={{ name: account.get('acct') }} />,
@ -257,7 +240,6 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
};
const handleOpen: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
history.push(`/@${status.getIn(['account', 'acct'])}/posts/${status.id}`);
};
@ -269,12 +251,10 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
};
const handleReport: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
dispatch(initReport(status.account as Account, { status }));
};
const handleConversationMuteClick: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
dispatch(toggleMuteStatus(status));
};
@ -282,8 +262,6 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
const { uri } = status;
const textarea = document.createElement('textarea');
e.stopPropagation();
textarea.textContent = uri;
textarea.style.position = 'fixed';
@ -300,18 +278,15 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
};
const onModerate: React.MouseEventHandler = (e) => {
e.stopPropagation();
const account = status.account as Account;
dispatch(openModal('ACCOUNT_MODERATION', { accountId: account.id }));
};
const handleDeleteStatus: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
dispatch(deleteStatusModal(intl, status.id));
};
const handleToggleStatusSensitivity: React.EventHandler<React.MouseEvent> = (e) => {
e.stopPropagation();
dispatch(toggleStatusSensitivityModal(intl, status.id, status.sensitive));
};
@ -550,74 +525,75 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
const canShare = ('share' in navigator) && status.visibility === 'public';
return (
<div
data-testid='status-action-bar'
className={classNames('flex flex-row', {
'justify-between': space === 'expand',
'space-x-2': space === 'compact',
})}
>
<StatusActionButton
title={replyTitle}
icon={require('@tabler/icons/message-circle-2.svg')}
onClick={handleReplyClick}
count={replyCount}
text={withLabels ? intl.formatMessage(messages.reply) : undefined}
/>
{(features.quotePosts && me) ? (
<DropdownMenuContainer
items={reblogMenu}
disabled={!publicStatus}
onShiftClick={handleReblogClick}
>
{reblogButton}
</DropdownMenuContainer>
) : (
reblogButton
)}
<HStack data-testid='status-action-bar'>
<HStack
justifyContent={space === 'expand' ? 'between' : undefined}
space={space === 'compact' ? 2 : undefined}
grow={space === 'expand'}
onClick={e => e.stopPropagation()}
>
<StatusActionButton
title={replyTitle}
icon={require('@tabler/icons/message-circle-2.svg')}
onClick={handleReplyClick}
count={replyCount}
text={withLabels ? intl.formatMessage(messages.reply) : undefined}
/>
{features.emojiReacts ? (
<EmojiButtonWrapper statusId={status.id}>
{(features.quotePosts && me) ? (
<DropdownMenuContainer
items={reblogMenu}
disabled={!publicStatus}
onShiftClick={handleReblogClick}
>
{reblogButton}
</DropdownMenuContainer>
) : (
reblogButton
)}
{features.emojiReacts ? (
<EmojiButtonWrapper statusId={status.id}>
<StatusActionButton
title={meEmojiTitle}
icon={require('@tabler/icons/heart.svg')}
filled
color='accent'
active={Boolean(meEmojiReact)}
count={emojiReactCount}
emoji={meEmojiReact}
text={withLabels ? meEmojiTitle : undefined}
/>
</EmojiButtonWrapper>
) : (
<StatusActionButton
title={meEmojiTitle}
title={intl.formatMessage(messages.favourite)}
icon={require('@tabler/icons/heart.svg')}
filled
color='accent'
filled
onClick={handleFavouriteClick}
active={Boolean(meEmojiReact)}
count={emojiReactCount}
emoji={meEmojiReact}
count={favouriteCount}
text={withLabels ? meEmojiTitle : undefined}
/>
</EmojiButtonWrapper>
) : (
<StatusActionButton
title={intl.formatMessage(messages.favourite)}
icon={require('@tabler/icons/heart.svg')}
color='accent'
filled
onClick={handleFavouriteClick}
active={Boolean(meEmojiReact)}
count={favouriteCount}
text={withLabels ? meEmojiTitle : undefined}
/>
)}
)}
{canShare && (
<StatusActionButton
title={intl.formatMessage(messages.share)}
icon={require('@tabler/icons/upload.svg')}
onClick={handleShareClick}
/>
)}
{canShare && (
<StatusActionButton
title={intl.formatMessage(messages.share)}
icon={require('@tabler/icons/upload.svg')}
onClick={handleShareClick}
/>
)}
<DropdownMenuContainer items={menu} status={status}>
<StatusActionButton
title={intl.formatMessage(messages.more)}
icon={require('@tabler/icons/dots.svg')}
/>
</DropdownMenuContainer>
</div>
<DropdownMenuContainer items={menu} status={status}>
<StatusActionButton
title={intl.formatMessage(messages.more)}
icon={require('@tabler/icons/dots.svg')}
/>
</DropdownMenuContainer>
</HStack>
</HStack>
);
};

@ -41,7 +41,7 @@ const StatusActionButton = React.forwardRef<HTMLButtonElement, IStatusActionButt
const renderIcon = () => {
if (emoji) {
return (
<span className='block w-6 h-6 flex items-center justify-center'>
<span className='flex w-6 h-6 items-center justify-center'>
<Emoji className='w-full h-full p-0.5' emoji={emoji} />
</span>
);

@ -10,19 +10,14 @@ import { onlyEmoji as isOnlyEmoji } from 'soapbox/utils/rich-content';
import { isRtl } from '../rtl';
import Markup from './markup';
import Poll from './polls/poll';
import './status-content.css';
import type { Status, Mention } from 'soapbox/types/entities';
const MAX_HEIGHT = 642; // 20px * 32 (+ 2px padding at the top)
const BIG_EMOJI_LIMIT = 10;
type Point = [
x: number,
y: number,
]
interface IReadMoreButton {
onClick: React.MouseEventHandler,
}
@ -49,7 +44,6 @@ const StatusContent: React.FC<IStatusContent> = ({ status, onClick, collapsable
const [collapsed, setCollapsed] = useState(false);
const [onlyEmoji, setOnlyEmoji] = useState(false);
const startXY = useRef<Point>();
const node = useRef<HTMLDivElement>(null);
const { greentext } = useSoapboxConfig();
@ -131,29 +125,6 @@ const StatusContent: React.FC<IStatusContent> = ({ status, onClick, collapsable
updateStatusLinks();
});
const handleMouseDown: React.EventHandler<React.MouseEvent> = (e) => {
startXY.current = [e.clientX, e.clientY];
};
const handleMouseUp: React.EventHandler<React.MouseEvent> = (e) => {
if (!startXY.current) return;
const target = e.target as HTMLElement;
const parentNode = target.parentNode as HTMLElement;
const [startX, startY] = startXY.current;
const [deltaX, deltaY] = [Math.abs(e.clientX - startX), Math.abs(e.clientY - startY)];
if (target.localName === 'button' || target.localName === 'a' || (parentNode && (parentNode.localName === 'button' || parentNode.localName === 'a'))) {
return;
}
if (deltaX + deltaY < 5 && e.button === 0 && !(e.ctrlKey || e.metaKey) && onClick) {
onClick();
}
startXY.current = undefined;
};
const parsedHtml = useMemo((): string => {
const html = translatable && status.translation ? status.translation.get('content')! : status.contentHtml;
@ -173,30 +144,24 @@ const StatusContent: React.FC<IStatusContent> = ({ status, onClick, collapsable
const baseClassName = 'text-gray-900 dark:text-gray-100 break-words text-ellipsis overflow-hidden relative focus:outline-none';
const content = { __html: parsedHtml };
const directionStyle: React.CSSProperties = { direction: 'ltr' };
const className = classNames(baseClassName, 'status-content', {
const direction = isRtl(status.search_index) ? 'rtl' : 'ltr';
const className = classNames(baseClassName, {
'cursor-pointer': onClick,
'whitespace-normal': withSpoiler,
'max-h-[300px]': collapsed,
'leading-normal big-emoji': onlyEmoji,
});
if (isRtl(status.search_index)) {
directionStyle.direction = 'rtl';
}
if (onClick) {
const output = [
<div
<Markup
ref={node}
tabIndex={0}
key='content'
className={className}
style={directionStyle}
direction={direction}
dangerouslySetInnerHTML={content}
lang={status.language || undefined}
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
/>,
];
@ -212,14 +177,14 @@ const StatusContent: React.FC<IStatusContent> = ({ status, onClick, collapsable
return <div className={classNames({ 'bg-gray-100 dark:bg-primary-800 rounded-md p-4': hasPoll })}>{output}</div>;
} else {
const output = [
<div
<Markup
ref={node}
tabIndex={0}
key='content'
className={classNames(baseClassName, 'status-content', {
className={classNames(baseClassName, {
'leading-normal big-emoji': onlyEmoji,
})}
style={directionStyle}
direction={direction}
dangerouslySetInnerHTML={content}
lang={status.language || undefined}
/>,

@ -173,7 +173,16 @@ const StatusMedia: React.FC<IStatusMedia> = ({
);
}
return media;
if (media) {
return (
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
<div onClick={e => e.stopPropagation()}>
{media}
</div>
);
} else {
return null;
}
};
export default StatusMedia;

@ -79,8 +79,10 @@ const Status: React.FC<IStatus> = (props) => {
const displayMedia = settings.get('displayMedia') as string;
const didShowCard = useRef(false);
const node = useRef<HTMLDivElement>(null);
const overlay = useRef<HTMLDivElement>(null);
const [showMedia, setShowMedia] = useState<boolean>(defaultMediaVisibility(status, displayMedia));
const [minHeight, setMinHeight] = useState(208);
const actualStatus = getActualStatus(status);
@ -95,6 +97,12 @@ const Status: React.FC<IStatus> = (props) => {
setShowMedia(defaultMediaVisibility(status, displayMedia));
}, [status.id]);
useEffect(() => {
if (overlay.current) {
setMinHeight(overlay.current.getBoundingClientRect().height);
}
}, [overlay.current]);
const handleToggleMediaVisibility = (): void => {
setShowMedia(!showMedia);
};
@ -102,6 +110,11 @@ const Status: React.FC<IStatus> = (props) => {
const handleClick = (e?: React.MouseEvent): void => {
e?.stopPropagation();
// If the user is selecting text, don't focus the status.
if (getSelection()?.toString().length) {
return;
}
if (!e || !(e.ctrlKey || e.metaKey)) {
if (onClick) {
onClick();
@ -358,17 +371,15 @@ const Status: React.FC<IStatus> = (props) => {
<StatusReplyMentions status={actualStatus} hoverable={hoverable} />
<Stack
className={
classNames('relative z-0', {
'min-h-[220px]': isUnderReview || isSensitive,
})
}
className='relative z-0'
style={{ minHeight: isUnderReview || isSensitive ? Math.max(minHeight, 208) + 12 : undefined }}
>
{(isUnderReview || isSensitive) && (
<SensitiveContentOverlay
status={status}
visible={showMedia}
onToggleVisibility={handleToggleMediaVisibility}
ref={overlay}
/>
)}

@ -25,7 +25,7 @@ interface ISensitiveContentOverlay {
visible?: boolean
}
const SensitiveContentOverlay = (props: ISensitiveContentOverlay) => {
const SensitiveContentOverlay = React.forwardRef<HTMLDivElement, ISensitiveContentOverlay>((props, ref) => {
const { onToggleVisibility, status } = props;
const isUnderReview = status.visibility === 'self';
@ -72,7 +72,7 @@ const SensitiveContentOverlay = (props: ISensitiveContentOverlay) => {
size='sm'
/>
) : (
<div className='text-center w-3/4 mx-auto space-y-4'>
<div className='text-center w-3/4 mx-auto space-y-4' ref={ref}>
<div className='space-y-1'>
<Text theme='white' weight='semibold'>
{intl.formatMessage(isUnderReview ? messages.underReviewTitle : messages.sensitiveTitle)}
@ -84,7 +84,7 @@ const SensitiveContentOverlay = (props: ISensitiveContentOverlay) => {
{status.spoiler_text && (
<div className='py-4 italic'>
<Text theme='white' size='md' weight='medium'>
<Text className='line-clamp-6' theme='white' size='md' weight='medium'>
&ldquo;<span dangerouslySetInnerHTML={{ __html: status.spoilerHtml }} />&rdquo;
</Text>
</div>
@ -127,6 +127,6 @@ const SensitiveContentOverlay = (props: ISensitiveContentOverlay) => {
)}
</div>
);
};
});
export default SensitiveContentOverlay;
export default SensitiveContentOverlay;

@ -27,7 +27,7 @@ const spaces = {
8: 'space-x-8',
};
interface IHStack {
interface IHStack extends Pick<React.HTMLAttributes<HTMLDivElement>, 'onClick'> {
/** Vertical alignment of children. */
alignItems?: keyof typeof alignItemsOptions
/** Extra class names on the <div> element. */

@ -54,7 +54,9 @@ export type Sizes = keyof typeof sizes
type Tags = 'abbr' | 'p' | 'span' | 'pre' | 'time' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label'
type Directions = 'ltr' | 'rtl'
interface IText extends Pick<React.HTMLAttributes<HTMLParagraphElement>, 'dangerouslySetInnerHTML'> {
interface IText extends Pick<React.HTMLAttributes<HTMLParagraphElement>, 'dangerouslySetInnerHTML' | 'tabIndex' | 'lang'> {
/** Text content. */
children?: React.ReactNode,
/** How to align the text. */
align?: keyof typeof alignments,
/** Extra class names for the outer element. */
@ -84,8 +86,8 @@ interface IText extends Pick<React.HTMLAttributes<HTMLParagraphElement>, 'danger
}
/** UI-friendly text container with dark mode support. */
const Text: React.FC<IText> = React.forwardRef(
(props: IText, ref: React.LegacyRef<any>) => {
const Text = React.forwardRef<any, IText>(
(props, ref) => {
const {
align,
className,

@ -1,10 +1,9 @@
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { NavLink } from 'react-router-dom';
import AvatarOverlay from 'soapbox/components/avatar-overlay';
import DisplayName from 'soapbox/components/display-name';
import Account from 'soapbox/components/account';
import Icon from 'soapbox/components/icon';
import { HStack, Text } from 'soapbox/components/ui';
import type { Account as AccountEntity } from 'soapbox/types/entities';
@ -13,22 +12,30 @@ interface IMovedNote {
to: AccountEntity,
}
const MovedNote: React.FC<IMovedNote> = ({ from, to }) => {
const displayNameHtml = { __html: from.display_name_html };
const MovedNote: React.FC<IMovedNote> = ({ from, to }) => (
<div className='account__moved-note'>
<HStack className='mb-2' alignItems='center' space={1.5}>
<Icon
src={require('@tabler/icons/briefcase.svg')}
className='text-primary-600 dark:text-primary-400 flex-none'
/>
return (
<div className='account__moved-note'>
<div className='account__moved-note__message'>
<div className='account__moved-note__icon-wrapper'><Icon src={require('feather-icons/dist/icons/briefcase.svg')} className='account__moved-note__icon' fixedWidth /></div>
<FormattedMessage id='account.moved_to' defaultMessage='{name} has moved to:' values={{ name: <bdi><strong dangerouslySetInnerHTML={displayNameHtml} /></bdi> }} />
<div className='truncate'>
<Text theme='muted' size='sm' truncate>
<FormattedMessage
id='notification.move'
defaultMessage='{name} moved to {targetName}'
values={{
name: <span dangerouslySetInnerHTML={{ __html: from.display_name_html }} />,
targetName: to.acct,
}}
/>
</Text>
</div>
</HStack>
<NavLink to={`/@${to.acct}`} className='detailed-status__display-name'>
<div className='detailed-status__display-avatar'><AvatarOverlay account={to} friend={from} /></div>
<DisplayName account={to} />
</NavLink>
</div>
);
};
<Account account={to} withRelationship={false} />
</div>
);
export default MovedNote;

@ -63,7 +63,7 @@ const Aliases = () => {
<FormattedMessage id='empty_column.aliases.suggestions' defaultMessage='There are no account suggestions available for the provided term.' />
</div>
) : (
<div className='aliases__accounts'>
<div className='aliases__accounts mb-4'>
{searchAccountIds.map(accountId => <Account key={accountId} accountId={accountId} aliases={aliases} />)}
</div>
)

@ -449,6 +449,7 @@ const Audio: React.FC<IAudio> = (props) => {
onMouseLeave={handleMouseLeave}
tabIndex={0}
onKeyDown={handleKeyDown}
onClick={e => e.stopPropagation()}
>
<audio
src={src}

@ -13,7 +13,6 @@ import type { AutoSuggestion } from 'soapbox/components/autosuggest-input';
const messages = defineMessages({
option_placeholder: { id: 'compose_form.poll.option_placeholder', defaultMessage: 'Answer #{number}' },
add_option: { id: 'compose_form.poll.add_option', defaultMessage: 'Add an answer' },
remove_option: { id: 'compose_form.poll.remove_option', defaultMessage: 'Remove this answer' },
pollDuration: { id: 'compose_form.poll.duration', defaultMessage: 'Duration' },
removePoll: { id: 'compose_form.poll.remove', defaultMessage: 'Remove poll' },
switchToMultiple: { id: 'compose_form.poll.switch_to_multiple', defaultMessage: 'Change poll to allow multiple answers' },
@ -95,7 +94,9 @@ const Option: React.FC<IOption> = ({
{index > 1 && (
<div>
<Button theme='danger' size='sm' onClick={handleOptionRemove}>Delete</Button>
<Button theme='danger' size='sm' onClick={handleOptionRemove}>
<FormattedMessage id='compose_form.poll.remove_option' defaultMessage='Delete' />
</Button>
</div>
)}
</HStack>

@ -48,8 +48,9 @@ const DomainBlocks: React.FC = () => {
onLoadMore={() => handleLoadMore(dispatch)}
hasMore={hasMore}
emptyMessage={emptyMessage}
className='divide-y divide-gray-200 dark:divide-gray-800'
>
{domains.map((domain) =>
{['gab.com', 'gab.ai'].map((domain) =>
<Domain key={domain} domain={domain} />,
)}
</ScrollableList>

@ -2,14 +2,13 @@ import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { prepareRequest } from 'soapbox/actions/consumer-auth';
import Markup from 'soapbox/components/markup';
import { Button, Card, CardBody, Stack, Text } from 'soapbox/components/ui';
import VerificationBadge from 'soapbox/components/verification-badge';
import RegistrationForm from 'soapbox/features/auth-login/components/registration-form';
import { useAppDispatch, useAppSelector, useFeatures, useSoapboxConfig } from 'soapbox/hooks';
import { capitalize } from 'soapbox/utils/strings';
import './instance-description.css';
const LandingPage = () => {
const dispatch = useAppDispatch();
const features = useFeatures();
@ -114,12 +113,10 @@ const LandingPage = () => {
{instance.title}
</h1>
<Text size='lg'>
<span
className='instance-description'
dangerouslySetInnerHTML={{ __html: instance.short_description || instance.description }}
/>
</Text>
<Markup
size='lg'
dangerouslySetInnerHTML={{ __html: instance.short_description || instance.description }}
/>
</Stack>
</div>
</div>

@ -1,14 +0,0 @@
/* Instance HTML from the API. */
.instance-description a {
@apply underline;
}
.instance-description b,
.instance-description strong {
@apply font-bold;
}
.instance-description i,
.instance-description em {
@apply italic;
}

@ -1,5 +1,4 @@
import classNames from 'clsx';
import React, { useRef } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { FormattedDate, FormattedMessage, useIntl } from 'react-intl';
import Icon from 'soapbox/components/icon';
@ -35,7 +34,17 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
showMedia,
}) => {
const intl = useIntl();
const node = useRef<HTMLDivElement>(null);
const overlay = useRef<HTMLDivElement>(null);
const [minHeight, setMinHeight] = useState(208);
useEffect(() => {
if (overlay.current) {
setMinHeight(overlay.current.getBoundingClientRect().height);
}
}, [overlay.current]);
const handleOpenCompareHistoryModal = () => {
onOpenCompareHistoryModal(status);
@ -87,17 +96,15 @@ const DetailedStatus: React.FC<IDetailedStatus> = ({
<StatusReplyMentions status={actualStatus} />
<Stack
className={
classNames('relative z-0', {
'min-h-[220px]': isUnderReview || isSensitive,
})
}
className='relative z-0'
style={{ minHeight: isUnderReview || isSensitive ? Math.max(minHeight, 208) + 12 : undefined }}
>
{(isUnderReview || isSensitive) && (
<SensitiveContentOverlay
status={status}
visible={showMedia}
onToggleVisibility={onToggleMediaVisibility}
ref={overlay}
/>
)}

@ -402,7 +402,7 @@ const Thread: React.FC<IThread> = (props) => {
offset: -80,
});
setImmediate(() => statusRef.current?.querySelector<HTMLDivElement>('.detailed-status')?.focus());
setImmediate(() => statusRef.current?.querySelector<HTMLDivElement>('.detailed-actualStatus')?.focus());
}, [props.params.statusId, status?.id, ancestorsIds.size, isLoaded]);
const handleRefresh = () => {
@ -456,11 +456,11 @@ const Thread: React.FC<IThread> = (props) => {
const titleMessage = status.visibility === 'direct' ? messages.titleDirect : messages.title;
const focusedStatus = (
<div className={classNames('thread__detailed-status', { 'pb-4': hasDescendants })} key={status.id}>
<div className={classNames({ 'pb-4': hasDescendants })} key={status.id}>
<HotKeys handlers={handlers}>
<div
ref={statusRef}
className='detailed-status__wrapper focusable relative'
className='focusable relative'
tabIndex={0}
// FIXME: no "reblogged by" text is added for the screen reader
aria-label={textForScreenReader(intl, status)}

@ -32,7 +32,7 @@ const BundleModalError: React.FC<IBundleModalError> = ({ onRetry, onClose }) =>
<div>
<button
onClick={onClose}
className='error-modal__nav onboarding-modal__skip'
className='error-modal__nav'
>
{intl.formatMessage(messages.close)}
</button>

@ -11,7 +11,7 @@ const ModalLoading = () => (
</div>
<div className='error-modal__footer'>
<div>
<button className='error-modal__nav onboarding-modal__skip' />
<button className='error-modal__nav' />
</div>
</div>
</div>

@ -246,6 +246,7 @@ const ReportModal = ({ onClose }: IReportModal) => {
<Modal
title={renderTitle()}
onClose={onClose}
cancelText={<FormattedMessage id='common.cancel' defaultMessage='Cancel' />}
cancelAction={currentStep === Steps.THREE ? undefined : onClose}
confirmationAction={handleNextStep}
confirmationText={confirmationText}

@ -2,7 +2,8 @@ import classNames from 'clsx';
import React from 'react';
import { defineMessages, useIntl, FormattedMessage, FormatDateOptions } from 'react-intl';
import { Widget, Stack, HStack, Icon, Text } from 'soapbox/components/ui';
import Markup from 'soapbox/components/markup';
import { Widget, Stack, HStack, Icon } from 'soapbox/components/ui';
import BundleContainer from 'soapbox/features/ui/containers/bundle-container';
import { CryptoAddress } from 'soapbox/features/ui/util/async-components';
@ -51,7 +52,7 @@ const ProfileField: React.FC<IProfileField> = ({ field }) => {
return (
<dl>
<dt title={field.name}>
<Text weight='bold' tag='span' dangerouslySetInnerHTML={{ __html: field.name_emojified }} />
<Markup weight='bold' tag='span' dangerouslySetInnerHTML={{ __html: field.name_emojified }} />
</dt>
<dd
@ -65,7 +66,7 @@ const ProfileField: React.FC<IProfileField> = ({ field }) => {
</span>
)}
<Text className='break-words overflow-hidden' tag='span' dangerouslySetInnerHTML={{ __html: field.value_emojified }} />
<Markup className='break-words overflow-hidden' tag='span' dangerouslySetInnerHTML={{ __html: field.value_emojified }} />
</HStack>
</dd>
</dl>

@ -4,6 +4,7 @@ import React from 'react';
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
import Badge from 'soapbox/components/badge';
import Markup from 'soapbox/components/markup';
import { Icon, HStack, Stack, Text } from 'soapbox/components/ui';
import VerificationBadge from 'soapbox/components/verification-badge';
import { useSoapboxConfig } from 'soapbox/hooks';
@ -139,13 +140,6 @@ const ProfileInfoPanel: React.FC<IProfileInfoPanel> = ({ account, username }) =>
return (
<div className='mt-6 min-w-0 flex-1 sm:px-2'>
<Stack space={2}>
{/* Not sure if this is actual used. */}
{/* <div className='profile-info-panel-content__deactivated'>
<FormattedMessage
id='account.deactivated_description' defaultMessage='This account has been deactivated.'
/>
</div> */}
<Stack>
<HStack space={1} alignItems='center'>
<Text size='lg' weight='bold' dangerouslySetInnerHTML={displayNameHtml} />
@ -178,8 +172,8 @@ const ProfileInfoPanel: React.FC<IProfileInfoPanel> = ({ account, username }) =>
<ProfileStats account={account} />
{account.note.length > 0 && account.note !== '<p></p>' && (
<Text size='sm' dangerouslySetInnerHTML={content} />
{account.note.length > 0 && (
<Markup size='sm' dangerouslySetInnerHTML={content} />
)}
<div className='flex flex-col md:flex-row items-start md:flex-wrap md:items-center gap-2'>

@ -5,7 +5,7 @@ import { useDispatch } from 'react-redux';
import { openModal } from 'soapbox/actions/modals';
import { expandAccountMediaTimeline } from 'soapbox/actions/timelines';
import { Spinner, Widget } from 'soapbox/components/ui';
import { Spinner, Text, Widget } from 'soapbox/components/ui';
import { useAppSelector } from 'soapbox/hooks';
import { getAccountGallery } from 'soapbox/selectors';
@ -52,7 +52,7 @@ const ProfileMediaPanel: React.FC<IProfileMediaPanel> = ({ account }) => {
if (!nineAttachments.isEmpty()) {
return (
<div className='media-panel__list'>
<div className='flex flex-wrap'>
{nineAttachments.map((attachment, _index) => (
<MediaItem
key={`${attachment.getIn(['status', 'id'])}+${attachment.id}`}
@ -65,9 +65,9 @@ const ProfileMediaPanel: React.FC<IProfileMediaPanel> = ({ account }) => {
);
} else {
return (
<div className='media-panel__empty'>
<Text size='sm' theme='muted'>
<FormattedMessage id='media_panel.empty_message' defaultMessage='No media found.' />
</div>
</Text>
);
}
};
@ -75,7 +75,7 @@ const ProfileMediaPanel: React.FC<IProfileMediaPanel> = ({ account }) => {
return (
<Widget title={<FormattedMessage id='media_panel.title' defaultMessage='Media' />}>
{account && (
<div className='media-panel__content'>
<div className='w-full py-2'>
{loading ? (
<Spinner />
) : (

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Publish",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Раздумай",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Publish",

File diff suppressed because it is too large Load Diff

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Publish",

@ -4,7 +4,7 @@
"accordion.expand": "הרחבה",
"account.add_or_remove_from_list": "הוסף או הסר מהרשימות",
"account.badges.bot": "בוט",
"account.birthday": "Born {date}",
"account.birthday": "נולד ב-{date}",
"account.birthday_today": "Birthday is today!",
"account.block": "חסימת @{name}",
"account.block_domain": "להסתיר הכל מהקהילה {domain}",
@ -122,11 +122,11 @@
"admin_nav.dashboard": "לוח מחוונים",
"admin_nav.reports": "דיווחים",
"alert.unexpected.body": "We're sorry for the interruption. If the problem persists, please reach out to our support team. You may also try to {clearCookies} (this will log you out).",
"alert.unexpected.browser": "Browser",
"alert.unexpected.browser": "דפדפן",
"alert.unexpected.clear_cookies": "נקה קובצי 'עוגיות' ונתוני דפדפן",
"alert.unexpected.links.help": "Help Center",
"alert.unexpected.links.status": "Status",
"alert.unexpected.links.support": "Support",
"alert.unexpected.links.status": "סטטוס",
"alert.unexpected.links.support": "תמיכה",
"alert.unexpected.message": "אירעה שגיאה בלתי צפויה.",
"alert.unexpected.return_home": "חזור הביתה",
"alert.unexpected.title": "אופס!",
@ -154,8 +154,8 @@
"backups.empty_message": "לא נמצאו גיבויים. {action}",
"backups.empty_message.action": "האם ליצור אחד עכשיו?",
"backups.pending": "בהמתנה",
"beta.also_available": "Available in:",
"birthday_panel.title": "Birthdays",
"beta.also_available": "זמין ב:",
"birthday_panel.title": "ימי הולדת",
"boost_modal.combo": "ניתן להקיש {combo} כדי לדלג בפעם הבאה",
"bundle_column_error.body": "משהו השתבש בעת הצגת הרכיב הזה.",
"bundle_column_error.retry": "לנסות שוב",
@ -257,7 +257,7 @@
"column_forbidden.body": "אין לך הרשאה לגשת לדף זה.",
"column_forbidden.title": "אסור",
"column_header.show_settings": "הצגת העדפות",
"common.cancel": "Cancel",
"common.cancel": "בטל",
"community.column_settings.media_only": "רק מדיה",
"community.column_settings.title": "הגדרות ציר זמן מקומי",
"compose.character_counter.title": "השתמת ב{chars} מתוך {maxChars} תווים",
@ -345,21 +345,21 @@
"crypto_donate_panel.heading": "תרום מטבעות קריפטו",
"crypto_donate_panel.intro.message": "{siteTitle} מקבל תרומות של מטבעות קריפטוגרפיים כדי לממן את השירות שלנו. תודה על תמיכתך!",
"datepicker.hint": "מתוכנן לפרסם ב...",
"datepicker.next_month": "Next month",
"datepicker.next_year": "Next year",
"datepicker.previous_month": "Previous month",
"datepicker.previous_year": "Previous year",
"developers.challenge.answer_label": "Answer",
"developers.challenge.answer_placeholder": "Your answer",
"developers.challenge.fail": "Wrong answer",
"datepicker.next_month": "חודש הבא",
"datepicker.next_year": "שנה הבאה",
"datepicker.previous_month": "חודש קודם",
"datepicker.previous_year": "שנה קודמת",
"developers.challenge.answer_label": "תשובה",
"developers.challenge.answer_placeholder": "התשובה שלך",
"developers.challenge.fail": "תשובה שגויה",
"developers.challenge.message": "What is the result of calling {function}?",
"developers.challenge.submit": "Become a developer",
"developers.challenge.success": "You are now a developer",
"developers.challenge.success": "אתה עכשיו מפתח",
"developers.leave": "You have left developers",
"developers.navigation.app_create_label": "צור אפליקציה",
"developers.navigation.intentional_error_label": "הפעלת שגיאה",
"developers.navigation.leave_developers_label": "Leave developers",
"developers.navigation.network_error_label": "Network error",
"developers.navigation.network_error_label": "שגיאת רשת",
"developers.navigation.settings_store_label": "Settings store",
"developers.navigation.test_timeline_label": "Test timeline",
"developers.settings_store.hint": "It is possible to directly edit your user settings here. BE CAREFUL! Editing this section can break your account, and you will only be able to recover through the API.",
@ -375,7 +375,7 @@
"edit_federation.save": "שמור",
"edit_federation.success": "הפדרציה של {host} עודכנה",
"edit_federation.unlisted": "לכפות פוסטים כלא רשומים",
"edit_password.header": "Change Password",
"edit_password.header": "שנה סיסמא",
"edit_profile.error": "עדכון הפרופיל נכשל",
"edit_profile.fields.accepts_email_list_label": "הירשם לעדכונים",
"edit_profile.fields.avatar_label": "אווטאר",
@ -395,9 +395,9 @@
"edit_profile.fields.meta_fields.content_placeholder": "תוכן",
"edit_profile.fields.meta_fields.label_placeholder": "תווית",
"edit_profile.fields.stranger_notifications_label": "חסום התראות מזרים",
"edit_profile.fields.website_label": "Website",
"edit_profile.fields.website_label": "אתר",
"edit_profile.fields.website_placeholder": "Display a Link",
"edit_profile.header": "Edit Profile",
"edit_profile.header": "ערוך פרופיל",
"edit_profile.hints.accepts_email_list": "הצטרפו לעדכוני חדשות ועדכונים שיווקיים.",
"edit_profile.hints.avatar": "PNG, GIF או JPG. יוקטן ל-{size}",
"edit_profile.hints.bot": "חשבון זה מבצע בעיקר פעולות אוטומטיות וייתכן שלא יהיה פיקוח",
@ -409,13 +409,13 @@
"edit_profile.save": "שמירה",
"edit_profile.success": "הפרופיל נשמר!",
"email_passthru.confirmed.body": "Close this tab and continue the registration process on the {bold} from which you sent this email confirmation.",
"email_passthru.confirmed.heading": "Email Confirmed!",
"email_passthru.confirmed.heading": "אימייל אומת!",
"email_passthru.generic_fail.body": "Please request a new email confirmation.",
"email_passthru.generic_fail.heading": "Something Went Wrong",
"email_passthru.generic_fail.heading": "משהו השתבש",
"email_passthru.token_expired.body": "Your email token has expired. Please request a new email confirmation from the {bold} from which you sent this email confirmation.",
"email_passthru.token_expired.heading": "Token Expired",
"email_passthru.token_expired.heading": "טוקן פג תוקף",
"email_passthru.token_not_found.body": "Your email token was not found. Please request a new email confirmation from the {bold} from which you sent this email confirmation.",
"email_passthru.token_not_found.heading": "Invalid Token",
"email_passthru.token_not_found.heading": "טוקן לא תקין",
"embed.instructions": "ניתן להטמיע את ההודעה באתרך ע\"י העתקת הקוד שלהלן.",
"embed.preview": "דוגמא כיצד זה יראה:",
"emoji_button.activity": "פעילות",
@ -564,8 +564,8 @@
"import_data.success.blocks": "חסימות יובאו בהצלחה",
"import_data.success.followers": "מעקבים יובאו בהצלחה",
"import_data.success.mutes": "השתקות יובאו בהצלחה",
"input.password.hide_password": "Hide password",
"input.password.show_password": "Show password",
"input.password.hide_password": "הסתר סיסמא",
"input.password.show_password": "הצג סיסמא",
"intervals.full.days": "{number, plural, one {# יום} other {# ימים}}",
"intervals.full.hours": "{number, plural, one {# שעה} other {# שעות}}",
"intervals.full.minutes": "{number, plural, one {# דקה} other {# דקות}}",
@ -635,7 +635,7 @@
"login.fields.otp_code_hint": "הזן את קוד שני הגורמים שנוצר על ידי אפליקציות הטלפון שלך או השתמש באחד מקודי השחזור שלך",
"login.fields.otp_code_label": "קוד דו גורמי:",
"login.fields.password_placeholder": "סיסמא",
"login.fields.username_label": "Email or username",
"login.fields.username_label": "שם משתמש או אימייל",
"login.log_in": "התחברות",
"login.otp_log_in": "התחברות OTP",
"login.reset_password_hint": "בעיה בהתחברות?",
@ -659,12 +659,12 @@
"mfa.setup_warning": "רשום את הקודים האלה או שמור אותם במקום מאובטח - אחרת לא תראה אותם שוב. אם תאבד את הגישה לאפליקציית 2FA ולקודי השחזור שלך תינעל מחוץ לחשבון שלך.",
"migration.fields.acct.label": "Handle of the new account",
"migration.fields.acct.placeholder": "username@domain",
"migration.fields.confirm_password.label": "Current password",
"migration.fields.confirm_password.label": "סיסמא נוכחית",
"migration.hint": "This will move your followers to the new account. No other data will be moved. To perform migration, you need to {link} on your new account first.",
"migration.hint.link": "create an account alias",
"migration.move_account.fail": "Account migration failed.",
"migration.move_account.success": "Account successfully moved.",
"migration.submit": "Move followers",
"migration.move_account.fail": "העברת חשבון נכשלה.",
"migration.move_account.success": "חשבון הועבר בהצלחה.",
"migration.submit": "העבר עוקבים",
"missing_description_modal.cancel": "בטל",
"missing_description_modal.continue": "שלח",
"missing_description_modal.description": "המשך בכל זאת?",
@ -720,8 +720,8 @@
"notifications.clear_confirmation": "להסיר את כל ההתראות? בטוח?",
"notifications.clear_heading": "Clear notifications",
"notifications.column_settings.alert": "התראות לשולחן העבודה",
"notifications.column_settings.birthdays.category": "Birthdays",
"notifications.column_settings.birthdays.show": "Show birthday reminders",
"notifications.column_settings.birthdays.category": "ימי הולדת",
"notifications.column_settings.birthdays.show": "הראה תזכורות לימי הולדת",
"notifications.column_settings.emoji_react": "הגבות אימוג'י:",
"notifications.column_settings.favourite": "מחובבים:",
"notifications.column_settings.filter_bar.advanced": "הצג את כל הקטגוריות",
@ -891,7 +891,7 @@
"security.fields.email.label": "אימייל",
"security.fields.new_password.label": "סיסמא חדשה",
"security.fields.old_password.label": "סיסמא נוכחית",
"security.fields.password.label": "Password",
"security.fields.password.label": "סיסמא",
"security.fields.password_confirmation.label": "סיסמא חדשה (שוב)",
"security.headers.delete": "מחק חשבון",
"security.headers.tokens": "הפעלות",
@ -910,16 +910,16 @@
"security.update_email.success": "האימייל עודכן בהצלחה.",
"security.update_password.fail": "עדכון הסיסמא נכשל.",
"security.update_password.success": "הסיסמה עודכנה בהצלחה.",
"settings.change_email": "Change Email",
"settings.change_password": "Change Password",
"settings.change_email": "שנה אימייל",
"settings.change_password": "שנה סיסמא",
"settings.configure_mfa": "Configure MFA",
"settings.delete_account": "Delete Account",
"settings.edit_profile": "Edit Profile",
"settings.delete_account": "מחק חשבון",
"settings.edit_profile": "ערוך פרופיל",
"settings.preferences": "Preferences",
"settings.profile": "Profile",
"settings.profile": "פרופיל",
"settings.save.success": "Your preferences have been saved!",
"settings.security": "Security",
"settings.settings": "Settings",
"settings.settings": "הגדרות",
"signup_panel.subtitle": "הירשם כעת כדי לדון.",
"signup_panel.title": "חדש ל{site_title}?",
"snackbar.view": "View",
@ -1029,12 +1029,12 @@
"tabs_bar.dashboard": "לוח מחוונים",
"tabs_bar.fediverse": "פדרציה",
"tabs_bar.home": "בית",
"tabs_bar.more": "More",
"tabs_bar.more": "עוד",
"tabs_bar.notifications": "התראות",
"tabs_bar.post": "פוסט",
"tabs_bar.profile": "Profile",
"tabs_bar.profile": "פרופיל",
"tabs_bar.search": "חיפוש",
"tabs_bar.settings": "Settings",
"tabs_bar.settings": "הגדרות",
"tabs_bar.theme_toggle_dark": "עבור לערכת נושא כהה",
"tabs_bar.theme_toggle_light": "עבור לערכת נושא בהירה",
"time_remaining.days": "{number, plural, one {# יום} other {# ימים}} נותרו",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Publish",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Publish",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Թթել",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Siflar",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "ტუტი",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Publish",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Publicēt",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Publish",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Publish",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Tut",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Postează",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Mesazh",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Tutni",

@ -274,7 +274,7 @@
"compose_form.poll.add_option": "Add a choice",
"compose_form.poll.duration": "Poll duration",
"compose_form.poll.option_placeholder": "Choice {number}",
"compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.remove_option": "Delete",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Труби",

@ -277,6 +277,15 @@ const fixBirthday = (account: ImmutableMap<string, any>) => {
return account.set('birthday', birthday || '');
};
/** Rewrite `<p></p>` to empty string. */
const fixNote = (account: ImmutableMap<string, any>) => {
if (account.get('note') === '<p></p>') {
return account.set('note', '');
} else {
return account;
}
};
export const normalizeAccount = (account: Record<string, any>) => {
return AccountRecord(
ImmutableMap(fromJS(account)).withMutations(account => {
@ -298,6 +307,7 @@ export const normalizeAccount = (account: Record<string, any>) => {
fixUsername(account);
fixDisplayName(account);
fixBirthday(account);
fixNote(account);
addInternalFields(account);
}),
);

@ -29,15 +29,6 @@
border-bottom: 1px solid var(--brand-color--med);
}
&.compact {
padding: 0;
border-bottom: 0;
.account__avatar-wrapper {
margin-left: 0;
}
}
.account__display-name {
flex: 1 1 auto;
display: block;
@ -50,13 +41,6 @@
display: flex;
}
}
&__note {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--primary-text-color--faint);
}
}
.account__wrapper {
@ -69,30 +53,6 @@
margin-right: 12px;
}
.account__avatar {
@include avatar-radius;
position: relative;
background-color: var(--brand-color--faint);
&-inline {
display: inline-block;
vertical-align: middle;
margin-right: 5px;
}
&-composite {
@include avatar-radius;
overflow: hidden;
& > div {
@include avatar-radius;
float: left;
position: relative;
box-sizing: border-box;
}
}
}
a .account__avatar {
cursor: pointer;
}
@ -136,16 +96,6 @@ a .account__avatar {
}
}
.account-authorize {
padding: 14px 10px;
.detailed-status__display-name {
display: block;
margin-bottom: 15px;
overflow: hidden;
}
}
.account-authorize__avatar {
float: left;
margin-right: 10px;
@ -230,35 +180,6 @@ a .account__avatar {
left: -26px;
position: absolute;
}
.detailed-status__display-avatar {
position: relative;
}
.detailed-status__display-name {
margin-bottom: 0;
}
}
.relationship-tag {
color: var(--primary-text-color);
margin-bottom: 4px;
margin-left: 4px;
display: block;
vertical-align: top;
background-color: var(--background-color);
text-transform: uppercase;
font-size: 11px;
font-weight: 500;
padding: 4px;
border-radius: 4px;
opacity: 0.7;
white-space: nowrap;
transition: 0.2s;
&:hover {
opacity: 1;
}
}
.account__joined-at {

@ -21,7 +21,6 @@
@import 'rtl';
@import 'accessibility';
@import 'dyslexic';
@import 'demetricator';
@import 'chats';
@import 'navigation';
@import 'placeholder';
@ -46,8 +45,6 @@
@import 'components/search';
@import 'components/react-toggle';
@import 'components/still-image';
@import 'components/profile-media-panel';
@import 'components/profile-info-panel';
@import 'components/spoiler-button';
@import 'components/video-player';
@import 'components/audio-player';

@ -14,10 +14,6 @@
.search--account {
border-top: 1px solid hsla(var(--primary-text-color_hsl), 0.2);
padding: 5px;
input.search__input {
border-radius: 6px;
}
}
&__header {
@ -64,17 +60,6 @@
transform: translateY(2px);
}
}
.icon-with-badge__badge {
position: static;
pointer-events: none;
width: 18px;
height: 18px;
display: flex;
align-items: center;
justify-content: center;
margin-right: 7px;
}
}
&__content {
@ -224,13 +209,6 @@
}
}
}
.icon-with-badge__badge {
top: 0;
right: 0;
left: auto;
bottom: auto;
}
}
.chat-box {
@ -321,16 +299,6 @@
}
}
.chatroom__back {
display: flex;
align-items: center;
background: var(--accent-color--faint);
.column-back-button {
background: transparent;
}
}
.chat {
&__attachment-icon {
float: right;

@ -1,43 +1,4 @@
.account__header__subscribe {
position: absolute;
top: 10px;
right: 10px;
right: max(10px, env(safe-area-inset-right));
z-index: 1;
.subscription-button {
color: var(--primary-text-color);
margin-bottom: 4px;
display: flex;
align-items: center;
justify-content: center;
background-color: var(--background-color);
text-transform: uppercase;
font-size: 13px;
font-weight: 500;
padding: 4px;
border-radius: 4px;
opacity: 0.7;
&:active,
&:focus,
&:hover {
opacity: 1;
}
&:not(.button-active) i.fa {
margin: 0;
}
.svg-icon {
width: 20px;
height: 20px;
}
}
}
.account__header__content {
color: var(--primary-text-color--faint);
font-size: 14px;
font-weight: 400;
overflow: hidden;

@ -1,53 +1,3 @@
.columns-area {
display: flex;
flex: 1 1 auto;
flex-direction: row;
justify-content: flex-start;
position: relative;
&__panels {
display: flex;
justify-content: center;
width: 100%;
height: 100%;
&__pane {
height: 100%;
pointer-events: none;
display: flex;
justify-content: flex-end;
padding-top: 15px;
&--start {
justify-content: flex-start;
}
&__inner {
width: 265px;
pointer-events: auto;
height: 100%;
}
}
&__main {
display: flex;
flex-direction: column;
box-sizing: border-box;
width: 100%;
max-width: 600px;
padding: 0 20px;
@media screen and (max-width: 580px) {
padding: 0;
}
@media screen and (min-width: 896px) {
margin: 0 20px;
padding: 0;
}
}
}
}
.column {
width: 350px;
@ -59,10 +9,6 @@
}
@media screen and (min-width: 631px) {
.columns-area {
padding: 0;
}
.column {
flex: 0 0 auto;
padding: 10px;
@ -77,154 +23,6 @@
padding-right: 10px;
}
}
.columns-area > div {
.column {
padding-left: 5px;
padding-right: 5px;
}
}
}
.columns-area {
display: block;
flex-direction: column;
width: 100%;
margin: 0 auto;
padding-top: 15px;
@media screen and (max-width: 580px) {
padding-top: 0;
}
.column {
width: 100%;
padding: 0;
}
.search__input {
line-height: 18px;
font-size: 16px;
padding: 15px;
padding-right: 30px;
border-radius: 0;
background-color: var(--foreground-color);
}
.search__icon .fa {
top: 15px;
}
@media (max-width: 580px) {
.timeline-compose-block {
border-radius: 0;
margin-top: 10px;
}
}
@media screen and (min-width: 630px) {
.detailed-status {
padding: 15px;
.media-gallery,
.video-player {
margin-top: 15px;
}
}
.compose-form {
padding: 15px;
}
.status {
padding: 15px 15px 15px (48px + 15px * 2);
min-height: 48px + 2px;
&__avatar {
left: 15px;
top: 17px;
}
&__content {
padding-top: 5px;
}
&__prepend {
margin-left: 48px + 15px * 2;
padding-top: 15px;
}
&__prepend-icon-wrapper {
left: -32px;
}
.media-gallery,
.video-player {
margin-top: 10px;
}
}
.account {
padding: 15px 10px;
}
.notification {
&__message {
margin-left: 48px + 15px * 2;
padding-top: 15px;
}
&__favourite-icon-wrapper {
left: -32px;
}
.status {
padding-top: 8px;
}
.account {
padding-top: 8px;
}
.account__avatar-wrapper {
margin-left: 17px;
margin-right: 15px;
}
}
}
}
// This controls where the left column breaks.
@media screen and (max-width: 600px + (285px * 1) + (10px * 1)) {
.columns-area__panels__pane--left {
display: none;
}
}
@media screen and (max-width: 600px + (285px * 2) + (10px * 2)) {
.columns-area__panels__pane--right {
display: none;
}
}
.column-back-button {
background: var(--accent-color--faint);
color: var(--highlight-text-color);
cursor: pointer;
flex: 0 0 auto;
font-size: 16px;
line-height: inherit;
border: 0;
text-align: unset;
padding: 15px;
margin: 0;
z-index: 3;
outline: 0;
&:hover,
&:focus {
text-decoration: underline;
}
}
.column-link {
@ -289,24 +87,6 @@
cursor: default;
}
.columns-area .column {
@include standard-panel;
&--transparent {
background: transparent;
border-radius: 0;
box-shadow: none;
}
@media screen and (max-width: 580px) {
border-radius: 0;
.material-status__status {
border-radius: 0;
}
}
}
.column-header__wrapper {
position: relative;
flex: 0 0 auto;
@ -611,10 +391,6 @@
}
}
.column-link--transparent .icon-with-badge__badge {
border-color: var(--background-color);
}
.column__switch .audio-toggle {
position: absolute;
z-index: 4;
@ -663,79 +439,3 @@
}
}
}
.column-title {
text-align: center;
padding: 40px;
.logo {
fill: var(--primary-text-color);
width: 50px;
margin: 0 auto;
margin-bottom: 40px;
}
h3 {
font-size: 24px;
line-height: 1.5;
font-weight: 700;
margin-bottom: 10px;
}
p {
font-size: 16px;
line-height: 24px;
font-weight: 400;
color: var(--primary-text-color--faint);
}
}
.column-actions {
display: flex;
align-items: center;
justify-content: center;
padding: 40px;
padding-top: 40px;
&__background {
position: absolute;
left: 0;
bottom: 0;
height: 220px;
width: auto;
}
}
.column-list {
position: relative;
&__empty-message {
padding: 0 20px;
}
}
.follow_subhead {
margin: 50px 0;
font-size: 20px;
}
// Pull to refresh
.columns-area .column {
.ptr,
.ptr__children {
background: var(--foreground-color);
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
@media screen and (max-width: 580px) {
border-radius: 0;
}
}
&--transparent {
.ptr,
.ptr__children {
background: transparent;
}
}
}

@ -1,32 +1,4 @@
.compose-form {
&__sensitive-button {
padding: 10px;
padding-top: 0;
font-size: 14px;
font-weight: 500;
&.active { color: var(--highlight-text-color); }
input[type=checkbox] { display: none; }
.checkbox {
display: inline-block;
position: relative;
border: 1px solid var(--brand-color);
box-sizing: border-box;
width: 18px;
height: 18px;
flex: 0 0 auto;
margin-right: 10px;
top: -1px;
border-radius: 4px;
vertical-align: middle;
&.active {
border-color: var(--highlight-text-color);
background: var(--highlight-text-color);
}
}
}
&__warning {
@apply text-xs mb-2.5 px-2.5 py-2 shadow-md rounded bg-accent-300 text-white;
@ -145,24 +117,6 @@
}
}
} // end .compose-form .compose-form__modifiers
&__publish {
display: flex;
justify-content: flex-end;
min-width: 0;
flex: 0 0 auto;
.compose-form__publish-button-wrapper {
overflow: hidden;
}
}
&__counter {
display: flex;
align-items: center;
align-self: center;
margin-left: auto;
}
} // end .compose-form
.privacy-dropdown__dropdown {

@ -1,96 +1,3 @@
.detailed-status {
// padding: 14px 10px;
&--flex {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: flex-start;
.status__content {
flex: 100%;
}
}
.status__content {
font-size: 19px;
line-height: 24px;
.emojione {
width: 24px;
height: 24px;
margin: -1px 0 0;
}
&--big {
img.emojione {
width: 56px;
height: 56px;
}
}
}
.video-player,
.audio-player {
margin-top: 8px;
}
}
.detailed-status__timestamp {
display: flex;
align-items: center;
.svg-icon {
width: 20px;
height: 20px;
svg {
stroke-width: 1.3px;
}
}
.svg-icon {
margin-right: 5px;
}
}
.detailed-status__wrapper {
position: relative;
}
.detailed-status__display-name {
color: var(--primary-text-color--faint);
display: flex;
line-height: 24px;
margin-bottom: 15px;
overflow: hidden;
strong,
span {
text-overflow: ellipsis;
overflow: hidden;
}
strong {
font-size: 16px;
color: var(--primary-text-color);
}
span.hover-ref-wrapper {
display: inline;
}
.display-name__account {
display: block;
margin-top: -5px;
}
}
.detailed-status__display-avatar {
float: left;
margin-right: 10px;
}
.thread {
@apply bg-white dark:bg-primary-900 p-4 shadow-xl dark:shadow-none sm:p-6 sm:rounded-xl;

@ -1,10 +1,7 @@
.status__display-name,
.detailed-status__display-name,
.account__display-name {
text-decoration: none;
}
.status__display-name,
.account__display-name {
strong {
@apply text-gray-800 dark:text-gray-200;
@ -17,8 +14,6 @@
}
}
.status__display-name,
.detailed-status__display-name,
a.account__display-name {
&:hover strong {
text-decoration: underline;

@ -86,11 +86,6 @@
}
}
.detailed-status__wrapper .emoji-react-selector {
bottom: 40px;
right: 10px;
}
.status .emoji-react-selector {
bottom: 100%;
left: -20px;

@ -92,8 +92,7 @@
}
}
.status__wrapper,
.detailed-status__wrapper {
.status__wrapper {
.media-gallery__item-thumbnail.letterboxed {
&,
.still-image {

@ -6,18 +6,6 @@
overflow-y: hidden;
}
.video-modal {
max-width: 100vw;
max-height: 100vh;
position: relative;
}
.video-modal {
.video-player video {
height: auto;
}
}
.media-modal {
width: 100%;
height: 100%;
@ -176,7 +164,6 @@
}
}
.onboarding-modal,
.error-modal {
background: var(--background-color);
color: var(--primary-text-color);
@ -229,7 +216,6 @@
min-width: 33px;
}
.onboarding-modal__nav,
.error-modal__nav {
color: var(--highlight-text-color);
border: 0;
@ -266,12 +252,9 @@
position: relative;
flex-direction: column;
overflow: hidden;
width: 480px;
max-width: 90vw;
border-radius: 10px;
border: 1px solid var(--background-color);
color: var(--primary-text-color--faint);
background: var(--foreground-color);
.status__display-name {
display: block;

@ -1,4 +0,0 @@
.profile-info-panel-content__deactivated {
color: var(--primary-text-color--faint);
display: block;
}

@ -1,16 +0,0 @@
.media-panel {
&__content {
width: 100%;
padding: 8px 0;
}
&__list {
display: flex;
flex-wrap: wrap;
}
&__empty {
font-size: 14px;
color: var(--primary-text-color--faint);
}
}

@ -6,8 +6,7 @@
}
}
.status__wrapper,
.detailed-status {
.status__wrapper {
.reply-mentions {
display: block;

@ -2,12 +2,6 @@
position: relative;
}
input.search__input {
@include search-input;
display: block;
padding: 7px 30px 6px 10px;
}
.search__icon {
&::-moz-focus-inner {
border: 0;
@ -55,52 +49,6 @@ input.search__input {
}
}
.search-header {
display: block;
width: 100%;
&__text-container {
display: none;
padding: 25px 0;
background-color: var(--accent-color--med);
@media (min-width: 896px) {
display: block;
}
}
&__title-text {
color: var(--primary-text-color);
font-size: 27px;
font-weight: bold;
line-height: 32px;
overflow: hidden;
padding-left: 20px;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 1200px;
margin: 0 auto;
}
&__type-filters-tabs {
display: flex;
width: 100%;
max-width: 1200px;
margin: 0 auto;
@media screen and (max-width: 895px) {
max-width: 580px;
}
}
@media (min-width: 896px) and (max-width: 1190px) {
&__title-text,
&__type-filters-tabs {
max-width: 900px;
}
}
}
.column {
.search {
padding: 10px 15px;
@ -108,12 +56,6 @@ input.search__input {
border-bottom: 1px solid hsla(var(--primary-text-color_hsl), 0.2);
}
input.search__input {
background-color: var(--background-color);
border-radius: 8px;
padding: 12px 36px 12px 16px;
}
.search__icon .svg-icon {
right: 24px;
}

@ -6,14 +6,6 @@
position: absolute;
z-index: 40;
&--minified {
display: block;
left: 4px;
top: 4px;
width: auto;
height: auto;
}
&--hidden {
display: none;
}

@ -218,21 +218,6 @@ a.status-card {
}
}
@media screen and (min-width: 630px) {
.columns-area .material-status .status {
padding: 15px;
&__avatar {
top: 0;
left: 0;
}
&__content {
padding-top: 10px;
}
}
}
.attachment-thumbs {
position: relative;

@ -1,69 +1,3 @@
.video-error-cover {
align-items: center;
background: var(--background-color);
color: var(--primary-text-color);
cursor: pointer;
display: flex;
flex-direction: column;
height: 100%;
justify-content: center;
position: relative;
text-align: center;
z-index: 100;
}
.status__video-player {
background: var(--background-color);
box-sizing: border-box;
cursor: default; /* May not be needed */
margin-top: 8px;
overflow: hidden;
position: relative;
}
.status__video-player-video {
height: 100%;
object-fit: cover;
position: relative;
top: 50%;
transform: translateY(-50%);
width: 100%;
z-index: 1;
}
.status__video-player-expand,
.status__video-player-mute {
color: var(--primary-text-color);
opacity: 0.8;
position: absolute;
right: 4px;
text-shadow: 0 1px 1px $base-shadow-color, 1px 0 1px $base-shadow-color;
}
.status__video-player-spoiler {
display: none;
color: var(--primary-text-color);
left: 4px;
position: absolute;
text-shadow: 0 1px 1px $base-shadow-color, 1px 0 1px $base-shadow-color;
top: 4px;
z-index: 100;
&.status__video-player-spoiler--visible {
display: block;
}
}
.status__video-player-expand {
bottom: 4px;
z-index: 100;
}
.status__video-player-mute {
top: 4px;
z-index: 5;
}
.detailed,
.fullscreen {
.video-player__volume__current,
@ -423,14 +357,3 @@
border: 0;
display: block;
}
.media-spoiler-video-play-icon {
border-radius: 100px;
color: var(--primary-text-color--faint);
font-size: 36px;
left: 50%;
padding: 5px;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
}

@ -1,5 +0,0 @@
body.demetricator {
.icon-with-badge__badge {
display: none;
}
}

@ -58,25 +58,3 @@
line-height: #{$px + "px"};
line-height: #{$rem + "rem"};
}
// Soapbox icon font
@font-face {
font-family: 'soapbox';
src: url('../assets/fonts/soapbox/soapbox.eot?pryg6i');
src: url('../assets/fonts/soapbox/soapbox.eot?pryg6i#iefix') format('embedded-opentype'),
url('../assets/fonts/soapbox/soapbox.ttf?pryg6i') format('truetype'),
url('../assets/fonts/soapbox/soapbox.woff?pryg6i') format('woff'),
url('../assets/fonts/soapbox/soapbox.svg?pryg6i#soapbox') format('svg');
font-weight: normal;
font-style: normal;
}
.fa-fediverse::before {
font-family: 'soapbox';
content: "\e901";
}
.fa-spinster::before {
font-family: 'soapbox';
content: "\e900";
}

@ -586,38 +586,6 @@ code {
margin-bottom: 14px;
font-weight: bold;
}
.showable-password {
position: relative;
input {
padding-right: 36px;
}
.icon-button {
@apply text-black dark:text-white;
position: absolute;
top: 0;
right: 0;
height: 38px;
width: 36px;
padding: 0;
margin: 0;
background: transparent;
.svg-icon {
height: 20px;
width: 20px;
}
}
}
}
.block-icon {
display: block;
margin: 0 auto;
margin-bottom: 10px;
font-size: 24px;
}
.simple_form {
@ -660,14 +628,6 @@ code {
}
}
.columns-area {
form.simple_form--public {
@include standard-panel;
margin-top: 20px;
padding: 60px 30px;
}
}
.captcha {
background-color: #fff;
border-radius: 4px;

@ -13,11 +13,6 @@ body.rtl {
margin-left: 5px;
}
.search__input {
padding-right: 10px;
padding-left: 30px;
}
.search__icon .fa {
right: auto;
left: 10px;
@ -69,16 +64,6 @@ body.rtl {
margin-right: 0;
}
.detailed-status__display-name .display-name {
text-align: right;
}
.detailed-status__display-avatar {
margin-right: 0;
margin-left: 10px;
float: right;
}
.fa-ul {
margin-left: 0;
margin-left: 2.14285714em;
@ -134,13 +119,6 @@ body.rtl {
padding-right: 10px;
}
}
.columns-area > div {
.column {
padding-left: 5px;
padding-right: 5px;
}
}
}
.public-layout {

@ -151,30 +151,6 @@
.ellipsis::after { content: ""; }
.timeline-compose-block {
@include standard-panel;
display: flex;
align-items: flex-start;
padding: 20px;
margin-bottom: 10px;
.compose-form {
flex: 1 1;
padding: 0 0 0 20px !important;
position: relative;
@media (max-width: 405px) {
padding: 0 !important;
}
}
&__avatar {
display: block;
border-radius: 50%;
@media (max-width: 405px) { display: none; }
}
}
.no-reduce-motion .spoiler-input {
transition: height 0.4s ease, opacity 0.4s ease;
}
@ -193,33 +169,6 @@
}
}
.domain {
padding: 10px;
border-bottom: 1px solid var(--brand-color--med);
.domain__domain-name {
flex: 1 1 auto;
display: block;
color: var(--primary-text-color);
text-decoration: none;
font-size: 14px;
font-weight: 500;
}
&__buttons .svg-icon {
height: 18px;
width: 18px;
}
}
article:last-child > .domain {
border-bottom: none;
}
.domain__wrapper {
display: flex;
}
.image-loader {
position: relative;
width: 100%;
@ -253,7 +202,6 @@ article:last-child > .domain {
.react-swipeable-view-container {
&,
.columns-area,
.column {
height: 100%;
}
@ -320,26 +268,6 @@ article:last-child > .domain {
}
}
.icon-with-badge__badge {
@include font-size(14);
@include line-height(14);
position: absolute;
box-sizing: border-box;
left: -10px;
top: 3px;
min-width: 16px;
height: 16px;
padding: 1px 3px 0;
border-radius: 8px;
text-align: center;
color: #fff;
background: var(--accent-color);
@media screen and (max-width: 895px) {
top: 0;
}
}
.slist {
&--flex {
display: flex;
@ -589,12 +517,6 @@ article:last-child > .domain {
100% { opacity: 1; }
}
.page__top + .page__columns .columns-area {
@media screen and (max-width: 580px) {
padding-top: 10px;
}
}
.text-muted {
color: var(--gray-500);
}

@ -68,6 +68,7 @@
"@sentry/tracing": "^7.11.1",
"@tabler/icons": "^1.111.0",
"@tailwindcss/forms": "^0.5.3",
"@tailwindcss/line-clamp": "^0.4.2",
"@tailwindcss/typography": "^0.5.7",
"@tanstack/react-query": "^4.0.10",
"@testing-library/react": "^12.1.4",

@ -86,6 +86,7 @@ module.exports = {
},
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/line-clamp'),
require('@tailwindcss/typography'),
],
};

@ -2272,6 +2272,11 @@
dependencies:
mini-svg-data-uri "^1.2.3"
"@tailwindcss/line-clamp@^0.4.2":
version "0.4.2"
resolved "https://registry.yarnpkg.com/@tailwindcss/line-clamp/-/line-clamp-0.4.2.tgz#f353c5a8ab2c939c6267ac5b907f012e5ee130f9"
integrity sha512-HFzAQuqYCjyy/SX9sLGB1lroPzmcnWv1FHkIpmypte10hptf4oPUfucryMKovZh2u0uiS9U5Ty3GghWfEJGwVw==
"@tailwindcss/typography@^0.5.7":
version "0.5.7"
resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.7.tgz#e0b95bea787ee14c5a34a74fc824e6fe86ea8855"

Loading…
Cancel
Save