Merge remote-tracking branch 'soapbox/develop' into cleanup

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak
2023-01-03 21:09:43 +01:00
12 changed files with 644 additions and 537 deletions

View File

@@ -5,7 +5,7 @@ import Blurhash from 'soapbox/components/blurhash';
import Icon from 'soapbox/components/icon';
import StillImage from 'soapbox/components/still-image';
import { MIMETYPE_ICONS } from 'soapbox/components/upload';
import { useSettings } from 'soapbox/hooks';
import { useSettings, useSoapboxConfig } from 'soapbox/hooks';
import { Attachment } from 'soapbox/types/entities';
import { truncateFilename } from 'soapbox/utils/media';
@@ -72,6 +72,7 @@ const Item: React.FC<IItem> = ({
}) => {
const settings = useSettings();
const autoPlayGif = settings.get('autoPlayGif') === true;
const { mediaPreview } = useSoapboxConfig();
const handleMouseEnter: React.MouseEventHandler<HTMLVideoElement> = ({ currentTarget: video }) => {
if (hoverToPlay()) {
@@ -171,7 +172,7 @@ const Item: React.FC<IItem> = ({
>
<StillImage
className='w-full h-full'
src={attachment.url}
src={mediaPreview ? attachment.preview_url : attachment.url}
alt={attachment.description}
letterboxed={letterboxed}
showExt

View File

@@ -1,5 +1,5 @@
import classNames from 'clsx';
import React, { useEffect, useMemo, useState } from 'react';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { FormattedMessage } from 'react-intl';
import { replaceHomeTimeline } from 'soapbox/actions/timelines';
@@ -11,7 +11,7 @@ import PlaceholderAvatar from '../placeholder/components/placeholder-avatar';
const CarouselItem = React.forwardRef((
{ avatar, seen, onViewed, onPinned }: { avatar: Avatar, seen: boolean, onViewed: (account_id: string) => void, onPinned?: (avatar: null | Avatar) => void },
ref: any,
ref: React.ForwardedRef<HTMLDivElement>,
) => {
const dispatch = useAppDispatch();
@@ -40,8 +40,11 @@ const CarouselItem = React.forwardRef((
onPinned(avatar);
}
onViewed(avatar.account_id);
markAsSeen.mutate(avatar.account_id);
if (!seen) {
onViewed(avatar.account_id);
markAsSeen.mutate(avatar.account_id);
}
dispatch(replaceHomeTimeline(avatar.account_id, { maxId: null }, () => setLoading(false)));
}
};
@@ -51,7 +54,7 @@ const CarouselItem = React.forwardRef((
ref={ref}
aria-disabled={isFetching}
onClick={handleClick}
className='cursor-pointer snap-start py-4'
className='cursor-pointer py-4'
role='filter-feed-by-user'
data-testid='carousel-item'
>
@@ -87,6 +90,7 @@ const FeedCarousel = () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_ref, setContainerRef, { width }] = useDimensions();
const carouselItemRef = useRef<HTMLDivElement>(null);
const [seenAccountIds, setSeenAccountIds] = useState<string[]>([]);
const [pageSize, setPageSize] = useState<number>(0);
@@ -151,18 +155,18 @@ const FeedCarousel = () => {
data-testid='feed-carousel'
>
<HStack alignItems='stretch'>
<div className='z-10 rounded-l-xl bg-white dark:bg-gray-900 w-8 flex self-stretch items-center justify-center'>
<div className='z-10 rounded-l-xl bg-white dark:bg-primary-900 w-8 flex self-stretch items-center justify-center'>
<button
data-testid='prev-page'
onClick={handlePrevPage}
className='h-7 w-7 flex items-center justify-center disabled:opacity-25 transition-opacity duration-500'
className='w-7 flex items-center justify-center disabled:opacity-25 transition-opacity duration-500'
disabled={!hasPrevPage}
>
<Icon src={require('@tabler/icons/chevron-left.svg')} className='text-black dark:text-white h-5 w-5' />
</button>
</div>
<div className='overflow-hidden relative'>
<div className='overflow-hidden relative w-full'>
{pinnedAvatar ? (
<div
className='z-10 flex items-center justify-center absolute left-0 top-0 bottom-0 bg-white dark:bg-primary-900'
@@ -175,6 +179,7 @@ const FeedCarousel = () => {
seen={seenAccountIds?.includes(pinnedAvatar.account_id)}
onViewed={markAsSeen}
onPinned={(avatar) => setPinnedAvatar(avatar)}
ref={carouselItemRef}
/>
</div>
) : null}
@@ -203,7 +208,11 @@ const FeedCarousel = () => {
}}
>
{avatar === null ? (
<Stack className='w-14 snap-start py-4 h-auto' space={3}>
<Stack
className='w-14 py-4 h-auto'
space={3}
style={{ height: carouselItemRef.current?.clientHeight }}
>
<div className='block mx-auto relative w-16 h-16 rounded-full'>
<div className='w-16 h-16' />
</div>
@@ -227,11 +236,11 @@ const FeedCarousel = () => {
</HStack>
</div>
<div className='z-10 rounded-r-xl bg-white dark:bg-gray-900 w-8 self-stretch flex items-center justify-center'>
<div className='z-10 rounded-r-xl bg-white dark:bg-primary-900 w-8 self-stretch flex items-center justify-center'>
<button
data-testid='next-page'
onClick={handleNextPage}
className='h-7 w-7 flex items-center justify-center disabled:opacity-25 transition-opacity duration-500'
className='w-7 flex items-center justify-center disabled:opacity-25 transition-opacity duration-500'
disabled={!hasNextPage}
>
<Icon src={require('@tabler/icons/chevron-right.svg')} className='text-black dark:text-white h-5 w-5' />

View File

@@ -50,6 +50,8 @@ const messages = defineMessages({
singleUserModeHint: { id: 'soapbox_config.single_user_mode_hint', defaultMessage: 'Front page will redirect to a given user profile.' },
singleUserModeProfileLabel: { id: 'soapbox_config.single_user_mode_profile_label', defaultMessage: 'Main user handle' },
singleUserModeProfileHint: { id: 'soapbox_config.single_user_mode_profile_hint', defaultMessage: '@handle' },
mediaPreviewLabel: { id: 'soapbox_config.media_preview_label', defaultMessage: 'Prefer preview media for thumbnails' },
mediaPreviewHint: { id: 'soapbox_config.media_preview_hint', defaultMessage: 'Some backends provide an optimized version of media for display in timelines. However, these preview images may be too small without additional configuration.' },
feedInjectionLabel: { id: 'soapbox_config.feed_injection_label', defaultMessage: 'Feed injection' },
feedInjectionHint: { id: 'soapbox_config.feed_injection_hint', defaultMessage: 'Inject the feed with additional content, such as suggested profiles.' },
tileServerLabel: { id: 'soapbox_config.tile_server_label', defaultMessage: 'Map tile server' },
@@ -250,6 +252,16 @@ const SoapboxConfig: React.FC = () => {
/>
</ListItem>
<ListItem
label={intl.formatMessage(messages.mediaPreviewLabel)}
hint={intl.formatMessage(messages.mediaPreviewHint)}
>
<Toggle
checked={soapbox.mediaPreview === true}
onChange={handleChange(['mediaPreview'], (e) => e.target.checked)}
/>
</ListItem>
<ListItem label={intl.formatMessage(messages.displayCtaLabel)}>
<Toggle
checked={soapbox.displayCta === true}

View File

@@ -1191,6 +1191,8 @@
"soapbox_config.hints.promo_panel_icons.link": "Soapbox Icons List",
"soapbox_config.home_footer.meta_fields.label_placeholder": "Label",
"soapbox_config.home_footer.meta_fields.url_placeholder": "URL",
"soapbox_config.media_preview_hint": "Some backends provide an optimized version of media for display in timelines. However, these preview images may be too small without additional configuration.",
"soapbox_config.media_preview_label": "Prefer preview media for thumbnails",
"soapbox_config.promo_panel.meta_fields.icon_placeholder": "Icon",
"soapbox_config.promo_panel.meta_fields.label_placeholder": "Label",
"soapbox_config.promo_panel.meta_fields.url_placeholder": "URL",

View File

@@ -115,6 +115,11 @@ export const SoapboxConfigRecord = ImmutableRecord({
feedInjection: true,
tileServer: '',
tileServerAttribution: '',
/**
* Whether to use the preview URL for media thumbnails.
* On some platforms this can be too blurry without additional configuration.
*/
mediaPreview: false,
}, 'SoapboxConfig');
type SoapboxConfigMap = ImmutableMap<string, any>;