fix the rest of warnings
continuous-integration/drone/push Build is failing Details

This commit is contained in:
Martti Malmi 2024-01-10 20:16:30 +02:00
parent e6a42db658
commit 5baffd00b9
37 changed files with 415 additions and 390 deletions

View File

@ -1,4 +1,4 @@
import {ExternalStore} from "@snort/shared";
import { ExternalStore } from "@snort/shared";
class CommunityLeadersStore extends ExternalStore<Array<string>> {
#leaders: Array<string> = [];
@ -13,4 +13,4 @@ class CommunityLeadersStore extends ExternalStore<Array<string>> {
}
}
export const LeadersStore = new CommunityLeadersStore();
export const LeadersStore = new CommunityLeadersStore();

View File

@ -1,6 +1,6 @@
import {ParsedFragment} from "@snort/system";
import {LRUCache} from "typescript-lru-cache";
import { ParsedFragment } from "@snort/system";
import { LRUCache } from "typescript-lru-cache";
export const TextCache = new LRUCache<string, Array<ParsedFragment>>({
maxSize: 1000
});
maxSize: 1000,
});

View File

@ -8,7 +8,7 @@ import IconButton from "@/Components/Button/IconButton";
import Icon from "@/Components/Icons/Icon";
import useEventPublisher from "@/Hooks/useEventPublisher";
import useLogin from "@/Hooks/useLogin";
import { saveRelays } from "@/Pages/settings/Relays";
import { saveRelays } from "@/Pages/settings/saveRelays";
import { getRelayName } from "@/Utils";
import { removeRelay } from "@/Utils/Login";

View File

@ -9,8 +9,8 @@ import NoteHeader from "@/Components/Event/Note/NoteHeader";
import { NoteText } from "@/Components/Event/Note/NoteText";
import { TranslationInfo } from "@/Components/Event/Note/TranslationInfo";
import useModeration from "@/Hooks/useModeration";
import { chainKey } from "@/Hooks/useThreadContext";
import { findTag } from "@/Utils";
import { chainKey } from "@/Utils/Thread/ChainKey";
import messages from "../../messages";
import Text from "../../Text/Text";

View File

@ -10,7 +10,9 @@ import BackButton from "@/Components/Button/BackButton";
import Collapsed from "@/Components/Collapsed";
import Note from "@/Components/Event/EventComponent";
import NoteGhost from "@/Components/Event/Note/NoteGhost";
import { chainKey, ThreadContext, ThreadContextWrapper } from "@/Hooks/useThreadContext";
import { chainKey } from "@/Utils/Thread/ChainKey";
import { ThreadContext } from "@/Utils/Thread/ThreadContext";
import { ThreadContextWrapper } from "@/Utils/Thread/ThreadContextWrapper";
import messages from "../messages";

View File

