();
@@ -27,6 +33,7 @@ const fac = new FastAverageColor();
/** Round profile avatar for accounts. */
const Avatar = (props: IAvatar) => {
const intl = useIntl();
+ const { disableUserProvidedMedia } = useSettings();
const { alt, src, size = AVATAR_SIZE, className, isCat } = props;
@@ -58,6 +65,29 @@ const Avatar = (props: IAvatar) => {
color,
}), [size, color]);
+ if (disableUserProvidedMedia) {
+ if (isAvatarMissing || !alt) return null;
+ return (
+
+
+
+
+
+ {alt}
+
+
+ }
+ isFlush
+ >
+ } />
+
+ );
+ }
+
if (isAvatarMissing) {
return (
, 'alt' |
/** A single emoji image. */
const Emoji: React.FC
= (props): JSX.Element | null => {
+ const { disableUserProvidedMedia } = useSettings();
const { emoji, alt, src, noGroup, ...rest } = props;
let filename;
@@ -24,6 +26,7 @@ const Emoji: React.FC = (props): JSX.Element | null => {
if (!filename && !src) return null;
if (src) {
+ if (disableUserProvidedMedia) return <>{alt || emoji}>;
return (
= (props): JSX.Element | null => {
);
diff --git a/packages/pl-fe/src/components/upload.tsx b/packages/pl-fe/src/components/upload.tsx
index dcf751360..332785944 100644
--- a/packages/pl-fe/src/components/upload.tsx
+++ b/packages/pl-fe/src/components/upload.tsx
@@ -3,9 +3,12 @@ import fileCodeIcon from '@tabler/icons/outline/file-code.svg';
import fileSpreadsheetIcon from '@tabler/icons/outline/file-spreadsheet.svg';
import fileTextIcon from '@tabler/icons/outline/file-text.svg';
import fileZipIcon from '@tabler/icons/outline/file-zip.svg';
+import audioIcon from '@tabler/icons/outline/music.svg';
import defaultIcon from '@tabler/icons/outline/paperclip.svg';
import editIcon from '@tabler/icons/outline/pencil.svg';
+import imageIcon from '@tabler/icons/outline/photo.svg';
import presentationIcon from '@tabler/icons/outline/presentation.svg';
+import videoIcon from '@tabler/icons/outline/video.svg';
import xIcon from '@tabler/icons/outline/x.svg';
import zoomInIcon from '@tabler/icons/outline/zoom-in.svg';
import clsx from 'clsx';
@@ -55,6 +58,10 @@ const MIMETYPE_ICONS: Record = {
'application/x-abiword': fileTextIcon,
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': fileTextIcon,
'application/vnd.oasis.opendocument.text': fileTextIcon,
+ image: imageIcon,
+ video: videoIcon,
+ gifv: videoIcon,
+ audio: audioIcon,
};
const messages = defineMessages({
diff --git a/packages/pl-fe/src/features/account/components/header.tsx b/packages/pl-fe/src/features/account/components/header.tsx
index 6cc3c773e..8c7a04fb0 100644
--- a/packages/pl-fe/src/features/account/components/header.tsx
+++ b/packages/pl-fe/src/features/account/components/header.tsx
@@ -1,4 +1,5 @@
import { useMutation } from '@tanstack/react-query';
+import clsx from 'clsx';
import { GOTOSOCIAL, MASTODON, mediaAttachmentSchema } from 'pl-api';
import React from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
@@ -9,12 +10,16 @@ import { biteAccount, blockAccount, pinAccount, removeFromFollowers, unblockAcco
import { mentionCompose, directCompose } from 'pl-fe/actions/compose';
import { initReport, ReportableEntities } from 'pl-fe/actions/reports';
import { useFollow } from 'pl-fe/api/hooks/accounts/use-follow';
+import AltIndicator from 'pl-fe/components/alt-indicator';
import Badge from 'pl-fe/components/badge';
import DropdownMenu, { Menu } from 'pl-fe/components/dropdown-menu';
import StillImage from 'pl-fe/components/still-image';
import Avatar from 'pl-fe/components/ui/avatar';
import HStack from 'pl-fe/components/ui/hstack';
import IconButton from 'pl-fe/components/ui/icon-button';
+import Popover from 'pl-fe/components/ui/popover';
+import Stack from 'pl-fe/components/ui/stack';
+import Text from 'pl-fe/components/ui/text';
import VerificationBadge from 'pl-fe/components/verification-badge';
import MovedNote from 'pl-fe/features/account-timeline/components/moved-note';
import ActionButton from 'pl-fe/features/ui/components/action-button';
@@ -23,11 +28,11 @@ import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch';
import { useClient } from 'pl-fe/hooks/use-client';
import { useFeatures } from 'pl-fe/hooks/use-features';
import { useOwnAccount } from 'pl-fe/hooks/use-own-account';
+import { useSettings } from 'pl-fe/hooks/use-settings';
import { useChats } from 'pl-fe/queries/chats';
import { queryClient } from 'pl-fe/queries/client';
import { blockDomainMutationOptions, unblockDomainMutationOptions } from 'pl-fe/queries/settings/domain-blocks';
import { useModalsStore } from 'pl-fe/stores/modals';
-import { useSettingsStore } from 'pl-fe/stores/settings';
import toast from 'pl-fe/toast';
import { isDefaultHeader } from 'pl-fe/utils/accounts';
import copy from 'pl-fe/utils/copy';
@@ -98,7 +103,7 @@ const Header: React.FC = ({ account }) => {
const { account: ownAccount } = useOwnAccount();
const { follow } = useFollow();
const { openModal } = useModalsStore();
- const { settings } = useSettingsStore();
+ const settings = useSettings();
const { software } = features.version;
@@ -566,6 +571,29 @@ const Header: React.FC = ({ account }) => {
const renderHeader = () => {
let header: React.ReactNode;
+ if (settings.disableUserProvidedMedia) {
+ if (!account.header_description) return null;
+ else return (
+
+
+
+
+
+ {account.header_description}
+
+
+ }
+ isFlush
+ >
+ } />
+
+ );
+ }
+
if (account.header) {
header = (
= ({ account }) => {
)}
-
+
{renderHeader()}
diff --git a/packages/pl-fe/src/features/emoji/emojify.tsx b/packages/pl-fe/src/features/emoji/emojify.tsx
index 9549b04ef..862132185 100644
--- a/packages/pl-fe/src/features/emoji/emojify.tsx
+++ b/packages/pl-fe/src/features/emoji/emojify.tsx
@@ -1,6 +1,7 @@
import split from 'graphemesplit';
import React from 'react';
+import { useSettings } from 'pl-fe/hooks/use-settings';
import { makeEmojiMap } from 'pl-fe/utils/normalizers';
import unicodeMapping from './mapping';
@@ -34,6 +35,8 @@ interface IEmojify {
}
const Emojify: React.FC
= React.memo(({ text, emojis = {} }) => {
+ const { disableUserProvidedMedia } = useSettings();
+
if (Array.isArray(emojis)) emojis = makeEmojiMap(emojis);
const nodes = [];
@@ -76,7 +79,7 @@ const Emojify: React.FC = React.memo(({ text, emojis = {} }) => {
nodes.push(
,
);
- } else if (c === ':') {
+ } else if (!disableUserProvidedMedia && c === ':') {
if (!open) {
clearStack();
}
diff --git a/packages/pl-fe/src/features/preferences/index.tsx b/packages/pl-fe/src/features/preferences/index.tsx
index 7a0d41599..50e5d187c 100644
--- a/packages/pl-fe/src/features/preferences/index.tsx
+++ b/packages/pl-fe/src/features/preferences/index.tsx
@@ -282,6 +282,13 @@ const Preferences = () => {
)}
+
+ }
+ hint={}
+ >
+
+
diff --git a/packages/pl-fe/src/features/ui/components/panels/user-panel.tsx b/packages/pl-fe/src/features/ui/components/panels/user-panel.tsx
index 9aad816cc..90a97aba5 100644
--- a/packages/pl-fe/src/features/ui/components/panels/user-panel.tsx
+++ b/packages/pl-fe/src/features/ui/components/panels/user-panel.tsx
@@ -25,7 +25,7 @@ interface IUserPanel {
const UserPanel: React.FC = ({ accountId, action, badges, domain }) => {
const intl = useIntl();
- const { demetricator } = useSettings();
+ const { demetricator, disableUserProvidedMedia } = useSettings();
const { account } = useAccount(accountId);
const fqn = useAppSelector((state) => displayFqn(state));
@@ -38,26 +38,30 @@ const UserPanel: React.FC = ({ accountId, action, badges, domain })
-
- {header && (
-
- )}
-
+ {!disableUserProvidedMedia && (
+
+ {header && (
+
+ )}
+
+ )}
-
-
-
-
+
+ {!disableUserProvidedMedia && (
+
+
+
+ )}
{action && (
{action}
diff --git a/packages/pl-fe/src/locales/en.json b/packages/pl-fe/src/locales/en.json
index 2cf58fdac..c839f7c97 100644
--- a/packages/pl-fe/src/locales/en.json
+++ b/packages/pl-fe/src/locales/en.json
@@ -4,6 +4,7 @@
"accordion.expand": "Expand",
"account.add_or_remove_from_list": "Add or Remove from lists",
"account.avatar.alt": "Avatar",
+ "account.avatar.description": "Avatar description",
"account.badges.bot": "Bot",
"account.birthday": "Born {date}",
"account.birthday_today": "Birthday is today!",
@@ -31,6 +32,7 @@
"account.follows.empty": "This user doesn't follow anyone yet.",
"account.follows_you": "Follows you",
"account.header.alt": "Profile header",
+ "account.header.description": "Header description",
"account.hide_reblogs": "Hide reposts from @{name}",
"account.last_status": "Last active",
"account.link_verified_on": "Ownership of this link was checked on {date}",
@@ -657,12 +659,14 @@
"edit_federation.success": "{host} federation was updated",
"edit_federation.unlisted": "Force posts unlisted",
"edit_password.header": "Change password",
+ "edit_profile.custom_css.remaining_characters": "{remaining, plural, one {# character} other {# characters}} remaining",
"edit_profile.error": "Profile update failed",
"edit_profile.fields.bio_label": "Bio",
"edit_profile.fields.bio_placeholder": "Tell us about yourself.",
"edit_profile.fields.birthday_label": "Birthday",
"edit_profile.fields.birthday_placeholder": "Your birthday",
"edit_profile.fields.bot_label": "This is a bot account",
+ "edit_profile.fields.custom_css_label": "Custom CSS",
"edit_profile.fields.discoverable_label": "Allow account discovery",
"edit_profile.fields.display_name_label": "Display name",
"edit_profile.fields.display_name_placeholder": "Name",
@@ -681,6 +685,11 @@
"edit_profile.fields.rss_label": "Enable RSS feed for public posts",
"edit_profile.fields.speak_as_cat_label": "The user speaks as a cat",
"edit_profile.fields.stranger_notifications_label": "Block notifications from strangers",
+ "edit_profile.fields.web_layout.gallery": "Media-only gallery layout",
+ "edit_profile.fields.web_layout.microblog": "Classic microblog layout",
+ "edit_profile.fields.web_visibility.none": "Show no posts",
+ "edit_profile.fields.web_visibility.public": "Show public posts only",
+ "edit_profile.fields.web_visibility.unlisted": "Show public and unlisted posts",
"edit_profile.header": "Edit profile",
"edit_profile.hints.bot": "This account mainly performs automated actions and might not be monitored",
"edit_profile.hints.discoverable": "Display account in profile directory and allow indexing by external services",
@@ -1068,6 +1077,11 @@
"manage_group.fields.name_placeholder": "Group Name",
"manage_group.pending_requests": "Pending requests",
"media-gallery.description": "Image description",
+ "media.default_description.attachment": "Attachment",
+ "media.default_description.audio": "Audio",
+ "media.default_description.gifv": "GIFV",
+ "media.default_description.image": "Image",
+ "media.default_description.video": "Video",
"media_panel.empty_message": "No media found.",
"media_panel.title": "Media",
"mfa.confirm.success_message": "MFA confirmed",
@@ -1292,6 +1306,8 @@
"preferences.fields.demetricator_label": "Hide social media counters",
"preferences.fields.demo_hint": "Use the default pl-fe logo and color scheme. Useful for taking screenshots.",
"preferences.fields.demo_label": "Demo mode",
+ "preferences.fields.disable_user_provided_media_hint": "This will hide images, videos, and other media uploaded by users and display alternative text instead.",
+ "preferences.fields.disable_user_provided_media_label": "Do not display user-provided media",
"preferences.fields.display_media.default": "Hide posts marked as sensitive",
"preferences.fields.display_media.hide_all": "Always hide media posts",
"preferences.fields.display_media.show_all": "Always show posts",
@@ -1310,6 +1326,8 @@
"preferences.fields.theme_reset": "Reset theme",
"preferences.fields.underline_links_label": "Always underline links in posts",
"preferences.fields.unfollow_modal_label": "Show confirmation dialog before unfollowing someone",
+ "preferences.fields.web_layout_label": "Layout of the web view of your profile",
+ "preferences.fields.web_visibility_label": "Visibility level of posts displayed on your profile",
"preferences.fields.wrench_label": "Display wrench reaction button",
"preferences.hints.demetricator": "Decrease social media anxiety by hiding all numbers from the site.",
"preferences.hints.mention_policy": "Applies to direct messages and public posts",
diff --git a/packages/pl-fe/src/schemas/pl-fe/settings.ts b/packages/pl-fe/src/schemas/pl-fe/settings.ts
index db1d1920f..7b98817f1 100644
--- a/packages/pl-fe/src/schemas/pl-fe/settings.ts
+++ b/packages/pl-fe/src/schemas/pl-fe/settings.ts
@@ -49,6 +49,7 @@ const settingsSchema = v.object({
redirectServices: v.fallback(v.record(v.string(), v.string()), {}),
}),
checkEmojiReactsSupport: v.fallback(v.boolean(), false),
+ disableUserProvidedMedia: v.fallback(v.boolean(), false),
theme: v.fallback(v.optional(v.object({
brandColor: v.fallback(v.string(), ''),