kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
Merge branch 'lang-stream' into 'main'
Rework LanguageDropdown, disable streaming when a language is set Closes #1745 See merge request soapbox-pub/soapbox!3137environments/review-main-yi2y9f/deployments/4869
commit
1de38c5ac7
|
@ -213,8 +213,8 @@ const expandHomeTimeline = ({ url, maxId }: ExpandHomeTimelineOpts = {}, done =
|
||||||
return expandTimeline('home', endpoint, params, done);
|
return expandTimeline('home', endpoint, params, done);
|
||||||
};
|
};
|
||||||
|
|
||||||
const expandPublicTimeline = ({ url, maxId, onlyMedia }: Record<string, any> = {}, done = noOp) =>
|
const expandPublicTimeline = ({ url, maxId, onlyMedia, language }: Record<string, any> = {}, done = noOp) =>
|
||||||
expandTimeline(`public${onlyMedia ? ':media' : ''}`, url || '/api/v1/timelines/public', url ? {} : { max_id: maxId, only_media: !!onlyMedia }, done);
|
expandTimeline(`public${onlyMedia ? ':media' : ''}`, url || '/api/v1/timelines/public', url ? {} : { max_id: maxId, only_media: !!onlyMedia, language: language || undefined }, done);
|
||||||
|
|
||||||
const expandRemoteTimeline = (instance: string, { url, maxId, onlyMedia }: Record<string, any> = {}, done = noOp) =>
|
const expandRemoteTimeline = (instance: string, { url, maxId, onlyMedia }: Record<string, any> = {}, done = noOp) =>
|
||||||
expandTimeline(`remote${onlyMedia ? ':media' : ''}:${instance}`, url || '/api/v1/timelines/public', url ? {} : { local: false, instance: instance, max_id: maxId, only_media: !!onlyMedia }, done);
|
expandTimeline(`remote${onlyMedia ? ':media' : ''}:${instance}`, url || '/api/v1/timelines/public', url ? {} : { local: false, instance: instance, max_id: maxId, only_media: !!onlyMedia }, done);
|
||||||
|
|
|
@ -2,12 +2,16 @@ import { useTimelineStream } from './useTimelineStream';
|
||||||
|
|
||||||
interface UsePublicStreamOpts {
|
interface UsePublicStreamOpts {
|
||||||
onlyMedia?: boolean;
|
onlyMedia?: boolean;
|
||||||
|
language?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function usePublicStream({ onlyMedia }: UsePublicStreamOpts = {}) {
|
function usePublicStream({ onlyMedia, language }: UsePublicStreamOpts = {}) {
|
||||||
return useTimelineStream(
|
return useTimelineStream(
|
||||||
`public${onlyMedia ? ':media' : ''}`,
|
`public${onlyMedia ? ':media' : ''}`,
|
||||||
`public${onlyMedia ? ':media' : ''}`,
|
`public${onlyMedia ? ':media' : ''}`,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
{ enabled: !language }, // TODO: support language streaming
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,54 +1,43 @@
|
||||||
import React, { useState } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { openDropdownMenu } from 'soapbox/actions/dropdown-menu';
|
import { openDropdownMenu } from 'soapbox/actions/dropdown-menu';
|
||||||
import { clearTimeline, expandPublicTimeline } from 'soapbox/actions/timelines';
|
import DropdownMenu, { MenuItem } from 'soapbox/components/dropdown-menu';
|
||||||
import DropdownMenu from 'soapbox/components/dropdown-menu';
|
|
||||||
import SvgIcon from 'soapbox/components/ui/icon/svg-icon';
|
import SvgIcon from 'soapbox/components/ui/icon/svg-icon';
|
||||||
import { languages } from 'soapbox/features/preferences';
|
import { languages } from 'soapbox/features/preferences';
|
||||||
import { useAppDispatch } from 'soapbox/hooks';
|
import { useAppDispatch } from 'soapbox/hooks';
|
||||||
|
|
||||||
const formatterLanguage = (lang: {}) => {
|
function formatLanguages(languageMap: Record<string, string>) {
|
||||||
|
const langCodes = Object.keys(languageMap).sort().map((sig) => {
|
||||||
const sigLanguage = Object.keys(lang).sort().map((sig) => {
|
|
||||||
return sig.substring(0, 2);
|
return sig.substring(0, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
return [...new Set(sigLanguage)];
|
return [...new Set(langCodes)];
|
||||||
};
|
}
|
||||||
|
|
||||||
|
interface ILanguageDropdown {
|
||||||
|
language: string;
|
||||||
|
setLanguage(language: string): void;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Let the user select a language to filter the public timeline.
|
||||||
*/
|
*/
|
||||||
const LanguageDropdown = () => {
|
const LanguageDropdown: React.FC<ILanguageDropdown> = ({ language, setLanguage }) => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const [languageIcon, setLanguageIcon] = useState('');
|
const formattedLanguages = formatLanguages(languages);
|
||||||
|
|
||||||
const handleChangeLanguage = (language?: string) => {
|
const newMenu: MenuItem[] = [{ icon: require('@tabler/icons/outline/world.svg'), text: 'Default', action: () => {
|
||||||
if (language) {
|
setLanguage('');
|
||||||
dispatch(clearTimeline('public'));
|
|
||||||
dispatch(expandPublicTimeline({ url: `/api/v1/timelines/public?language=${language}` }));
|
|
||||||
} else {
|
|
||||||
dispatch(clearTimeline('public'));
|
|
||||||
dispatch(expandPublicTimeline({ url: '/api/v1/timelines/public' }));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const formattedLanguage = formatterLanguage(languages);
|
|
||||||
|
|
||||||
const newMenu: any[] = [{ icon: require('@tabler/icons/outline/world.svg'), text: 'Default', action: () => {
|
|
||||||
setLanguageIcon('');
|
|
||||||
handleChangeLanguage();
|
|
||||||
} }];
|
} }];
|
||||||
|
|
||||||
formattedLanguage.map((lg: string) => {
|
formattedLanguages.map((lang: string) => {
|
||||||
const languageText = languages[lg as keyof typeof languages];
|
const languageName = languages[lang as keyof typeof languages];
|
||||||
|
|
||||||
if (languageText !== undefined) {
|
if (languageName) {
|
||||||
newMenu.push({
|
newMenu.push({
|
||||||
text: `${lg.toUpperCase()} - ${languageText}`,
|
text: `${lang.toUpperCase()} - ${languageName}`,
|
||||||
action: () => {
|
action: () => {
|
||||||
setLanguageIcon(lg.toUpperCase());
|
setLanguage(lang);
|
||||||
handleChangeLanguage(lg);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -57,14 +46,13 @@ const LanguageDropdown = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownMenu items={newMenu} modal>
|
<DropdownMenu items={newMenu} modal>
|
||||||
{ languageIcon === '' ?
|
{language ? (
|
||||||
<SvgIcon src={require('@tabler/icons/outline/world.svg')} className='text-gray-700 hover:cursor-pointer hover:text-gray-500 black:absolute black:right-0 black:top-4 black:text-white black:hover:text-gray-600 sm:mr-4 dark:text-white' />
|
|
||||||
|
|
||||||
:
|
|
||||||
<button type='button' className='flex h-full rounded-lg border-2 border-gray-700 px-1 text-gray-700 hover:cursor-pointer hover:border-gray-500 hover:text-gray-500 sm:mr-4 dark:border-white dark:text-white dark:hover:border-gray-700' onClick={() => dispatch(openDropdownMenu())}>
|
<button type='button' className='flex h-full rounded-lg border-2 border-gray-700 px-1 text-gray-700 hover:cursor-pointer hover:border-gray-500 hover:text-gray-500 sm:mr-4 dark:border-white dark:text-white dark:hover:border-gray-700' onClick={() => dispatch(openDropdownMenu())}>
|
||||||
{languageIcon}
|
{language.toUpperCase()}
|
||||||
</button>
|
</button>
|
||||||
}
|
) : (
|
||||||
|
<SvgIcon src={require('@tabler/icons/outline/world.svg')} className='text-gray-700 hover:cursor-pointer hover:text-gray-500 black:absolute black:right-0 black:top-4 black:text-white black:hover:text-gray-600 sm:mr-4 dark:text-white' />
|
||||||
|
)}
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
@ -25,6 +25,8 @@ const PublicTimeline = () => {
|
||||||
const features = useFeatures();
|
const features = useFeatures();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
|
const [language, setLanguage] = useState<string>(localStorage.getItem('soapbox:global:language') || '');
|
||||||
|
|
||||||
const instance = useInstance();
|
const instance = useInstance();
|
||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
const onlyMedia = settings.public.other.onlyMedia;
|
const onlyMedia = settings.public.other.onlyMedia;
|
||||||
|
@ -52,24 +54,23 @@ const PublicTimeline = () => {
|
||||||
return dispatch(expandPublicTimeline({ onlyMedia }));
|
return dispatch(expandPublicTimeline({ onlyMedia }));
|
||||||
};
|
};
|
||||||
|
|
||||||
usePublicStream({ onlyMedia });
|
usePublicStream({ onlyMedia, language });
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
dispatch(expandPublicTimeline({ onlyMedia }));
|
|
||||||
}, [onlyMedia]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
dispatch(clearTimeline('public'));
|
dispatch(clearTimeline('public'));
|
||||||
dispatch(expandPublicTimeline({ url: '/api/v1/timelines/public' }));
|
localStorage.setItem('soapbox:global:language', language);
|
||||||
}, []);
|
}, [language]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(expandPublicTimeline({ onlyMedia, language }));
|
||||||
|
}, [onlyMedia, language]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column
|
<Column
|
||||||
className='-mt-3 sm:mt-0'
|
className='-mt-3 sm:mt-0'
|
||||||
label={intl.formatMessage(messages.title)}
|
label={intl.formatMessage(messages.title)}
|
||||||
transparent={!isMobile}
|
transparent={!isMobile}
|
||||||
action={features.publicTimelineLanguage ? <LanguageDropdown /> : null}
|
action={features.publicTimelineLanguage ? <LanguageDropdown language={language} setLanguage={setLanguage} /> : null}
|
||||||
// actionRightPosition
|
|
||||||
>
|
>
|
||||||
<PinnedHostsPicker />
|
<PinnedHostsPicker />
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue