pl-fe: default avatar/header detection cleanup
Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
import pick from 'lodash.pick';
|
||||
import * as v from 'valibot';
|
||||
|
||||
import { isDefaultAvatar, isDefaultHeader } from '../utils/accounts';
|
||||
import { guessFqn } from '../utils/domain';
|
||||
|
||||
import { customEmojiSchema } from './custom-emoji';
|
||||
@ -30,6 +31,8 @@ const preprocessAccount = v.transform((account: any) => {
|
||||
domain,
|
||||
avatar: account.avatar || account.avatar_static,
|
||||
header: account.header || account.header_static,
|
||||
avatar_default: isDefaultAvatar(account.avatar || account.avatar_static),
|
||||
header_default: isDefaultHeader(account.header || account.header_static),
|
||||
local: typeof account.pleroma?.is_local === 'boolean' ? account.pleroma.is_local : account.acct.split('@')[1] === undefined,
|
||||
discoverable: account.discoverable || account.pleroma?.source?.discoverable,
|
||||
verified: account.verified || account.pleroma?.tags?.includes('verified'),
|
||||
@ -187,6 +190,9 @@ const baseAccountSchema = v.object({
|
||||
pleroma: v.optional(v.any(), undefined),
|
||||
source: v.optional(v.any(), undefined),
|
||||
}),
|
||||
|
||||
avatar_default: v.fallback(v.boolean(), false),
|
||||
header_default: v.fallback(v.boolean(), false),
|
||||
});
|
||||
|
||||
const accountWithMovedAccountSchema = v.object({
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import * as v from 'valibot';
|
||||
|
||||
import { isDefaultAvatar, isDefaultHeader } from '../utils/accounts';
|
||||
import { getDomainFromURL } from '../utils/domain';
|
||||
|
||||
import { customEmojiSchema } from './custom-emoji';
|
||||
@ -35,6 +36,8 @@ const groupSchema = v.pipe(v.any(), v.transform((group: any) => {
|
||||
...group,
|
||||
avatar: group.avatar || group.avatar_static,
|
||||
header: group.header || group.header_static,
|
||||
avatar_default: isDefaultAvatar(group.avatar || group.avatar_static),
|
||||
header_default: isDefaultHeader(group.header || group.header_static),
|
||||
};
|
||||
}), v.object({
|
||||
avatar: v.fallback(v.string(), ''),
|
||||
@ -58,6 +61,9 @@ const groupSchema = v.pipe(v.any(), v.transform((group: any) => {
|
||||
|
||||
avatar_description: v.fallback(v.string(), ''),
|
||||
header_description: v.fallback(v.string(), ''),
|
||||
|
||||
avatar_default: v.fallback(v.boolean(), false),
|
||||
header_default: v.fallback(v.boolean(), false),
|
||||
}));
|
||||
|
||||
/**
|
||||
|
||||
27
packages/pl-api/lib/utils/accounts.ts
Normal file
27
packages/pl-api/lib/utils/accounts.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/** Default header filenames from various backends */
|
||||
const DEFAULT_HEADERS: string[] = [
|
||||
'/assets/default_header.webp', // GoToSocial
|
||||
'/headers/original/missing.png', // Mastodon
|
||||
'/api/v1/accounts/identicon', // Mitra
|
||||
'/images/banner.png', // Pleroma
|
||||
'/assets/transparent.png', // Iceshrimp.net
|
||||
];
|
||||
|
||||
/** Check if the avatar is a default avatar */
|
||||
const isDefaultHeader = (url: string = '') => url === '' || DEFAULT_HEADERS.some(header => url.endsWith(header));
|
||||
|
||||
/** Default avatar filenames from various backends */
|
||||
const DEFAULT_AVATARS = [
|
||||
...([1, 2, 3, 4, 5, 6].map(i => `/assets/default_avatars/GoToSocial_icon${i}.webp`)), // GoToSocial
|
||||
'/avatars/original/missing.png', // Mastodon
|
||||
'/api/v1/accounts/identicon', // Mitra
|
||||
'/images/avi.png', // Pleroma
|
||||
];
|
||||
|
||||
/** Check if the avatar is a default avatar */
|
||||
const isDefaultAvatar = (url: string = '') => url === '' || DEFAULT_AVATARS.some(avatar => url.endsWith(avatar));
|
||||
|
||||
export {
|
||||
isDefaultHeader,
|
||||
isDefaultAvatar,
|
||||
};
|
||||
@ -5,7 +5,6 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import StillImage, { IStillImage } from 'pl-fe/components/still-image';
|
||||
import { useSettings } from 'pl-fe/stores/settings';
|
||||
import { isDefaultAvatar } from 'pl-fe/utils/accounts';
|
||||
|
||||
import AltIndicator from '../alt-indicator';
|
||||
|
||||
|
||||
@ -43,7 +43,6 @@ import { blockDomainMutationOptions, unblockDomainMutationOptions } from 'pl-fe/
|
||||
import { useModalsActions } from 'pl-fe/stores/modals';
|
||||
import { useSettings } 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';
|
||||
|
||||
import type { PlfeResponse } from 'pl-fe/api';
|
||||
@ -614,7 +613,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
||||
let header: React.ReactNode;
|
||||
|
||||
if (settings.disableUserProvidedMedia) {
|
||||
if (!account.header_description || isDefaultHeader(account.header)) return null;
|
||||
if (!account.header_description || account.header_default) return null;
|
||||
else return (
|
||||
<Popover
|
||||
interaction='hover'
|
||||
@ -644,7 +643,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
||||
/>
|
||||
);
|
||||
|
||||
if (!isDefaultHeader(account.header)) {
|
||||
if (!account.header_default) {
|
||||
header = (
|
||||
<a href={account.header} onClick={handleHeaderClick} target='_blank'>
|
||||
{header}
|
||||
|
||||
@ -12,7 +12,6 @@ import Stack from 'pl-fe/components/ui/stack';
|
||||
import Text from 'pl-fe/components/ui/text';
|
||||
import Emojify from 'pl-fe/features/emoji/emojify';
|
||||
import { useModalsActions } from 'pl-fe/stores/modals';
|
||||
import { isDefaultHeader } from 'pl-fe/utils/accounts';
|
||||
|
||||
import GroupActionButton from './group-action-button';
|
||||
import GroupMemberCount from './group-member-count';
|
||||
@ -101,7 +100,7 @@ const GroupHeader: React.FC<IGroupHeader> = ({ group }) => {
|
||||
/>
|
||||
);
|
||||
|
||||
if (!isDefaultHeader(group.header)) {
|
||||
if (!group.header_default) {
|
||||
header = (
|
||||
<a href={group.header} onClick={handleHeaderClick} target='_blank' className='relative w-full'>
|
||||
{header}
|
||||
|
||||
@ -19,12 +19,8 @@ import { useTextField } from 'pl-fe/hooks/forms/use-text-field';
|
||||
import { useAppSelector } from 'pl-fe/hooks/use-app-selector';
|
||||
import { useInstance } from 'pl-fe/hooks/use-instance';
|
||||
import toast from 'pl-fe/toast';
|
||||
import { isDefaultAvatar, isDefaultHeader } from 'pl-fe/utils/accounts';
|
||||
import { unescapeHTML } from 'pl-fe/utils/html';
|
||||
|
||||
const nonDefaultAvatar = (url: string | undefined) => url && isDefaultAvatar(url) ? undefined : url;
|
||||
const nonDefaultHeader = (url: string | undefined) => url && isDefaultHeader(url) ? undefined : url;
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'navigation_bar.edit_group', defaultMessage: 'Edit Group' },
|
||||
groupNamePlaceholder: { id: 'manage_group.fields.name_placeholder', defaultMessage: 'Group Name' },
|
||||
@ -47,8 +43,8 @@ const EditGroup: React.FC<IEditGroup> = ({ params: { groupId } }) => {
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const avatar = useImageField({ maxPixels: 400 * 400, preview: nonDefaultAvatar(group?.avatar) });
|
||||
const header = useImageField({ maxPixels: 1920 * 1080, preview: nonDefaultHeader(group?.header) });
|
||||
const avatar = useImageField({ maxPixels: 400 * 400, preview: group?.avatar_default === false ? group.avatar : undefined });
|
||||
const header = useImageField({ maxPixels: 1920 * 1080, preview: group?.header_default === false ? group.header : undefined });
|
||||
|
||||
const displayName = useTextField(group?.display_name);
|
||||
const note = useTextField(unescapeHTML(group?.note));
|
||||
|
||||
@ -28,13 +28,9 @@ import { useFeatures } from 'pl-fe/hooks/use-features';
|
||||
import { useInstance } from 'pl-fe/hooks/use-instance';
|
||||
import { useOwnAccount } from 'pl-fe/hooks/use-own-account';
|
||||
import toast from 'pl-fe/toast';
|
||||
import { isDefaultAvatar, isDefaultHeader } from 'pl-fe/utils/accounts';
|
||||
|
||||
import type { StreamfieldComponent } from 'pl-fe/components/ui/streamfield';
|
||||
|
||||
const nonDefaultAvatar = (url: string | undefined) => url && isDefaultAvatar(url) ? undefined : url;
|
||||
const nonDefaultHeader = (url: string | undefined) => url && isDefaultHeader(url) ? undefined : url;
|
||||
|
||||
/**
|
||||
* Whether the user is hiding their follows and/or followers.
|
||||
* Pleroma's config is granular, but we simplify it into one setting.
|
||||
@ -209,8 +205,8 @@ const EditProfilePage: React.FC = () => {
|
||||
const [muteStrangers, setMuteStrangers] = useState(false);
|
||||
const [customCSSEditorExpanded, setCustomCSSEditorExpanded] = useState(false);
|
||||
|
||||
const avatar = useImageField({ maxPixels: 400 * 400, preview: nonDefaultAvatar(account?.avatar) });
|
||||
const header = useImageField({ maxPixels: 1920 * 1080, preview: nonDefaultHeader(account?.header) });
|
||||
const avatar = useImageField({ maxPixels: 400 * 400, preview: account?.avatar_default === false ? account.avatar : undefined });
|
||||
const header = useImageField({ maxPixels: 1920 * 1080, preview: account?.header_default === false ? account.header : undefined });
|
||||
|
||||
useEffect(() => {
|
||||
client.settings.verifyCredentials().then((credentialAccount) => {
|
||||
|
||||
@ -28,35 +28,8 @@ const getAcct = (account: Pick<Account, 'fqn' | 'acct'>, displayFqn: boolean): s
|
||||
displayFqn === true ? account.fqn : account.acct
|
||||
);
|
||||
|
||||
/** Default header filenames from various backends */
|
||||
const DEFAULT_HEADERS: string[] = [
|
||||
'/assets/default_header.webp', // GoToSocial
|
||||
'/headers/original/missing.png', // Mastodon
|
||||
'/api/v1/accounts/identicon', // Mitra
|
||||
'/images/banner.png', // Pleroma
|
||||
'/assets/transparent.png', // Iceshrimp.net
|
||||
require('pl-fe/assets/images/header-missing.png'), // header not provided by backend
|
||||
];
|
||||
|
||||
/** Check if the avatar is a default avatar */
|
||||
const isDefaultHeader = (url: string) => url === '' || DEFAULT_HEADERS.some(header => url.endsWith(header));
|
||||
|
||||
/** Default avatar filenames from various backends */
|
||||
const DEFAULT_AVATARS = [
|
||||
...(range(1, 6).map(i => `/assets/default_avatars/GoToSocial_icon${i}.webp`)), // GoToSocial
|
||||
'/avatars/original/missing.png', // Mastodon
|
||||
'/api/v1/accounts/identicon', // Mitra
|
||||
'/images/avi.png', // Pleroma
|
||||
require('pl-fe/assets/images/avatar-missing.png'), // avatar not provided by backend
|
||||
];
|
||||
|
||||
/** Check if the avatar is a default avatar */
|
||||
const isDefaultAvatar = (url: string) => url === '' || DEFAULT_AVATARS.some(avatar => url.endsWith(avatar));
|
||||
|
||||
export {
|
||||
getDomain,
|
||||
getBaseURL,
|
||||
getAcct,
|
||||
isDefaultHeader,
|
||||
isDefaultAvatar,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user