kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
Just to save first changes
rodzic
eca2978fc2
commit
d93439f396
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 70 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 11 KiB |
|
@ -1,18 +1,22 @@
|
|||
import xIcon from '@tabler/icons/outline/x.svg';
|
||||
import clsx from 'clsx';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
|
||||
import {
|
||||
FormattedMessage,
|
||||
// defineMessages,
|
||||
// useIntl
|
||||
} from 'react-intl';
|
||||
|
||||
import { expandSearch, setFilter, setSearchAccount } from 'soapbox/actions/search.ts';
|
||||
import {
|
||||
expandSearch,
|
||||
// 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 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 Tabs from 'soapbox/components/ui/tabs.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';
|
||||
|
@ -24,18 +28,18 @@ import { useSuggestions } from 'soapbox/queries/suggestions.ts';
|
|||
|
||||
import type { OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||
import type { VirtuosoHandle } from 'react-virtuoso';
|
||||
import type { SearchFilter } from 'soapbox/reducers/search.ts';
|
||||
// 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.accounts', defaultMessage: 'People' },
|
||||
// statuses: { id: 'search_results.statuses', defaultMessage: 'Posts' },
|
||||
// hashtags: { id: 'search_results.hashtags', defaultMessage: 'Hashtags' },
|
||||
// });
|
||||
|
||||
const SearchResults = () => {
|
||||
const node = useRef<VirtuosoHandle>(null);
|
||||
|
||||
const intl = useIntl();
|
||||
// const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { data: suggestions } = useSuggestions();
|
||||
|
@ -47,8 +51,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) {
|
||||
|
@ -58,35 +62,35 @@ const SearchResults = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const handleUnsetAccount = () => dispatch(setSearchAccount(null));
|
||||
// const handleUnsetAccount = () => dispatch(setSearchAccount(null));
|
||||
|
||||
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(
|
||||
// {
|
||||
// text: intl.formatMessage(messages.statuses),
|
||||
// action: () => selectFilter('statuses'),
|
||||
// name: 'statuses',
|
||||
// },
|
||||
// {
|
||||
// text: intl.formatMessage(messages.accounts),
|
||||
// action: () => selectFilter('accounts'),
|
||||
// name: 'accounts',
|
||||
// },
|
||||
// );
|
||||
|
||||
items.push(
|
||||
{
|
||||
text: intl.formatMessage(messages.hashtags),
|
||||
action: () => selectFilter('hashtags'),
|
||||
name: 'hashtags',
|
||||
},
|
||||
);
|
||||
// items.push(
|
||||
// {
|
||||
// text: intl.formatMessage(messages.hashtags),
|
||||
// action: () => selectFilter('hashtags'),
|
||||
// name: 'hashtags',
|
||||
// },
|
||||
// );
|
||||
|
||||
return <Tabs items={items} activeItem={selectedFilter} />;
|
||||
};
|
||||
// return <Tabs items={items} activeItem={selectedFilter} />;
|
||||
// };
|
||||
|
||||
const getCurrentIndex = (id: string): number => {
|
||||
return resultsIds?.keySeq().findIndex(key => key === id);
|
||||
|
@ -215,7 +219,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>
|
||||
|
@ -228,7 +232,7 @@ const SearchResults = () => {
|
|||
</HStack>
|
||||
) : (
|
||||
<div className='px-4'>{renderFilterBar()}</div>
|
||||
)}
|
||||
)} */}
|
||||
|
||||
{noResultsMessage || (
|
||||
<ScrollableList
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
import arrowIcon from '@tabler/icons/outline/chevron-down.svg';
|
||||
import rocketIcon from '@tabler/icons/outline/rocket.svg';
|
||||
import { useState } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import bridgeImg from 'soapbox/assets/images/bridge-image.png';
|
||||
import nostrImg from 'soapbox/assets/images/nostr-image.png';
|
||||
import HStack from 'soapbox/components/ui/hstack.tsx';
|
||||
import IconButton from 'soapbox/components/ui/icon-button.tsx';
|
||||
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';
|
||||
|
||||
const messages = defineMessages({
|
||||
welcomeTitle: { id: 'column.explorer.welcome_card.title', defaultMessage: 'Welcome to Explorer' },
|
||||
welcomeText: { id: 'column.explorer.welcome_card.text', defaultMessage: 'Explore the world of <span>decentralized social media</span>, dive into <span>Nostr</span> or cross the bridge to other networks, and connect with a global community. All in one place.' },
|
||||
nostrTitle: { id: 'column.explorer.nostr_card.title', defaultMessage: 'Nostr' },
|
||||
nostrText: { id: 'column.explorer.nostr_card.text', defaultMessage: 'Wondering about Nostr? Find Out More' },
|
||||
bridgeTitle: { id: 'column.explorer.bridge_card.title', defaultMessage: 'Bridge' },
|
||||
bridgeText: { id: 'column.explorer.bridge_card.text', defaultMessage: 'Curious about Bridges? Click here' },
|
||||
});
|
||||
|
||||
const ExplorerCards = () => {
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
const intl = useIntl();
|
||||
return (
|
||||
<Stack>
|
||||
<Stack
|
||||
space={4}
|
||||
className={`rounded-xl bg-gradient-to-r from-pink-400 via-purple-500 to-blue-400 ${isOpen ? 'mx-4 mb-4 px-5 pb-8 pt-4' : 'm-4 p-4'}`}
|
||||
>
|
||||
<HStack justifyContent='between' className='text-white'>
|
||||
<HStack space={2}>
|
||||
<SvgIcon src={rocketIcon} />
|
||||
<p className='text-xl font-bold'>
|
||||
{intl.formatMessage(messages.welcomeTitle)}
|
||||
</p>
|
||||
</HStack>
|
||||
<IconButton
|
||||
src={arrowIcon}
|
||||
theme='transparent'
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
className={`transition-transform duration-300${
|
||||
isOpen ? 'rotate-0' : 'rotate-180'
|
||||
}`}
|
||||
/>
|
||||
</HStack>
|
||||
|
||||
<Text className={`text-white ${isOpen ? 'max-h-96 opacity-100' : 'hidden max-h-0 opacity-0'}`}>
|
||||
{intl.formatMessage(messages.welcomeText, {
|
||||
span: (node) => <span className='text-black'>{node}</span>,
|
||||
})}
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
<HStack className={`mx-4 mb-4 ${isOpen ? 'max-h-96 opacity-100' : 'hidden max-h-0 opacity-0'}`} space={4}>
|
||||
{/* Nostr */}
|
||||
<Stack
|
||||
space={4}
|
||||
className='w-1/2 rounded-xl bg-gradient-to-r from-pink-400 to-purple-500 px-5 pb-8 pt-4'
|
||||
justifyContent='center'
|
||||
>
|
||||
<HStack space={2} alignItems='center' justifyContent='center'>
|
||||
{/* Title */}
|
||||
<Stack space={2}>
|
||||
<p className='text-xl font-bold text-white'>
|
||||
{intl.formatMessage(messages.nostrTitle)}
|
||||
</p>
|
||||
<Text className='text-white'>
|
||||
{intl.formatMessage(messages.nostrText)}
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
<div className='w-1/2 rounded-full bg-white p-2'>
|
||||
<img src={nostrImg} alt='' />
|
||||
</div>
|
||||
</HStack>
|
||||
</Stack>
|
||||
|
||||
{/* Bridge */}
|
||||
<Stack
|
||||
space={4}
|
||||
className='w-1/2 rounded-xl bg-gradient-to-r from-purple-500 to-blue-400 px-5 pb-8 pt-4'
|
||||
>
|
||||
<HStack space={2} alignItems='center'>
|
||||
{/* Title */}
|
||||
<Stack space={2}>
|
||||
<p className='text-xl font-bold text-white'> {intl.formatMessage(messages.bridgeTitle)} </p>
|
||||
<Text className='text-white'>
|
||||
{intl.formatMessage(messages.bridgeText)}
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
<div className='w-1/2 rounded-full bg-white p-2'>
|
||||
<img src={bridgeImg} alt='' />
|
||||
</div>
|
||||
</HStack>
|
||||
</Stack>
|
||||
</HStack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default ExplorerCards;
|
|
@ -0,0 +1,358 @@
|
|||
import arrowIcon from '@tabler/icons/outline/chevron-down.svg';
|
||||
import searchIcon from '@tabler/icons/outline/search.svg';
|
||||
import xIcon from '@tabler/icons/outline/x.svg';
|
||||
import clsx from 'clsx';
|
||||
import { useState } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import Button from 'soapbox/components/ui/button.tsx';
|
||||
import Checkbox from 'soapbox/components/ui/checkbox.tsx';
|
||||
import Divider from 'soapbox/components/ui/divider.tsx';
|
||||
import HStack from 'soapbox/components/ui/hstack.tsx';
|
||||
import IconButton from 'soapbox/components/ui/icon-button.tsx';
|
||||
import Input from 'soapbox/components/ui/input.tsx';
|
||||
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 { SelectDropdown } from 'soapbox/features/forms/index.tsx';
|
||||
|
||||
const messages = defineMessages({
|
||||
filters: { id: 'column.explorer.filters', defaultMessage: 'Filters:' },
|
||||
showReplies: { id: 'column.explorer.filters.show_replies', defaultMessage: 'Show replies:' },
|
||||
language: { id: 'column.explorer.filters.language', defaultMessage: 'Language:' },
|
||||
platforms: { id: 'column.explorer.filters.platforms', defaultMessage: 'Platforms:' },
|
||||
createYourFilter: { id: 'column.explorer.filters.create_your_filter', defaultMessage: 'Create your filter' },
|
||||
filterByWords: { id: 'column.explorer.filters.filter_by_words', defaultMessage: 'Filter by this/these words' },
|
||||
include: { id: 'column.explorer.filters.include', defaultMessage: 'Include' },
|
||||
exclude: { id: 'column.explorer.filters.exclude', defaultMessage: 'Exclude' },
|
||||
nostr: { id: 'column.explorer.filters.nostr', defaultMessage: 'Nostr' },
|
||||
bluesky: { id: 'column.explorer.filters.bluesky', defaultMessage: 'Bluesky' },
|
||||
fediverse: { id: 'column.explorer.filters.fediverse', defaultMessage: 'Fediverse' },
|
||||
cancel: { id: 'column.explorer.filters.cancel', defaultMessage: 'Cancel' },
|
||||
applyFilter: { id: 'column.explorer.filters.apply_filter', defaultMessage: 'Apply Filter' },
|
||||
});
|
||||
|
||||
const languages = {
|
||||
en: 'English',
|
||||
ar: 'العربية',
|
||||
ast: 'Asturianu',
|
||||
bg: 'Български',
|
||||
bn: 'বাংলা',
|
||||
ca: 'Català',
|
||||
co: 'Corsu',
|
||||
cs: 'Čeština',
|
||||
cy: 'Cymraeg',
|
||||
da: 'Dansk',
|
||||
de: 'Deutsch',
|
||||
el: 'Ελληνικά',
|
||||
'en-Shaw': '𐑖𐑱𐑝𐑾𐑯',
|
||||
eo: 'Esperanto',
|
||||
es: 'Español',
|
||||
eu: 'Euskara',
|
||||
fa: 'فارسی',
|
||||
fi: 'Suomi',
|
||||
fr: 'Français',
|
||||
ga: 'Gaeilge',
|
||||
gl: 'Galego',
|
||||
he: 'עברית',
|
||||
hi: 'हिन्दी',
|
||||
hr: 'Hrvatski',
|
||||
hu: 'Magyar',
|
||||
hy: 'Հայերեն',
|
||||
id: 'Bahasa Indonesia',
|
||||
io: 'Ido',
|
||||
is: 'íslenska',
|
||||
it: 'Italiano',
|
||||
ja: '日本語',
|
||||
jv: 'ꦧꦱꦗꦮ',
|
||||
ka: 'ქართული',
|
||||
kk: 'Қазақша',
|
||||
ko: '한국어',
|
||||
lt: 'Lietuvių',
|
||||
lv: 'Latviešu',
|
||||
ml: 'മലയാളം',
|
||||
ms: 'Bahasa Melayu',
|
||||
nl: 'Nederlands',
|
||||
no: 'Norsk',
|
||||
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: 'తెలుగు',
|
||||
th: 'ไทย',
|
||||
tr: 'Türkçe',
|
||||
uk: 'Українська',
|
||||
zh: '中文',
|
||||
'zh-CN': '简体中文',
|
||||
'zh-HK': '繁體中文(香港)',
|
||||
'zh-TW': '繁體中文(臺灣)',
|
||||
};
|
||||
|
||||
interface IGenerateFilter {
|
||||
name: string;
|
||||
status: boolean | null;
|
||||
}
|
||||
|
||||
const ExplorerFilter = () => {
|
||||
const [showReplies, setShowReplies] = useState(false);
|
||||
const [inputValue, setInputValue] = useState('');
|
||||
const [include, setInclude] = useState(true);
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
|
||||
const hasValue = inputValue.length > 0;
|
||||
|
||||
const intl = useIntl();
|
||||
|
||||
const [testList, setTestList] = useState([
|
||||
{ 'name': 'EN', 'status': true },
|
||||
{ 'name': 'Nostr', 'status': null },
|
||||
{ 'name': 'Bluesky', 'status': null },
|
||||
{ 'name': 'Fediverse', 'status': null },
|
||||
{ 'name': 'Bitcoin', 'status': false },
|
||||
{ 'name': 'NostrInArgentina', 'status': true },
|
||||
{ 'name': 'ElonForPresident', 'status': false },
|
||||
]);
|
||||
|
||||
const generateFilter = ({ name, status }: IGenerateFilter) => {
|
||||
let borderColor = '';
|
||||
let textColor = '';
|
||||
switch (name.toLowerCase()) {
|
||||
case 'nostr':
|
||||
borderColor = 'border-purple-500';
|
||||
textColor = 'text-purple-500';
|
||||
break;
|
||||
case 'bluesky':
|
||||
borderColor = 'border-blue-500';
|
||||
textColor = 'text-blue-500';
|
||||
break;
|
||||
case 'fediverse':
|
||||
borderColor = 'border-indigo-500';
|
||||
textColor = 'text-indigo-500';
|
||||
break;
|
||||
default:
|
||||
borderColor = status ? 'border-green-500' : 'border-red-500';
|
||||
textColor = status ? 'text-green-500' : 'text-red-500';
|
||||
}
|
||||
|
||||
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-lg font-medium shadow-sm hover:cursor-pointer hover:pr-1 ${borderColor} `}
|
||||
>
|
||||
{name}
|
||||
<IconButton
|
||||
iconClassName='!w-4' className={`hidden !p-0 px-1 group-hover:block ${textColor}`} src={xIcon} onClick={() => setTestList((prevValue) => {
|
||||
return prevValue.filter((x) => x.name !== name);
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack className='px-4' space={3}>
|
||||
|
||||
{/* Filters */}
|
||||
<HStack alignItems='start' space={1}>
|
||||
<HStack className='flex-wrap whitespace-normal' alignItems='center' space={2}>
|
||||
<Text size='lg' weight='bold'>
|
||||
{intl.formatMessage(messages.filters)}
|
||||
</Text>
|
||||
|
||||
{testList.map(generateFilter)}
|
||||
|
||||
</HStack>
|
||||
<IconButton
|
||||
src={arrowIcon}
|
||||
theme='transparent'
|
||||
className={`transition-transform duration-300${ isOpen ? 'rotate-0' : 'rotate-180'}`}
|
||||
onClick={() => setIsOpen(!isOpen)}
|
||||
/>
|
||||
</HStack>
|
||||
|
||||
<Stack className={`overflow-hidden transition-all duration-500 ease-in-out ${isOpen ? 'max-h-[1000px] opacity-100' : 'max-h-0 opacity-0'}`} space={3}>
|
||||
|
||||
{/* Show Reply toggle */}
|
||||
<HStack className='flex-wrap whitespace-normal' alignItems='center' space={2}>
|
||||
<Text size='lg' weight='bold'>
|
||||
{intl.formatMessage(messages.showReplies)}
|
||||
</Text>
|
||||
|
||||
<Toggle
|
||||
checked={showReplies}
|
||||
onChange={() => setShowReplies(!showReplies)}
|
||||
/>
|
||||
|
||||
</HStack>
|
||||
|
||||
{/* Language */}
|
||||
<HStack alignItems='center' space={2}>
|
||||
<Text size='lg' weight='bold'>
|
||||
{intl.formatMessage(messages.language)}
|
||||
</Text>
|
||||
|
||||
<SelectDropdown
|
||||
className='max-w-[200px]'
|
||||
items={languages}
|
||||
defaultValue={languages.en}
|
||||
/>
|
||||
</HStack>
|
||||
|
||||
{/* Platforms */}
|
||||
<HStack className='flex-wrap whitespace-normal' alignItems='center' space={2}>
|
||||
<Text size='lg' weight='bold'>
|
||||
{intl.formatMessage(messages.platforms)}
|
||||
</Text>
|
||||
|
||||
{/* Nostr */}
|
||||
<HStack alignItems='center' space={2}>
|
||||
<Checkbox
|
||||
name='nostr'
|
||||
checked={testList.some((tag)=> tag.name.toLowerCase() === 'nostr')}
|
||||
onChange={() => setTestList((prevValue) => {
|
||||
const exists = prevValue.some((x) => x.name.toLowerCase() === 'nostr');
|
||||
if (exists) {
|
||||
return prevValue.filter((x) => x.name.toLowerCase() !== 'nostr');
|
||||
} else {
|
||||
return [...prevValue, { name: 'Nostr', status: null }];
|
||||
}
|
||||
})}
|
||||
// checked={params.get('agreement', false)}
|
||||
// required
|
||||
/>
|
||||
<Text size='lg'>
|
||||
{intl.formatMessage(messages.nostr)}
|
||||
</Text>
|
||||
</HStack>
|
||||
|
||||
{/* Bluesky */}
|
||||
<HStack alignItems='center' space={2}>
|
||||
<Checkbox
|
||||
name='bluesky'
|
||||
checked={testList.some((tag)=> tag.name.toLowerCase() === 'bluesky')}
|
||||
onChange={() => setTestList((prevValue) => {
|
||||
const exists = prevValue.some((x) => x.name.toLowerCase() === 'bluesky');
|
||||
if (exists) {
|
||||
return prevValue.filter((x) => x.name.toLowerCase() !== 'bluesky');
|
||||
} else {
|
||||
return [...prevValue, { name: 'Bluesky', status: null }];
|
||||
}
|
||||
})}
|
||||
/>
|
||||
<Text size='lg'>
|
||||
{intl.formatMessage(messages.bluesky)}
|
||||
</Text>
|
||||
</HStack>
|
||||
|
||||
{/* Fediverse */}
|
||||
<HStack alignItems='center' space={2}>
|
||||
<Checkbox
|
||||
name='fediverse'
|
||||
checked={testList.some((tag)=> tag.name.toLowerCase() === 'fediverse')}
|
||||
onChange={() => setTestList((prevValue) => {
|
||||
const exists = prevValue.some((x) => x.name.toLowerCase() === 'fediverse');
|
||||
if (exists) {
|
||||
return prevValue.filter((x) => x.name.toLowerCase() !== 'fediverse');
|
||||
} else {
|
||||
return [...prevValue, { name: 'Fediverse', status: null }];
|
||||
}
|
||||
})}
|
||||
/>
|
||||
<Text size='lg'>
|
||||
{intl.formatMessage(messages.fediverse)}
|
||||
</Text>
|
||||
</HStack>
|
||||
|
||||
</HStack>
|
||||
|
||||
<Divider />
|
||||
|
||||
{/* Create your filter */}
|
||||
<Stack space={3}>
|
||||
<Text size='lg' weight='bold'>
|
||||
{intl.formatMessage(messages.createYourFilter)}
|
||||
</Text>
|
||||
|
||||
<Stack>
|
||||
<Text size='lg'>
|
||||
{intl.formatMessage(messages.filterByWords)}
|
||||
</Text>
|
||||
|
||||
<HStack space={6}>
|
||||
|
||||
|
||||
<div className='relative w-full items-center'>
|
||||
<Input theme='search' value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
|
||||
<div
|
||||
role='button'
|
||||
tabIndex={0}
|
||||
className='absolute inset-y-0 right-0 flex cursor-pointer items-center px-3 rtl:left-0 rtl:right-auto'
|
||||
>
|
||||
<SvgIcon
|
||||
src={searchIcon}
|
||||
className={clsx('size-4 text-gray-600', { hidden: hasValue })}
|
||||
/>
|
||||
|
||||
<SvgIcon
|
||||
src={xIcon}
|
||||
className={clsx('size-4 text-gray-600', { hidden: !hasValue })}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Include */}
|
||||
<HStack alignItems='center' space={2}>
|
||||
<Checkbox
|
||||
name='include'
|
||||
checked={include}
|
||||
onChange={() => setInclude(!include)}
|
||||
/>
|
||||
<Text size='lg'>
|
||||
{intl.formatMessage(messages.include)}
|
||||
</Text>
|
||||
</HStack>
|
||||
|
||||
{/* Exclude */}
|
||||
<HStack alignItems='center' space={2}>
|
||||
<Checkbox
|
||||
name='exclude'
|
||||
checked={!include}
|
||||
onChange={() => setInclude(!include)}
|
||||
/>
|
||||
<Text size='lg'>
|
||||
{intl.formatMessage(messages.exclude)}
|
||||
</Text>
|
||||
</HStack>
|
||||
</HStack>
|
||||
</Stack>
|
||||
|
||||
<HStack className='w-full' space={2}>
|
||||
<Button className='w-1/2' theme='secondary'>
|
||||
{intl.formatMessage(messages.cancel)}
|
||||
</Button>
|
||||
|
||||
<Button className='w-1/2' theme='primary'>
|
||||
{intl.formatMessage(messages.applyFilter)}
|
||||
</Button>
|
||||
</HStack>
|
||||
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default ExplorerFilter;
|
|
@ -1,12 +1,15 @@
|
|||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
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/explorerCards.tsx';
|
||||
import ExplorerFilter from 'soapbox/features/search/components/explorerFilter.tsx';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.search', defaultMessage: 'Discover' },
|
||||
heading: { id: 'column.search', defaultMessage: 'Explorer' },
|
||||
});
|
||||
|
||||
const SearchPage = () => {
|
||||
|
@ -14,10 +17,20 @@ const SearchPage = () => {
|
|||
|
||||
return (
|
||||
<Column label={intl.formatMessage(messages.heading)} slim>
|
||||
|
||||
<Stack space={4}>
|
||||
<ExplorerCards />
|
||||
|
||||
<Divider text='Explorer' />
|
||||
|
||||
<ExplorerFilter />
|
||||
|
||||
<Divider />
|
||||
|
||||
<div className='px-4'>
|
||||
<Search autoSubmit />
|
||||
</div>
|
||||
|
||||
<SearchResults />
|
||||
</Stack>
|
||||
</Column>
|
||||
|
|
|
@ -430,13 +430,33 @@
|
|||
"column.reblogs": "Reposts",
|
||||
"column.registration": "Sign Up",
|
||||
"column.scheduled_statuses": "Scheduled Posts",
|
||||
"column.search": "Discover",
|
||||
"column.search": "Explorer",
|
||||
"column.settings_store": "Settings store",
|
||||
"column.soapbox_config": "Soapbox config",
|
||||
"column.test": "Test timeline",
|
||||
"column.zaps": "Zaps",
|
||||
"column_forbidden.body": "You do not have permission to access this page.",
|
||||
"column_forbidden.title": "Forbidden",
|
||||
"column.explorer": "Explorer",
|
||||
"column.explorer.welcome_card.title": "Welcome to Explorer",
|
||||
"column.explorer.welcome_card.text": "Explore the world of <span>decentralized social media</span>, dive into <span>Nostr</span> or cross the bridge to other networks, and connect with a global community. All in one place.",
|
||||
"column.explorer.nostr_card.title": "Nostr",
|
||||
"column.explorer.nostr_card.text": "Wondering about Nostr? Find Out More",
|
||||
"column.explorer.bridge_card.title": "Bridge",
|
||||
"column.explorer.bridge_card.text": "Curious about Bridges? Click Here",
|
||||
"column.explorer.filters.show_replies": "Show replies:",
|
||||
"column.explorer.filters": "Fiters:",
|
||||
"column.explorer.filters.language": "Language:",
|
||||
"column.explorer.filters.platforms": "Platforms:",
|
||||
"column.explorer.filters.create_filter": "Create your filter",
|
||||
"column.explorer.filters.filter_words": "Filter by this/these words",
|
||||
"column.explorer.filters.checkbox.include": "Include",
|
||||
"column.explorer.filters.checkbox.exclude": "Exclude",
|
||||
"column.explorer.filters.checkbox.nostr": "Nostr",
|
||||
"column.explorer.filters.checkbox.bluesky": "Bluesky",
|
||||
"column.explorer.filters.checkbox.fediverse": "Fediverse",
|
||||
"column.explorer.filters.cancel": "Cancel",
|
||||
"column.explorer.filters.apply_filter": "Apply Filter",
|
||||
"common.cancel": "Cancel",
|
||||
"compare_history_modal.header": "Edit history",
|
||||
"compose.character_counter.title": "Used {chars} out of {maxChars} {maxChars, plural, one {character} other {characters}}",
|
||||
|
|
Ładowanie…
Reference in New Issue