kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
Merge branch 'implement-explorer' into change-to-redux
commit
781aaefbe1
|
@ -280,15 +280,6 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
|
||||||
text={features.federating ? instance.domain : <FormattedMessage id='tabs_bar.all' defaultMessage='All' />}
|
text={features.federating ? instance.domain : <FormattedMessage id='tabs_bar.all' defaultMessage='All' />}
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{features.federating && (
|
|
||||||
<SidebarLink
|
|
||||||
to='/timeline/global'
|
|
||||||
icon={worldIcon}
|
|
||||||
text={<FormattedMessage id='tabs_bar.global' defaultMessage='Global' />}
|
|
||||||
onClick={onClose}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>}
|
</>}
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
|
@ -6,6 +6,7 @@ import userFilledIcon from '@tabler/icons/filled/user.svg';
|
||||||
import atIcon from '@tabler/icons/outline/at.svg';
|
import atIcon from '@tabler/icons/outline/at.svg';
|
||||||
import bellIcon from '@tabler/icons/outline/bell.svg';
|
import bellIcon from '@tabler/icons/outline/bell.svg';
|
||||||
import bookmarkIcon from '@tabler/icons/outline/bookmark.svg';
|
import bookmarkIcon from '@tabler/icons/outline/bookmark.svg';
|
||||||
|
import compassIcon from '@tabler/icons/outline/brand-safari.svg';
|
||||||
import calendarEventIcon from '@tabler/icons/outline/calendar-event.svg';
|
import calendarEventIcon from '@tabler/icons/outline/calendar-event.svg';
|
||||||
import circlesIcon from '@tabler/icons/outline/circles.svg';
|
import circlesIcon from '@tabler/icons/outline/circles.svg';
|
||||||
import codeIcon from '@tabler/icons/outline/code.svg';
|
import codeIcon from '@tabler/icons/outline/code.svg';
|
||||||
|
@ -15,7 +16,6 @@ import homeIcon from '@tabler/icons/outline/home.svg';
|
||||||
import listIcon from '@tabler/icons/outline/list.svg';
|
import listIcon from '@tabler/icons/outline/list.svg';
|
||||||
import mailIcon from '@tabler/icons/outline/mail.svg';
|
import mailIcon from '@tabler/icons/outline/mail.svg';
|
||||||
import messagesIcon from '@tabler/icons/outline/messages.svg';
|
import messagesIcon from '@tabler/icons/outline/messages.svg';
|
||||||
import rocketIcon from '@tabler/icons/outline/rocket.svg';
|
|
||||||
import settingsIcon from '@tabler/icons/outline/settings.svg';
|
import settingsIcon from '@tabler/icons/outline/settings.svg';
|
||||||
import userPlusIcon from '@tabler/icons/outline/user-plus.svg';
|
import userPlusIcon from '@tabler/icons/outline/user-plus.svg';
|
||||||
import userIcon from '@tabler/icons/outline/user.svg';
|
import userIcon from '@tabler/icons/outline/user.svg';
|
||||||
|
@ -162,8 +162,8 @@ const SidebarNavigation = () => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SidebarNavigationLink
|
<SidebarNavigationLink
|
||||||
to='/search'
|
to='/explorer'
|
||||||
icon={rocketIcon}
|
icon={compassIcon}
|
||||||
text={<FormattedMessage id='tabs_bar.search' defaultMessage='Explorer' />}
|
text={<FormattedMessage id='tabs_bar.search' defaultMessage='Explorer' />}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -223,14 +223,6 @@ const SidebarNavigation = () => {
|
||||||
text={features.federating ? instance.domain : <FormattedMessage id='tabs_bar.global' defaultMessage='Global' />}
|
text={features.federating ? instance.domain : <FormattedMessage id='tabs_bar.global' defaultMessage='Global' />}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(features.federating && (account || !restrictUnauth.timelines.federated)) && (
|
|
||||||
<SidebarNavigationLink
|
|
||||||
to='/timeline/global'
|
|
||||||
icon={worldIcon}
|
|
||||||
text={<FormattedMessage id='tabs_bar.global' defaultMessage='Global' />}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,12 @@ import circlesFilledIcon from '@tabler/icons/filled/circles.svg';
|
||||||
import homeFilledIcon from '@tabler/icons/filled/home.svg';
|
import homeFilledIcon from '@tabler/icons/filled/home.svg';
|
||||||
import mailFilledIcon from '@tabler/icons/filled/mail.svg';
|
import mailFilledIcon from '@tabler/icons/filled/mail.svg';
|
||||||
import bellIcon from '@tabler/icons/outline/bell.svg';
|
import bellIcon from '@tabler/icons/outline/bell.svg';
|
||||||
|
import compassIcon from '@tabler/icons/outline/brand-safari.svg';
|
||||||
import circlesIcon from '@tabler/icons/outline/circles.svg';
|
import circlesIcon from '@tabler/icons/outline/circles.svg';
|
||||||
import dashboardIcon from '@tabler/icons/outline/dashboard.svg';
|
import dashboardIcon from '@tabler/icons/outline/dashboard.svg';
|
||||||
import homeIcon from '@tabler/icons/outline/home.svg';
|
import homeIcon from '@tabler/icons/outline/home.svg';
|
||||||
import mailIcon from '@tabler/icons/outline/mail.svg';
|
import mailIcon from '@tabler/icons/outline/mail.svg';
|
||||||
import messagesIcon from '@tabler/icons/outline/messages.svg';
|
import messagesIcon from '@tabler/icons/outline/messages.svg';
|
||||||
import rocketIcon from '@tabler/icons/outline/rocket.svg';
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
import ThumbNavigationLink from 'soapbox/components/thumb-navigation-link.tsx';
|
import ThumbNavigationLink from 'soapbox/components/thumb-navigation-link.tsx';
|
||||||
|
@ -84,9 +84,9 @@ const ThumbNavigation: React.FC = (): JSX.Element => {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<ThumbNavigationLink
|
<ThumbNavigationLink
|
||||||
src={rocketIcon}
|
src={compassIcon}
|
||||||
text={<FormattedMessage id='navigation.search' defaultMessage='Explorer' />}
|
text={<FormattedMessage id='navigation.search' defaultMessage='Explorer' />}
|
||||||
to='/search'
|
to='/explorer'
|
||||||
exact
|
exact
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
import HStack from 'soapbox/components/ui/hstack.tsx';
|
||||||
|
import SvgIcon from 'soapbox/components/ui/svg-icon.tsx';
|
||||||
|
import Text from 'soapbox/components/ui/text.tsx';
|
||||||
|
import Search from 'soapbox/features/compose/components/search.tsx';
|
||||||
|
import { useIsMobile } from 'soapbox/hooks/useIsMobile.ts';
|
||||||
|
|
||||||
|
interface TabItem {
|
||||||
|
name: string;
|
||||||
|
label: string;
|
||||||
|
action: () => void;
|
||||||
|
icon: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TabsProps {
|
||||||
|
items: TabItem[];
|
||||||
|
activeItem?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
const ExplorerTabs: React.FC<TabsProps> = ({ items, activeItem }) => {
|
||||||
|
const [activeTab, setActiveTab] = useState(activeItem || items[0].name);
|
||||||
|
const [lastSelected, setLastSelected] = useState('');
|
||||||
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
|
const handleTabClick = (name: string) => {
|
||||||
|
setLastSelected(activeTab);
|
||||||
|
setActiveTab(name);
|
||||||
|
const activeItem = items.find(item => item.name === name);
|
||||||
|
if (activeItem && typeof activeItem.action === 'function') {
|
||||||
|
activeItem.action();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HStack className='inset-x-0 bottom-4 z-[999] w-full p-2' alignItems='center' justifyContent='center'>
|
||||||
|
{/* Header */}
|
||||||
|
<HStack space={1} className='w-full rounded-full bg-gray-200/60 p-1.5 dark:bg-gray-800' justifyContent='around'>
|
||||||
|
{items.map(({ name, label, icon }) => {
|
||||||
|
const isSelected = activeTab === name;
|
||||||
|
const shouldKeepBg = lastSelected === name && activeTab === 'search';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<HStack key={name} alignItems='center' justifyContent='center'>
|
||||||
|
{name === 'search' && isSelected ? (
|
||||||
|
<Search autoSubmit />
|
||||||
|
) : (
|
||||||
|
<HStack
|
||||||
|
space={1}
|
||||||
|
alignItems='center'
|
||||||
|
justifyContent='center'
|
||||||
|
onClick={() => handleTabClick(name)}
|
||||||
|
/* eslint-disable-next-line tailwindcss/no-custom-classname */
|
||||||
|
className={clsx(
|
||||||
|
'group cursor-pointer rounded-full px-5 py-3 text-sm font-medium transition-all duration-300',
|
||||||
|
isSelected || shouldKeepBg
|
||||||
|
? 'border-gray-500 bg-gray-500 text-white shadow-md dark:border-gray-700 dark:bg-gray-700'
|
||||||
|
: 'dark:hover:bg-gray-800/200 text-gray-500 hover:bg-gray-400/60 hover:!text-white',
|
||||||
|
{ '!p-2': shouldKeepBg },
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<SvgIcon
|
||||||
|
src={icon}
|
||||||
|
className='size-5 '
|
||||||
|
/>
|
||||||
|
{(activeTab !== 'search' || isSelected) &&
|
||||||
|
(isMobile ? isSelected : !isMobile) && (
|
||||||
|
<Text
|
||||||
|
className={clsx('transition-all duration-300', {
|
||||||
|
'!text-gray-500 group-hover:!text-white': !isSelected,
|
||||||
|
'!text-white': isSelected || shouldKeepBg,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</HStack>
|
||||||
|
)}
|
||||||
|
</HStack>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</HStack>
|
||||||
|
</HStack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ExplorerTabs;
|
|
@ -68,7 +68,6 @@ const Input = forwardRef<HTMLInputElement, IInput>(
|
||||||
clsx('relative', {
|
clsx('relative', {
|
||||||
'rounded-md': theme !== 'search',
|
'rounded-md': theme !== 'search',
|
||||||
'rounded-full': theme === 'search',
|
'rounded-full': theme === 'search',
|
||||||
'mt-1': !String(outerClassName).includes('mt-'),
|
|
||||||
[String(outerClassName)]: typeof outerClassName !== 'undefined',
|
[String(outerClassName)]: typeof outerClassName !== 'undefined',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -259,7 +259,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
||||||
|
|
||||||
const onSearch = () => {
|
const onSearch = () => {
|
||||||
dispatch(setSearchAccount(account.id));
|
dispatch(setSearchAccount(account.id));
|
||||||
history.push('/search');
|
history.push('/explorer');
|
||||||
};
|
};
|
||||||
|
|
||||||
const onAvatarClick = () => {
|
const onAvatarClick = () => {
|
||||||
|
|
|
@ -1,48 +1,59 @@
|
||||||
|
import globeIcon from '@tabler/icons/outline/globe.svg';
|
||||||
|
import searchIcon from '@tabler/icons/outline/search.svg';
|
||||||
|
import trendIcon from '@tabler/icons/outline/trending-up.svg';
|
||||||
|
import userIcon from '@tabler/icons/outline/user.svg';
|
||||||
|
import xIcon from '@tabler/icons/outline/x.svg';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
FormattedMessage,
|
FormattedMessage,
|
||||||
// defineMessages,
|
defineMessages,
|
||||||
// useIntl
|
useIntl,
|
||||||
} from 'react-intl';
|
} from 'react-intl';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
expandSearch,
|
expandSearch,
|
||||||
// setFilter,
|
setFilter,
|
||||||
// setSearchAccount
|
setSearchAccount,
|
||||||
} from 'soapbox/actions/search.ts';
|
} from 'soapbox/actions/search.ts';
|
||||||
import { expandTrendingStatuses, fetchTrendingStatuses } from 'soapbox/actions/trending-statuses.ts';
|
import { expandTrendingStatuses, fetchTrendingStatuses } from 'soapbox/actions/trending-statuses.ts';
|
||||||
// import { useAccount } from 'soapbox/api/hooks/index.ts';
|
import { useAccount } from 'soapbox/api/hooks/index.ts';
|
||||||
import Hashtag from 'soapbox/components/hashtag.tsx';
|
import Hashtag from 'soapbox/components/hashtag.tsx';
|
||||||
|
import IconButton from 'soapbox/components/icon-button.tsx';
|
||||||
import ScrollableList from 'soapbox/components/scrollable-list.tsx';
|
import ScrollableList from 'soapbox/components/scrollable-list.tsx';
|
||||||
|
import ExplorerTabs from 'soapbox/components/ui/explorer-tabs.tsx';
|
||||||
|
import HStack from 'soapbox/components/ui/hstack.tsx';
|
||||||
import Spinner from 'soapbox/components/ui/spinner.tsx';
|
import Spinner from 'soapbox/components/ui/spinner.tsx';
|
||||||
// import Tabs from 'soapbox/components/ui/tabs.tsx';
|
import Text from 'soapbox/components/ui/text.tsx';
|
||||||
import AccountContainer from 'soapbox/containers/account-container.tsx';
|
import AccountContainer from 'soapbox/containers/account-container.tsx';
|
||||||
import StatusContainer from 'soapbox/containers/status-container.tsx';
|
import StatusContainer from 'soapbox/containers/status-container.tsx';
|
||||||
import PlaceholderAccount from 'soapbox/features/placeholder/components/placeholder-account.tsx';
|
import PlaceholderAccount from 'soapbox/features/placeholder/components/placeholder-account.tsx';
|
||||||
import PlaceholderHashtag from 'soapbox/features/placeholder/components/placeholder-hashtag.tsx';
|
import PlaceholderHashtag from 'soapbox/features/placeholder/components/placeholder-hashtag.tsx';
|
||||||
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder-status.tsx';
|
import PlaceholderStatus from 'soapbox/features/placeholder/components/placeholder-status.tsx';
|
||||||
|
import PublicTimeline from 'soapbox/features/public-timeline/index.tsx';
|
||||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||||
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||||
import { useSuggestions } from 'soapbox/queries/suggestions.ts';
|
import { useSuggestions } from 'soapbox/queries/suggestions.ts';
|
||||||
|
import { SearchFilter } from 'soapbox/reducers/search.ts';
|
||||||
|
|
||||||
import type { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
import type { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||||
import type { VirtuosoHandle } from 'react-virtuoso';
|
import type { VirtuosoHandle } from 'react-virtuoso';
|
||||||
// import type { SearchFilter } from 'soapbox/reducers/search.ts';
|
|
||||||
|
|
||||||
// const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
// accounts: { id: 'search_results.accounts', defaultMessage: 'People' },
|
accounts: { id: 'search_results.posts', defaultMessage: 'Accounts' },
|
||||||
// statuses: { id: 'search_results.statuses', defaultMessage: 'Posts' },
|
statuses: { id: 'search_results.accounts', defaultMessage: 'Posts' },
|
||||||
// hashtags: { id: 'search_results.hashtags', defaultMessage: 'Hashtags' },
|
trends: { id: 'search_results.trends', defaultMessage: 'Trends' },
|
||||||
// });
|
search: { id: 'common.search', defaultMessage: 'Search' },
|
||||||
|
});
|
||||||
|
|
||||||
const SearchResults = () => {
|
const SearchResults = () => {
|
||||||
const node = useRef<VirtuosoHandle>(null);
|
const node = useRef<VirtuosoHandle>(null);
|
||||||
|
|
||||||
// const intl = useIntl();
|
const intl = useIntl();
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const { data: suggestions } = useSuggestions();
|
const { data: suggestions } = useSuggestions();
|
||||||
|
const [globalTimeline, setGlobalTimeline] = useState(true);
|
||||||
|
|
||||||
const value = useAppSelector((state) => state.search.submittedValue);
|
const value = useAppSelector((state) => state.search.submittedValue);
|
||||||
const results = useAppSelector((state) => state.search.results);
|
const results = useAppSelector((state) => state.search.results);
|
||||||
|
@ -51,8 +62,8 @@ const SearchResults = () => {
|
||||||
const trends = useAppSelector((state) => state.trends.items);
|
const trends = useAppSelector((state) => state.trends.items);
|
||||||
const submitted = useAppSelector((state) => state.search.submitted);
|
const submitted = useAppSelector((state) => state.search.submitted);
|
||||||
const selectedFilter = useAppSelector((state) => state.search.filter);
|
const selectedFilter = useAppSelector((state) => state.search.filter);
|
||||||
// const filterByAccount = useAppSelector((state) => state.search.accountId || undefined);
|
const filterByAccount = useAppSelector((state) => state.search.accountId || undefined);
|
||||||
// const { account } = useAccount(filterByAccount);
|
const { account } = useAccount(filterByAccount);
|
||||||
|
|
||||||
const handleLoadMore = () => {
|
const handleLoadMore = () => {
|
||||||
if (results.accounts.size || results.statuses.size || results.hashtags.size) {
|
if (results.accounts.size || results.statuses.size || results.hashtags.size) {
|
||||||
|
@ -62,35 +73,45 @@ const SearchResults = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// const handleUnsetAccount = () => dispatch(setSearchAccount(null));
|
const handleUnsetAccount = () => dispatch(setSearchAccount(null));
|
||||||
|
const handleAction = (filter: SearchFilter) =>{
|
||||||
|
setGlobalTimeline(false);
|
||||||
|
selectFilter(filter);
|
||||||
|
};
|
||||||
|
|
||||||
// const selectFilter = (newActiveFilter: SearchFilter) => dispatch(setFilter(newActiveFilter));
|
const selectFilter = (newActiveFilter: SearchFilter) => dispatch(setFilter(newActiveFilter));
|
||||||
|
|
||||||
// const renderFilterBar = () => {
|
const renderFilterBar = () => {
|
||||||
// const items = [];
|
const items = [];
|
||||||
// items.push(
|
items.push(
|
||||||
// {
|
{
|
||||||
// text: intl.formatMessage(messages.statuses),
|
label: intl.formatMessage(messages.statuses),
|
||||||
// action: () => selectFilter('statuses'),
|
action: () => setGlobalTimeline(true),
|
||||||
// name: 'statuses',
|
name: 'statuses',
|
||||||
// },
|
icon: globeIcon,
|
||||||
// {
|
},
|
||||||
// text: intl.formatMessage(messages.accounts),
|
{
|
||||||
// action: () => selectFilter('accounts'),
|
label: intl.formatMessage(messages.trends),
|
||||||
// name: 'accounts',
|
action: () => handleAction('statuses'),
|
||||||
// },
|
name: 'trends',
|
||||||
// );
|
icon: trendIcon,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(messages.accounts),
|
||||||
|
action: () => handleAction('accounts'),
|
||||||
|
name: 'accounts',
|
||||||
|
icon: userIcon,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: intl.formatMessage(messages.search),
|
||||||
|
action: () => null,
|
||||||
|
name: 'search',
|
||||||
|
icon: searchIcon,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// items.push(
|
return <ExplorerTabs items={items} activeItem={selectedFilter} />;
|
||||||
// {
|
};
|
||||||
// text: intl.formatMessage(messages.hashtags),
|
|
||||||
// action: () => selectFilter('hashtags'),
|
|
||||||
// name: 'hashtags',
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
|
|
||||||
// return <Tabs items={items} activeItem={selectedFilter} />;
|
|
||||||
// };
|
|
||||||
|
|
||||||
const getCurrentIndex = (id: string): number => {
|
const getCurrentIndex = (id: string): number => {
|
||||||
return resultsIds?.keySeq().findIndex(key => key === id);
|
return resultsIds?.keySeq().findIndex(key => key === id);
|
||||||
|
@ -219,7 +240,7 @@ const SearchResults = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* {filterByAccount ? (
|
{filterByAccount ? (
|
||||||
<HStack className='mb-4 border-b border-solid border-gray-200 px-2 pb-4 dark:border-gray-800' space={2}>
|
<HStack className='mb-4 border-b border-solid border-gray-200 px-2 pb-4 dark:border-gray-800' space={2}>
|
||||||
<IconButton iconClassName='h-5 w-5' src={xIcon} onClick={handleUnsetAccount} />
|
<IconButton iconClassName='h-5 w-5' src={xIcon} onClick={handleUnsetAccount} />
|
||||||
<Text truncate>
|
<Text truncate>
|
||||||
|
@ -231,10 +252,12 @@ const SearchResults = () => {
|
||||||
</Text>
|
</Text>
|
||||||
</HStack>
|
</HStack>
|
||||||
) : (
|
) : (
|
||||||
<div className='px-4'>{renderFilterBar()}</div>
|
<div className='relative px-4'>
|
||||||
)} */}
|
{renderFilterBar()}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{noResultsMessage || (
|
{globalTimeline ? <PublicTimeline /> : (noResultsMessage || (
|
||||||
<ScrollableList
|
<ScrollableList
|
||||||
id='search-results'
|
id='search-results'
|
||||||
ref={node}
|
ref={node}
|
||||||
|
@ -257,7 +280,7 @@ const SearchResults = () => {
|
||||||
>
|
>
|
||||||
{searchResults || []}
|
{searchResults || []}
|
||||||
</ScrollableList>
|
</ScrollableList>
|
||||||
)}
|
))}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -76,7 +76,7 @@ const SearchZapSplit = (props: ISearchZapSplit) => {
|
||||||
dispatch(setSearchAccount(null));
|
dispatch(setSearchAccount(null));
|
||||||
dispatch(submitSearch());
|
dispatch(submitSearch());
|
||||||
|
|
||||||
history.push('/search');
|
history.push('/explorer');
|
||||||
} else {
|
} else {
|
||||||
dispatch(submitSearch());
|
dispatch(submitSearch());
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ const Search = (props: ISearch) => {
|
||||||
dispatch(setSearchAccount(null));
|
dispatch(setSearchAccount(null));
|
||||||
dispatch(submitSearch());
|
dispatch(submitSearch());
|
||||||
|
|
||||||
history.push('/search');
|
history.push('/explorer');
|
||||||
} else {
|
} else {
|
||||||
dispatch(submitSearch());
|
dispatch(submitSearch());
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,10 @@ const ExplorerCards = () => {
|
||||||
const [isOpen, setIsOpen] = useState(true);
|
const [isOpen, setIsOpen] = useState(true);
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack className='mx-4 mt-4' space={2}>
|
||||||
<Stack
|
<Stack
|
||||||
space={4}
|
space={4}
|
||||||
className={`m-2 rounded-xl bg-gradient-to-r from-pink-400 via-purple-500 to-blue-400 sm:m-4 ${isOpen ? 'mt-0 px-5 pb-8 pt-4' : 'p-4'}`}
|
className={`rounded-xl bg-gradient-to-r from-primary-400 to-primary-700 ${isOpen ? 'mt-0 px-5 pb-8 pt-4' : 'p-4'}`}
|
||||||
>
|
>
|
||||||
<HStack justifyContent='between' className='text-white'>
|
<HStack justifyContent='between' className='text-white'>
|
||||||
<HStack space={2}>
|
<HStack space={2}>
|
||||||
|
@ -53,11 +53,11 @@ const ExplorerCards = () => {
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<HStack className={`mx-2 mb-2 sm:mx-4 sm:mb-4 ${isOpen ? 'max-h-96 opacity-100' : 'hidden max-h-0 opacity-0'}`} space={2}>
|
<HStack className={`${isOpen ? 'max-h-96 opacity-100' : 'hidden max-h-0 opacity-0'}`} space={2}>
|
||||||
{/* Nostr */}
|
{/* Nostr */}
|
||||||
<Stack
|
<Stack
|
||||||
space={4}
|
space={4}
|
||||||
className='w-1/2 rounded-xl bg-gradient-to-r from-pink-400 to-purple-500 px-5 pb-6 pt-4'
|
className='w-1/2 rounded-xl bg-gradient-to-r from-primary-400 to-primary-600 px-5 pb-6 pt-4'
|
||||||
justifyContent='center'
|
justifyContent='center'
|
||||||
>
|
>
|
||||||
<HStack alignItems='center' justifyContent='between'>
|
<HStack alignItems='center' justifyContent='between'>
|
||||||
|
@ -82,7 +82,7 @@ const ExplorerCards = () => {
|
||||||
{/* Bridge */}
|
{/* Bridge */}
|
||||||
<Stack
|
<Stack
|
||||||
space={4}
|
space={4}
|
||||||
className='w-1/2 rounded-xl bg-gradient-to-r from-purple-500 to-blue-400 px-5 pb-6 pt-4'
|
className='w-1/2 rounded-xl bg-gradient-to-r from-primary-600 to-primary-700 px-5 pb-6 pt-4'
|
||||||
>
|
>
|
||||||
<HStack alignItems='center' className='sm:min-w-48'>
|
<HStack alignItems='center' className='sm:min-w-48'>
|
||||||
{/* Title */}
|
{/* Title */}
|
|
@ -15,7 +15,7 @@ import {
|
||||||
PlatformFilters,
|
PlatformFilters,
|
||||||
RepliesFilter,
|
RepliesFilter,
|
||||||
generateFilter,
|
generateFilter,
|
||||||
} from 'soapbox/features/search/components/filters.tsx';
|
} from 'soapbox/features/explorer/components/filters.tsx';
|
||||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
|
@ -13,9 +13,8 @@ import Stack from 'soapbox/components/ui/stack.tsx';
|
||||||
import SvgIcon from 'soapbox/components/ui/svg-icon.tsx';
|
import SvgIcon from 'soapbox/components/ui/svg-icon.tsx';
|
||||||
import Text from 'soapbox/components/ui/text.tsx';
|
import Text from 'soapbox/components/ui/text.tsx';
|
||||||
import Toggle from 'soapbox/components/ui/toggle.tsx';
|
import Toggle from 'soapbox/components/ui/toggle.tsx';
|
||||||
|
import { IGenerateFilter } from 'soapbox/features/explorer/components/explorerFilter.tsx';
|
||||||
import { SelectDropdown } from 'soapbox/features/forms/index.tsx';
|
import { SelectDropdown } from 'soapbox/features/forms/index.tsx';
|
||||||
import { IGenerateFilter } from 'soapbox/features/search/components/explorerFilter.tsx';
|
|
||||||
// import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
filters: { id: 'column.explorer.filters', defaultMessage: 'Filters:' },
|
filters: { id: 'column.explorer.filters', defaultMessage: 'Filters:' },
|
||||||
|
@ -48,7 +47,6 @@ const languages = {
|
||||||
da: 'Dansk',
|
da: 'Dansk',
|
||||||
de: 'Deutsch',
|
de: 'Deutsch',
|
||||||
el: 'Ελληνικά',
|
el: 'Ελληνικά',
|
||||||
'en-Shaw': '𐑖𐑱𐑝𐑾𐑯',
|
|
||||||
eo: 'Esperanto',
|
eo: 'Esperanto',
|
||||||
es: 'Español',
|
es: 'Español',
|
||||||
eu: 'Euskara',
|
eu: 'Euskara',
|
||||||
|
@ -80,14 +78,12 @@ const languages = {
|
||||||
oc: 'Occitan',
|
oc: 'Occitan',
|
||||||
pl: 'Polski',
|
pl: 'Polski',
|
||||||
pt: 'Português',
|
pt: 'Português',
|
||||||
'pt-BR': 'Português do Brasil',
|
|
||||||
ro: 'Română',
|
ro: 'Română',
|
||||||
ru: 'Русский',
|
ru: 'Русский',
|
||||||
sk: 'Slovenčina',
|
sk: 'Slovenčina',
|
||||||
sl: 'Slovenščina',
|
sl: 'Slovenščina',
|
||||||
sq: 'Shqip',
|
sq: 'Shqip',
|
||||||
sr: 'Српски',
|
sr: 'Српски',
|
||||||
'sr-Latn': 'Srpski (latinica)',
|
|
||||||
sv: 'Svenska',
|
sv: 'Svenska',
|
||||||
ta: 'தமிழ்',
|
ta: 'தமிழ்',
|
||||||
te: 'తెలుగు',
|
te: 'తెలుగు',
|
||||||
|
@ -95,9 +91,6 @@ const languages = {
|
||||||
tr: 'Türkçe',
|
tr: 'Türkçe',
|
||||||
uk: 'Українська',
|
uk: 'Українська',
|
||||||
zh: '中文',
|
zh: '中文',
|
||||||
'zh-CN': '简体中文',
|
|
||||||
'zh-HK': '繁體中文(香港)',
|
|
||||||
'zh-TW': '繁體中文(臺灣)',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IFilter {
|
interface IFilter {
|
||||||
|
@ -370,6 +363,7 @@ const MediaFilter = ({ onChangeFilters }: IFilter) => {
|
||||||
const generateFilter = ({ name, state }: IGenerateFilter, onChangeFilters: React.Dispatch<React.SetStateAction<IGenerateFilter[]>>) => {
|
const generateFilter = ({ name, state }: IGenerateFilter, onChangeFilters: React.Dispatch<React.SetStateAction<IGenerateFilter[]>>) => {
|
||||||
let borderColor = '';
|
let borderColor = '';
|
||||||
let textColor = '';
|
let textColor = '';
|
||||||
|
let hasButton = false;
|
||||||
switch (name.toLowerCase()) {
|
switch (name.toLowerCase()) {
|
||||||
case 'nostr':
|
case 'nostr':
|
||||||
borderColor = 'border-purple-500';
|
borderColor = 'border-purple-500';
|
||||||
|
@ -391,19 +385,20 @@ const generateFilter = ({ name, state }: IGenerateFilter, onChangeFilters: React
|
||||||
}
|
}
|
||||||
borderColor = state ? 'border-green-500' : 'border-red-500';
|
borderColor = state ? 'border-green-500' : 'border-red-500';
|
||||||
textColor = state ? 'text-green-500' : 'text-red-500';
|
textColor = state ? 'text-green-500' : 'text-red-500';
|
||||||
|
hasButton = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={name}
|
key={name}
|
||||||
className={`group m-1 flex items-center gap-0.5 whitespace-normal break-words rounded-full border-2 bg-transparent px-3 text-base font-medium shadow-sm hover:cursor-pointer hover:pr-1 ${borderColor} `}
|
className={`group m-1 flex items-center gap-0.5 whitespace-normal break-words rounded-full border-2 bg-transparent px-3 text-base font-medium shadow-sm hover:cursor-pointer ${hasButton ? 'hover:pr-1' : '' } ${borderColor} `}
|
||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
<IconButton
|
{hasButton && <IconButton
|
||||||
iconClassName='!w-4' className={`hidden !p-0 px-1 group-hover:block ${textColor}`} src={xIcon} onClick={() => onChangeFilters((prevValue) => {
|
iconClassName='!w-4' className={`hidden !p-0 px-1 group-hover:block ${textColor}`} src={xIcon} onClick={() => onChangeFilters((prevValue) => {
|
||||||
return prevValue.filter((x) => x.name !== name);
|
return prevValue.filter((x) => x.name !== name);
|
||||||
})}
|
})}
|
||||||
/>
|
/>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
|
@ -17,9 +17,10 @@ import {
|
||||||
useSuggestions,
|
useSuggestions,
|
||||||
} from 'soapbox/queries/suggestions.ts';
|
} from 'soapbox/queries/suggestions.ts';
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
import 'swiper/css';
|
import 'swiper/css';
|
||||||
|
|
||||||
const PeopleToFollowCard = ({ id }: { id: string }) => {
|
const PopularAccounts = ({ id }: { id: string }) => {
|
||||||
const account = useAccount(id).account;
|
const account = useAccount(id).account;
|
||||||
const { logo } = useSoapboxConfig();
|
const { logo } = useSoapboxConfig();
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ const PeopleToFollowCard = ({ id }: { id: string }) => {
|
||||||
const AccountsCarousel = () => {
|
const AccountsCarousel = () => {
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
const { data: suggestions, isFetching } = useSuggestions();
|
const { data: suggestions, isFetching } = useSuggestions();
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(true);
|
||||||
|
|
||||||
|
|
||||||
if (!isFetching && !suggestions.length) {
|
if (!isFetching && !suggestions.length) {
|
||||||
|
@ -101,7 +102,7 @@ const AccountsCarousel = () => {
|
||||||
>
|
>
|
||||||
{suggestions.map((suggestion) => (
|
{suggestions.map((suggestion) => (
|
||||||
<SwiperSlide key={suggestion.account}>
|
<SwiperSlide key={suggestion.account}>
|
||||||
<PeopleToFollowCard id={suggestion.account} />
|
<PopularAccounts id={suggestion.account} />
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
|
@ -4,20 +4,19 @@ import { Column } from 'soapbox/components/ui/column.tsx';
|
||||||
import Divider from 'soapbox/components/ui/divider.tsx';
|
import Divider from 'soapbox/components/ui/divider.tsx';
|
||||||
import Stack from 'soapbox/components/ui/stack.tsx';
|
import Stack from 'soapbox/components/ui/stack.tsx';
|
||||||
import SearchResults from 'soapbox/features/compose/components/search-results.tsx';
|
import SearchResults from 'soapbox/features/compose/components/search-results.tsx';
|
||||||
import Search from 'soapbox/features/compose/components/search.tsx';
|
import ExplorerCards from 'soapbox/features/explorer/components/explorer-cards.tsx';
|
||||||
import ExplorerCards from 'soapbox/features/search/components/explorer-cards.tsx';
|
import ExplorerFilter from 'soapbox/features/explorer/components/explorerFilter.tsx';
|
||||||
import ExplorerFilter from 'soapbox/features/search/components/explorerFilter.tsx';
|
import AccountsCarousel from 'soapbox/features/explorer/components/popular-accounts.tsx';
|
||||||
import AccountsCarousel from 'soapbox/features/search/components/people-to-follow-card.tsx';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
heading: { id: 'column.search', defaultMessage: 'Explorer' },
|
heading: { id: 'column.explorer', defaultMessage: 'Explorer' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const SearchPage = () => {
|
const SearchPage = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column label={intl.formatMessage(messages.heading)} slim>
|
<Column label={intl.formatMessage(messages.heading)} withHeader={false} slim>
|
||||||
|
|
||||||
<Stack space={4}>
|
<Stack space={4}>
|
||||||
<ExplorerCards />
|
<ExplorerCards />
|
||||||
|
@ -32,11 +31,8 @@ const SearchPage = () => {
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<div className='px-4'>
|
|
||||||
<Search autoSubmit />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<SearchResults />
|
<SearchResults />
|
||||||
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
|
@ -70,6 +70,7 @@ const PublicTimeline = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column
|
<Column
|
||||||
|
withHeader={false}
|
||||||
label={intl.formatMessage(messages.title)}
|
label={intl.formatMessage(messages.title)}
|
||||||
action={features.publicTimelineLanguage ? <LanguageDropdown language={language} setLanguage={setLanguage} /> : null}
|
action={features.publicTimelineLanguage ? <LanguageDropdown language={language} setLanguage={setLanguage} /> : null}
|
||||||
slim
|
slim
|
||||||
|
|
|
@ -38,7 +38,7 @@ const TrendsPanel = ({ limit }: ITrendsPanel) => {
|
||||||
<Widget
|
<Widget
|
||||||
title={<FormattedMessage id='trends.title' defaultMessage='Trends' />}
|
title={<FormattedMessage id='trends.title' defaultMessage='Trends' />}
|
||||||
action={
|
action={
|
||||||
<Link className='text-right' to='/search' onClick={setHashtagsFilter}>
|
<Link className='text-right' to='/explorer' onClick={setHashtagsFilter}>
|
||||||
<Text tag='span' theme='primary' size='sm' className='hover:underline'>
|
<Text tag='span' theme='primary' size='sm' className='hover:underline'>
|
||||||
{intl.formatMessage(messages.viewAll)}
|
{intl.formatMessage(messages.viewAll)}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
|
@ -48,7 +48,6 @@ import Navbar from './components/navbar.tsx';
|
||||||
import {
|
import {
|
||||||
Status,
|
Status,
|
||||||
CommunityTimeline,
|
CommunityTimeline,
|
||||||
PublicTimeline,
|
|
||||||
RemoteTimeline,
|
RemoteTimeline,
|
||||||
AccountTimeline,
|
AccountTimeline,
|
||||||
AccountGallery,
|
AccountGallery,
|
||||||
|
@ -194,7 +193,6 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
||||||
https://stackoverflow.com/a/68637108
|
https://stackoverflow.com/a/68637108
|
||||||
*/}
|
*/}
|
||||||
{features.federating && <WrappedRoute path='/timeline/local' exact page={HomePage} component={CommunityTimeline} content={children} publicRoute />}
|
{features.federating && <WrappedRoute path='/timeline/local' exact page={HomePage} component={CommunityTimeline} content={children} publicRoute />}
|
||||||
{features.federating && <WrappedRoute path='/timeline/global' exact page={HomePage} component={PublicTimeline} content={children} publicRoute />}
|
|
||||||
{features.federating && <WrappedRoute path='/timeline/:instance' exact page={RemoteInstancePage} component={RemoteTimeline} content={children} publicRoute />}
|
{features.federating && <WrappedRoute path='/timeline/:instance' exact page={RemoteInstancePage} component={RemoteTimeline} content={children} publicRoute />}
|
||||||
|
|
||||||
{features.conversations && <WrappedRoute path='/conversations' page={DefaultPage} component={Conversations} content={children} />}
|
{features.conversations && <WrappedRoute path='/conversations' page={DefaultPage} component={Conversations} content={children} />}
|
||||||
|
@ -209,11 +207,11 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
||||||
<Redirect from='/web/:path' to='/:path' />
|
<Redirect from='/web/:path' to='/:path' />
|
||||||
<Redirect from='/timelines/home' to='/' />
|
<Redirect from='/timelines/home' to='/' />
|
||||||
<Redirect from='/timelines/public/local' to='/timeline/local' />
|
<Redirect from='/timelines/public/local' to='/timeline/local' />
|
||||||
<Redirect from='/timelines/public' to='/timeline/global' />
|
<Redirect from='/timelines/public' to='/explorer' />
|
||||||
<Redirect from='/timelines/direct' to='/messages' />
|
<Redirect from='/timelines/direct' to='/messages' />
|
||||||
|
|
||||||
{/* Pleroma FE web routes */}
|
{/* Pleroma FE web routes */}
|
||||||
<Redirect from='/main/all' to='/timeline/global' />
|
<Redirect from='/main/all' to='/explorer' />
|
||||||
<Redirect from='/main/public' to='/timeline/local' />
|
<Redirect from='/main/public' to='/timeline/local' />
|
||||||
<Redirect from='/main/friends' to='/' />
|
<Redirect from='/main/friends' to='/' />
|
||||||
<Redirect from='/tag/:id' to='/tags/:id' />
|
<Redirect from='/tag/:id' to='/tags/:id' />
|
||||||
|
@ -251,7 +249,7 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
||||||
<Redirect from='/auth/mfa' to='/settings/mfa' />
|
<Redirect from='/auth/mfa' to='/settings/mfa' />
|
||||||
<Redirect from='/auth/password/new' to='/reset-password' />
|
<Redirect from='/auth/password/new' to='/reset-password' />
|
||||||
<Redirect from='/auth/password/edit' to={`/edit-password${search}`} />
|
<Redirect from='/auth/password/edit' to={`/edit-password${search}`} />
|
||||||
<Redirect from='/timeline/fediverse' to='/timeline/global' />
|
<Redirect from='/timeline/fediverse' to='/explorer' />
|
||||||
|
|
||||||
<WrappedRoute path='/tags/:id' publicRoute page={DefaultPage} component={HashtagTimeline} content={children} />
|
<WrappedRoute path='/tags/:id' publicRoute page={DefaultPage} component={HashtagTimeline} content={children} />
|
||||||
|
|
||||||
|
@ -261,7 +259,7 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
||||||
|
|
||||||
<WrappedRoute path='/notifications' page={DefaultPage} component={Notifications} content={children} />
|
<WrappedRoute path='/notifications' page={DefaultPage} component={Notifications} content={children} />
|
||||||
|
|
||||||
<WrappedRoute path='/search' page={SearchPage} component={Search} content={children} publicRoute />
|
<WrappedRoute path='/explorer' page={SearchPage} component={Search} content={children} publicRoute />
|
||||||
{features.suggestionsLocal && <WrappedRoute path='/suggestions/local' publicRoute page={DefaultPage} component={FollowRecommendations} content={children} componentParams={{ local: true }} />}
|
{features.suggestionsLocal && <WrappedRoute path='/suggestions/local' publicRoute page={DefaultPage} component={FollowRecommendations} content={children} componentParams={{ local: true }} />}
|
||||||
{features.suggestions && <WrappedRoute path='/suggestions' exact publicRoute page={DefaultPage} component={FollowRecommendations} content={children} />}
|
{features.suggestions && <WrappedRoute path='/suggestions' exact publicRoute page={DefaultPage} component={FollowRecommendations} content={children} />}
|
||||||
{features.profileDirectory && <WrappedRoute path='/directory' exact publicRoute page={DefaultPage} component={Directory} content={children} />}
|
{features.profileDirectory && <WrappedRoute path='/directory' exact publicRoute page={DefaultPage} component={Directory} content={children} />}
|
||||||
|
|
|
@ -58,7 +58,7 @@ export const BirthdaysModal = lazy(() => import('soapbox/features/ui/components/
|
||||||
export const BirthdayPanel = lazy(() => import('soapbox/components/birthday-panel.tsx'));
|
export const BirthdayPanel = lazy(() => import('soapbox/components/birthday-panel.tsx'));
|
||||||
export const ListEditor = lazy(() => import('soapbox/features/list-editor/index.tsx'));
|
export const ListEditor = lazy(() => import('soapbox/features/list-editor/index.tsx'));
|
||||||
export const ListAdder = lazy(() => import('soapbox/features/list-adder/index.tsx'));
|
export const ListAdder = lazy(() => import('soapbox/features/list-adder/index.tsx'));
|
||||||
export const Search = lazy(() => import('soapbox/features/search/index.tsx'));
|
export const Search = lazy(() => import('soapbox/features/explorer/index.tsx'));
|
||||||
export const LoginPage = lazy(() => import('soapbox/features/auth-login/components/login-page.tsx'));
|
export const LoginPage = lazy(() => import('soapbox/features/auth-login/components/login-page.tsx'));
|
||||||
export const ExternalLogin = lazy(() => import('soapbox/features/external-login/index.tsx'));
|
export const ExternalLogin = lazy(() => import('soapbox/features/external-login/index.tsx'));
|
||||||
export const LogoutPage = lazy(() => import('soapbox/features/auth-login/components/logout.tsx'));
|
export const LogoutPage = lazy(() => import('soapbox/features/auth-login/components/logout.tsx'));
|
||||||
|
|
|
@ -368,6 +368,7 @@
|
||||||
"column.event_map": "Event location",
|
"column.event_map": "Event location",
|
||||||
"column.event_participants": "Event participants",
|
"column.event_participants": "Event participants",
|
||||||
"column.events": "Events",
|
"column.events": "Events",
|
||||||
|
"column.explorer": "Explorer",
|
||||||
"column.explorer.bridge_card.text": "Curious about Bridges? <a>Click here</a>",
|
"column.explorer.bridge_card.text": "Curious about Bridges? <a>Click here</a>",
|
||||||
"column.explorer.bridge_card.title": "Bridge",
|
"column.explorer.bridge_card.title": "Bridge",
|
||||||
"column.explorer.filters": "Filters:",
|
"column.explorer.filters": "Filters:",
|
||||||
|
@ -451,7 +452,6 @@
|
||||||
"column.reblogs": "Reposts",
|
"column.reblogs": "Reposts",
|
||||||
"column.registration": "Sign Up",
|
"column.registration": "Sign Up",
|
||||||
"column.scheduled_statuses": "Scheduled Posts",
|
"column.scheduled_statuses": "Scheduled Posts",
|
||||||
"column.search": "Explorer",
|
|
||||||
"column.settings_store": "Settings store",
|
"column.settings_store": "Settings store",
|
||||||
"column.soapbox_config": "Soapbox config",
|
"column.soapbox_config": "Soapbox config",
|
||||||
"column.test": "Test timeline",
|
"column.test": "Test timeline",
|
||||||
|
@ -459,6 +459,7 @@
|
||||||
"column_forbidden.body": "You do not have permission to access this page.",
|
"column_forbidden.body": "You do not have permission to access this page.",
|
||||||
"column_forbidden.title": "Forbidden",
|
"column_forbidden.title": "Forbidden",
|
||||||
"common.cancel": "Cancel",
|
"common.cancel": "Cancel",
|
||||||
|
"common.search": "Search",
|
||||||
"compare_history_modal.header": "Edit history",
|
"compare_history_modal.header": "Edit history",
|
||||||
"compose.character_counter.title": "Used {chars} out of {maxChars} {maxChars, plural, one {character} other {characters}}",
|
"compose.character_counter.title": "Used {chars} out of {maxChars} {maxChars, plural, one {character} other {characters}}",
|
||||||
"compose.edit_success": "Your post was edited",
|
"compose.edit_success": "Your post was edited",
|
||||||
|
@ -1442,6 +1443,10 @@
|
||||||
"scheduled_status.cancel": "Cancel",
|
"scheduled_status.cancel": "Cancel",
|
||||||
"search.action": "Search for “{query}”",
|
"search.action": "Search for “{query}”",
|
||||||
"search.placeholder": "Search",
|
"search.placeholder": "Search",
|
||||||
|
"search_results.accounts": "Posts",
|
||||||
|
"search_results.filter_message": "You are searching for posts from @{acct}.",
|
||||||
|
"search_results.posts": "Accounts",
|
||||||
|
"search_results.trends": "Trends",
|
||||||
"security.codes.fail": "Failed to fetch backup codes",
|
"security.codes.fail": "Failed to fetch backup codes",
|
||||||
"security.confirm.fail": "Incorrect code or password. Try again.",
|
"security.confirm.fail": "Incorrect code or password. Try again.",
|
||||||
"security.delete_account.fail": "Account deletion failed.",
|
"security.delete_account.fail": "Account deletion failed.",
|
||||||
|
|
Ładowanie…
Reference in New Issue