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' />}
|
||||
onClick={onClose}
|
||||
/>
|
||||
|
||||
{features.federating && (
|
||||
<SidebarLink
|
||||
to='/timeline/global'
|
||||
icon={worldIcon}
|
||||
text={<FormattedMessage id='tabs_bar.global' defaultMessage='Global' />}
|
||||
onClick={onClose}
|
||||
/>
|
||||
)}
|
||||
</>}
|
||||
|
||||
<Divider />
|
||||
|
|
|
@ -6,6 +6,7 @@ import userFilledIcon from '@tabler/icons/filled/user.svg';
|
|||
import atIcon from '@tabler/icons/outline/at.svg';
|
||||
import bellIcon from '@tabler/icons/outline/bell.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 circlesIcon from '@tabler/icons/outline/circles.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 mailIcon from '@tabler/icons/outline/mail.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 userPlusIcon from '@tabler/icons/outline/user-plus.svg';
|
||||
import userIcon from '@tabler/icons/outline/user.svg';
|
||||
|
@ -162,8 +162,8 @@ const SidebarNavigation = () => {
|
|||
/>
|
||||
|
||||
<SidebarNavigationLink
|
||||
to='/search'
|
||||
icon={rocketIcon}
|
||||
to='/explorer'
|
||||
icon={compassIcon}
|
||||
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' />}
|
||||
/>
|
||||
)}
|
||||
|
||||
{(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 mailFilledIcon from '@tabler/icons/filled/mail.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 dashboardIcon from '@tabler/icons/outline/dashboard.svg';
|
||||
import homeIcon from '@tabler/icons/outline/home.svg';
|
||||
import mailIcon from '@tabler/icons/outline/mail.svg';
|
||||
import messagesIcon from '@tabler/icons/outline/messages.svg';
|
||||
import rocketIcon from '@tabler/icons/outline/rocket.svg';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import ThumbNavigationLink from 'soapbox/components/thumb-navigation-link.tsx';
|
||||
|
@ -84,9 +84,9 @@ const ThumbNavigation: React.FC = (): JSX.Element => {
|
|||
)}
|
||||
|
||||
<ThumbNavigationLink
|
||||
src={rocketIcon}
|
||||
src={compassIcon}
|
||||
text={<FormattedMessage id='navigation.search' defaultMessage='Explorer' />}
|
||||
to='/search'
|
||||
to='/explorer'
|
||||
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', {
|
||||
'rounded-md': theme !== 'search',
|
||||
'rounded-full': theme === 'search',
|
||||
'mt-1': !String(outerClassName).includes('mt-'),
|
||||
[String(outerClassName)]: typeof outerClassName !== 'undefined',
|
||||
})
|
||||
}
|
||||
|
|
|
@ -259,7 +259,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
|
|||
|
||||
const onSearch = () => {
|
||||
dispatch(setSearchAccount(account.id));
|
||||
history.push('/search');
|
||||
history.push('/explorer');
|
||||
};
|
||||
|
||||
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 { useEffect, useRef } from 'react';
|
||||
import {
|
||||
FormattedMessage,
|
||||
// defineMessages,
|
||||
// useIntl
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
FormattedMessage,
|
||||
defineMessages,
|
||||
useIntl,
|
||||
} from 'react-intl';
|
||||
|
||||
import {
|
||||
import {
|
||||
expandSearch,
|
||||
// setFilter,
|
||||
// setSearchAccount
|
||||
setFilter,
|
||||
setSearchAccount,
|
||||
} from 'soapbox/actions/search.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 IconButton from 'soapbox/components/icon-button.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 Tabs from 'soapbox/components/ui/tabs.tsx';
|
||||
import Text from 'soapbox/components/ui/text.tsx';
|
||||
import AccountContainer from 'soapbox/containers/account-container.tsx';
|
||||
import StatusContainer from 'soapbox/containers/status-container.tsx';
|
||||
import PlaceholderAccount from 'soapbox/features/placeholder/components/placeholder-account.tsx';
|
||||
import PlaceholderHashtag from 'soapbox/features/placeholder/components/placeholder-hashtag.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 { useAppSelector } from 'soapbox/hooks/useAppSelector.ts';
|
||||
import { useSuggestions } from 'soapbox/queries/suggestions.ts';
|
||||
import { SearchFilter } from 'soapbox/reducers/search.ts';
|
||||
|
||||
import type { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||
import type { VirtuosoHandle } from 'react-virtuoso';
|
||||
// import type { SearchFilter } from 'soapbox/reducers/search.ts';
|
||||
|
||||
// const messages = defineMessages({
|
||||
// accounts: { id: 'search_results.accounts', defaultMessage: 'People' },
|
||||
// statuses: { id: 'search_results.statuses', defaultMessage: 'Posts' },
|
||||
// hashtags: { id: 'search_results.hashtags', defaultMessage: 'Hashtags' },
|
||||
// });
|
||||
const messages = defineMessages({
|
||||
accounts: { id: 'search_results.posts', defaultMessage: 'Accounts' },
|
||||
statuses: { id: 'search_results.accounts', defaultMessage: 'Posts' },
|
||||
trends: { id: 'search_results.trends', defaultMessage: 'Trends' },
|
||||
search: { id: 'common.search', defaultMessage: 'Search' },
|
||||
});
|
||||
|
||||
const SearchResults = () => {
|
||||
const node = useRef<VirtuosoHandle>(null);
|
||||
|
||||
// const intl = useIntl();
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { data: suggestions } = useSuggestions();
|
||||
const [globalTimeline, setGlobalTimeline] = useState(true);
|
||||
|
||||
const value = useAppSelector((state) => state.search.submittedValue);
|
||||
const results = useAppSelector((state) => state.search.results);
|
||||
|
@ -51,8 +62,8 @@ const SearchResults = () => {
|
|||
const trends = useAppSelector((state) => state.trends.items);
|
||||
const submitted = useAppSelector((state) => state.search.submitted);
|
||||
const selectedFilter = useAppSelector((state) => state.search.filter);
|
||||
// const filterByAccount = useAppSelector((state) => state.search.accountId || undefined);
|
||||
// const { account } = useAccount(filterByAccount);
|
||||
const filterByAccount = useAppSelector((state) => state.search.accountId || undefined);
|
||||
const { account } = useAccount(filterByAccount);
|
||||
|
||||
const handleLoadMore = () => {
|
||||
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 items = [];
|
||||
// items.push(
|
||||
// {
|
||||
// text: intl.formatMessage(messages.statuses),
|
||||
// action: () => selectFilter('statuses'),
|
||||
// name: 'statuses',
|
||||
// },
|
||||
// {
|
||||
// text: intl.formatMessage(messages.accounts),
|
||||
// action: () => selectFilter('accounts'),
|
||||
// name: 'accounts',
|
||||
// },
|
||||
// );
|
||||
const renderFilterBar = () => {
|
||||
const items = [];
|
||||
items.push(
|
||||
{
|
||||
label: intl.formatMessage(messages.statuses),
|
||||
action: () => setGlobalTimeline(true),
|
||||
name: 'statuses',
|
||||
icon: globeIcon,
|
||||
},
|
||||
{
|
||||
label: intl.formatMessage(messages.trends),
|
||||
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(
|
||||
// {
|
||||
// text: intl.formatMessage(messages.hashtags),
|
||||
// action: () => selectFilter('hashtags'),
|
||||
// name: 'hashtags',
|
||||
// },
|
||||
// );
|
||||
|
||||
// return <Tabs items={items} activeItem={selectedFilter} />;
|
||||
// };
|
||||
return <ExplorerTabs items={items} activeItem={selectedFilter} />;
|
||||
};
|
||||
|
||||
const getCurrentIndex = (id: string): number => {
|
||||
return resultsIds?.keySeq().findIndex(key => key === id);
|
||||
|
@ -219,7 +240,7 @@ const SearchResults = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
{/* {filterByAccount ? (
|
||||
{filterByAccount ? (
|
||||
<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} />
|
||||
<Text truncate>
|
||||
|
@ -231,10 +252,12 @@ const SearchResults = () => {
|
|||
</Text>
|
||||
</HStack>
|
||||
) : (
|
||||
<div className='px-4'>{renderFilterBar()}</div>
|
||||
)} */}
|
||||
<div className='relative px-4'>
|
||||
{renderFilterBar()}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{noResultsMessage || (
|
||||
{globalTimeline ? <PublicTimeline /> : (noResultsMessage || (
|
||||
<ScrollableList
|
||||
id='search-results'
|
||||
ref={node}
|
||||
|
@ -257,7 +280,7 @@ const SearchResults = () => {
|
|||
>
|
||||
{searchResults || []}
|
||||
</ScrollableList>
|
||||
)}
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -76,7 +76,7 @@ const SearchZapSplit = (props: ISearchZapSplit) => {
|
|||
dispatch(setSearchAccount(null));
|
||||
dispatch(submitSearch());
|
||||
|
||||
history.push('/search');
|
||||
history.push('/explorer');
|
||||
} else {
|
||||
dispatch(submitSearch());
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ const Search = (props: ISearch) => {
|
|||
dispatch(setSearchAccount(null));
|
||||
dispatch(submitSearch());
|
||||
|
||||
history.push('/search');
|
||||
history.push('/explorer');
|
||||
} else {
|
||||
dispatch(submitSearch());
|
||||
}
|
||||
|
|
|
@ -24,10 +24,10 @@ const ExplorerCards = () => {
|
|||
const [isOpen, setIsOpen] = useState(true);
|
||||
const intl = useIntl();
|
||||
return (
|
||||
<Stack>
|
||||
<Stack className='mx-4 mt-4' space={2}>
|
||||
<Stack
|
||||
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 space={2}>
|
||||
|
@ -53,11 +53,11 @@ const ExplorerCards = () => {
|
|||
</Text>
|
||||
</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 */}
|
||||
<Stack
|
||||
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'
|
||||
>
|
||||
<HStack alignItems='center' justifyContent='between'>
|
||||
|
@ -82,7 +82,7 @@ const ExplorerCards = () => {
|
|||
{/* Bridge */}
|
||||
<Stack
|
||||
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'>
|
||||
{/* Title */}
|
|
@ -15,7 +15,7 @@ import {
|
|||
PlatformFilters,
|
||||
RepliesFilter,
|
||||
generateFilter,
|
||||
} from 'soapbox/features/search/components/filters.tsx';
|
||||
} from 'soapbox/features/explorer/components/filters.tsx';
|
||||
import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||
|
||||
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 Text from 'soapbox/components/ui/text.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 { IGenerateFilter } from 'soapbox/features/search/components/explorerFilter.tsx';
|
||||
// import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts';
|
||||
|
||||
const messages = defineMessages({
|
||||
filters: { id: 'column.explorer.filters', defaultMessage: 'Filters:' },
|
||||
|
@ -48,7 +47,6 @@ const languages = {
|
|||
da: 'Dansk',
|
||||
de: 'Deutsch',
|
||||
el: 'Ελληνικά',
|
||||
'en-Shaw': '𐑖𐑱𐑝𐑾𐑯',
|
||||
eo: 'Esperanto',
|
||||
es: 'Español',
|
||||
eu: 'Euskara',
|
||||
|
@ -80,14 +78,12 @@ const languages = {
|
|||
oc: 'Occitan',
|
||||
pl: 'Polski',
|
||||
pt: 'Português',
|
||||
'pt-BR': 'Português do Brasil',
|
||||
ro: 'Română',
|
||||
ru: 'Русский',
|
||||
sk: 'Slovenčina',
|
||||
sl: 'Slovenščina',
|
||||
sq: 'Shqip',
|
||||
sr: 'Српски',
|
||||
'sr-Latn': 'Srpski (latinica)',
|
||||
sv: 'Svenska',
|
||||
ta: 'தமிழ்',
|
||||
te: 'తెలుగు',
|
||||
|
@ -95,9 +91,6 @@ const languages = {
|
|||
tr: 'Türkçe',
|
||||
uk: 'Українська',
|
||||
zh: '中文',
|
||||
'zh-CN': '简体中文',
|
||||
'zh-HK': '繁體中文(香港)',
|
||||
'zh-TW': '繁體中文(臺灣)',
|
||||
};
|
||||
|
||||
interface IFilter {
|
||||
|
@ -370,6 +363,7 @@ const MediaFilter = ({ onChangeFilters }: IFilter) => {
|
|||
const generateFilter = ({ name, state }: IGenerateFilter, onChangeFilters: React.Dispatch<React.SetStateAction<IGenerateFilter[]>>) => {
|
||||
let borderColor = '';
|
||||
let textColor = '';
|
||||
let hasButton = false;
|
||||
switch (name.toLowerCase()) {
|
||||
case 'nostr':
|
||||
borderColor = 'border-purple-500';
|
||||
|
@ -391,19 +385,20 @@ const generateFilter = ({ name, state }: IGenerateFilter, onChangeFilters: React
|
|||
}
|
||||
borderColor = state ? 'border-green-500' : 'border-red-500';
|
||||
textColor = state ? 'text-green-500' : 'text-red-500';
|
||||
hasButton = true;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
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}
|
||||
<IconButton
|
||||
{hasButton && <IconButton
|
||||
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);
|
||||
})}
|
||||
/>
|
||||
/>}
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -17,9 +17,10 @@ import {
|
|||
useSuggestions,
|
||||
} from 'soapbox/queries/suggestions.ts';
|
||||
|
||||
// @ts-ignore
|
||||
import 'swiper/css';
|
||||
|
||||
const PeopleToFollowCard = ({ id }: { id: string }) => {
|
||||
const PopularAccounts = ({ id }: { id: string }) => {
|
||||
const account = useAccount(id).account;
|
||||
const { logo } = useSoapboxConfig();
|
||||
|
||||
|
@ -70,7 +71,7 @@ const PeopleToFollowCard = ({ id }: { id: string }) => {
|
|||
const AccountsCarousel = () => {
|
||||
const isMobile = useIsMobile();
|
||||
const { data: suggestions, isFetching } = useSuggestions();
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
|
||||
|
||||
if (!isFetching && !suggestions.length) {
|
||||
|
@ -101,7 +102,7 @@ const AccountsCarousel = () => {
|
|||
>
|
||||
{suggestions.map((suggestion) => (
|
||||
<SwiperSlide key={suggestion.account}>
|
||||
<PeopleToFollowCard id={suggestion.account} />
|
||||
<PopularAccounts id={suggestion.account} />
|
||||
</SwiperSlide>
|
||||
))}
|
||||
</Swiper>
|
|
@ -4,20 +4,19 @@ import { Column } from 'soapbox/components/ui/column.tsx';
|
|||
import Divider from 'soapbox/components/ui/divider.tsx';
|
||||
import Stack from 'soapbox/components/ui/stack.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/search/components/explorer-cards.tsx';
|
||||
import ExplorerFilter from 'soapbox/features/search/components/explorerFilter.tsx';
|
||||
import AccountsCarousel from 'soapbox/features/search/components/people-to-follow-card.tsx';
|
||||
import ExplorerCards from 'soapbox/features/explorer/components/explorer-cards.tsx';
|
||||
import ExplorerFilter from 'soapbox/features/explorer/components/explorerFilter.tsx';
|
||||
import AccountsCarousel from 'soapbox/features/explorer/components/popular-accounts.tsx';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.search', defaultMessage: 'Explorer' },
|
||||
heading: { id: 'column.explorer', defaultMessage: 'Explorer' },
|
||||
});
|
||||
|
||||
const SearchPage = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.heading)} slim>
|
||||
<Column label={intl.formatMessage(messages.heading)} withHeader={false} slim>
|
||||
|
||||
<Stack space={4}>
|
||||
<ExplorerCards />
|
||||
|
@ -32,11 +31,8 @@ const SearchPage = () => {
|
|||
|
||||
<Divider />
|
||||
|
||||
<div className='px-4'>
|
||||
<Search autoSubmit />
|
||||
</div>
|
||||
|
||||
<SearchResults />
|
||||
|
||||
</Stack>
|
||||
</Column>
|
||||
);
|
|
@ -70,6 +70,7 @@ const PublicTimeline = () => {
|
|||
|
||||
return (
|
||||
<Column
|
||||
withHeader={false}
|
||||
label={intl.formatMessage(messages.title)}
|
||||
action={features.publicTimelineLanguage ? <LanguageDropdown language={language} setLanguage={setLanguage} /> : null}
|
||||
slim
|
||||
|
|
|
@ -38,7 +38,7 @@ const TrendsPanel = ({ limit }: ITrendsPanel) => {
|
|||
<Widget
|
||||
title={<FormattedMessage id='trends.title' defaultMessage='Trends' />}
|
||||
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'>
|
||||
{intl.formatMessage(messages.viewAll)}
|
||||
</Text>
|
||||
|
|
|
@ -48,7 +48,6 @@ import Navbar from './components/navbar.tsx';
|
|||
import {
|
||||
Status,
|
||||
CommunityTimeline,
|
||||
PublicTimeline,
|
||||
RemoteTimeline,
|
||||
AccountTimeline,
|
||||
AccountGallery,
|
||||
|
@ -194,7 +193,6 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
|||
https://stackoverflow.com/a/68637108
|
||||
*/}
|
||||
{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.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='/timelines/home' to='/' />
|
||||
<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' />
|
||||
|
||||
{/* 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/friends' to='/' />
|
||||
<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/password/new' to='/reset-password' />
|
||||
<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} />
|
||||
|
||||
|
@ -261,7 +259,7 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ 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.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} />}
|
||||
|
|
|
@ -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 ListEditor = lazy(() => import('soapbox/features/list-editor/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 ExternalLogin = lazy(() => import('soapbox/features/external-login/index.tsx'));
|
||||
export const LogoutPage = lazy(() => import('soapbox/features/auth-login/components/logout.tsx'));
|
||||
|
|
|
@ -368,6 +368,7 @@
|
|||
"column.event_map": "Event location",
|
||||
"column.event_participants": "Event participants",
|
||||
"column.events": "Events",
|
||||
"column.explorer": "Explorer",
|
||||
"column.explorer.bridge_card.text": "Curious about Bridges? <a>Click here</a>",
|
||||
"column.explorer.bridge_card.title": "Bridge",
|
||||
"column.explorer.filters": "Filters:",
|
||||
|
@ -451,7 +452,6 @@
|
|||
"column.reblogs": "Reposts",
|
||||
"column.registration": "Sign Up",
|
||||
"column.scheduled_statuses": "Scheduled Posts",
|
||||
"column.search": "Explorer",
|
||||
"column.settings_store": "Settings store",
|
||||
"column.soapbox_config": "Soapbox config",
|
||||
"column.test": "Test timeline",
|
||||
|
@ -459,6 +459,7 @@
|
|||
"column_forbidden.body": "You do not have permission to access this page.",
|
||||
"column_forbidden.title": "Forbidden",
|
||||
"common.cancel": "Cancel",
|
||||
"common.search": "Search",
|
||||
"compare_history_modal.header": "Edit history",
|
||||
"compose.character_counter.title": "Used {chars} out of {maxChars} {maxChars, plural, one {character} other {characters}}",
|
||||
"compose.edit_success": "Your post was edited",
|
||||
|
@ -1442,6 +1443,10 @@
|
|||
"scheduled_status.cancel": "Cancel",
|
||||
"search.action": "Search for “{query}”",
|
||||
"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.confirm.fail": "Incorrect code or password. Try again.",
|
||||
"security.delete_account.fail": "Account deletion failed.",
|
||||
|
|
Ładowanie…
Reference in New Issue