Merge branch 'mastodon-badges' into 'main'

Support role badges on Mastodon

See merge request soapbox-pub/soapbox!2985
environments/review-main-yi2y9f/deployments/4552
marcin mikołajczak 2024-04-16 10:49:48 +00:00
commit 1518615767
4 zmienionych plików z 39 dodań i 10 usunięć

Wyświetl plik

@ -1,18 +1,32 @@
import clsx from 'clsx';
import React from 'react';
import React, { useMemo } from 'react';
import { hexToHsl } from 'soapbox/utils/theme';
interface IBadge {
title: React.ReactNode;
slug: string;
color?: string;
}
/** Badge to display on a user's profile. */
const Badge: React.FC<IBadge> = ({ title, slug }) => {
const Badge: React.FC<IBadge> = ({ title, slug, color }) => {
const fallback = !['patron', 'admin', 'moderator', 'opaque', 'badge:donor'].includes(slug);
const isDark = useMemo(() => {
const hsl = hexToHsl(color!);
if (hsl && hsl.l > 50) return false;
return true;
}, [color]);
return (
<span
data-testid='badge'
className={clsx('inline-flex items-center rounded px-2 py-0.5 text-xs font-medium', {
className={clsx('inline-flex items-center rounded px-2 py-0.5 text-xs font-medium', color ? {
'bg-gray-100 text-gray-100': isDark,
'bg-gray-800 text-gray-900': !isDark,
} : {
'bg-fuchsia-700 text-white': slug === 'patron',
'bg-emerald-800 text-white': slug === 'badge:donor',
'bg-black text-white': slug === 'admin',
@ -20,6 +34,7 @@ const Badge: React.FC<IBadge> = ({ title, slug }) => {
'bg-gray-100 dark:bg-gray-800 text-gray-900 dark:text-gray-100': fallback,
'bg-white/75 text-gray-900': slug === 'opaque',
})}
style={color ? { background: color } : undefined}
>
{title}
</span>

Wyświetl plik

@ -7,7 +7,6 @@ import Markup from 'soapbox/components/markup';
import { dateFormatOptions } from 'soapbox/components/relative-timestamp';
import { Icon, HStack, Stack, Text } from 'soapbox/components/ui';
import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
import { badgeToTag, getBadges as getAccountBadges } from 'soapbox/utils/badges';
import { capitalize } from 'soapbox/utils/strings';
import ProfileFamiliarFollowers from './profile-familiar-followers';
@ -58,13 +57,14 @@ const ProfileInfoPanel: React.FC<IProfileInfoPanel> = ({ account, username }) =>
};
const getCustomBadges = (): React.ReactNode[] => {
const badges = account ? getAccountBadges(account) : [];
const badges = account?.roles || [];
return badges.map(badge => (
return badges.filter(badge => badge.highlighted).map(badge => (
<Badge
key={badge}
slug={badge}
title={capitalize(badgeToTag(badge))}
key={badge.id || badge.name}
slug={badge.name}
title={capitalize(badge.name)}
color={badge.color}
/>
));
};

Wyświetl plik

@ -17,12 +17,21 @@ const headerMissing = require('soapbox/assets/images/header-missing.png');
const birthdaySchema = z.string().regex(/^\d{4}-\d{2}-\d{2}$/);
const hexSchema = z.string().regex(/^#[a-f0-9]{6}$/i);
const fieldSchema = z.object({
name: z.string(),
value: z.string(),
verified_at: z.string().datetime().nullable().catch(null),
});
const roleSchema = z.object({
id: z.string().catch(''),
name: z.string().catch(''),
color: hexSchema.catch(''),
highlighted: z.boolean().catch(true),
});
const baseAccountSchema = z.object({
acct: z.string().catch(''),
avatar: z.string().catch(avatarMissing),
@ -85,6 +94,7 @@ const baseAccountSchema = z.object({
relationship: relationshipSchema.optional().catch(undefined),
tags: z.array(z.string()).catch([]),
}).optional().catch(undefined),
roles: filteredArray(roleSchema),
source: z.object({
approved: z.boolean().catch(true),
chats_onboarded: z.boolean().catch(true),
@ -118,6 +128,9 @@ const getDomain = (url: string) => {
}
};
const filterBadges = (tags?: string[]) =>
tags?.filter(tag => tag.startsWith('badge:')).map(tag => ({ id: tag, name: tag.replace(/^badge:/, '') }));
/** Add internal fields to the account. */
const transformAccount = <T extends TransformableAccount>({ pleroma, other_settings, fields, ...account }: T) => {
const customEmojiMap = makeCustomEmojiMap(account.emojis);
@ -156,6 +169,7 @@ const transformAccount = <T extends TransformableAccount>({ pleroma, other_setti
const { relationship, ...rest } = pleroma;
return rest;
})(),
roles: account.roles || filterBadges(pleroma?.tags),
relationship: pleroma?.relationship,
staff: pleroma?.is_admin || pleroma?.is_moderator || false,
suspended: account.suspended || pleroma?.deactivated || false,

Wyświetl plik

@ -117,7 +117,7 @@ export const generateThemeCss = (soapboxConfig: SoapboxConfig): string => {
return colorsToCss(soapboxConfig.colors.toJS() as TailwindColorPalette);
};
const hexToHsl = (hex: string): Hsl | null => {
export const hexToHsl = (hex: string): Hsl | null => {
const rgb = hexToRgb(hex);
return rgb ? rgbToHsl(rgb) : null;
};