Merge remote-tracking branch 'origin/hardcore-hedgehog' into follow-hashtag

This commit is contained in:
clovis 2023-08-12 18:49:46 +02:00
commit 75cac220f0
15 changed files with 230 additions and 93 deletions

View File

@ -4,6 +4,123 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- Compatibility: rudimentary support for Takahē.
- UI: added backdrop blur behind modals.
- Admin: let admins configure media preview for attachment thumbnails.
- Login: accept `?server` param in external login, eg `fe.soapbox.pub/login/external?server=gleasonator.com`.
- Backups: restored Pleroma backups functionality.
- Export: restored "Export data" to CSV.
### Changed
- Posts: letterbox images to 19:6 again.
- Status Info: moved context (repost, pinned) to improve UX.
- Posts: remove file icon from empty link previews.
- Settings: moved "Import data" under settings.
### Fixed
- Layout: use accent color for "floating action button" (mobile compose button).
- ServiceWorker: don't serve favicon, robots.txt, and others from ServiceWorker.
- Datepicker: correctly default to the current year.
- Scheduled posts: fix page crashing on deleting a scheduled post.
- Events: don't crash when searching for a location.
- Search: fixes an abort error when using the navbar search component.
- Posts: fix monospace font in Markdown code blocks.
- Modals: fix action buttons overflow
- Editing: don't insert edited posts to the top of the feed.
- Modals: close modal when navigating to a different page.
- Modals: fix "View context" button in media modal.
- Posts: let unauthenticated users to translate posts if allowed by backend.
- Chats: fix jumpy scrollbar.
## [3.0.0] - 2022-12-25
### Added
- Editing: ability to edit posts and view edit history (on Rebased, Pleroma, and Mastodon).
- Events: ability to create, view, and comment on Events (on Rebased).
- Onboarding: display an introduction wizard to newly registered accounts.
- Posts: translate foreign language posts into your native language (on Rebased, Mastodon; if configured by the admin).
- Posts: ability to view quotes of a post (on Rebased).
- Posts: hover the "replying to" line to see a preview card of the parent post.
- Chats: ability to leave a chat (on Rebased, Truth Social).
- Chats: ability to disable chats for yourself.
- Layout: added right-to-left support for Arabic, Hebrew, Persian, and Central Kurdish languages.
- Composer: support custom emoji categories.
- Search: ability to search posts from a specific account (on Pleroma, Rebased).
- Theme: auto-detect system theme by default.
- Profile: remove a specific user from your followers (on Rebased, Mastodon).
- Suggestions: ability to view all suggested profiles.
- Feeds: display suggested accounts in Home feed (optional by admin).
- Compatibility: added compatibility with Truth Social, Fedibird, Pixelfed, Akkoma, and Glitch.
- Developers: added Test feed, Service Worker debugger, and Network Error preview.
- Reports: display server rules in reports. Let users select rule violations when submitting a report.
- Admin: added Theme Editor, a GUI for customizing the color scheme.
- Admin: custom badges. Admins can add non-federating badges to any user's profile (on Rebased, Pleroma).
- Admin: consolidated user dropdown actions (verify/suggest/etc) into a unified "Moderate User" modal.
- i18n: updated translations for Italian, Polish, Arabic, Hebrew, and German.
- Toast: added the ability to dismiss toast notifications.
### Changed
- UI: the whole UI has been overhauled both inside and out. 97% of the codebase has been rewritten to TypeScript, and a new component library has been introduced with Tailwind CSS.
- Chats: redesigned chats. Includes an improved desktop UI, unified chat widget, expanding textarea, and autosuggestions.
- Lists: ability to edit and delete a list.
- Settings: unified settings under one path with separate sections.
- Posts: changed the thumbs-up icon to a heart.
- Posts: move instance favicon beside username instead of post timestamp.
- Posts: changed the behavior of content warnings. CWs and sensitive media are unified into one design.
- Posts: redesigned interaction counters to use text instead of icons.
- Posts: letterbox images taller than 1:1.
- Profile: overhauled user profiles to be consistent with the rest of the UI.
- Composer: move emoji button alongside other composer buttons, add numerical counter.
- Birthdays: move today's birthdays out of notifications into right sidebar.
- Performance: improve scrolling/navigation between feeds by using a virtual window library.
- Admin: reorganize UI into 3-column layout.
- Admin: include external link to frontend repo for the running commit.
- Toast: redesigned toast notifications.
### Removed
- Theme: Halloween theme.
- Settings: advanced notification settings.
- Settings: dyslexic mode.
- Settings: demetricator.
- Profile: ability to set and view private notes on an account.
- Feeds: per-feed filters for replies, media, etc.
- Backup and export functionality (for now).
- Posts: hide non-emoji images embedded in post content.
### Security
- Glitch Social: fixed XSS vulnerability on Glitch Social where custom emojis could be exploited to embed a script tag.
## [2.0.0] - 2022-05-01
### Added
- Quote Posting: repost with comment on Fedibird and Rebased.
- Profile: ability to feature other users on your profile (on Rebased, Mastodon).
- Profile: ability to add location to the user's profile (on Rebased, Truth Social).
- Birthdays: ability to add a birthday to your profile (on Rebased, Pleroma).
- Birthdays: support for age-gated registration if configured by the admin (on Rebased, Pleroma).
- Birthdays: display today's birthdays in notifications.
- Notifications: added unread badge to favicon when user has notifications.
- Notifications: display full attachments in notifications instead of links.
- Search: added a dedicated search page with prefilled suggestions.
- Compatibility: improved support for Mastodon, added support for Mitra.
- Ethereum: Metamask sign-in with Mitra.
- i18n: added Shavian alphabet (`en-Shaw`) transliteration.
- i18n: added Icelandic translation.
### Changed
- Feeds: added gaps between posts in feeds.
- Feeds: automatically load new posts when scrolled to the top of the feed.
- Layout: improved design of top navigation bar.
- Layout: add left sidebar navigation.
- Icons: replaced Fork Awesome icons with Tabler icons.
- Posts: moved mentions out of the post content into an area above the post for replies (on Pleroma and Rebased - Mastodon falls back to the old behavior).
- Composer: use graphical ring counter for character count.
### Fixed
- Multi-Account: fix switching between profiles on different servers with the same local username.
## [1.3.0] - 2021-07-02
### Changed
- Layout: show right sidebar on all pages.

