Merge branch 'main' into fix-font-problem
This commit is contained in:
commit
c070f64309
|
@ -146,7 +146,6 @@ const messages = defineMessages({
|
||||||
|
|
||||||
interface IStatusActionBar {
|
interface IStatusActionBar {
|
||||||
status: Status;
|
status: Status;
|
||||||
withLabels?: boolean;
|
|
||||||
expandable?: boolean;
|
expandable?: boolean;
|
||||||
space?: 'sm' | 'md' | 'lg';
|
space?: 'sm' | 'md' | 'lg';
|
||||||
statusActionButtonTheme?: 'default' | 'inverse';
|
statusActionButtonTheme?: 'default' | 'inverse';
|
||||||
|
@ -155,7 +154,6 @@ interface IStatusActionBar {
|
||||||
|
|
||||||
const StatusActionBar: React.FC<IStatusActionBar> = ({
|
const StatusActionBar: React.FC<IStatusActionBar> = ({
|
||||||
status,
|
status,
|
||||||
withLabels = false,
|
|
||||||
expandable = true,
|
expandable = true,
|
||||||
space = 'sm',
|
space = 'sm',
|
||||||
statusActionButtonTheme = 'default',
|
statusActionButtonTheme = 'default',
|
||||||
|
@ -740,7 +738,6 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
||||||
active={status.reblogged}
|
active={status.reblogged}
|
||||||
onClick={handleReblogClick}
|
onClick={handleReblogClick}
|
||||||
count={reblogCount}
|
count={reblogCount}
|
||||||
text={withLabels ? intl.formatMessage(messages.reblog) : undefined}
|
|
||||||
theme={statusActionButtonTheme}
|
theme={statusActionButtonTheme}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -780,7 +777,6 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
||||||
icon={messageCircleIcon}
|
icon={messageCircleIcon}
|
||||||
onClick={handleReplyClick}
|
onClick={handleReplyClick}
|
||||||
count={replyCount}
|
count={replyCount}
|
||||||
text={withLabels ? intl.formatMessage(messages.reply) : undefined}
|
|
||||||
disabled={replyDisabled}
|
disabled={replyDisabled}
|
||||||
theme={statusActionButtonTheme}
|
theme={statusActionButtonTheme}
|
||||||
/>
|
/>
|
||||||
|
@ -808,7 +804,6 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
||||||
active={Boolean(meEmojiName)}
|
active={Boolean(meEmojiName)}
|
||||||
count={emojiReactCount}
|
count={emojiReactCount}
|
||||||
emoji={meEmojiReact}
|
emoji={meEmojiReact}
|
||||||
text={withLabels ? meEmojiTitle : undefined}
|
|
||||||
theme={statusActionButtonTheme}
|
theme={statusActionButtonTheme}
|
||||||
/>
|
/>
|
||||||
</StatusReactionWrapper>
|
</StatusReactionWrapper>
|
||||||
|
@ -821,7 +816,6 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
||||||
onClick={handleFavouriteClick}
|
onClick={handleFavouriteClick}
|
||||||
active={Boolean(meEmojiName)}
|
active={Boolean(meEmojiName)}
|
||||||
count={favouriteCount}
|
count={favouriteCount}
|
||||||
text={withLabels ? meEmojiTitle : undefined}
|
|
||||||
theme={statusActionButtonTheme}
|
theme={statusActionButtonTheme}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -835,7 +829,6 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
||||||
onClick={handleDislikeClick}
|
onClick={handleDislikeClick}
|
||||||
active={status.disliked}
|
active={status.disliked}
|
||||||
count={status.dislikes_count}
|
count={status.dislikes_count}
|
||||||
text={withLabels ? intl.formatMessage(messages.disfavourite) : undefined}
|
|
||||||
theme={statusActionButtonTheme}
|
theme={statusActionButtonTheme}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -848,7 +841,6 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
||||||
filled
|
filled
|
||||||
onClick={handleZapClick}
|
onClick={handleZapClick}
|
||||||
active={status.zapped}
|
active={status.zapped}
|
||||||
text={withLabels ? intl.formatMessage(messages.zap) : undefined}
|
|
||||||
theme={statusActionButtonTheme}
|
theme={statusActionButtonTheme}
|
||||||
count={status?.zaps_amount ? status.zaps_amount / 1000 : 0}
|
count={status?.zaps_amount ? status.zaps_amount / 1000 : 0}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -36,12 +36,11 @@ interface IStatusActionButton extends React.ButtonHTMLAttributes<HTMLButtonEleme
|
||||||
color?: Color;
|
color?: Color;
|
||||||
filled?: boolean;
|
filled?: boolean;
|
||||||
emoji?: EmojiReaction;
|
emoji?: EmojiReaction;
|
||||||
text?: React.ReactNode;
|
|
||||||
theme?: 'default' | 'inverse';
|
theme?: 'default' | 'inverse';
|
||||||
}
|
}
|
||||||
|
|
||||||
const StatusActionButton = forwardRef<HTMLButtonElement, IStatusActionButton>((props, ref): JSX.Element => {
|
const StatusActionButton = forwardRef<HTMLButtonElement, IStatusActionButton>((props, ref): JSX.Element => {
|
||||||
const { icon, className, iconClassName, active, color, filled = false, count = 0, emoji, text, theme = 'default', ...filteredProps } = props;
|
const { icon, className, iconClassName, active, color, filled = false, count = 0, emoji, theme = 'default', ...filteredProps } = props;
|
||||||
|
|
||||||
const renderIcon = () => {
|
const renderIcon = () => {
|
||||||
if (emoji) {
|
if (emoji) {
|
||||||
|
@ -70,13 +69,7 @@ const StatusActionButton = forwardRef<HTMLButtonElement, IStatusActionButton>((p
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderText = () => {
|
const renderText = () => {
|
||||||
if (text) {
|
if (count) {
|
||||||
return (
|
|
||||||
<Text tag='span' theme='inherit' size='sm'>
|
|
||||||
{text}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
} else if (count) {
|
|
||||||
return (
|
return (
|
||||||
<StatusActionCounter count={count} />
|
<StatusActionCounter count={count} />
|
||||||
);
|
);
|
||||||
|
@ -88,7 +81,7 @@ const StatusActionButton = forwardRef<HTMLButtonElement, IStatusActionButton>((p
|
||||||
ref={ref}
|
ref={ref}
|
||||||
type='button'
|
type='button'
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'flex items-center rounded-full p-1 rtl:space-x-reverse',
|
'flex items-center space-x-1 rounded-full p-1 rtl:space-x-reverse',
|
||||||
'focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 dark:ring-offset-0',
|
'focus:outline-none focus:ring-2 focus:ring-primary-500 focus:ring-offset-2 dark:ring-offset-0',
|
||||||
{
|
{
|
||||||
'text-gray-600 hover:text-gray-600 dark:hover:text-white bg-white dark:bg-transparent': theme === 'default',
|
'text-gray-600 hover:text-gray-600 dark:hover:text-white bg-white dark:bg-transparent': theme === 'default',
|
||||||
|
@ -97,8 +90,6 @@ const StatusActionButton = forwardRef<HTMLButtonElement, IStatusActionButton>((p
|
||||||
'hover:text-gray-600 dark:hover:text-white': !filteredProps.disabled,
|
'hover:text-gray-600 dark:hover:text-white': !filteredProps.disabled,
|
||||||
'text-accent-300 hover:text-accent-300 dark:hover:text-accent-300': active && !emoji && color === COLORS.accent,
|
'text-accent-300 hover:text-accent-300 dark:hover:text-accent-300': active && !emoji && color === COLORS.accent,
|
||||||
'text-success-600 hover:text-success-600 dark:hover:text-success-600': active && !emoji && color === COLORS.success,
|
'text-success-600 hover:text-success-600 dark:hover:text-success-600': active && !emoji && color === COLORS.success,
|
||||||
'space-x-1': !text,
|
|
||||||
'space-x-2': text,
|
|
||||||
},
|
},
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -9,11 +9,14 @@ import Form from 'soapbox/components/ui/form.tsx';
|
||||||
import Stack from 'soapbox/components/ui/stack.tsx';
|
import Stack from 'soapbox/components/ui/stack.tsx';
|
||||||
import RelayEditor, { RelayData } from 'soapbox/features/nostr-relays/components/relay-editor.tsx';
|
import RelayEditor, { RelayData } from 'soapbox/features/nostr-relays/components/relay-editor.tsx';
|
||||||
import { useApi } from 'soapbox/hooks/useApi.ts';
|
import { useApi } from 'soapbox/hooks/useApi.ts';
|
||||||
|
import { queryClient } from 'soapbox/queries/client.ts';
|
||||||
|
import toast from 'soapbox/toast.tsx';
|
||||||
|
|
||||||
import { useAdminNostrRelays } from './hooks/useAdminNostrRelays.ts';
|
import { useAdminNostrRelays } from './hooks/useAdminNostrRelays.ts';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
title: { id: 'column.admin.nostr_relays', defaultMessage: 'Relays' },
|
title: { id: 'column.admin.nostr_relays', defaultMessage: 'Relays' },
|
||||||
|
success: { id: 'generic.saved', defaultMessage: 'Saved' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const AdminNostrRelays: React.FC = () => {
|
const AdminNostrRelays: React.FC = () => {
|
||||||
|
@ -25,6 +28,13 @@ const AdminNostrRelays: React.FC = () => {
|
||||||
|
|
||||||
const mutation = useMutation({
|
const mutation = useMutation({
|
||||||
mutationFn: async () => api.put('/api/v1/admin/ditto/relays', relays),
|
mutationFn: async () => api.put('/api/v1/admin/ditto/relays', relays),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.refetchQueries({ queryKey: ['NostrRelay'] });
|
||||||
|
toast.success(messages.success);
|
||||||
|
},
|
||||||
|
onError: (data) => {
|
||||||
|
toast.error(data.message); // `data.message` is a generic error message, not the `error` message returned from the backend
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
|
|
|
@ -390,7 +390,6 @@ const Thread = (props: IThread) => {
|
||||||
status={status}
|
status={status}
|
||||||
expandable={false}
|
expandable={false}
|
||||||
space='lg'
|
space='lg'
|
||||||
withLabels
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -135,13 +135,13 @@ class ImageLoader extends PureComponent<IImageLoader> {
|
||||||
const { alt, src, width, height, onClick } = this.props;
|
const { alt, src, width, height, onClick } = this.props;
|
||||||
const { loading } = this.state;
|
const { loading } = this.state;
|
||||||
|
|
||||||
const className = 'relative size-full flex items-center justify-center flex-col';
|
const className = 'relative h-screen flex items-center justify-center flex-col';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<canvas
|
<canvas
|
||||||
className={clsx('max-h-[80%] max-w-full object-contain', { 'hidden': !this.hasSize() })}
|
className={clsx('max-h-[100%] max-w-full object-contain', { 'hidden': !this.hasSize() })}
|
||||||
style={{
|
style={{
|
||||||
background: 'url(\'../assets/images/void.png\') repeat',
|
background: 'url(\'../assets/images/void.png\') repeat',
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -243,7 +243,7 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='pointer-events-auto fixed inset-0 z-[9999] h-full bg-gray-900/90'>
|
<div className='media-modal pointer-events-auto fixed inset-0 z-[9999] flex size-full bg-gray-900/90'>
|
||||||
<div
|
<div
|
||||||
className='absolute inset-0'
|
className='absolute inset-0'
|
||||||
role='presentation'
|
role='presentation'
|
||||||
|
@ -258,10 +258,11 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
|
||||||
}
|
}
|
||||||
justifyContent='between'
|
justifyContent='between'
|
||||||
>
|
>
|
||||||
|
<Stack className='relative h-full'>
|
||||||
<HStack
|
<HStack
|
||||||
alignItems='center'
|
alignItems='center'
|
||||||
justifyContent='between'
|
justifyContent='between'
|
||||||
className={clsx('flex-[0_0_60px] p-4 transition-opacity', navigationHiddenClassName)}
|
className={clsx('absolute z-[9999] flex w-full p-4 transition-opacity', navigationHiddenClassName)}
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
title={intl.formatMessage(messages.close)}
|
title={intl.formatMessage(messages.close)}
|
||||||
|
@ -311,15 +312,17 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<div className='size-full'>
|
||||||
<ReactSwipeableViews
|
<ReactSwipeableViews
|
||||||
style={swipeableViewsStyle}
|
style={swipeableViewsStyle}
|
||||||
containerStyle={containerStyle}
|
containerStyle={containerStyle}
|
||||||
onChangeIndex={handleSwipe}
|
onChangeIndex={handleSwipe}
|
||||||
className='flex items-center justify-center '
|
className='flex items-center justify-center'
|
||||||
index={getIndex()}
|
index={getIndex()}
|
||||||
>
|
>
|
||||||
{content}
|
{content}
|
||||||
</ReactSwipeableViews>
|
</ReactSwipeableViews>
|
||||||
|
</div>
|
||||||
|
|
||||||
{hasMultipleImages && (
|
{hasMultipleImages && (
|
||||||
<div className={clsx('absolute inset-y-0 right-5 z-10 flex items-center transition-opacity', navigationHiddenClassName)}>
|
<div className={clsx('absolute inset-y-0 right-5 z-10 flex items-center transition-opacity', navigationHiddenClassName)}>
|
||||||
|
@ -338,7 +341,7 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
|
||||||
{actualStatus && (
|
{actualStatus && (
|
||||||
<HStack
|
<HStack
|
||||||
justifyContent='center'
|
justifyContent='center'
|
||||||
className={clsx('flex-[0_0_60px] transition-opacity', navigationHiddenClassName)}
|
className={clsx('absolute bottom-2 flex w-full transition-opacity', navigationHiddenClassName)}
|
||||||
>
|
>
|
||||||
<StatusActionBar
|
<StatusActionBar
|
||||||
status={actualStatus}
|
status={actualStatus}
|
||||||
|
@ -348,6 +351,7 @@ const MediaModal: React.FC<IMediaModal> = (props) => {
|
||||||
</HStack>
|
</HStack>
|
||||||
)}
|
)}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
|
||||||
{actualStatus && (
|
{actualStatus && (
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import clsx from 'clsx';
|
||||||
import { PureComponent } from 'react';
|
import { PureComponent } from 'react';
|
||||||
|
|
||||||
const MIN_SCALE = 1;
|
const MIN_SCALE = 1;
|
||||||
|
@ -132,7 +133,7 @@ class ZoomableImage extends PureComponent<IZoomableImage> {
|
||||||
role='presentation'
|
role='presentation'
|
||||||
ref={this.setImageRef}
|
ref={this.setImageRef}
|
||||||
alt={alt}
|
alt={alt}
|
||||||
className='size-auto max-h-[80%] max-w-full object-contain shadow-2xl'
|
className={clsx('size-auto max-h-[80%] max-w-full object-contain', { 'size-full max-h-full': scale !== 1 })}
|
||||||
title={alt}
|
title={alt}
|
||||||
src={src}
|
src={src}
|
||||||
style={{
|
style={{
|
||||||
|
|
|
@ -1217,17 +1217,16 @@
|
||||||
"onboarding.avatar.title": "Escolha uma foto de perfil",
|
"onboarding.avatar.title": "Escolha uma foto de perfil",
|
||||||
"onboarding.bio.hint": "Máx 500 caracteres",
|
"onboarding.bio.hint": "Máx 500 caracteres",
|
||||||
"onboarding.bio.placeholder": "Conte um pouco sobre você…",
|
"onboarding.bio.placeholder": "Conte um pouco sobre você…",
|
||||||
|
"onboarding.display_identity.fields.reason_placeholder": "Por que você quer fazer parte da comunidade {siteTitle}?",
|
||||||
|
"onboarding.display_identity.help_text": "Este identificador é um nome de usuário único que representa você na plataforma. Ele é gerado automaticamente com base no site, garantindo que você tenha uma identidade distinta para interagir com outros usuários. Este nome de usuário pode ser usado para personalizar sua experiência e facilitar a comunicação dentro da comunidade.",
|
||||||
|
"onboarding.display_identity.label": "Identidade",
|
||||||
|
"onboarding.display_identity.request": "Nome de usúario solicitado",
|
||||||
|
"onboarding.display_identity.subtitle": "Mostre quem você é! Crie um nome de usuário único e deixe sua marca.",
|
||||||
|
"onboarding.display_identity.title": "Escolha uma Identidade",
|
||||||
"onboarding.display_name.label": "Nome de exibição",
|
"onboarding.display_name.label": "Nome de exibição",
|
||||||
"onboarding.display_name.placeholder": "Ex. João Silva",
|
"onboarding.display_name.placeholder": "Ex. João Silva",
|
||||||
"onboarding.display_name.subtitle": "Você pode sempre editar isso depois.",
|
"onboarding.display_name.subtitle": "Você pode sempre editar isso depois.",
|
||||||
"onboarding.display_name.title": "Escolha um nome de exibição",
|
"onboarding.display_name.title": "Escolha um nome de exibição",
|
||||||
"onboarding.display_identity.title": "Escolha uma Identidade",
|
|
||||||
"onboarding.display_identity.label": "Identidade",
|
|
||||||
"onboarding.display_identity.request": "Nome de usúario solicitado",
|
|
||||||
"onboarding.display_identity.subtitle": "Mostre quem você é! Crie um nome de usuário único e deixe sua marca.",
|
|
||||||
"onboarding.display_identity.help_text": "Este identificador é um nome de usuário único que representa você na plataforma. Ele é gerado automaticamente com base no site, garantindo que você tenha uma identidade distinta para interagir com outros usuários. Este nome de usuário pode ser usado para personalizar sua experiência e facilitar a comunicação dentro da comunidade.",
|
|
||||||
"onboarding.display_identity.fields.nip05_label": "Nome de usuário",
|
|
||||||
"onboarding.display_identity.fields.reason_placeholder": "Por que você quer fazer parte da comunidade {siteTitle}?",
|
|
||||||
"onboarding.done": "Concluído",
|
"onboarding.done": "Concluído",
|
||||||
"onboarding.error": "Ocorreu um erro inesperado. Por favor, tente novamente ou pule esta etapa.",
|
"onboarding.error": "Ocorreu um erro inesperado. Por favor, tente novamente ou pule esta etapa.",
|
||||||
"onboarding.finished.message": "Estamos muito empolgados para te receber em nossa comunidade! Toque no botão abaixo para começar.",
|
"onboarding.finished.message": "Estamos muito empolgados para te receber em nossa comunidade! Toque no botão abaixo para começar.",
|
||||||
|
|
|
@ -883,6 +883,7 @@ const getInstanceFeatures = (instance: InstanceV1 | InstanceV2) => {
|
||||||
v.software === MASTODON,
|
v.software === MASTODON,
|
||||||
v.software === PLEROMA,
|
v.software === PLEROMA,
|
||||||
v.software === TAKAHE && gte(v.version, '0.7.0'),
|
v.software === TAKAHE && gte(v.version, '0.7.0'),
|
||||||
|
v.software === DITTO,
|
||||||
]),
|
]),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue