diff --git a/packages/pl-api/lib/entities/account.ts b/packages/pl-api/lib/entities/account.ts index 254a5709a..35ee9c76c 100644 --- a/packages/pl-api/lib/entities/account.ts +++ b/packages/pl-api/lib/entities/account.ts @@ -33,12 +33,14 @@ const preprocessAccount = v.transform((account: any) => { if (!account?.acct) return null; const username = account.username || account.acct.split('@')[0]; - const fqn = guessFqn(account); + + const fqn = account.fqn || guessFqn(account); + const domain = fqn.split('@')[1] || ''; return { username, fqn, - domain: fqn.split('@')[1] || '', + domain, avatar_static: account.avatar_static || account.avatar, header_static: account.header_static || account.header, local: typeof account.pleroma?.is_local === 'boolean' ? account.pleroma.is_local : account.acct.split('@')[1] === undefined, @@ -96,7 +98,7 @@ const baseAccountSchema = v.object({ acct: v.fallback(v.string(), ''), url: v.pipe(v.string(), v.url()), display_name: v.fallback(v.string(), ''), - content: v.fallback(v.pipe(v.string(), v.transform((note => note === '

' ? '' : note))), ''), + note: v.fallback(v.pipe(v.string(), v.transform(note => note === '

' ? '' : note)), ''), avatar: v.fallback(v.string(), ''), avatar_static: v.fallback(v.pipe(v.string(), v.url()), ''), header: v.fallback(v.pipe(v.string(), v.url()), ''), @@ -110,7 +112,7 @@ const baseAccountSchema = v.object({ noindex: v.fallback(v.nullable(v.boolean()), null), suspended: v.fallback(v.optional(v.boolean()), undefined), limited: v.fallback(v.optional(v.boolean()), undefined), - created_at: v.fallback(datetimeSchema, new Date().toUTCString()), + created_at: v.fallback(datetimeSchema, new Date().toISOString()), last_status_at: v.fallback(v.nullable(v.pipe(v.string(), v.isoDate())), null), statuses_count: v.fallback(v.number(), 0), followers_count: v.fallback(v.number(), 0), diff --git a/packages/pl-api/lib/entities/admin/account.ts b/packages/pl-api/lib/entities/admin/account.ts index 58c713bf5..7d5274dc6 100644 --- a/packages/pl-api/lib/entities/admin/account.ts +++ b/packages/pl-api/lib/entities/admin/account.ts @@ -7,7 +7,7 @@ import { datetimeSchema, filteredArray } from '../utils'; import { adminIpSchema } from './ip'; /** @see {@link https://docs.joinmastodon.org/entities/Admin_Account/} */ -const adminAccountSchema = v.pipe( +const adminAccountSchema = v.pipe( v.any(), v.transform((account: any) => { if (!account.account) { diff --git a/packages/pl-api/lib/entities/admin/announcement.ts b/packages/pl-api/lib/entities/admin/announcement.ts index 5cef6c4a1..93d9bca26 100644 --- a/packages/pl-api/lib/entities/admin/announcement.ts +++ b/packages/pl-api/lib/entities/admin/announcement.ts @@ -4,7 +4,7 @@ import * as v from 'valibot'; import { announcementSchema } from '../announcement'; /** @see {@link https://docs.pleroma.social/backend/development/API/admin_api/#get-apiv1pleromaadminannouncements} */ -const adminAnnouncementSchema = v.pipe( +const adminAnnouncementSchema = v.pipe( v.any(), v.transform((announcement: any) => ({ ...announcement, diff --git a/packages/pl-api/lib/entities/admin/relay.ts b/packages/pl-api/lib/entities/admin/relay.ts index efe2df0a8..e5d4e6993 100644 --- a/packages/pl-api/lib/entities/admin/relay.ts +++ b/packages/pl-api/lib/entities/admin/relay.ts @@ -1,6 +1,6 @@ import * as v from 'valibot'; -const adminRelaySchema = v.pipe( +const adminRelaySchema = v.pipe( v.any(), v.transform((data: any) => ({ id: data.actor, ...data })), v.object({ diff --git a/packages/pl-api/lib/entities/admin/report.ts b/packages/pl-api/lib/entities/admin/report.ts index c3386aec1..6a0526f75 100644 --- a/packages/pl-api/lib/entities/admin/report.ts +++ b/packages/pl-api/lib/entities/admin/report.ts @@ -8,7 +8,7 @@ import { datetimeSchema, filteredArray } from '../utils'; import { adminAccountSchema } from './account'; /** @see {@link https://docs.joinmastodon.org/entities/Admin_Report/} */ -const adminReportSchema = v.pipe( +const adminReportSchema = v.pipe( v.any(), v.transform((report: any) => { if (report.actor) { diff --git a/packages/pl-api/lib/entities/instance.ts b/packages/pl-api/lib/entities/instance.ts index 6a1413781..22a7fc055 100644 --- a/packages/pl-api/lib/entities/instance.ts +++ b/packages/pl-api/lib/entities/instance.ts @@ -203,7 +203,7 @@ const pleromaSchema = coerceObject({ )), enabled: v.fallback(v.boolean(), false), }), - post_formats: v.fallback(v.optional(v.array(v.string())), undefined), + post_formats: v.fallback(v.array(v.string()), ['text/plain']), restrict_unauthenticated: coerceObject({ activities: coerceObject({ local: v.fallback(v.boolean(), false), diff --git a/packages/pl-api/lib/entities/rule.ts b/packages/pl-api/lib/entities/rule.ts index a94f2d117..c1077cb0d 100644 --- a/packages/pl-api/lib/entities/rule.ts +++ b/packages/pl-api/lib/entities/rule.ts @@ -7,7 +7,7 @@ const baseRuleSchema = v.object({ }); /** @see {@link https://docs.joinmastodon.org/entities/Rule/} */ -const ruleSchema = v.pipe( +const ruleSchema = v.pipe( v.any(), v.transform((data: any) => ({ ...data, diff --git a/packages/pl-api/lib/entities/scrobble.ts b/packages/pl-api/lib/entities/scrobble.ts index e27d2d607..483805caf 100644 --- a/packages/pl-api/lib/entities/scrobble.ts +++ b/packages/pl-api/lib/entities/scrobble.ts @@ -3,7 +3,7 @@ import * as v from 'valibot'; import { accountSchema } from './account'; import { datetimeSchema } from './utils'; -const scrobbleSchema = v.pipe( +const scrobbleSchema = v.pipe( v.any(), v.transform((scrobble: any) => scrobble ? { external_link: scrobble.externalLink, diff --git a/packages/pl-api/lib/entities/suggestion.ts b/packages/pl-api/lib/entities/suggestion.ts index 9b9f12168..875c0f8d1 100644 --- a/packages/pl-api/lib/entities/suggestion.ts +++ b/packages/pl-api/lib/entities/suggestion.ts @@ -3,7 +3,7 @@ import * as v from 'valibot'; import { accountSchema } from './account'; /** @see {@link https://docs.joinmastodon.org/entities/Suggestion} */ -const suggestionSchema = v.pipe( +const suggestionSchema = v.pipe( v.any(), v.transform((suggestion: any) => { /** diff --git a/packages/pl-api/lib/entities/translation.ts b/packages/pl-api/lib/entities/translation.ts index 07ffa270d..ed2727841 100644 --- a/packages/pl-api/lib/entities/translation.ts +++ b/packages/pl-api/lib/entities/translation.ts @@ -15,7 +15,7 @@ const translationMediaAttachment = v.object({ }); /** @see {@link https://docs.joinmastodon.org/entities/Translation/} */ -const translationSchema = v.pipe( +const translationSchema = v.pipe( v.any(), v.transform((translation: any) => { /** diff --git a/packages/pl-api/lib/entities/trends-link.ts b/packages/pl-api/lib/entities/trends-link.ts index 0ed03dbd2..e2909347a 100644 --- a/packages/pl-api/lib/entities/trends-link.ts +++ b/packages/pl-api/lib/entities/trends-link.ts @@ -4,7 +4,7 @@ import { blurhashSchema } from './media-attachment'; import { historySchema } from './tag'; /** @see {@link https://docs.joinmastodon.org/entities/PreviewCard/#trends-link} */ -const trendsLinkSchema = v.pipe( +const trendsLinkSchema = v.pipe( v.any(), v.transform((link: any) => ({ ...link, id: link.url })), v.object({ diff --git a/packages/pl-api/lib/features.ts b/packages/pl-api/lib/features.ts index f1056035f..82058cff3 100644 --- a/packages/pl-api/lib/features.ts +++ b/packages/pl-api/lib/features.ts @@ -1000,6 +1000,7 @@ const getFeatures = (instance: Instance) => { v.software === PLEROMA, v.software === MITRA, v.software === GOTOSOCIAL, + instance.pleroma.metadata.post_formats.length > 1, ]), /** diff --git a/packages/pl-api/package.json b/packages/pl-api/package.json index f9cdc9b72..6df7d29b5 100644 --- a/packages/pl-api/package.json +++ b/packages/pl-api/package.json @@ -1,6 +1,6 @@ { "name": "pl-api", - "version": "0.1.2", + "version": "0.1.3", "type": "module", "homepage": "https://github.com/mkljczk/pl-fe/tree/fork/packages/pl-api", "repository": { diff --git a/packages/pl-fe/package.json b/packages/pl-fe/package.json index 583511b49..b6ae6c9e4 100644 --- a/packages/pl-fe/package.json +++ b/packages/pl-fe/package.json @@ -102,7 +102,7 @@ "mini-css-extract-plugin": "^2.9.1", "multiselect-react-dropdown": "^2.0.25", "path-browserify": "^1.0.1", - "pl-api": "^0.1.2", + "pl-api": "^0.1.3", "pl-hooks": "^0.0.1", "postcss": "^8.4.47", "process": "^0.11.10", diff --git a/packages/pl-fe/src/api/hooks/admin/useAnnouncements.ts b/packages/pl-fe/src/api/hooks/admin/useAnnouncements.ts index c20dc1ce9..6c2c78ff1 100644 --- a/packages/pl-fe/src/api/hooks/admin/useAnnouncements.ts +++ b/packages/pl-fe/src/api/hooks/admin/useAnnouncements.ts @@ -1,14 +1,13 @@ import { useMutation, useQuery } from '@tanstack/react-query'; import { adminAnnouncementSchema, - type AdminAnnouncement as BaseAdminAnnouncement, + type AdminAnnouncement, type AdminCreateAnnouncementParams, type AdminUpdateAnnouncementParams, } from 'pl-api'; import * as v from 'valibot'; import { useClient } from 'pl-fe/hooks/useClient'; -import { normalizeAnnouncement, AdminAnnouncement } from 'pl-fe/normalizers/announcement'; import { queryClient } from 'pl-fe/queries/client'; import { useAnnouncements as useUserAnnouncements } from '../announcements/useAnnouncements'; @@ -20,7 +19,7 @@ const useAnnouncements = () => { const getAnnouncements = async () => { const data = await client.admin.announcements.getAnnouncements(); - return data.items.map(normalizeAnnouncement); + return data.items; }; const result = useQuery>({ diff --git a/packages/pl-fe/src/api/hooks/announcements/useAnnouncements.ts b/packages/pl-fe/src/api/hooks/announcements/useAnnouncements.ts index d505fd38c..04443affd 100644 --- a/packages/pl-fe/src/api/hooks/announcements/useAnnouncements.ts +++ b/packages/pl-fe/src/api/hooks/announcements/useAnnouncements.ts @@ -1,9 +1,8 @@ import { useMutation, useQuery } from '@tanstack/react-query'; -import { announcementReactionSchema, type AnnouncementReaction } from 'pl-api'; +import { announcementReactionSchema, type AnnouncementReaction, type Announcement } from 'pl-api'; import * as v from 'valibot'; import { useClient } from 'pl-fe/hooks/useClient'; -import { type Announcement, normalizeAnnouncement } from 'pl-fe/normalizers/announcement'; import { queryClient } from 'pl-fe/queries/client'; const updateReaction = (reaction: AnnouncementReaction, count: number, me?: boolean, overwrite?: boolean) => v.parse(announcementReactionSchema, { @@ -25,14 +24,9 @@ const updateReactions = (reactions: AnnouncementReaction[], name: string, count: const useAnnouncements = () => { const client = useClient(); - const getAnnouncements = async () => { - const data = await client.announcements.getAnnouncements(); - return data.map(normalizeAnnouncement); - }; - const { data, ...result } = useQuery>({ queryKey: ['announcements'], - queryFn: getAnnouncements, + queryFn: () => client.announcements.getAnnouncements(), placeholderData: [], }); diff --git a/packages/pl-fe/src/components/account-hover-card.tsx b/packages/pl-fe/src/components/account-hover-card.tsx index 01b6a22d3..0426fba86 100644 --- a/packages/pl-fe/src/components/account-hover-card.tsx +++ b/packages/pl-fe/src/components/account-hover-card.tsx @@ -160,7 +160,7 @@ const AccountHoverCard: React.FC = ({ visible = true }) => { size='sm' className='mr-2 rtl:ml-2 rtl:mr-0 [&_br]:hidden [&_p:first-child]:inline [&_p:first-child]:truncate [&_p]:hidden' > - + )} diff --git a/packages/pl-fe/src/components/account.tsx b/packages/pl-fe/src/components/account.tsx index fcb716158..affda2e66 100644 --- a/packages/pl-fe/src/components/account.tsx +++ b/packages/pl-fe/src/components/account.tsx @@ -11,6 +11,7 @@ import IconButton from 'pl-fe/components/ui/icon-button'; 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 Emojify from 'pl-fe/features/emoji/emojify'; import ActionButton from 'pl-fe/features/ui/components/action-button'; import { useAppSelector } from 'pl-fe/hooks/useAppSelector'; import { getAcct } from 'pl-fe/utils/accounts'; @@ -219,8 +220,9 @@ const Account = ({ size='sm' weight='semibold' truncate - dangerouslySetInnerHTML={{ __html: account.display_name_html }} - /> + > + + {account.verified && } @@ -281,8 +283,9 @@ const Account = ({ size='sm' weight='semibold' truncate - dangerouslySetInnerHTML={{ __html: account.display_name_html }} - /> + > + + {account.verified && } @@ -356,7 +359,7 @@ const Account = ({ truncate size='sm' > - + )} diff --git a/packages/pl-fe/src/components/announcements/announcement-content.tsx b/packages/pl-fe/src/components/announcements/announcement-content.tsx index d9bfb3408..6c405c166 100644 --- a/packages/pl-fe/src/components/announcements/announcement-content.tsx +++ b/packages/pl-fe/src/components/announcements/announcement-content.tsx @@ -3,8 +3,9 @@ import { useHistory } from 'react-router-dom'; import { getTextDirection } from 'pl-fe/utils/rtl'; -import type { Mention as MentionEntity } from 'pl-api'; -import type { Announcement } from 'pl-fe/normalizers/announcement'; +import { ParsedContent } from '../parsed-content'; + +import type { Announcement, Mention as MentionEntity } from 'pl-api'; interface IAnnouncementContent { announcement: Announcement; @@ -83,8 +84,9 @@ const AnnouncementContent: React.FC = ({ announcement }) = dir={direction} className='text-sm ltr:ml-0 rtl:mr-0' ref={node} - dangerouslySetInnerHTML={{ __html: announcement.contentHtml }} - /> + > + + ); }; diff --git a/packages/pl-fe/src/components/announcements/announcement.tsx b/packages/pl-fe/src/components/announcements/announcement.tsx index d83d01feb..c99cb6385 100644 --- a/packages/pl-fe/src/components/announcements/announcement.tsx +++ b/packages/pl-fe/src/components/announcements/announcement.tsx @@ -10,8 +10,7 @@ import AnnouncementContent from './announcement-content'; import ReactionsBar from './reactions-bar'; import type { Map as ImmutableMap } from 'immutable'; -import type { CustomEmoji } from 'pl-api'; -import type { Announcement as AnnouncementEntity } from 'pl-fe/normalizers/announcement'; +import type { Announcement as AnnouncementEntity, CustomEmoji } from 'pl-api'; interface IAnnouncement { announcement: AnnouncementEntity; diff --git a/packages/pl-fe/src/components/event-preview.tsx b/packages/pl-fe/src/components/event-preview.tsx index 115d08512..c952cbdb7 100644 --- a/packages/pl-fe/src/components/event-preview.tsx +++ b/packages/pl-fe/src/components/event-preview.tsx @@ -8,6 +8,7 @@ import HStack from 'pl-fe/components/ui/hstack'; 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 Emojify from 'pl-fe/features/emoji/emojify'; import EventActionButton from 'pl-fe/features/event/components/event-action-button'; import EventDate from 'pl-fe/features/event/components/event-date'; import { useAppSelector } from 'pl-fe/hooks/useAppSelector'; @@ -71,7 +72,9 @@ const EventPreview: React.FC = ({ status, className, hideAction, - + + + {account.verified && } diff --git a/packages/pl-fe/src/components/group-card.tsx b/packages/pl-fe/src/components/group-card.tsx index 66c604e56..1a384169a 100644 --- a/packages/pl-fe/src/components/group-card.tsx +++ b/packages/pl-fe/src/components/group-card.tsx @@ -3,6 +3,7 @@ import React from 'react'; import HStack from 'pl-fe/components/ui/hstack'; 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 GroupHeaderImage from 'pl-fe/features/group/components/group-header-image'; import GroupMemberCount from 'pl-fe/features/group/components/group-member-count'; import GroupPrivacy from 'pl-fe/features/group/components/group-privacy'; @@ -37,7 +38,9 @@ const GroupCard: React.FC = ({ group }) => ( {/* Group Info */} - + + + diff --git a/packages/pl-fe/src/components/groups/popover/group-popover.tsx b/packages/pl-fe/src/components/groups/popover/group-popover.tsx index 88daf39e8..c2f5f5bed 100644 --- a/packages/pl-fe/src/components/groups/popover/group-popover.tsx +++ b/packages/pl-fe/src/components/groups/popover/group-popover.tsx @@ -8,6 +8,7 @@ import HStack from 'pl-fe/components/ui/hstack'; 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 Emojify from 'pl-fe/features/emoji/emojify'; import GroupMemberCount from 'pl-fe/features/group/components/group-member-count'; import GroupPrivacy from 'pl-fe/features/group/components/group-privacy'; @@ -71,7 +72,9 @@ const GroupPopover = (props: IGroupPopoverContainer) => { {/* Group Info */} - + + + diff --git a/packages/pl-fe/src/components/parsed-content.tsx b/packages/pl-fe/src/components/parsed-content.tsx index 234a86c85..2573a3c4b 100644 --- a/packages/pl-fe/src/components/parsed-content.tsx +++ b/packages/pl-fe/src/components/parsed-content.tsx @@ -3,11 +3,14 @@ import DOMPurify from 'isomorphic-dompurify'; import React, { useMemo } from 'react'; import { Link } from 'react-router-dom'; +import Emojify from 'pl-fe/features/emoji/emojify'; +import { makeEmojiMap } from 'pl-fe/utils/normalizers'; + import HashtagLink from './hashtag-link'; import HoverAccountWrapper from './hover-account-wrapper'; import StatusMention from './status-mention'; -import type { Mention } from 'pl-api'; +import type { CustomEmoji, Mention } from 'pl-api'; const nodesToText = (nodes: Array): string => nodes.map(node => node.type === 'text' ? node.data : node.type === 'tag' ? nodesToText(node.children as Array) : '').join(''); @@ -19,14 +22,18 @@ interface IParsedContent { mentions?: Array; /** Whether it's a status which has a quote. */ hasQuote?: boolean; + /** Related custom emojis. */ + emojis?: Array; } -const ParsedContent: React.FC = (({ html, mentions, hasQuote }) => { +const ParsedContent: React.FC = (({ html, mentions, hasQuote, emojis }) => { return useMemo(() => { if (html.length === 0) { return null; } + const emojiMap = emojis ? makeEmojiMap(emojis) : undefined; + const selectors: Array = []; // Explicit mentions @@ -99,6 +106,14 @@ const ParsedContent: React.FC = (({ html, mentions, hasQuote }) return fallback; } }, + + transform(reactNode) { + if (typeof reactNode === 'string') { + return ; + } + + return reactNode as JSX.Element; + }, }; return parse(DOMPurify.sanitize(html, { ADD_ATTR: ['target'], USE_PROFILES: { html: true } }), options); diff --git a/packages/pl-fe/src/components/polls/poll-footer.tsx b/packages/pl-fe/src/components/polls/poll-footer.tsx index d619a4bc4..b63aaa4a5 100644 --- a/packages/pl-fe/src/components/polls/poll-footer.tsx +++ b/packages/pl-fe/src/components/polls/poll-footer.tsx @@ -12,7 +12,7 @@ import { useAppDispatch } from 'pl-fe/hooks/useAppDispatch'; import RelativeTimestamp from '../relative-timestamp'; import type { Selected } from './poll'; -import type { Poll } from 'pl-fe/normalizers/poll'; +import type { Poll } from 'pl-api'; const messages = defineMessages({ closed: { id: 'poll.closed', defaultMessage: 'Closed' }, diff --git a/packages/pl-fe/src/components/polls/poll-option.tsx b/packages/pl-fe/src/components/polls/poll-option.tsx index 99cf9c14b..caef4e4fa 100644 --- a/packages/pl-fe/src/components/polls/poll-option.tsx +++ b/packages/pl-fe/src/components/polls/poll-option.tsx @@ -7,7 +7,9 @@ import HStack from 'pl-fe/components/ui/hstack'; import Icon from 'pl-fe/components/ui/icon'; import Text from 'pl-fe/components/ui/text'; -import type { Poll } from 'pl-fe/normalizers/poll'; +import { ParsedContent } from '../parsed-content'; + +import type { Poll } from 'pl-api'; const messages = defineMessages({ voted: { id: 'poll.voted', defaultMessage: 'You voted for this answer' }, @@ -65,8 +67,9 @@ const PollOptionText: React.FC = ({ poll, option, index, active theme='inherit' weight='medium' align='center' - dangerouslySetInnerHTML={{ __html: option.title_emojified }} - /> + > + + @@ -133,9 +136,10 @@ const PollOption: React.FC = (props): JSX.Element | null => { + > + + diff --git a/packages/pl-fe/src/components/status-action-bar.tsx b/packages/pl-fe/src/components/status-action-bar.tsx index ca96e3a67..f4588cfa9 100644 --- a/packages/pl-fe/src/components/status-action-bar.tsx +++ b/packages/pl-fe/src/components/status-action-bar.tsx @@ -5,7 +5,7 @@ import { useHistory, useRouteMatch } from 'react-router-dom'; import { blockAccount } from 'pl-fe/actions/accounts'; import { directCompose, mentionCompose, quoteCompose, replyCompose } from 'pl-fe/actions/compose'; -import { emojiReact } from 'pl-fe/actions/emoji-reacts'; +import { emojiReact, unEmojiReact } from 'pl-fe/actions/emoji-reacts'; import { editEvent } from 'pl-fe/actions/events'; import { toggleBookmark, toggleDislike, toggleFavourite, togglePin, toggleReblog } from 'pl-fe/actions/interactions'; import { deleteStatusModal, toggleStatusSensitivityModal } from 'pl-fe/actions/moderation'; @@ -104,6 +104,7 @@ const messages = defineMessages({ unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' }, unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' }, viewReactions: { id: 'status.view_reactions', defaultMessage: 'View reactions' }, + wrench: { id: 'status.wrench', defaultMessage: 'Wrench reaction' }, addKnownLanguage: { id: 'status.add_known_language', defaultMessage: 'Do not auto-translate posts in {language}.' }, translate: { id: 'status.translate', defaultMessage: 'Translate' }, hideTranslation: { id: 'status.hide_translation', defaultMessage: 'Hide translation' }, @@ -143,7 +144,9 @@ const StatusActionBar: React.FC = ({ const { groupRelationship } = useGroupRelationship(status.group_id || undefined); const features = useFeatures(); const instance = useInstance(); - const { autoTranslate, boostModal, deleteModal, knownLanguages } = useSettings(); + const { autoTranslate, boostModal, deleteModal, knownLanguages, showWrenchButton } = useSettings(); + + const wrenches = showWrenchButton && status.emoji_reactions.find(emoji => emoji.name === '🔧') || undefined; const { translationLanguages } = useTranslationLanguages(); @@ -153,7 +156,7 @@ const StatusActionBar: React.FC = ({ allow_unauthenticated: allowUnauthenticated, } = instance.pleroma.metadata.translation; - const renderTranslate = (me || allowUnauthenticated) && (allowRemote || status.account.local) && ['public', 'unlisted'].includes(status.visibility) && status.contentHtml.length > 0 && status.language !== null && !knownLanguages.includes(status.language); + const renderTranslate = (me || allowUnauthenticated) && (allowRemote || status.account.local) && ['public', 'unlisted'].includes(status.visibility) && status.content.length > 0 && status.language !== null && !knownLanguages.includes(status.language); const supportsLanguages = (translationLanguages[status.language!]?.includes(intl.locale)); return autoTranslate && features.translations && renderTranslate && supportsLanguages; @@ -211,10 +214,24 @@ const StatusActionBar: React.FC = ({ } }; + const handleWrenchClick: React.EventHandler = (e) => { + if (!me) { + onOpenUnauthorizedModal('DISLIKE'); + } else if (wrenches?.me) { + dispatch(unEmojiReact(status, '🔧')); + } else { + dispatch(emojiReact(status, '🔧')); + } + }; + const handleDislikeLongPress = status.dislikes_count ? () => { openModal('DISLIKES', { statusId: status.id }); } : undefined; + const handleWrenchLongPress = wrenches?.count ? () => { + openModal('REACTIONS', { statusId: status.id, reaction: wrenches.name }); + } : undefined; + const handlePickEmoji = (emoji: EmojiType) => { dispatch(emojiReact(status, emoji.custom ? emoji.id : emoji.native, emoji.custom ? emoji.imageUrl : undefined)); }; @@ -784,6 +801,20 @@ const StatusActionBar: React.FC = ({ /> )} + {me && !withLabels && features.emojiReacts && showWrenchButton && ( + + )} + {me && !withLabels && features.emojiReacts && ( = React.memo(({ maybeSetOnlyEmoji(); }); - const parsedHtml = useMemo( + const content = useMemo( (): string => translatable && status.translation ? status.translation.content! - : (status.contentMapHtml && status.currentLanguage) - ? (status.contentMapHtml[status.currentLanguage] || status.contentHtml) - : status.contentHtml, - [status.contentHtml, status.translation, status.currentLanguage], + : (status.content_map && status.currentLanguage) + ? (status.content_map[status.currentLanguage] || status.content) + : status.content, + [status.content, status.translation, status.currentLanguage], ); useEffect(() => { @@ -121,9 +122,9 @@ const StatusContent: React.FC = React.memo(({ const withSpoiler = status.spoiler_text.length > 0; - const spoilerText = status.spoilerMapHtml && status.currentLanguage - ? status.spoilerMapHtml[status.currentLanguage] || status.spoilerHtml - : status.spoilerHtml; + const spoilerText = status.spoiler_text_map && status.currentLanguage + ? status.spoiler_text_map[status.currentLanguage] || status.spoiler_text + : status.spoiler_text; const direction = getTextDirection(status.search_index); const className = clsx('relative text-ellipsis break-words text-gray-900 focus:outline-none dark:text-gray-100', { @@ -142,11 +143,9 @@ const StatusContent: React.FC = React.memo(({ if (spoilerText) { output.push( - + + + {status.content && expandable && (