@ -1,8 +1,8 @@
import {ReactNode} from "react";
import {FormattedMessage} from "react-intl";
import { ReactNode } from "react";
import { FormattedMessage } from "react-intl";
import Icon from "@/Components/Icons/Icon";
import {Newest} from "@/Utils/Login";
import { Newest } from "@/Utils/Login";
export type RootTab =
| "following"
@ -22,8 +22,8 @@ export function rootTabItems(base: string, pubKey: string | undefined, tags: New
show: Boolean(pubKey),
element: (
<>
<Icon name="user-v2"/>
<FormattedMessage defaultMessage="Following" id="cPIKU2"/>
<Icon name="user-v2" />
<FormattedMessage defaultMessage="Following" id="cPIKU2" />
</>
),
},
@ -33,8 +33,8 @@ export function rootTabItems(base: string, pubKey: string | undefined, tags: New
show: true,
element: (
<>
<Icon name="fire"/>
<FormattedMessage defaultMessage="Trending Notes" id="Ix8l+B"/>
<Icon name="fire" />
<FormattedMessage defaultMessage="Trending Notes" id="Ix8l+B" />
</>
),
},
@ -44,8 +44,8 @@ export function rootTabItems(base: string, pubKey: string | undefined, tags: New
show: Boolean(pubKey),
element: (
<>
<Icon name="message-chat-circle"/>
<FormattedMessage defaultMessage="Conversations" id="1udzha"/>
<Icon name="message-chat-circle" />
<FormattedMessage defaultMessage="Conversations" id="1udzha" />
</>
),
},
@ -55,8 +55,8 @@ export function rootTabItems(base: string, pubKey: string | undefined, tags: New
show: Boolean(pubKey),
element: (
<>
<Icon name="user-v2"/>
<FormattedMessage defaultMessage="Followed by friends" id="voxBKC"/>
<Icon name="user-v2" />
<FormattedMessage defaultMessage="Followed by friends" id="voxBKC" />
</>
),
},
@ -66,8 +66,8 @@ export function rootTabItems(base: string, pubKey: string | undefined, tags: New
show: Boolean(pubKey),
element: (
<>
<Icon name="thumbs-up"/>
<FormattedMessage defaultMessage="Suggested Follows" id="C8HhVE"/>
<Icon name="thumbs-up" />
<FormattedMessage defaultMessage="Suggested Follows" id="C8HhVE" />
</>
),
},
@ -77,8 +77,8 @@ export function rootTabItems(base: string, pubKey: string | undefined, tags: New
show: true,
element: (
<>
<Icon name="hash"/>
<FormattedMessage defaultMessage="Trending Hashtags" id="XXm7jJ"/>
<Icon name="hash" />
<FormattedMessage defaultMessage="Trending Hashtags" id="XXm7jJ" />
</>
),
},
@ -88,8 +88,8 @@ export function rootTabItems(base: string, pubKey: string | undefined, tags: New
show: true,
element: (
<>
<Icon name="globe"/>
<FormattedMessage defaultMessage="Global" id="EWyQH5"/>
<Icon name="globe" />
<FormattedMessage defaultMessage="Global" id="EWyQH5" />
</>
),
},
@ -99,8 +99,8 @@ export function rootTabItems(base: string, pubKey: string | undefined, tags: New
show: tags.item.length > 0,
element: (
<>
<Icon name="hash"/>
<FormattedMessage defaultMessage="Topics" id="kc79d3"/>
<Icon name="hash" />
<FormattedMessage defaultMessage="Topics" id="kc79d3" />
</>
),
},
@ -111,4 +111,4 @@ export function rootTabItems(base: string, pubKey: string | undefined, tags: New
element: ReactNode;
}>;
return menuItems;
}
}

View File

