diff --git a/src/features/explore/components/exploreFilter.tsx b/src/features/explore/components/exploreFilter.tsx index f91704532..1f5865198 100644 --- a/src/features/explore/components/exploreFilter.tsx +++ b/src/features/explore/components/exploreFilter.tsx @@ -1,7 +1,8 @@ import arrowIcon from '@tabler/icons/outline/chevron-down.svg'; +import xIcon from '@tabler/icons/outline/x.svg'; import { debounce } from 'es-toolkit'; import { useEffect, useMemo, useState } from 'react'; -// import { useIntl } from 'react-intl'; +import { defineMessages, useIntl } from 'react-intl'; import { changeSearch, submitSearch } from 'soapbox/actions/search.ts'; import Divider from 'soapbox/components/ui/divider.tsx'; @@ -18,16 +19,22 @@ import { import { useSearchTokens } from 'soapbox/features/explore/useSearchTokens.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; -interface IGenerateFilter { - name: string; - status: boolean | null; - value: string; -} +const messages = defineMessages({ + allMedia: { id: 'column.explore.media_filters.all_media', defaultMessage: 'All media' }, + imageOnly: { id: 'column.explore.media_filters.image', defaultMessage: 'Image only' }, + videoOnly: { id: 'column.explore.media_filters.video', defaultMessage: 'Video only' }, + noMedia: { id: 'column.explore.media_filters.no_media', defaultMessage: 'No media' }, + showReplies: { id: 'home.column_settings.show_replies', defaultMessage: 'Show replies' }, + nostr: { id: 'column.explore.filters.nostr', defaultMessage: 'Nostr' }, + atproto: { id: 'column.explore.filters.bluesky', defaultMessage: 'Bluesky' }, + activitypub: { id: 'column.explore.filters.fediverse', defaultMessage: 'Fediverse' }, + removeFilter: { id: 'column.explore.filters.remove_filter', defaultMessage: 'Remove filter' }, +}); const ExploreFilter = () => { - // const intl = useIntl(); + const intl = useIntl(); const dispatch = useAppDispatch(); - const { tokens } = useSearchTokens(); + const { tokens, addToken, removeToken, removeTokens } = useSearchTokens(); const [isOpen, setIsOpen] = useState(false); const handleClick = () => { @@ -66,14 +73,106 @@ const ExploreFilter = () => { } , []); + const filters = new Set(['protocol:nostr', 'protocol:atproto', 'protocol:activitypub']); + + for (const token of tokens) { + if (token.startsWith('-protocol:')) { + filters.delete(token.replace(/^-/, '')); + } + filters.add(token); + } + + function renderMediaFilter(): JSX.Element | null { + const clearMediaFilters = () => removeTokens(['media:true', '-video:true', 'video:true', '-media:true']); + + if (tokens.has('media:true') && tokens.has('-video:true')) { + return ( + + ); + } + + if (tokens.has('video:true')) { + return ( + + ); + } + + if (tokens.has('-media:true')) { + return ( + + ); + } + + return null; + } + return ( - - {/* Filters */} - {/* {tokens.size > 0 && [...filters.slice(0, 8).filter((value) => value.status).map((value) => generateFilter(dispatch, intl, value)), ...filters.slice(8).map((value) => generateFilter(dispatch, intl, value))]} */} + {!tokens.has('-protocol:nostr') ? ( + addToken('-protocol:nostr')} + /> + ) : null} + {!tokens.has('-protocol:atproto') ? ( + addToken('-protocol:atproto')} + /> + ) : null} + + {!tokens.has('-protocol:activitypub') ? ( + addToken('-protocol:activitypub')} + /> + ) : null} + + {renderMediaFilter()} + + {[...filters].filter((token) => token.startsWith('language:')).map((token) => ( + removeToken(token)} + /> + ))} + + {[...filters].filter((token) => !token.includes(':')).map((token) => ( + removeToken(token)} + /> + ))} { - - {/* Show Reply toggle */} - - {/* Media toggle */} - - {/* Language */} - - {/* Platforms */} - {/* Create your filter */} - - ); }; -// const generateFilter = (dispatch: AppDispatch, intl: IntlShape, { name, value, status }: IGenerateFilter) => { -// let borderColor = ''; -// let textColor = ''; +interface IFilterToken { + label: string; + textColor: string; + borderColor: string; + onRemove: () => void; +} -// if (Object.keys(languages).some((lang) => value.includes('language:'))) { -// borderColor = 'border-gray-500'; -// textColor = 'text-gray-500'; -// } else { -// switch (value) { -// case 'reply:false': -// case 'media:true -video:true': -// case 'video:true': -// case '-media:true': -// borderColor = 'border-gray-500'; -// textColor = 'text-gray-500'; -// break; -// case 'protocol:nostr': -// borderColor = 'border-purple-500'; -// textColor = 'text-purple-500'; -// break; -// case 'protocol:atproto': -// borderColor = 'border-blue-500'; -// textColor = 'text-blue-500'; -// break; -// case 'protocol:activitypub': -// 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'; -// } -// } +const FilterToken: React.FC = ({ label, textColor, borderColor, onRemove }) => { + const intl = useIntl(); -// const handleChangeFilters = (e: React.MouseEvent) => { -// e.stopPropagation(); - -// if (['protocol:nostr', 'protocol:atproto', 'protocol:activitypub'].includes(value)) { -// dispatch(selectProtocol(value)); -// } else if (['reply:false', 'media:true -video:true', 'video:true', '-media:true'].includes(value)) { -// dispatch(changeStatus({ value: value, status: false })); -// } else if (value.includes('language:')) { -// dispatch(changeLanguage('default')); -// } else { -// dispatch(removeFilter(value)); -// } -// }; - -// return ( -//
-// {name.toLowerCase() !== 'default' ? name : } -// -//
-// ); -// }; + const handleChangeFilters = (e: React.MouseEvent) => { + e.stopPropagation(); + onRemove(); + }; + return ( +
+ {label} + +
+ ); +}; export default ExploreFilter; -export type { IGenerateFilter }; \ No newline at end of file diff --git a/src/features/explore/components/filters.tsx b/src/features/explore/components/filters.tsx index bf2d3ca22..34b3f5cf7 100644 --- a/src/features/explore/components/filters.tsx +++ b/src/features/explore/components/filters.tsx @@ -20,24 +20,23 @@ import toast from 'soapbox/toast.tsx'; const messages = defineMessages({ showReplies: { id: 'home.column_settings.show_replies', defaultMessage: 'Show replies' }, - media: { id: 'column.explore.filters.media', defaultMessage: 'Media:' }, - language: { id: 'column.explore.filters.language', defaultMessage: 'Language:' }, - platforms: { id: 'column.explore.filters.platforms', defaultMessage: 'Platforms:' }, + media: { id: 'column.explore.filters.media', defaultMessage: 'Media' }, + language: { id: 'column.explore.filters.language', defaultMessage: 'Language' }, + platforms: { id: 'column.explore.filters.platforms', defaultMessage: 'Platforms' }, createYourFilter: { id: 'column.explore.filters.create_your_filter', defaultMessage: 'Create your filter' }, resetFilter: { id: 'column.explore.filters.reset', defaultMessage: 'Reset Filters' }, - filterByWords: { id: 'column.explore.filters.filter_by_words', defaultMessage: 'Filter by this/these words' }, + filterByWords: { id: 'column.explore.filters.filter_by_words', defaultMessage: 'Filter word' }, negative: { id: 'column.explore.filters.invert', defaultMessage: 'Invert' }, nostr: { id: 'column.explore.filters.nostr', defaultMessage: 'Nostr' }, atproto: { id: 'column.explore.filters.bluesky', defaultMessage: 'Bluesky' }, activitypub: { id: 'column.explore.filters.fediverse', defaultMessage: 'Fediverse' }, cancel: { id: 'column.explore.filters.cancel', defaultMessage: 'Cancel' }, addFilter: { id: 'column.explore.filters.add_filter', defaultMessage: 'Add Filter' }, - all: { id: 'column.explore.media_filters.all', defaultMessage: 'All' }, + allMedia: { id: 'column.explore.media_filters.all_media', defaultMessage: 'All media' }, imageOnly: { id: 'column.explore.media_filters.image', defaultMessage: 'Image only' }, videoOnly: { id: 'column.explore.media_filters.video', defaultMessage: 'Video only' }, - none: { id: 'column.explore.media_filters.none', defaultMessage: 'No media' }, + noMedia: { id: 'column.explore.media_filters.no_media', defaultMessage: 'No media' }, clearSearch: { id: 'column.explore.filters.clear_input', defaultMessage: 'Clear filter input' }, - removeFilter: { id: 'column.explore.filters.remove_filter', defaultMessage: 'Remove filter: {name}' }, empty: { id: 'column.explore.filters.empty', defaultMessage: 'Hey there... You forget to write the filter!' }, }); @@ -235,7 +234,6 @@ const WordFilter = () => { - {/* Include */} { const mediaFilters = { all: { tokens: [], - label: intl.formatMessage(messages.all), + label: intl.formatMessage(messages.allMedia), }, image: { tokens: ['media:true', '-video:true'], @@ -285,7 +283,7 @@ const MediaFilter = () => { }, none: { tokens: ['-media:true'], - label: intl.formatMessage(messages.none), + label: intl.formatMessage(messages.noMedia), }, }; diff --git a/src/locales/en.json b/src/locales/en.json index 461e3bd1c..8a47f854e 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -383,13 +383,12 @@ "column.explore.filters.filter_by_words": "Filter by this/these words", "column.explore.filters.include": "Include", "column.explore.filters.language": "Language:", - "column.explore.filters.language.default": "Global", "column.explore.filters.media": "Media:", "column.explore.filters.no_replies": "No Replies:", "column.explore.filters.nostr": "Nostr", "column.explore.filters.platforms": "Platforms:", "column.explore.filters.platforms.error": "Protocol not found for: {name}", - "column.explore.filters.remove_filter": "Remove filter: {name}", + "column.explore.filters.remove_filter": "Remove filter", "column.explore.filters.reset": "Reset Filters", "column.explore.media_filters.all": "All", "column.explore.media_filters.image": "Image only",