mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-04-12 05:39:18 +02:00
add category filter to torrents
This commit is contained in:
parent
c2edced715
commit
4877f08f51
@ -34,7 +34,7 @@ export default function PeopleListSelection({
|
||||
};
|
||||
|
||||
return (
|
||||
<Menu>
|
||||
<Menu isLazy>
|
||||
<MenuButton as={Button} {...props}>
|
||||
{listEvent ? getListName(listEvent) : selected === "global" ? "Global" : "Loading..."}
|
||||
</MenuButton>
|
||||
|
@ -4,7 +4,6 @@ import { ButtonGroup, ButtonGroupProps, IconButton } from "@chakra-ui/react";
|
||||
|
||||
import { ImageGridTimelineIcon, NoteFeedIcon, TimelineHealthIcon } from "../icons";
|
||||
import { TimelineViewType } from "./index";
|
||||
import { searchParamsToJson } from "../../helpers/url";
|
||||
|
||||
export default function TimelineViewTypeButtons(props: ButtonGroupProps) {
|
||||
const [params, setParams] = useSearchParams();
|
||||
@ -12,7 +11,14 @@ export default function TimelineViewTypeButtons(props: ButtonGroupProps) {
|
||||
|
||||
const onChange = useCallback(
|
||||
(type: TimelineViewType) => {
|
||||
setParams((p) => ({ ...searchParamsToJson(p), view: type }), { replace: true });
|
||||
setParams(
|
||||
(p) => {
|
||||
const newParams = new URLSearchParams(p);
|
||||
newParams.set("view", type);
|
||||
return newParams;
|
||||
},
|
||||
{ replace: true },
|
||||
);
|
||||
},
|
||||
[setParams],
|
||||
);
|
||||
|
@ -54,13 +54,3 @@ export function replaceDomain(url: string | URL, replacementUrl: string | URL) {
|
||||
if (replacementUrl.password) newUrl.password = replacementUrl.password;
|
||||
return newUrl;
|
||||
}
|
||||
|
||||
export function searchParamsToJson(params: URLSearchParams) {
|
||||
const json: URLSearchParamsInit = {};
|
||||
|
||||
for (const [key, value] of params.entries()) {
|
||||
json[key] = value;
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
@ -41,11 +41,6 @@ export default function ({ community, onClose, ...props }: Omit<ModalProps, "chi
|
||||
const communityCoordinate = getEventCoordinate(community);
|
||||
const readRelays = useReadRelayUrls(getCommunityRelays(community));
|
||||
const timeline = useTimelineLoader(`${communityCoordinate}-members`, readRelays, [
|
||||
{
|
||||
"#a": [communityCoordinate],
|
||||
"#d": [SUBSCRIBED_COMMUNITIES_LIST_IDENTIFIER],
|
||||
kinds: [NOTE_LIST_KIND],
|
||||
},
|
||||
{ "#a": [communityCoordinate], kinds: [COMMUNITIES_LIST_KIND] },
|
||||
]);
|
||||
|
||||
|
@ -5,7 +5,6 @@ import { useSearchParams, useNavigate } from "react-router-dom";
|
||||
import { SEARCH_RELAYS } from "../../const";
|
||||
import { safeDecode } from "../../helpers/nip19";
|
||||
import { getMatchHashtag } from "../../helpers/regexp";
|
||||
import { searchParamsToJson } from "../../helpers/url";
|
||||
import { CommunityIcon, CopyToClipboardIcon, NotesIcon, QrCodeIcon } from "../../components/icons";
|
||||
import QrScannerModal from "../../components/qr-scanner-modal";
|
||||
import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
|
||||
@ -26,7 +25,14 @@ export function SearchPage() {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const mergeSearchParams = useCallback(
|
||||
(params: Record<string, any>) => {
|
||||
setSearchParams((p) => ({ ...searchParamsToJson(p), ...params }), { replace: true });
|
||||
setSearchParams(
|
||||
(p) => {
|
||||
const newParams = new URLSearchParams(p);
|
||||
for (const [key, value] of Object.entries(params)) newParams.set(key, value);
|
||||
return newParams;
|
||||
},
|
||||
{ replace: true },
|
||||
);
|
||||
},
|
||||
[setSearchParams],
|
||||
);
|
||||
|
25
src/views/torrents/components/category-select.tsx
Normal file
25
src/views/torrents/components/category-select.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { ReactNode } from "react";
|
||||
import { Select, SelectProps } from "@chakra-ui/react";
|
||||
import { Category, torrentCatagories } from "../../../helpers/nostr/torrents";
|
||||
|
||||
export default function CategorySelect({ ...props }: Omit<SelectProps, "children">) {
|
||||
function renderCategory(a: Category, tags: Array<string>): ReactNode {
|
||||
return (
|
||||
<>
|
||||
<option value={tags.join(",")}>{a.name}</option>
|
||||
{a.sub_category?.map((b) => renderCategory(b, [...tags, b.tag]))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Select {...props}>
|
||||
<option value="">All</option>
|
||||
{torrentCatagories.map((category) => (
|
||||
<optgroup key={category.tag} label={category.name}>
|
||||
{renderCategory(category, [category.tag])}
|
||||
</optgroup>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import { useMemo, useRef } from "react";
|
||||
import { memo, useMemo, useRef } from "react";
|
||||
import { ButtonGroup, IconButton, Link, Td, Tr } from "@chakra-ui/react";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
|
||||
@ -14,7 +14,7 @@ import { formatBytes } from "../../../helpers/number";
|
||||
import NoteZapButton from "../../../components/note/note-zap-button";
|
||||
import TorrentMenu from "./torrent-menu";
|
||||
|
||||
export default function TorrentTableRow({ torrent }: { torrent: NostrEvent }) {
|
||||
function TorrentTableRow({ torrent }: { torrent: NostrEvent }) {
|
||||
const ref = useRef<HTMLTableRowElement | null>(null);
|
||||
useRegisterIntersectionEntity(ref, getEventUID(torrent));
|
||||
|
||||
@ -29,7 +29,7 @@ export default function TorrentTableRow({ torrent }: { torrent: NostrEvent }) {
|
||||
.join(" > ")}
|
||||
</Td>
|
||||
<Td>
|
||||
<Link as={RouterLink} to={`/torrents/${getNeventCodeWithRelays(torrent.id)}`}>
|
||||
<Link as={RouterLink} to={`/torrents/${getNeventCodeWithRelays(torrent.id)}`} isTruncated maxW="lg">
|
||||
{getTorrentTitle(torrent)}
|
||||
</Link>
|
||||
</Td>
|
||||
@ -50,3 +50,4 @@ export default function TorrentTableRow({ torrent }: { torrent: NostrEvent }) {
|
||||
</Tr>
|
||||
);
|
||||
}
|
||||
export default memo(TorrentTableRow);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useCallback, useState } from "react";
|
||||
import { ChangeEventHandler, useCallback, useMemo, useState } from "react";
|
||||
import { Alert, Button, Flex, Spacer, Table, TableContainer, Tbody, Th, Thead, Tr, useToast } from "@chakra-ui/react";
|
||||
import { Link as RouterLink, useNavigate } from "react-router-dom";
|
||||
import { Link as RouterLink, useNavigate, useSearchParams } from "react-router-dom";
|
||||
import { generatePrivateKey, getPublicKey } from "nostr-tools";
|
||||
|
||||
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
|
||||
@ -20,6 +20,7 @@ import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import { useUserMetadata } from "../../hooks/use-user-metadata";
|
||||
import accountService from "../../services/account";
|
||||
import signingService from "../../services/signing";
|
||||
import CategorySelect from "./components/category-select";
|
||||
|
||||
function Warning() {
|
||||
const navigate = useNavigate();
|
||||
@ -58,21 +59,34 @@ function Warning() {
|
||||
function TorrentsPage() {
|
||||
const { filter, listId } = usePeopleListContext();
|
||||
const { relays } = useRelaySelectionContext();
|
||||
const [params, setParams] = useSearchParams();
|
||||
const tags = params.get("tags")?.split(",") ?? [];
|
||||
|
||||
const handleTagsChange = useCallback<ChangeEventHandler<HTMLSelectElement>>(
|
||||
(e) => {
|
||||
const newParams = new URLSearchParams(params);
|
||||
if (e.target.value) newParams.set("tags", e.target.value);
|
||||
else newParams.delete("tags");
|
||||
setParams(newParams, { replace: true });
|
||||
},
|
||||
[params],
|
||||
);
|
||||
|
||||
const muteFilter = useClientSideMuteFilter();
|
||||
|
||||
const eventFilter = useCallback(
|
||||
(e: NostrEvent) => {
|
||||
return !muteFilter(e) && validateTorrent(e);
|
||||
if (muteFilter(e)) return false;
|
||||
if (!validateTorrent(e)) return false;
|
||||
if (tags.length > 0 && tags.some((t) => !e.tags.some((e) => e[1] === t))) return false;
|
||||
return true;
|
||||
},
|
||||
[muteFilter],
|
||||
[muteFilter, tags.join(",")],
|
||||
);
|
||||
const timeline = useTimelineLoader(
|
||||
`${listId}-torrents`,
|
||||
relays,
|
||||
{ ...filter, kinds: [TORRENT_KIND] },
|
||||
{ eventFilter, enabled: !!filter },
|
||||
const query = useMemo(
|
||||
() => (tags.length > 0 ? { ...filter, kinds: [TORRENT_KIND], "#t": tags } : { ...filter, kinds: [TORRENT_KIND] }),
|
||||
[tags.join(",")],
|
||||
);
|
||||
const timeline = useTimelineLoader(`${listId}-torrents`, relays, query, { eventFilter, enabled: !!filter });
|
||||
|
||||
const torrents = useSubject(timeline.timeline);
|
||||
const callback = useTimelineCurserIntersectionCallback(timeline);
|
||||
@ -85,6 +99,7 @@ function TorrentsPage() {
|
||||
<Flex gap="2">
|
||||
<RelaySelectionButton />
|
||||
<PeopleListSelection />
|
||||
<CategorySelect maxW="xs" value={tags.join(",")} onChange={handleTagsChange} />
|
||||
<Spacer />
|
||||
<Button as={RouterLink} to="/torrents/new">
|
||||
New Torrent
|
||||
|
Loading…
x
Reference in New Issue
Block a user