@ -1,10 +1,10 @@
import "./RootTabs.css";
import {Menu, MenuItem} from "@szhsin/react-menu";
import {useEffect, useMemo, useState} from "react";
import {useLocation, useNavigate} from "react-router-dom";
import { Menu, MenuItem } from "@szhsin/react-menu";
import { useEffect, useMemo, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import {RootTab, rootTabItems} from "@/Components/Feed/RootTabItems";
import { RootTab, rootTabItems } from "@/Components/Feed/RootTabItems";
import Icon from "@/Components/Icons/Icon";
import useLogin from "@/Hooks/useLogin";

View File

@ -2,7 +2,7 @@ import { ReactNode, useEffect, useState } from "react";
import { IntlProvider as ReactIntlProvider } from "react-intl";
import { DefaultLocale } from "@/Components/IntlProvider/IntlProviderUtils";
import {useLocale} from "@/Components/IntlProvider/useLocale";
import { useLocale } from "@/Components/IntlProvider/useLocale";
import enMessages from "@/translations/en.json";
const getMessages = (locale: string) => {

View File

@ -1,4 +1,4 @@
import {ExternalStore} from "@snort/shared";
import { ExternalStore } from "@snort/shared";
class LangStore extends ExternalStore<string | null> {
setLang(s: string) {
@ -11,4 +11,4 @@ class LangStore extends ExternalStore<string | null> {
}
}
export const LangOverride = new LangStore();
export const LangOverride = new LangStore();

View File

@ -1,11 +1,11 @@
import {useSyncExternalStore} from "react";
import { useSyncExternalStore } from "react";
import {getLocale} from "@/Components/IntlProvider/IntlProviderUtils";
import {LangOverride} from "@/Components/IntlProvider/langStore";
import { getLocale } from "@/Components/IntlProvider/IntlProviderUtils";
import { LangOverride } from "@/Components/IntlProvider/langStore";
import useLogin from "@/Hooks/useLogin";
export function useLocale() {
const {language} = useLogin(s => ({language: s.appData.item.preferences.language}));
const { language } = useLogin(s => ({ language: s.appData.item.preferences.language }));
const loggedOutLang = useSyncExternalStore(
c => LangOverride.hook(c),
() => LangOverride.snapshot(),
@ -16,4 +16,4 @@ export function useLocale() {
lang: locale.toLowerCase().split(/[_-]+/)[0],
setOverride: (s: string) => LangOverride.setLang(s),
};
}
}

View File

@ -3,8 +3,8 @@ import { NostrLink, TaggedNostrEvent } from "@snort/system";
import { Thread } from "@/Components/Event/Thread";
import Modal from "@/Components/Modal/Modal";
import { SpotlightMedia } from "@/Components/Spotlight/SpotlightMedia";
import { ThreadContextWrapper } from "@/Hooks/useThreadContext";
import getEventMedia from "@/Utils/getEventMedia";
import { ThreadContextWrapper } from "@/Utils/Thread/ThreadContextWrapper";
interface SpotlightThreadModalProps {
thread?: NostrLink;

View File

@ -2,7 +2,7 @@ import classNames from "classnames";
import { ReactNode } from "react";
import { Link } from "react-router-dom";
import {useLocale} from "@/Components/IntlProvider/useLocale";
import { useLocale } from "@/Components/IntlProvider/useLocale";
import PageSpinner from "@/Components/PageSpinner";
import NostrBandApi from "@/External/NostrBand";
import useCachedFetch from "@/Hooks/useCachedFetch";

View File

@ -7,7 +7,7 @@ import { ErrorOrOffline } from "@/Components/ErrorOrOffline";
import Note from "@/Components/Event/EventComponent";
import { DisplayAs, DisplayAsSelector } from "@/Components/Feed/DisplayAsSelector";
import ImageGridItem from "@/Components/Feed/ImageGridItem";
import {useLocale} from "@/Components/IntlProvider/useLocale";
import { useLocale } from "@/Components/IntlProvider/useLocale";
import PageSpinner from "@/Components/PageSpinner";
import { SpotlightThreadModal } from "@/Components/Spotlight/SpotlightThreadModal";
import ShortNote from "@/Components/Trending/ShortNote";

View File

@ -1,10 +1,10 @@
import {unwrap} from "@snort/shared";
import {EventKind, parseNostrLink} from "@snort/system";
import {useEffect, useSyncExternalStore} from "react";
import { unwrap } from "@snort/shared";
import { EventKind, parseNostrLink } from "@snort/system";
import { useEffect, useSyncExternalStore } from "react";
import {LeadersStore} from "@/Cache/CommunityLeadersStore";
import { LeadersStore } from "@/Cache/CommunityLeadersStore";
import {useLinkList} from "./useLists";
import { useLinkList } from "./useLists";
export function useCommunityLeaders() {
const link = parseNostrLink(unwrap(CONFIG.communityLeaders).list);

View File

@ -1,10 +1,10 @@
import {bech32ToHex} from "@snort/shared";
import {EventKind, RequestBuilder} from "@snort/system";
import {useRequestBuilder} from "@snort/system-react";
import {useMemo} from "react";
import { bech32ToHex } from "@snort/shared";
import { EventKind, RequestBuilder } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
import { useMemo } from "react";
import {getNewest} from "@/Utils";
import {SnortPubkey} from "@/Utils/Const";
import { getNewest } from "@/Utils";
import { SnortPubkey } from "@/Utils/Const";
export function useRates(symbol: string, leaveOpen = true) {
const sub = useMemo(() => {

View File

@ -1,6 +1,6 @@
import {transformText} from "@snort/system";
import { transformText } from "@snort/system";
import {TextCache} from "@/Cache/TextCache";
import { TextCache } from "@/Cache/TextCache";
export function transformTextCached(id: string, content: string, tags: Array<Array<string>>) {
if (content.length > 0) {

View File

@ -5,7 +5,7 @@ import React, { useCallback, useMemo } from "react";
import { FormattedMessage } from "react-intl";
import { useLocation, useNavigate } from "react-router-dom";
import {rootTabItems} from "@/Components/Feed/RootTabItems";
import { rootTabItems } from "@/Components/Feed/RootTabItems";
import { RootTabs } from "@/Components/Feed/RootTabs";
import Icon from "@/Components/Icons/Icon";
import DisplayName from "@/Components/User/DisplayName";

View File

@ -1,273 +0,0 @@
import { unixNow } from "@snort/shared";
import { NostrLink } from "@snort/system";
import { SnortContext } from "@snort/system-react";
import { lazy, useContext, useEffect, useMemo, useState } from "react";
import { FormattedMessage } from "react-intl";
import { Link, Outlet, RouteObject, useParams } from "react-router-dom";
import Timeline from "@/Components/Feed/Timeline";
import TimelineFollows from "@/Components/Feed/TimelineFollows";
import SuggestedProfiles from "@/Components/SuggestedProfiles";
import { TaskList } from "@/Components/Tasks/TaskList";
import TrendingHashtags from "@/Components/Trending/TrendingHashtags";
import TrendingNotes from "@/Components/Trending/TrendingPosts";
import { TimelineSubject } from "@/Feed/TimelineFeed";
import useLogin from "@/Hooks/useLogin";
import { DeckContext } from "@/Pages/DeckLayout";
import Discover from "@/Pages/Discover";
import HashTagsPage from "@/Pages/HashTagsPage";
import { debounce, getCurrentRefCode, getRelayName, sha256 } from "@/Utils";
import { TopicsPage } from "./TopicsPage";
const InviteModal = lazy(() => import("@/Components/Invite"));
import useHistoryState from "@/Hooks/useHistoryState";
import messages from "./messages";
interface RelayOption {
url: string;
paid: boolean;
}
export default function RootPage() {
const code = getCurrentRefCode();
return (
<>
<div className="main-content">
<Outlet />
</div>
{code && <InviteModal />}
</>
);
}
const FollowsHint = () => {
const { publicKey: pubKey, follows } = useLogin();
if (follows.item?.length === 0 && pubKey) {
return (
<FormattedMessage
{...messages.NoFollows}
values={{
newUsersPage: (
<Link to={"/discover"}>
<FormattedMessage {...messages.NewUsers} />
</Link>
),
}}
/>
);
}
return null;
};
export const GlobalTab = () => {
const { relays } = useLogin();
const [relay, setRelay] = useHistoryState<RelayOption>(undefined, "global-relay");
const [allRelays, setAllRelays] = useHistoryState<RelayOption[]>(undefined, "global-relay-options");
const [now] = useState(unixNow());
const system = useContext(SnortContext);
function globalRelaySelector() {
if (!allRelays || allRelays.length === 0) return null;
const paidRelays = allRelays.filter(a => a.paid);
const publicRelays = allRelays.filter(a => !a.paid);
return (
<div className="flex items-center g8 justify-end nowrap">
<h3>
<FormattedMessage
defaultMessage="Relay"
id="KHK8B9"
description="Label for reading global feed from specific relays"
/>
</h3>
<select
className="f-ellipsis"
onChange={e => setRelay(allRelays.find(a => a.url === e.target.value))}
value={relay?.url}>
{paidRelays.length > 0 && (
<optgroup label="Paid Relays">
{paidRelays.map(a => (
<option key={a.url} value={a.url}>
{getRelayName(a.url)}
</option>
))}
</optgroup>
)}
<optgroup label="Public Relays">
{publicRelays.map(a => (
<option key={a.url} value={a.url}>
{getRelayName(a.url)}
</option>
))}
</optgroup>
</select>
</div>
);
}
useEffect(() => {
return debounce(500, () => {
const ret: RelayOption[] = [];
system.Sockets.forEach(v => {
if (v.connected) {
ret.push({
url: v.address,
paid: v.info?.limitation?.payment_required ?? false,
});
}
});
ret.sort(a => (a.paid ? -1 : 1));
if (ret.length > 0 && !relay) {
setRelay(ret[0]);
}
setAllRelays(ret);
});
}, [relays, relay]);
return (
<>
{globalRelaySelector()}
{relay && (
<Timeline
subject={{
type: "global",
items: [],
relay: [relay.url],
discriminator: `all-${sha256(relay.url)}`,
}}
postsOnly={false}
method={"TIME_RANGE"}
window={600}
now={now}
/>
)}
</>
);
};
export const FollowedByFriendsTab = () => {
const { publicKey } = useLogin();
const subject: TimelineSubject = {
type: "global",
items: [],
discriminator: `followed-by-friends-${publicKey}`,
streams: true,
};
return <Timeline followDistance={2} subject={subject} postsOnly={true} method={"TIME_RANGE"} />;
};
export const NotesTab = () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const deckContext = useContext(DeckContext);
const noteOnClick = useMemo(() => {
if (deckContext) {
return ev => {
deckContext.setThread(NostrLink.fromEvent(ev));
};
}
return undefined;
}, [deckContext]);
return (
<>
<FollowsHint />
<TaskList />
<TimelineFollows postsOnly={true} noteOnClick={noteOnClick} />
</>
);
};
export const ConversationsTab = () => {
return <TimelineFollows postsOnly={false} />;
};
export const TagsTab = (params: { tag?: string }) => {
const { tag } = useParams();
const t = params.tag ?? tag ?? "";
const subject: TimelineSubject = {
type: "hashtag",
items: [t],
discriminator: `tags-${t}`,
streams: true,
};
return <Timeline subject={subject} postsOnly={false} method={"TIME_RANGE"} />;
};
const DefaultTab = () => {
const { preferences, publicKey } = useLogin(s => ({
preferences: s.appData.item.preferences,
publicKey: s.publicKey,
}));
const tab = publicKey ? preferences.defaultRootTab ?? `notes` : `trending/notes`;
const elm = RootTabRoutes.find(a => a.path === tab)?.element;
return elm;
};
export const RootTabRoutes = [
{
path: "",
element: <DefaultTab />,
},
{
path: "global",
element: <GlobalTab />,
},
{
path: "notes",
element: <NotesTab />,
},
{
path: "followed-by-friends",
element: <FollowedByFriendsTab />,
},
{
path: "conversations",
element: <ConversationsTab />,
},
{
path: "discover",
element: <Discover />,
},
{
path: "tag/:tag",
element: <TagsTab />,
},
{
path: "trending/notes",
element: <TrendingNotes />,
},
{
path: "trending/hashtags",
element: <TrendingHashtags />,
},
{
path: "suggested",
element: (
<div className="p">
<SuggestedProfiles />
</div>
),
},
{
path: "t/:tag",
element: <HashTagsPage />,
},
{
path: "topics",
element: <TopicsPage />,
},
];
export const RootRoutes = [
{
path: "/",
element: <RootPage />,
children: RootTabRoutes,
},
] as RouteObject[];

View File

@ -0,0 +1,5 @@
import TimelineFollows from "@/Components/Feed/TimelineFollows";
export const ConversationsTab = () => {
return <TimelineFollows postsOnly={false} />;
};

View File

@ -0,0 +1,12 @@
import useLogin from "@/Hooks/useLogin";
import { RootTabRoutes } from "@/Pages/Root/RootTabRoutes";
export const DefaultTab = () => {
const { preferences, publicKey } = useLogin(s => ({
preferences: s.appData.item.preferences,
publicKey: s.publicKey,
}));
const tab = publicKey ? preferences.defaultRootTab ?? `notes` : `trending/notes`;
const elm = RootTabRoutes.find(a => a.path === tab)?.element;
return elm;
};

View File

@ -0,0 +1,15 @@
import Timeline from "@/Components/Feed/Timeline";
import { TimelineSubject } from "@/Feed/TimelineFeed";
import useLogin from "@/Hooks/useLogin";
export const FollowedByFriendsTab = () => {
const { publicKey } = useLogin();
const subject: TimelineSubject = {
type: "global",
items: [],
discriminator: `followed-by-friends-${publicKey}`,
streams: true,
};
return <Timeline followDistance={2} subject={subject} postsOnly={true} method={"TIME_RANGE"} />;
};

View File

@ -0,0 +1,101 @@
import { unixNow } from "@snort/shared";
import { SnortContext } from "@snort/system-react";
import { useContext, useEffect, useState } from "react";
import { FormattedMessage } from "react-intl";
import Timeline from "@/Components/Feed/Timeline";
import useHistoryState from "@/Hooks/useHistoryState";
import useLogin from "@/Hooks/useLogin";
import { debounce, getRelayName, sha256 } from "@/Utils";
interface RelayOption {
url: string;
paid: boolean;
}
export const GlobalTab = () => {
const { relays } = useLogin();
const [relay, setRelay] = useHistoryState<RelayOption>(undefined, "global-relay");
const [allRelays, setAllRelays] = useHistoryState<RelayOption[]>(undefined, "global-relay-options");
const [now] = useState(unixNow());
const system = useContext(SnortContext);
function globalRelaySelector() {
if (!allRelays || allRelays.length === 0) return null;
const paidRelays = allRelays.filter(a => a.paid);
const publicRelays = allRelays.filter(a => !a.paid);
return (
<div className="flex items-center g8 justify-end nowrap">
<h3>
<FormattedMessage
defaultMessage="Relay"
id="KHK8B9"
description="Label for reading global feed from specific relays"
/>
</h3>
<select
className="f-ellipsis"
onChange={e => setRelay(allRelays.find(a => a.url === e.target.value))}
value={relay?.url}>
{paidRelays.length > 0 && (
<optgroup label="Paid Relays">
{paidRelays.map(a => (
<option key={a.url} value={a.url}>
{getRelayName(a.url)}
</option>
))}
</optgroup>
)}
<optgroup label="Public Relays">
{publicRelays.map(a => (
<option key={a.url} value={a.url}>
{getRelayName(a.url)}
</option>
))}
</optgroup>
</select>
</div>
);
}
useEffect(() => {
return debounce(500, () => {
const ret: RelayOption[] = [];
system.Sockets.forEach(v => {
if (v.connected) {
ret.push({
url: v.address,
paid: v.info?.limitation?.payment_required ?? false,
});
}
});
ret.sort(a => (a.paid ? -1 : 1));
if (ret.length > 0 && !relay) {
setRelay(ret[0]);
}
setAllRelays(ret);
});
}, [relays, relay]);
return (
<>
{globalRelaySelector()}
{relay && (
<Timeline
subject={{
type: "global",
items: [],
relay: [relay.url],
discriminator: `all-${sha256(relay.url)}`,
}}
postsOnly={false}
method={"TIME_RANGE"}
window={600}
now={now}
/>
)}
</>
);
};

View File

@ -0,0 +1,50 @@
import { NostrLink } from "@snort/system";
import { useContext, useMemo } from "react";
import { FormattedMessage } from "react-intl";
import { Link } from "react-router-dom";
import TimelineFollows from "@/Components/Feed/TimelineFollows";
import { TaskList } from "@/Components/Tasks/TaskList";
import useLogin from "@/Hooks/useLogin";
import { DeckContext } from "@/Pages/DeckLayout";
import messages from "@/Pages/messages";
const FollowsHint = () => {
const { publicKey: pubKey, follows } = useLogin();
if (follows.item?.length === 0 && pubKey) {
return (
<FormattedMessage
{...messages.NoFollows}
values={{
newUsersPage: (
<Link to={"/discover"}>
<FormattedMessage {...messages.NewUsers} />
</Link>
),
}}
/>
);
}
return null;
};
export const NotesTab = () => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const deckContext = useContext(DeckContext);
const noteOnClick = useMemo(() => {
if (deckContext) {
return ev => {
deckContext.setThread(NostrLink.fromEvent(ev));
};
}
return undefined;
}, [deckContext]);
return (
<>
<FollowsHint />
<TaskList />
<TimelineFollows postsOnly={true} noteOnClick={noteOnClick} />
</>
);
};

View File

@ -0,0 +1,25 @@
import { lazy } from "react";
import { Outlet, RouteObject } from "react-router-dom";
import { RootTabRoutes } from "@/Pages/Root/RootTabRoutes";
import { getCurrentRefCode } from "@/Utils";
const InviteModal = lazy(() => import("@/Components/Invite"));
export default function RootPage() {
const code = getCurrentRefCode();
return (
<>
<div className="main-content">
<Outlet />
</div>
{code && <InviteModal />}
</>
);
}
export const RootRoutes = [
{
path: "/",
element: <RootPage />,
children: RootTabRoutes,
},
] as RouteObject[];

View File

@ -0,0 +1,67 @@
import SuggestedProfiles from "@/Components/SuggestedProfiles";
import TrendingHashtags from "@/Components/Trending/TrendingHashtags";
import TrendingNotes from "@/Components/Trending/TrendingPosts";
import Discover from "@/Pages/Discover";
import HashTagsPage from "@/Pages/HashTagsPage";
import { ConversationsTab } from "@/Pages/Root/ConversationsTab";
import { DefaultTab } from "@/Pages/Root/DefaultTab";
import { FollowedByFriendsTab } from "@/Pages/Root/FollowedByFriendsTab";
import { GlobalTab } from "@/Pages/Root/GlobalTab";
import { NotesTab } from "@/Pages/Root/NotesTab";
import { TagsTab } from "@/Pages/Root/TagsTab";
import { TopicsPage } from "@/Pages/TopicsPage";
export const RootTabRoutes = [
{
path: "",
element: <DefaultTab />,
},
{
path: "global",
element: <GlobalTab />,
},
{
path: "notes",
element: <NotesTab />,
},
{
path: "followed-by-friends",
element: <FollowedByFriendsTab />,
},
{
path: "conversations",
element: <ConversationsTab />,
},
{
path: "discover",
element: <Discover />,
},
{
path: "tag/:tag",
element: <TagsTab />,
},
{
path: "trending/notes",
element: <TrendingNotes />,
},
{
path: "trending/hashtags",
element: <TrendingHashtags />,
},
{
path: "suggested",
element: (
<div className="p">
<SuggestedProfiles />
</div>
),
},
{
path: "t/:tag",
element: <HashTagsPage />,
},
{
path: "topics",
element: <TopicsPage />,
},
];

View File

@ -0,0 +1,17 @@
import { useParams } from "react-router-dom";
import Timeline from "@/Components/Feed/Timeline";
import { TimelineSubject } from "@/Feed/TimelineFeed";
export const TagsTab = (params: { tag?: string }) => {
const { tag } = useParams();
const t = params.tag ?? tag ?? "";
const subject: TimelineSubject = {
type: "hashtag",
items: [t],
discriminator: `tags-${t}`,
streams: true,
};
return <Timeline subject={subject} postsOnly={false} method={"TIME_RANGE"} />;
};

View File

@ -4,7 +4,7 @@ import { Outlet, RouteObject } from "react-router-dom";
import Icon from "@/Components/Icons/Icon";
import { AllLanguageCodes } from "@/Components/IntlProvider/IntlProviderUtils";
import {useLocale} from "@/Components/IntlProvider/useLocale";
import { useLocale } from "@/Components/IntlProvider/useLocale";
import { Discover } from "./discover";
import { Moderation } from "./moderation";

View File

@ -3,7 +3,7 @@ import "./Preferences.css";
import { FormattedMessage, useIntl } from "react-intl";
import { AllLanguageCodes } from "@/Components/IntlProvider/IntlProviderUtils";
import {useLocale} from "@/Components/IntlProvider/useLocale";
import { useLocale } from "@/Components/IntlProvider/useLocale";
import useLogin from "@/Hooks/useLogin";
import { unwrap } from "@/Utils";
import { DefaultImgProxy } from "@/Utils/Const";

View File

@ -1,5 +1,4 @@
import { unixNowMs, unwrap } from "@snort/shared";
import { EventPublisher, FullRelaySettings, RelaySettings, SystemInterface } from "@snort/system";
import { useEffect, useMemo, useState } from "react";
import { FormattedMessage } from "react-intl";
@ -8,25 +7,13 @@ import Relay from "@/Components/Relay/Relay";
import SnortApi, { RelayDistance } from "@/External/SnortApi";
import useEventPublisher from "@/Hooks/useEventPublisher";
import useLogin from "@/Hooks/useLogin";
import { saveRelays } from "@/Pages/settings/saveRelays";
import { getCountry, getRelayName, sanitizeRelayUrl } from "@/Utils";
import { Blasters } from "@/Utils/Const";
import { setRelays } from "@/Utils/Login";
import { formatShort } from "@/Utils/Number";
import messages from "./messages";
export async function saveRelays(
system: SystemInterface,
publisher: EventPublisher | undefined,
relays: Array<FullRelaySettings> | Record<string, RelaySettings>,
) {
if (publisher) {
const ev = await publisher.relayList(relays);
await system.BroadcastEvent(ev);
await Promise.all(Blasters.map(a => system.WriteOnceToRelay(a, ev)));
}
}
const RelaySettingsPage = () => {
const { publisher, system } = useEventPublisher();
const login = useLogin();

View File

@ -16,18 +16,14 @@ import Relay from "@/Pages/settings/Relays";
import { ToolsPage, ToolsPages } from "./tools";
import { WalletSettingsRoutes } from "./wallet";
const SettingsPage = () => {
return (
<div className="px-3">
<Outlet />
</div>
);
};
export default [
{
path: "/settings",
element: <SettingsPage />,
element: (
<div className="px-3">
<Outlet />
</div>
),
children: [
{
path: "",

View File

@ -0,0 +1,15 @@
import { EventPublisher, FullRelaySettings, RelaySettings, SystemInterface } from "@snort/system";
import { Blasters } from "@/Utils/Const";
export async function saveRelays(
system: SystemInterface,
publisher: EventPublisher | undefined,
relays: Array<FullRelaySettings> | Record<string, RelaySettings>,
) {
if (publisher) {
const ev = await publisher.relayList(relays);
await system.BroadcastEvent(ev);
await Promise.all(Blasters.map(a => system.WriteOnceToRelay(a, ev)));
}
}

View File

@ -164,4 +164,4 @@ export const MaxAboutLength = 1000;
/*
* Snort backend publishes rates
*/
export const SnortPubkey = "npub1sn0rtcjcf543gj4wsg7fa59s700d5ztys5ctj0g69g2x6802npjqhjjtws";
export const SnortPubkey = "npub1sn0rtcjcf543gj4wsg7fa59s700d5ztys5ctj0g69g2x6802npjqhjjtws";

View File

@ -0,0 +1,18 @@
import { unwrap } from "@snort/shared";
import { EventExt, NostrLink, TaggedNostrEvent } from "@snort/system";
/**
* Get the chain key as a reply event
*/
export function replyChainKey(ev: TaggedNostrEvent) {
const t = EventExt.extractThread(ev);
return t?.replyTo?.value ?? t?.root?.value;
}
/**
* Get the chain key of this event
*/
export function chainKey(ev: TaggedNostrEvent) {
const link = NostrLink.fromEvent(ev);
return unwrap(link.toEventTag())[1];
}

View File

@ -0,0 +1,14 @@
/* eslint-disable no-debugger */
import { TaggedNostrEvent } from "@snort/system";
import { createContext } from "react";
interface ThreadContext {
current: string;
root?: TaggedNostrEvent;
chains: Map<string, Array<TaggedNostrEvent>>;
data: Array<TaggedNostrEvent>;
reactions: Array<TaggedNostrEvent>;
setCurrent: (i: string) => void;
}
export const ThreadContext = createContext({} as ThreadContext);

View File

@ -1,39 +1,12 @@
/* eslint-disable no-debugger */
import { unwrap } from "@snort/shared";
import { EventExt, NostrLink, TaggedNostrEvent, u256 } from "@snort/system";
import { createContext, ReactNode, useMemo, useState } from "react";
import { NostrLink, TaggedNostrEvent, u256 } from "@snort/system";
import { ReactNode, useMemo, useState } from "react";
import { useLocation } from "react-router-dom";
import useThreadFeed from "@/Feed/ThreadFeed";
import useModeration from "./useModeration";
export interface ThreadContext {
current: string;
root?: TaggedNostrEvent;
chains: Map<string, Array<TaggedNostrEvent>>;
data: Array<TaggedNostrEvent>;
reactions: Array<TaggedNostrEvent>;
setCurrent: (i: string) => void;
}
export const ThreadContext = createContext({} as ThreadContext);
/**
* Get the chain key as a reply event
*/
export function replyChainKey(ev: TaggedNostrEvent) {
const t = EventExt.extractThread(ev);
return t?.replyTo?.value ?? t?.root?.value;
}
/**
* Get the chain key of this event
*/
export function chainKey(ev: TaggedNostrEvent) {
const link = NostrLink.fromEvent(ev);
return unwrap(link.toEventTag())[1];
}
import useModeration from "@/Hooks/useModeration";
import { chainKey, replyChainKey } from "@/Utils/Thread/ChainKey";
import { ThreadContext } from "@/Utils/Thread/ThreadContext";
export function ThreadContextWrapper({ link, children }: { link: NostrLink; children?: ReactNode }) {
const location = useLocation();

View File

@ -29,7 +29,8 @@ import NostrLinkHandler from "@/Pages/NostrLinkHandler";
import NotificationsPage from "@/Pages/Notifications/Notifications";
import { OnboardingRoutes } from "@/Pages/onboarding";
import ProfilePage from "@/Pages/Profile/ProfilePage";
import { RootRoutes, RootTabRoutes } from "@/Pages/Root";
import { RootRoutes } from "@/Pages/Root/RootRoutes";
import { RootTabRoutes } from "@/Pages/Root/RootTabRoutes";
import SearchPage from "@/Pages/SearchPage";
import SettingsRoutes from "@/Pages/settings/Routes";
import { SubscribeRoutes } from "@/Pages/subscribe";