View File

@ -164,9 +164,9 @@ const Account = ({
const LinkEl: any = withLinkToProfile ? Link : 'div';
return (
<div data-testid='account' className='flex-shrink-0 group block w-full' ref={overflowRef}>
<div data-testid='account' className='shrink-0 group block w-full' ref={overflowRef}>
<HStack alignItems={actionAlignment} justifyContent='between'>
<HStack alignItems={withAccountNote ? 'top' : 'center'} space={3}>
<HStack className='grow min-w-0' alignItems={withAccountNote ? 'top' : 'center'} space={3}>
<ProfilePopper
condition={showProfileHoverCard}
wrapper={(children) => <HoverRefWrapper className='relative' accountId={account.id} inline>{children}</HoverRefWrapper>}
@ -186,7 +186,7 @@ const Account = ({
</LinkEl>
</ProfilePopper>
<div className='flex-grow'>
<div className='grow min-w-0'>
<ProfilePopper
condition={showProfileHoverCard}
wrapper={(children) => <HoverRefWrapper accountId={account.id} inline>{children}</HoverRefWrapper>}
@ -210,7 +210,7 @@ const Account = ({
</ProfilePopper>
<Stack space={withAccountNote ? 1 : 0}>
<HStack alignItems='center' space={1} style={style}>
<HStack className='grow' alignItems='center' space={1} style={style}>
<Text theme='muted' size='sm' truncate>@{username}</Text>
{account.favicon && (

View File

@ -30,7 +30,7 @@ const AnnouncementContent: React.FC<IAnnouncementContent> = ({ announcement }) =
if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
e.preventDefault();
e.stopPropagation();
history.push(`/tags/${hashtag}`);
history.push(`/tag/${hashtag}`);
}
};

View File

@ -23,7 +23,7 @@ const Hashtag: React.FC<IHashtag> = ({ hashtag }) => {
return (
<HStack alignItems='center' justifyContent='between' data-testid='hashtag'>
<Stack>
<Permalink href={hashtag.url} to={`/tags/${hashtag.name}`} className='hover:underline'>
<Permalink href={hashtag.url} to={`/tag/${hashtag.name}`} className='hover:underline'>
<Text tag='span' size='sm' weight='semibold'>#{hashtag.name}</Text>
</Permalink>

View File

@ -287,14 +287,14 @@ const Status: React.FC<IStatus> = (props) => {
data-id={status.id}
>
<div className='flex mb-3'>
<div className='grow'>
<div className={classNames('flex items-center', { 'mb-3': status.reblog && typeof status.reblog === 'object' })}>
<div className='grow min-w-0'>
{
status.reblog && typeof status.reblog === 'object' && (
<NavLink
to={`/@${status.getIn(['account', 'acct'])}`}
onClick={(event) => event.stopPropagation()}
className='flex items-center mb-3 text-gray-700 dark:text-gray-600 text-xs font-medium space-x-1 hover:underline'
className='flex items-center text-gray-700 dark:text-gray-600 text-xs font-medium space-x-1 hover:underline'
>
<Icon src={require('@tabler/icons/repeat.svg')} className='text-green-600' />
@ -312,21 +312,21 @@ const Status: React.FC<IStatus> = (props) => {
</NavLink>
)
}
<AccountContainer
key={String(actualStatus.getIn(['account', 'id']))}
id={String(actualStatus.getIn(['account', 'id']))}
timestamp={actualStatus.created_at}
timestampUrl={statusUrl}
hideActions
showEdit={!!actualStatus.edited_at}
showProfileHoverCard={hoverable}
withLinkToProfile={hoverable}
/>
</div>
<Icon aria-hidden src={privacyIcon} className='h-5 w-5 shrink-0 text-gray-400 dark:text-gray-600' />
</div>
<div className='mb-3'>
<AccountContainer
key={String(actualStatus.getIn(['account', 'id']))}
id={String(actualStatus.getIn(['account', 'id']))}
timestamp={actualStatus.created_at}
timestampUrl={statusUrl}
hideActions
showEdit={!!actualStatus.edited_at}
showProfileHoverCard={hoverable}
withLinkToProfile={hoverable}
/>
</div>
<div className='status__content-wrapper'>
{!group && actualStatus.group && (

View File

@ -99,7 +99,7 @@ const StatusContent: React.FC<IStatusContent> = ({ status, expanded = false, onE
if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
e.preventDefault();
e.stopPropagation();
history.push(`/tags/${hashtag}`);
history.push(`/tag/${hashtag}`);
}
};

View File

@ -1,9 +1,9 @@
import classNames from 'classnames';
import React, { useEffect, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { fetchBackups, createBackup } from 'soapbox/actions/backups';
import ScrollableList from 'soapbox/components/scrollable_list';
import { Button, FormActions, Text, Spinner } from 'soapbox/components/ui';
import { useAppDispatch, useAppSelector } from 'soapbox/hooks';
import Column from '../ui/components/better_column';
@ -24,22 +24,14 @@ const Backups = () => {
const [isLoading, setIsLoading] = useState(true);
const handleCreateBackup: React.MouseEventHandler<HTMLAnchorElement> = e => {
const handleCreateBackup: React.MouseEventHandler = e => {
dispatch(createBackup());
e.preventDefault();
};
const makeColumnMenu = () => {
return [{
text: intl.formatMessage(messages.create),
action: handleCreateBackup,
icon: require('@tabler/icons/plus.svg'),
}];
};
useEffect(() => {
dispatch(fetchBackups()).then(() => {
setIsLoading(true);
setIsLoading(false);
}).catch(() => {});
}, []);
@ -47,30 +39,47 @@ const Backups = () => {
const emptyMessageAction = (
<a href='#' onClick={handleCreateBackup}>
{intl.formatMessage(messages.emptyMessageAction)}
<Text tag='span' theme='primary' size='sm' className='hover:underline'>
{intl.formatMessage(messages.emptyMessageAction)}
</Text>
</a>
);
return (
<Column icon='cloud-download' label={intl.formatMessage(messages.heading)} menu={makeColumnMenu()}>
<Column label={intl.formatMessage(messages.heading)}>
<ScrollableList
isLoading={isLoading}
showLoading={showLoading}
scrollKey='backups'
emptyMessage={intl.formatMessage(messages.emptyMessage, { action: emptyMessageAction })}
>
{backups.map((backup) => (
<div
className={classNames('backup', { 'backup--pending': !backup.processed })}
key={backup.id}
>
{backup.processed
? <a href={backup.url} target='_blank'>{backup.inserted_at}</a>
: <div>{intl.formatMessage(messages.pending)}: {backup.inserted_at}</div>
}
</div>
))}
{backups.map((backup) => {
const insertedAt = new Date(backup.inserted_at).toLocaleDateString(undefined, { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' });
return (
<div
className='p-2 mb-3 rounded bg-gray-100 dark:bg-slate-900 flex justify-between items-center'
key={backup.id}
>
<div>
{backup.processed
? <a href={backup.url} target='_blank'>{insertedAt}</a>
: <Text theme='subtle'>{insertedAt}&nbsp;-&nbsp;{intl.formatMessage(messages.pending)}</Text>
}
</div>
{
!backup.processed && <Spinner withText={false} size={15} />
}
</div>
);
})}
</ScrollableList>
<div className='mt-4'>
<FormActions>
<Button theme='primary' disabled={isLoading} onClick={handleCreateBackup}>
{intl.formatMessage(messages.create)}
</Button>
</FormActions>
</div>
</Column>
);
};

View File

@ -33,6 +33,9 @@ const messages = defineMessages({
domainBlocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' },
backups: { id: 'column.backups', defaultMessage: 'Backups' },
importData: { id: 'navigation_bar.import_data', defaultMessage: 'Import data' },
exportData: { id: 'column.export_data', defaultMessage: 'Export data' },
});
/** User settings page. */
@ -54,6 +57,9 @@ const Settings = () => {
const navigateToDeleteAccount = () => history.push('/settings/account');
const navigateToMoveAccount = () => history.push('/settings/migration');
const navigateToAliases = () => history.push('/settings/aliases');
const navigateToBackups = () => history.push('/settings/backups');
const navigateToImportData = () => history.push('/settings/import');
const navigateToExportData = () => history.push('/settings/export');
const navigateToBlocks = () => history.push('/blocks');
const navigateToMutes = () => history.push('/mutes');
@ -150,14 +156,27 @@ const Settings = () => {
<CardBody>
<List>
{features.security && (
<ListItem label={intl.formatMessage(messages.deleteAccount)} onClick={navigateToDeleteAccount} />
{features.importData && (
<ListItem label={intl.formatMessage(messages.importData)} onClick={navigateToImportData} />
)}
{features.exportData && (
<ListItem label={intl.formatMessage(messages.exportData)} onClick={navigateToExportData} />
)}
{features.backups && (
<ListItem label={intl.formatMessage(messages.backups)} onClick={navigateToBackups} />
)}
{features.federating && (features.accountMoving ? (
<ListItem label={intl.formatMessage(messages.accountMigration)} onClick={navigateToMoveAccount} />
) : features.accountAliases && (
<ListItem label={intl.formatMessage(messages.accountAliases)} onClick={navigateToAliases} />
))}
{features.security && (
<ListItem label={intl.formatMessage(messages.deleteAccount)} onClick={navigateToDeleteAccount} />
)}
</List>
</CardBody>
</>

View File

@ -46,9 +46,6 @@ const LinkFooter: React.FC = (): JSX.Element => {
{account.locked && (
<FooterLink to='/follow_requests'><FormattedMessage id='navigation_bar.follow_requests' defaultMessage='Follow requests' /></FooterLink>
)}
{features.import && (
<FooterLink to='/settings/import'><FormattedMessage id='navigation_bar.import_data' defaultMessage='Import data' /></FooterLink>
)}
<FooterLink to='/logout' onClick={onClickLogOut}><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></FooterLink>
</>}
</div>

View File

@ -83,9 +83,9 @@ import {
EmailConfirmation,
DeleteAccount,
SoapboxConfig,
// ExportData,
ExportData,
ImportData,
// Backups,
Backups,
MfaForm,
ChatIndex,
ChatRoom,
@ -209,7 +209,7 @@ const SwitchingColumnsArea: React.FC = ({ children }) => {
<Redirect from='/main/all' to='/timeline/fediverse' />
<Redirect from='/main/public' to='/timeline/local' />
<Redirect from='/main/friends' to='/' />
<Redirect from='/tag/:id' to='/tags/:id' />
<Redirect from='/tags/:id' to='/tag/:id' />
<Redirect from='/user-settings' to='/settings/profile' />
<WrappedRoute path='/notice/:statusId' publicRoute exact page={DefaultPage} component={Status} content={children} />
<Redirect from='/users/:username/statuses/:statusId' to='/@:username/posts/:statusId' />
@ -245,7 +245,7 @@ const SwitchingColumnsArea: React.FC = ({ children }) => {
<Redirect from='/auth/password/new' to='/reset-password' />
<Redirect from='/auth/password/edit' to={`/edit-password${search}`} />
<WrappedRoute path='/tags/:id' publicRoute page={DefaultPage} component={HashtagTimeline} content={children} />
<WrappedRoute path='/tag/:id' publicRoute page={DefaultPage} component={HashtagTimeline} content={children} />
{features.lists && <WrappedRoute path='/lists' page={DefaultPage} component={Lists} content={children} />}
{features.lists && <WrappedRoute path='/list/:id' page={HomePage} component={ListTimeline} content={children} />}
@ -283,11 +283,11 @@ const SwitchingColumnsArea: React.FC = ({ children }) => {
{features.scheduledStatuses && <WrappedRoute path='/scheduled_statuses' page={DefaultPage} component={ScheduledStatuses} content={children} />}
<WrappedRoute path='/settings/profile' page={DefaultPage} component={EditProfile} content={children} />
{/* FIXME: this could DDoS our API? :\ */}
{/* <WrappedRoute path='/settings/export' page={DefaultPage} component={ExportData} content={children} /> */}
{features.exportData && <WrappedRoute path='/settings/export' page={DefaultPage} component={ExportData} content={children} />}
{features.importData && <WrappedRoute path='/settings/import' page={DefaultPage} component={ImportData} content={children} />}
{features.accountAliases && <WrappedRoute path='/settings/aliases' page={DefaultPage} component={Aliases} content={children} />}
{features.accountMoving && <WrappedRoute path='/settings/migration' page={DefaultPage} component={Migration} content={children} />}
{features.backups && <WrappedRoute path='/settings/backups' page={DefaultPage} component={Backups} content={children} />}
<WrappedRoute path='/settings/email' page={DefaultPage} component={EditEmail} content={children} />
{
!isLdapEnabled && (
@ -299,7 +299,6 @@ const SwitchingColumnsArea: React.FC = ({ children }) => {
<WrappedRoute path='/settings/mfa' page={DefaultPage} component={MfaForm} exact />
<WrappedRoute path='/settings/tokens' page={DefaultPage} component={AuthTokenList} content={children} />
<WrappedRoute path='/settings' page={DefaultPage} component={Settings} content={children} />
{/* <WrappedRoute path='/backups' page={DefaultPage} component={Backups} content={children} /> */}
<WrappedRoute path='/soapbox/config' adminOnly page={DefaultPage} component={SoapboxConfig} content={children} />
<WrappedRoute path='/soapbox/admin' staffOnly page={AdminPage} component={Dashboard} content={children} exact />

View File

@ -173,10 +173,10 @@
"auth.invalid_credentials": "Wrong username or password",
"auth.logged_out": "Logged out.",
"auth_layout.register": "Create an account",
"backups.actions.create": "Create backup",
"backups.empty_message": "No backups found. {action}",
"backups.empty_message.action": "Create one now?",
"backups.pending": "Pending",
"backups.actions.create": "Créer une sauvegarde",
"backups.empty_message": "Pas de sauvegarde. {action}",
"backups.empty_message.action": "Créer une sauvegarde maintenant ?",
"backups.pending": "Sauvegarde en cours",
"birthday_panel.title": "Birthdays",
"birthdays_modal.empty": "None of your friends have birthday today.",
"boost_modal.combo": "Vous pouvez appuyer sur {combo} pour passer ceci, la prochaine fois",
@ -213,7 +213,7 @@
"column.aliases.subheading_add_new": "Ajouter un alias",
"column.aliases.subheading_aliases": "Alias courants",
"column.app_create": "Create app",
"column.backups": "Backups",
"column.backups": "Sauvegardes",
"column.birthdays": "Birthdays",
"column.blocks": "Comptes bloqués",
"column.bookmarks": "Marque-pages",
@ -225,7 +225,7 @@
"column.directory": "Annuaire",
"column.domain_blocks": "Domaines cachés",
"column.edit_profile": "Éditer le profil",
"column.export_data": "Export data",
"column.export_data": "Exporter vos données",
"column.familiar_followers": "People you know following {name}",
"column.favourited_statuses": "Liked posts",
"column.favourites": "Likes",
@ -508,18 +508,18 @@
"empty_column.search.statuses": "Il n'y a pas de statuts correspondant à la recherche \"{term}\"",
"empty_column.test": "The test timeline is empty.",
"export_data.actions.export": "Export",
"export_data.actions.export_blocks": "Export blocks",
"export_data.actions.export_follows": "Export follows",
"export_data.actions.export_mutes": "Export mutes",
"export_data.blocks_label": "Blocks",
"export_data.follows_label": "Follows",
"export_data.hints.blocks": "Get a CSV file containing a list of blocked accounts",
"export_data.hints.follows": "Get a CSV file containing a list of followed accounts",
"export_data.hints.mutes": "Get a CSV file containing a list of muted accounts",
"export_data.mutes_label": "Mutes",
"export_data.success.blocks": "Blocks exported successfully",
"export_data.success.followers": "Followers exported successfully",
"export_data.success.mutes": "Mutes exported successfully",
"export_data.actions.export_blocks": "Exporter les comptes bloqués",
"export_data.actions.export_follows": "Exporter les comptes suivis",
"export_data.actions.export_mutes": "Exporter les comptes masqués",
"export_data.blocks_label": "Comptes bloqués",
"export_data.follows_label": "Comptes suivis",
"export_data.hints.blocks": "Obtenez un fichier csv contenant la liste des comptes bloqués",
"export_data.hints.follows": "Obtenez un fichier csv contenant la liste des comptes suivis",
"export_data.hints.mutes": "Obtenez un fichier csv contenant la liste des comptes masqués",
"export_data.mutes_label": "Comptes masqués",
"export_data.success.blocks": "Comptes bloqués exportés",
"export_data.success.followers": "Comptes suivis exportés",
"export_data.success.mutes": "Comptes masqués exportés",
"federation_restriction.federated_timeline_removal": "Fediverse timeline removal",
"federation_restriction.followers_only": "Hidden except to followers",
"federation_restriction.full_media_removal": "Full media removal",
@ -989,14 +989,14 @@
"security.update_email.success": "Email mis à jour.",
"security.update_password.fail": "Echec de la mise à jour du mot de passe.",
"security.update_password.success": "Mot de passe mis à jour.",
"settings.account_migration": "Move Account",
"settings.account_migration": "Migrer votre compte",
"settings.change_email": "Changer d'email",
"settings.change_password": "Changer de mot de passe",
"settings.configure_mfa": "Configurer le MFA",
"settings.content": "Contenu",
"settings.delete_account": "Supprimer le compte",
"settings.edit_profile": "Mettre à jour le profil",
"settings.other": "Other options",
"settings.other": "Compte",
"settings.preferences": "Préférences",
"settings.profile": "Profil",
"settings.save.success": "Vos préférences ont été enregistrées.",

View File

@ -166,6 +166,13 @@ const getInstanceFeatures = (instance: Instance) => {
*/
announcementsReactions: v.software === MASTODON && gte(v.compatVersion, '3.1.0'),
/**
* Pleroma backups.
* @see GET /api/v1/pleroma/backups
* @see POST /api/v1/pleroma/backups
*/
backups: v.software === PLEROMA || v.software === AKKOMA,
/**
* Set your birthday and view upcoming birthdays.
* @see GET /api/v1/pleroma/birthdays
@ -288,6 +295,9 @@ const getInstanceFeatures = (instance: Instance) => {
v.software === TRUTHSOCIAL,
]),
/** Whether to allow exporting follows/blocks/mutes to CSV by paginating the API. */
exportData: true,
/** Whether the accounts who favourited or emoji-reacted to a status can be viewed through the API. */
exposableReactions: any([
v.software === MASTODON,

View File

@ -66,7 +66,6 @@
@import 'components/accordion';
@import 'components/server-info';
@import 'components/admin';
@import 'components/backups';
@import 'components/crypto-donate';
@import 'components/remote-timeline';
@import 'components/aliases';

View File

@ -1,13 +0,0 @@
.backup {
padding: 15px;
border-bottom: 1px solid var(--brand-color--faint);
a {
color: var(--brand-color--hicontrast);
}
&--pending {
font-style: italic;
color: var(--primary-text-color--faint);
}
}

View File

@ -26,7 +26,7 @@
&::before {
@apply ml-4;
content: '\f057';
content: '\f06a';
}
}