fixes: mobile

This commit is contained in:
2024-03-05 13:04:24 +00:00
parent 4990e6dbca
commit bb207d7af1
7 changed files with 61 additions and 36 deletions

View File

@ -7,7 +7,7 @@ import { FormattedMessage } from "react-intl";
import VideoGrid from "./video-grid"; import VideoGrid from "./video-grid";
import { VideoTile } from "./video-tile"; import { VideoTile } from "./video-tile";
export default function VideoGridSorted({ evs }: { evs: Array<TaggedNostrEvent> }) { export default function VideoGridSorted({ evs, showAll }: { evs: Array<TaggedNostrEvent>, showAll?: boolean }) {
const login = useLogin(); const login = useLogin();
const mutedHosts = new Set(getTagValues(login?.muted.tags ?? [], "p")); const mutedHosts = new Set(getTagValues(login?.muted.tags ?? [], "p"));
const tags = login?.follows.tags ?? []; const tags = login?.follows.tags ?? [];
@ -17,7 +17,7 @@ export default function VideoGridSorted({ evs }: { evs: Array<TaggedNostrEvent>
}, },
[tags] [tags]
); );
const { live, planned, ended } = useLiveStreams(evs); const { live, planned, ended } = useLiveStreams(evs, showAll ? 0 : undefined);
const hashtags = getTagValues(tags, "t"); const hashtags = getTagValues(tags, "t");
const following = live.filter(followsHost); const following = live.filter(followsHost);
const liveNow = live.filter(e => !following.includes(e)); const liveNow = live.filter(e => !following.includes(e));

View File

@ -4,7 +4,7 @@ import { unixNow } from "@snort/shared";
import { NostrEvent, TaggedNostrEvent } from "@snort/system"; import { NostrEvent, TaggedNostrEvent } from "@snort/system";
import { useMemo } from "react"; import { useMemo } from "react";
export function useLiveStreams(feed: Array<TaggedNostrEvent>) { export function useLiveStreams(feed: Array<TaggedNostrEvent>, oldest?: number) {
function sortCreatedAt(a: NostrEvent, b: NostrEvent) { function sortCreatedAt(a: NostrEvent, b: NostrEvent) {
return b.created_at > a.created_at ? 1 : -1; return b.created_at > a.created_at ? 1 : -1;
} }
@ -18,7 +18,7 @@ export function useLiveStreams(feed: Array<TaggedNostrEvent>) {
const feedSorted = useMemo(() => { const feedSorted = useMemo(() => {
if (feed) { if (feed) {
return feed return feed
.filter(a => a.created_at > unixNow() - 7 * DAY) .filter(a => a.created_at > (oldest ?? (unixNow() - 7 * DAY)))
.filter(a => !import.meta.env.VITE_SINGLE_PUBLISHER || import.meta.env.VITE_SINGLE_PUBLISHER === getHost(a)); .filter(a => !import.meta.env.VITE_SINGLE_PUBLISHER || import.meta.env.VITE_SINGLE_PUBLISHER === getHost(a));
} }
return []; return [];

View File

@ -132,7 +132,7 @@ const router = createBrowserRouter([
), ),
}, },
{ {
path: "/search/:term", path: "/search/:term?",
element: <SearchPage />, element: <SearchPage />,
}, },
{ {

View File

@ -56,11 +56,7 @@ export default function Category() {
rb.withFilter().kinds([EventKind.LiveEvent]).tag("t", cat.tags); rb.withFilter().kinds([EventKind.LiveEvent]).tag("t", cat.tags);
return rb; return rb;
}, [cat]); }, [cat]);
const results = useRequestBuilder(sub).filter(a => { const results = useRequestBuilder(sub);
const { status } = extractStreamInfo(a);
return status === StreamState.Live;
});
return ( return (
<div> <div>
<div className="flex gap-4"> <div className="flex gap-4">
@ -69,7 +65,7 @@ export default function Category() {
))} ))}
</div> </div>
<h1 className="uppercase my-4">{id}</h1> <h1 className="uppercase my-4">{id}</h1>
<VideoGridSorted evs={results} /> <VideoGridSorted evs={results} showAll={true} />
</div> </div>
); );
} }

View File

