forked from Kieran/snort
tab selector vs content naming, refactoring
This commit is contained in:
parent
ffa4a192f6
commit
ef673c2a05
@ -583,7 +583,7 @@ https://git.v0l.io/Kieran/snort/compare/v0.1.9...v0.1.10
|
|||||||
- Fix event mention bug by @SamSamskies in https://github.com/v0l/snort/pull/421
|
- Fix event mention bug by @SamSamskies in https://github.com/v0l/snort/pull/421
|
||||||
- fix NaN when parsing empty string by @SamSamskies in https://github.com/v0l/snort/pull/422
|
- fix NaN when parsing empty string by @SamSamskies in https://github.com/v0l/snort/pull/422
|
||||||
- NIP06 support by @w3irdrobot in https://github.com/v0l/snort/pull/425
|
- NIP06 support by @w3irdrobot in https://github.com/v0l/snort/pull/425
|
||||||
- Added key attr to Tabs to remove React warning by @w3irdrobot in https://github.com/v0l/snort/pull/424
|
- Added key attr to TabSelectors to remove React warning by @w3irdrobot in https://github.com/v0l/snort/pull/424
|
||||||
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/426
|
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/426
|
||||||
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/436
|
- New Crowdin updates by @v0l in https://github.com/v0l/snort/pull/436
|
||||||
- Update Wavlake embed URL, add support for album & artist links by @blastshielddown in https://github.com/v0l/snort/pull/439
|
- Update Wavlake embed URL, add support for album & artist links by @blastshielddown in https://github.com/v0l/snort/pull/439
|
||||||
|
@ -8,7 +8,7 @@ import { FormattedMessage, useIntl } from "react-intl";
|
|||||||
import CloseButton from "@/Components/Button/CloseButton";
|
import CloseButton from "@/Components/Button/CloseButton";
|
||||||
import Icon from "@/Components/Icons/Icon";
|
import Icon from "@/Components/Icons/Icon";
|
||||||
import Modal from "@/Components/Modal/Modal";
|
import Modal from "@/Components/Modal/Modal";
|
||||||
import Tabs from "@/Components/Tabs/Tabs";
|
import TabSelectors from "@/Components/TabSelectors/TabSelectors";
|
||||||
import ProfileImage from "@/Components/User/ProfileImage";
|
import ProfileImage from "@/Components/User/ProfileImage";
|
||||||
import { formatShort } from "@/Utils/Number";
|
import { formatShort } from "@/Utils/Number";
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ const ReactionsModal = ({ onClose, event, initialTab = 0 }: ReactionsModalProps)
|
|||||||
<FormattedMessage {...messages.ReactionsCount} values={{ n: total }} />
|
<FormattedMessage {...messages.ReactionsCount} values={{ n: total }} />
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<Tabs tabs={tabs} tab={tab} setTab={setTab} />
|
<TabSelectors tabs={tabs} tab={tab} setTab={setTab} />
|
||||||
<div className="reactions-body" key={tab.value}>
|
<div className="reactions-body" key={tab.value}>
|
||||||
{tab.value === 0 && likes.map(ev => renderReactionItem(ev, "heart"))}
|
{tab.value === 0 && likes.map(ev => renderReactionItem(ev, "heart"))}
|
||||||
{tab.value === 1 &&
|
{tab.value === 1 &&
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import "./Tabs.css";
|
import "./TabSelectors.css";
|
||||||
|
|
||||||
import { ReactNode } from "react";
|
import { ReactNode } from "react";
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ interface TabElementProps extends Omit<TabsProps, "tabs"> {
|
|||||||
t: Tab;
|
t: Tab;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TabElement = ({ t, tab, setTab }: TabElementProps) => {
|
export const TabSelector = ({ t, tab, setTab }: TabElementProps) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`tab${tab.value === t.value ? " active" : ""}${t.disabled ? " disabled" : ""}`}
|
className={`tab${tab.value === t.value ? " active" : ""}${t.disabled ? " disabled" : ""}`}
|
||||||
@ -30,15 +30,15 @@ export const TabElement = ({ t, tab, setTab }: TabElementProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Tabs = ({ tabs, tab, setTab }: TabsProps) => {
|
const TabSelectors = ({ tabs, tab, setTab }: TabsProps) => {
|
||||||
const horizontalScroll = useHorizontalScroll();
|
const horizontalScroll = useHorizontalScroll();
|
||||||
return (
|
return (
|
||||||
<div className="tabs" ref={horizontalScroll}>
|
<div className="tabs" ref={horizontalScroll}>
|
||||||
{tabs.map((t, index) => (
|
{tabs.map((t, index) => (
|
||||||
<TabElement key={index} tab={tab} setTab={setTab} t={t} />
|
<TabSelector key={index} tab={tab} setTab={setTab} t={t} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Tabs;
|
export default TabSelectors;
|
@ -2,7 +2,7 @@ import { useState } from "react";
|
|||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
|
|
||||||
import SuggestedProfiles from "@/Components/SuggestedProfiles";
|
import SuggestedProfiles from "@/Components/SuggestedProfiles";
|
||||||
import { Tab, TabElement } from "@/Components/Tabs/Tabs";
|
import { Tab, TabSelector } from "@/Components/TabSelectors/TabSelectors";
|
||||||
import TrendingNotes from "@/Components/Trending/TrendingPosts";
|
import TrendingNotes from "@/Components/Trending/TrendingPosts";
|
||||||
import TrendingUsers from "@/Components/Trending/TrendingUsers";
|
import TrendingUsers from "@/Components/Trending/TrendingUsers";
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ export default function Discover() {
|
|||||||
<>
|
<>
|
||||||
<div className="tabs p">
|
<div className="tabs p">
|
||||||
{[Tabs.Follows, Tabs.Posts, Tabs.Profiles].map(a => (
|
{[Tabs.Follows, Tabs.Posts, Tabs.Profiles].map(a => (
|
||||||
<TabElement key={a.value} tab={tab} setTab={setTab} t={a} />
|
<TabSelector key={a.value} tab={tab} setTab={setTab} t={a} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{renderTab()}
|
{renderTab()}
|
||||||
|
@ -7,7 +7,7 @@ import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recha
|
|||||||
|
|
||||||
import { AsyncIcon } from "@/Components/Button/AsyncIcon";
|
import { AsyncIcon } from "@/Components/Button/AsyncIcon";
|
||||||
import Icon from "@/Components/Icons/Icon";
|
import Icon from "@/Components/Icons/Icon";
|
||||||
import Tabs, { Tab } from "@/Components/Tabs/Tabs";
|
import TabSelectors, { Tab } from "@/Components/TabSelectors/TabSelectors";
|
||||||
import { orderAscending } from "@/Utils";
|
import { orderAscending } from "@/Utils";
|
||||||
import { Day } from "@/Utils/Const";
|
import { Day } from "@/Utils/Const";
|
||||||
import { formatShort } from "@/Utils/Number";
|
import { formatShort } from "@/Utils/Number";
|
||||||
@ -123,7 +123,11 @@ export default function NotificationSummary({ evs }: { evs: Array<TaggedNostrEve
|
|||||||
{filterIcon(NotificationSummaryFilter.Mentions, "at-sign", "text-mention")}
|
{filterIcon(NotificationSummaryFilter.Mentions, "at-sign", "text-mention")}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Tabs tabs={periodTabs} tab={unwrap(periodTabs.find(a => a.value === period))} setTab={t => setPeriod(t.value)} />
|
<TabSelectors
|
||||||
|
tabs={periodTabs}
|
||||||
|
tab={unwrap(periodTabs.find(a => a.value === period))}
|
||||||
|
setTab={t => setPeriod(t.value)}
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
<ResponsiveContainer height={200}>
|
<ResponsiveContainer height={200}>
|
||||||
<BarChart data={Object.values(stats)} margin={{ left: 0, right: 0 }} style={{ userSelect: "none" }}>
|
<BarChart data={Object.values(stats)} margin={{ left: 0, right: 0 }} style={{ userSelect: "none" }}>
|
||||||
|
@ -1,29 +1,34 @@
|
|||||||
import "./ProfilePage.css";
|
import "./ProfilePage.css";
|
||||||
|
|
||||||
import { fetchNip05Pubkey, LNURL } from "@snort/shared";
|
import { fetchNip05Pubkey, LNURL } from "@snort/shared";
|
||||||
import { CachedMetadata, EventKind, NostrPrefix, tryParseNostrLink } from "@snort/system";
|
import { CachedMetadata, NostrPrefix, tryParseNostrLink } from "@snort/system";
|
||||||
import { useUserProfile } from "@snort/system-react";
|
import { useUserProfile } from "@snort/system-react";
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
||||||
|
|
||||||
import Note from "@/Components/Event/EventComponent";
|
|
||||||
import Timeline from "@/Components/Feed/Timeline";
|
|
||||||
import { ProxyImg } from "@/Components/ProxyImg";
|
import { ProxyImg } from "@/Components/ProxyImg";
|
||||||
import { SpotlightMediaModal } from "@/Components/Spotlight/SpotlightMedia";
|
import { SpotlightMediaModal } from "@/Components/Spotlight/SpotlightMedia";
|
||||||
import { Tab, TabElement } from "@/Components/Tabs/Tabs";
|
import { Tab, TabSelector } from "@/Components/TabSelectors/TabSelectors";
|
||||||
import BlockList from "@/Components/User/BlockList";
|
import BlockList from "@/Components/User/BlockList";
|
||||||
import FollowsList from "@/Components/User/FollowListBase";
|
import FollowsList from "@/Components/User/FollowListBase";
|
||||||
import MutedList from "@/Components/User/MutedList";
|
import MutedList from "@/Components/User/MutedList";
|
||||||
import useFollowsFeed from "@/Feed/FollowsFeed";
|
import useFollowsFeed from "@/Feed/FollowsFeed";
|
||||||
import useHorizontalScroll from "@/Hooks/useHorizontalScroll";
|
import useHorizontalScroll from "@/Hooks/useHorizontalScroll";
|
||||||
import { useMuteList, usePinList } from "@/Hooks/useLists";
|
import { useMuteList } from "@/Hooks/useLists";
|
||||||
import useLogin from "@/Hooks/useLogin";
|
import useLogin from "@/Hooks/useLogin";
|
||||||
import useModeration from "@/Hooks/useModeration";
|
import useModeration from "@/Hooks/useModeration";
|
||||||
import AvatarSection from "@/Pages/Profile/AvatarSection";
|
import AvatarSection from "@/Pages/Profile/AvatarSection";
|
||||||
import ProfileDetails from "@/Pages/Profile/ProfileDetails";
|
import ProfileDetails from "@/Pages/Profile/ProfileDetails";
|
||||||
import ProfileTab from "@/Pages/Profile/ProfileTab";
|
import {
|
||||||
import { BookMarksTab, FollowersTab, FollowsTab, RelaysTab, ZapsProfileTab } from "@/Pages/Profile/ProfileTabs";
|
BookMarksTab,
|
||||||
|
FollowersTab,
|
||||||
|
FollowsTab,
|
||||||
|
RelaysTab,
|
||||||
|
ZapsProfileTab,
|
||||||
|
} from "@/Pages/Profile/ProfileTabComponents";
|
||||||
|
import ProfileTabSelectors from "@/Pages/Profile/ProfileTabSelectors";
|
||||||
import { ProfileTabType } from "@/Pages/Profile/ProfileTabType";
|
import { ProfileTabType } from "@/Pages/Profile/ProfileTabType";
|
||||||
|
import { NotesTab } from "@/Pages/Root/NotesTab";
|
||||||
import { parseId, unwrap } from "@/Utils";
|
import { parseId, unwrap } from "@/Utils";
|
||||||
import { EmailRegex } from "@/Utils/Const";
|
import { EmailRegex } from "@/Utils/Const";
|
||||||
|
|
||||||
@ -58,15 +63,17 @@ export default function ProfilePage({ id: propId, state }: ProfilePageProps) {
|
|||||||
|
|
||||||
// feeds
|
// feeds
|
||||||
const { blocked } = useModeration();
|
const { blocked } = useModeration();
|
||||||
const pinned = usePinList(id);
|
|
||||||
const muted = useMuteList(id);
|
const muted = useMuteList(id);
|
||||||
const follows = useFollowsFeed(id);
|
const follows = useFollowsFeed(id);
|
||||||
|
|
||||||
// tabs
|
// tabs
|
||||||
const [tab, setTab] = useState<Tab>(ProfileTab.Notes);
|
const [tab, setTab] = useState<Tab>(ProfileTabSelectors.Notes);
|
||||||
const optionalTabs = [ProfileTab.Zaps, ProfileTab.Relays, ProfileTab.Bookmarks, ProfileTab.Muted].filter(a =>
|
const optionalTabs = [
|
||||||
unwrap(a),
|
ProfileTabSelectors.Zaps,
|
||||||
) as Tab[];
|
ProfileTabSelectors.Relays,
|
||||||
|
ProfileTabSelectors.Bookmarks,
|
||||||
|
ProfileTabSelectors.Muted,
|
||||||
|
].filter(a => unwrap(a)) as Tab[];
|
||||||
const horizontalScroll = useHorizontalScroll();
|
const horizontalScroll = useHorizontalScroll();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -98,7 +105,7 @@ export default function ProfilePage({ id: propId, state }: ProfilePageProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setTab(ProfileTab.Notes);
|
setTab(ProfileTabSelectors.Notes);
|
||||||
}, [id, propId, params]);
|
}, [id, propId, params]);
|
||||||
|
|
||||||
function tabContent() {
|
function tabContent() {
|
||||||
@ -106,35 +113,7 @@ export default function ProfilePage({ id: propId, state }: ProfilePageProps) {
|
|||||||
|
|
||||||
switch (tab.value) {
|
switch (tab.value) {
|
||||||
case ProfileTabType.NOTES:
|
case ProfileTabType.NOTES:
|
||||||
return (
|
return <NotesTab id={id} relays={relays} isMe={isMe} />;
|
||||||
<>
|
|
||||||
{pinned
|
|
||||||
.filter(a => a.kind === EventKind.TextNote)
|
|
||||||
.map(n => {
|
|
||||||
return (
|
|
||||||
<Note
|
|
||||||
key={`pinned-${n.id}`}
|
|
||||||
data={n}
|
|
||||||
options={{ showTime: false, showPinned: true, canUnpin: isMe }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<Timeline
|
|
||||||
key={id}
|
|
||||||
subject={{
|
|
||||||
type: "pubkey",
|
|
||||||
items: [id],
|
|
||||||
discriminator: id.slice(0, 12),
|
|
||||||
relay: relays,
|
|
||||||
}}
|
|
||||||
postsOnly={false}
|
|
||||||
method={"LIMIT_UNTIL"}
|
|
||||||
loadMore={false}
|
|
||||||
ignoreModeration={true}
|
|
||||||
window={60 * 60 * 6}
|
|
||||||
/>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
case ProfileTabType.ZAPS: {
|
case ProfileTabType.ZAPS: {
|
||||||
return <ZapsProfileTab id={id} />;
|
return <ZapsProfileTab id={id} />;
|
||||||
}
|
}
|
||||||
@ -163,8 +142,8 @@ export default function ProfilePage({ id: propId, state }: ProfilePageProps) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderTab(v: Tab) {
|
function renderTabSelector(v: Tab) {
|
||||||
return <TabElement key={v.value} t={v} tab={tab} setTab={setTab} />;
|
return <TabSelector key={v.value} t={v} tab={tab} setTab={setTab} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bannerWidth = Math.min(window.innerWidth, 940);
|
const bannerWidth = Math.min(window.innerWidth, 940);
|
||||||
@ -189,9 +168,11 @@ export default function ProfilePage({ id: propId, state }: ProfilePageProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="main-content">
|
<div className="main-content">
|
||||||
<div className="tabs p" ref={horizontalScroll}>
|
<div className="tabs p" ref={horizontalScroll}>
|
||||||
{[ProfileTab.Notes, ProfileTab.Followers, ProfileTab.Follows].map(renderTab)}
|
{[ProfileTabSelectors.Notes, ProfileTabSelectors.Followers, ProfileTabSelectors.Follows].map(
|
||||||
{optionalTabs.map(renderTab)}
|
renderTabSelector,
|
||||||
{isMe && blocked.length > 0 && renderTab(ProfileTab.Blocked)}
|
)}
|
||||||
|
{optionalTabs.map(renderTabSelector)}
|
||||||
|
{isMe && blocked.length > 0 && renderTabSelector(ProfileTabSelectors.Blocked)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="main-content">{tabContent()}</div>
|
<div className="main-content">{tabContent()}</div>
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
import { HexKey, NostrLink, NostrPrefix } from "@snort/system";
|
import { EventKind, HexKey, NostrLink, NostrPrefix } from "@snort/system";
|
||||||
|
import { useMemo } from "react";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
import { Note } from "@/Components/Event/Note/Note";
|
||||||
import Zap from "@/Components/Event/Zap";
|
import Zap from "@/Components/Event/Zap";
|
||||||
|
import Timeline from "@/Components/Feed/Timeline";
|
||||||
import RelaysMetadata from "@/Components/Relay/RelaysMetadata";
|
import RelaysMetadata from "@/Components/Relay/RelaysMetadata";
|
||||||
import Bookmarks from "@/Components/User/Bookmarks";
|
import Bookmarks from "@/Components/User/Bookmarks";
|
||||||
import FollowsList from "@/Components/User/FollowListBase";
|
import FollowsList from "@/Components/User/FollowListBase";
|
||||||
@ -9,7 +12,7 @@ import useFollowersFeed from "@/Feed/FollowersFeed";
|
|||||||
import useFollowsFeed from "@/Feed/FollowsFeed";
|
import useFollowsFeed from "@/Feed/FollowsFeed";
|
||||||
import useRelaysFeed from "@/Feed/RelaysFeed";
|
import useRelaysFeed from "@/Feed/RelaysFeed";
|
||||||
import useZapsFeed from "@/Feed/ZapsFeed";
|
import useZapsFeed from "@/Feed/ZapsFeed";
|
||||||
import { useBookmarkList } from "@/Hooks/useLists";
|
import { useBookmarkList, usePinList } from "@/Hooks/useLists";
|
||||||
import messages from "@/Pages/messages";
|
import messages from "@/Pages/messages";
|
||||||
import { formatShort } from "@/Utils/Number";
|
import { formatShort } from "@/Utils/Number";
|
||||||
|
|
||||||
@ -47,3 +50,31 @@ export function BookMarksTab({ id }: { id: HexKey }) {
|
|||||||
const bookmarks = useBookmarkList(id);
|
const bookmarks = useBookmarkList(id);
|
||||||
return <Bookmarks pubkey={id} bookmarks={bookmarks} />;
|
return <Bookmarks pubkey={id} bookmarks={bookmarks} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function NotesTab({ id, relays, isMe }: { id: HexKey; relays?: Array<string>; isMe: boolean }) {
|
||||||
|
const pinned = usePinList(id);
|
||||||
|
const options = useMemo(() => ({ showTime: false, showPinned: true, canUnpin: isMe }), [isMe]);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{pinned
|
||||||
|
.filter(a => a.kind === EventKind.TextNote)
|
||||||
|
.map(n => {
|
||||||
|
return <Note key={`pinned-${n.id}`} data={n} options={options} />;
|
||||||
|
})}
|
||||||
|
<Timeline
|
||||||
|
key={id}
|
||||||
|
subject={{
|
||||||
|
type: "pubkey",
|
||||||
|
items: [id],
|
||||||
|
discriminator: id.slice(0, 12),
|
||||||
|
relay: relays,
|
||||||
|
}}
|
||||||
|
postsOnly={false}
|
||||||
|
method={"LIMIT_UNTIL"}
|
||||||
|
loadMore={false}
|
||||||
|
ignoreModeration={true}
|
||||||
|
window={60 * 60 * 6}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import Icon from "@/Components/Icons/Icon";
|
import Icon from "@/Components/Icons/Icon";
|
||||||
import { Tab } from "@/Components/Tabs/Tabs";
|
import { Tab } from "@/Components/TabSelectors/TabSelectors";
|
||||||
import { ProfileTabType } from "@/Pages/Profile/ProfileTabType";
|
import { ProfileTabType } from "@/Pages/Profile/ProfileTabType";
|
||||||
|
|
||||||
const ProfileTab = {
|
const ProfileTabSelectors = {
|
||||||
Notes: {
|
Notes: {
|
||||||
text: (
|
text: (
|
||||||
<>
|
<>
|
||||||
@ -88,4 +88,4 @@ const ProfileTab = {
|
|||||||
},
|
},
|
||||||
} as { [key: string]: Tab };
|
} as { [key: string]: Tab };
|
||||||
|
|
||||||
export default ProfileTab;
|
export default ProfileTabSelectors;
|
@ -3,7 +3,7 @@ import { FormattedMessage, useIntl } from "react-intl";
|
|||||||
import { useNavigate, useParams } from "react-router-dom";
|
import { useNavigate, useParams } from "react-router-dom";
|
||||||
|
|
||||||
import Timeline from "@/Components/Feed/Timeline";
|
import Timeline from "@/Components/Feed/Timeline";
|
||||||
import Tabs, { Tab } from "@/Components/Tabs/Tabs";
|
import TabSelectors, { Tab } from "@/Components/TabSelectors/TabSelectors";
|
||||||
import TrendingNotes from "@/Components/Trending/TrendingPosts";
|
import TrendingNotes from "@/Components/Trending/TrendingPosts";
|
||||||
import TrendingUsers from "@/Components/Trending/TrendingUsers";
|
import TrendingUsers from "@/Components/Trending/TrendingUsers";
|
||||||
import FollowListBase from "@/Components/User/FollowListBase";
|
import FollowListBase from "@/Components/User/FollowListBase";
|
||||||
@ -107,7 +107,7 @@ const SearchPage = () => {
|
|||||||
value={search}
|
value={search}
|
||||||
onChange={e => setSearch(e.target.value)}
|
onChange={e => setSearch(e.target.value)}
|
||||||
/>
|
/>
|
||||||
<Tabs tabs={SearchTab} tab={tab} setTab={setTab} />
|
<TabSelectors tabs={SearchTab} tab={tab} setTab={setTab} />
|
||||||
</div>
|
</div>
|
||||||
{tabContent()}
|
{tabContent()}
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user