@ -146,10 +146,10 @@ export function LayoutPage() {
<Logo width={40} height={40} /> <Logo width={40} height={40} />
</div> </div>
<SearchBar /> <SearchBar />
<Link to="/category"> <Link to="/category" className="max-xl:hidden">
<FormattedMessage defaultMessage="Categories" id="VKb1MS" /> <FormattedMessage defaultMessage="Categories" id="VKb1MS" />
</Link> </Link>
<Link to="/faq"> <Link to="/faq" className="max-xl:hidden">
<FormattedMessage defaultMessage="FAQ" id="W8nHSd" /> <FormattedMessage defaultMessage="FAQ" id="W8nHSd" />
</Link> </Link>
</div> </div>
@ -178,9 +178,10 @@ function SearchBar() {
const [search, setSearch] = useState(term ?? ""); const [search, setSearch] = useState(term ?? "");
return ( return (
<div className="bg-layer-2 rounded-xl pr-4 py-1 flex items-center"> <div className="max-xl:bg-white xl:bg-layer-2 rounded-xl pr-4 py-1 flex items-center">
<input <input
type="text" type="text"
className="max-xl:hidden"
placeholder={formatMessage({ placeholder={formatMessage({
defaultMessage: "Search", defaultMessage: "Search",
id: "xmcVZ0", id: "xmcVZ0",
@ -193,7 +194,13 @@ function SearchBar() {
} }
}} }}
/> />
<Icon name="search" className="text-layer-4" size={16} /> <Icon
name="search"
className="max-xl:text-black mx:text-layer-4 max-xl:ml-4 max-xl:my-1"
size={16}
onClick={() => {
navigate("/search")
}}/>
</div> </div>
); );
} }

View File

@ -8,7 +8,7 @@ export function RootPage() {
return ( return (
<div className="flex flex-col gap-6"> <div className="flex flex-col gap-6">
<div className="flex gap-4"> <div className="flex gap-4 overflow-x-scroll scrollbar-hidden">
{AllCategories.filter(a => a.priority === 0).map(a => ( {AllCategories.filter(a => a.priority === 0).map(a => (
<CategoryLink key={a.id} {...a} /> <CategoryLink key={a.id} {...a} />
))} ))}

View File

@ -1,10 +1,10 @@
import VideoGrid from "@/element/video-grid"; import { Icon } from "@/element/icon";
import { VideoTile } from "@/element/video-tile"; import VideoGridSorted from "@/element/video-grid-sorted";
import { EventKind, RequestBuilder } from "@snort/system"; import { EventKind, RequestBuilder } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react"; import { useRequestBuilder } from "@snort/system-react";
import { useMemo } from "react"; import { useMemo, useState } from "react";
import { FormattedMessage } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
export const SearchRelays = [ export const SearchRelays = [
"wss://relay.nostr.band", "wss://relay.nostr.band",
@ -15,12 +15,13 @@ export const SearchRelays = [
export default function SearchPage() { export default function SearchPage() {
const { term } = useParams(); const { term } = useParams();
const { formatMessage } = useIntl();
const navigate = useNavigate();
const [search, setSearch] = useState(term ?? "");
const sub = useMemo(() => { const sub = useMemo(() => {
if (!term) return; if (!term) return;
const rb = new RequestBuilder(`search:${term}`); const rb = new RequestBuilder(`search:${term}`);
rb.withOptions({
skipDiff: true,
});
rb.withFilter().relay(SearchRelays).kinds([EventKind.LiveEvent]).search(term).limit(50); rb.withFilter().relay(SearchRelays).kinds([EventKind.LiveEvent]).search(term).limit(50);
return rb; return rb;
}, [term]); }, [term]);
@ -28,6 +29,30 @@ export default function SearchPage() {
const results = useRequestBuilder(sub); const results = useRequestBuilder(sub);
return ( return (
<div> <div>
<div className="bg-layer-2 rounded-xl pr-4 py-1 flex items-center xl:hidden">
<input
type="text"
placeholder={formatMessage({
defaultMessage: "Search",
id: "xmcVZ0",
})}
value={search}
onChange={e => setSearch(e.target.value)}
onKeyDown={e => {
if (e.key === "Enter") {
navigate(`/search/${encodeURIComponent(search)}`);
}
}}
/>
<Icon
name="search"
className="text-layer-4 ml-4 my-1"
size={16}
onClick={() => {
navigate("/search")
}} />
</div>
{term && <>
<h2 className="mb-4"> <h2 className="mb-4">
<FormattedMessage <FormattedMessage
defaultMessage="Search results: {term}" defaultMessage="Search results: {term}"
@ -37,11 +62,8 @@ export default function SearchPage() {
}} }}
/> />
</h2> </h2>
<VideoGrid> <VideoGridSorted evs={results} showAll={true} />
{results.map(a => ( </>}
<VideoTile ev={a} key={a.id} />
))}
</VideoGrid>
</div> </div>
); );
} }