This commit is contained in:
parent
b38b6b27ef
commit
290dedb333
@ -1,6 +1,6 @@
|
||||
import "./ZapButton.css";
|
||||
|
||||
import { HexKey } from "@snort/system";
|
||||
import { HexKey, NostrLink } from "@snort/system";
|
||||
import { useUserProfile } from "@snort/system-react";
|
||||
import { useState } from "react";
|
||||
|
||||
@ -17,7 +17,7 @@ const ZapButton = ({
|
||||
pubkey: HexKey;
|
||||
lnurl?: string;
|
||||
children?: React.ReactNode;
|
||||
event?: string;
|
||||
event?: NostrLink;
|
||||
}) => {
|
||||
const profile = useUserProfile(pubkey);
|
||||
const [zap, setZap] = useState(false);
|
||||
@ -37,12 +37,11 @@ const ZapButton = ({
|
||||
value: service,
|
||||
weight: 1,
|
||||
name: profile?.display_name || profile?.name,
|
||||
zap: { pubkey: pubkey },
|
||||
zap: { pubkey: pubkey, event },
|
||||
} as ZapTarget,
|
||||
]}
|
||||
show={zap}
|
||||
onClose={() => setZap(false)}
|
||||
note={event}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
@ -1,50 +1,30 @@
|
||||
import { unixNow } from "@snort/shared";
|
||||
import { EventKind, NostrEvent, NostrLink, RequestBuilder } from "@snort/system";
|
||||
import { useRequestBuilder, useUserProfile } from "@snort/system-react";
|
||||
import { CSSProperties, useMemo } from "react";
|
||||
import { NostrEvent, NostrLink } from "@snort/system";
|
||||
import { useUserProfile } from "@snort/system-react";
|
||||
import classNames from "classnames";
|
||||
import { CSSProperties } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
import useImgProxy from "@/Hooks/useImgProxy";
|
||||
import useLiveStreams from "@/Hooks/useLiveStreams";
|
||||
import { findTag } from "@/Utils";
|
||||
import { Hour } from "@/Utils/Const";
|
||||
|
||||
import Avatar from "../User/Avatar";
|
||||
|
||||
export function LiveStreams() {
|
||||
const sub = useMemo(() => {
|
||||
const rb = new RequestBuilder("streams");
|
||||
rb.withFilter()
|
||||
.kinds([EventKind.LiveEvent])
|
||||
.since(unixNow() - Hour);
|
||||
rb.withFilter()
|
||||
.kinds([EventKind.LiveEvent])
|
||||
.since(unixNow() - Hour);
|
||||
return rb;
|
||||
}, []);
|
||||
|
||||
const streams = useRequestBuilder(sub);
|
||||
const streams = useLiveStreams();
|
||||
if (streams.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div className="flex mx-2 gap-4 overflow-x-auto sm-hide-scrollbar">
|
||||
{streams
|
||||
.filter(a => {
|
||||
return findTag(a, "status") === "live";
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const sA = Number(findTag(a, "starts"));
|
||||
const sB = Number(findTag(b, "starts"));
|
||||
return sA > sB ? -1 : 1;
|
||||
})
|
||||
.map(v => (
|
||||
<LiveStreamEvent ev={v} key={`${v.kind}:${v.pubkey}:${findTag(v, "d")}`} />
|
||||
))}
|
||||
{streams.map(v => (
|
||||
<LiveStreamEvent ev={v} key={`${v.kind}:${v.pubkey}:${findTag(v, "d")}`} className="h-[80px]" />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function LiveStreamEvent({ ev }: { ev: NostrEvent }) {
|
||||
export function LiveStreamEvent({ ev, className }: { ev: NostrEvent; className?: string }) {
|
||||
const { proxy } = useImgProxy();
|
||||
const title = findTag(ev, "title");
|
||||
const image = findTag(ev, "image");
|
||||
@ -57,7 +37,7 @@ function LiveStreamEvent({ ev }: { ev: NostrEvent }) {
|
||||
const imageProxy = proxy(image ?? "");
|
||||
|
||||
return (
|
||||
<Link className="flex gap-2 h-[80px]" to={`https://zap.stream/${link}`} target="_blank">
|
||||
<Link className={classNames("flex gap-2", className)} to={`https://zap.stream/${link}`} target="_blank">
|
||||
<div className="relative aspect-video">
|
||||
<div
|
||||
className="absolute h-full w-full bg-center bg-cover bg-gray-ultradark rounded-lg"
|
||||
|
31
packages/app/src/Components/RightWidgets/base.tsx
Normal file
31
packages/app/src/Components/RightWidgets/base.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import { ReactNode } from "react";
|
||||
|
||||
import Icon from "../Icons/Icon";
|
||||
|
||||
export interface BaseWidgetProps {
|
||||
title?: ReactNode;
|
||||
icon?: string;
|
||||
iconClassName?: string;
|
||||
children?: ReactNode;
|
||||
contextMenu?: ReactNode;
|
||||
}
|
||||
export function BaseWidget({ children, title, icon, iconClassName, contextMenu }: BaseWidgetProps) {
|
||||
return (
|
||||
<div className="br p bg-gray-ultradark">
|
||||
{title && (
|
||||
<div className="flex justify-between items-center">
|
||||
<div className="flex gap-2 items-center text-xl text-white font-semibold mb-1">
|
||||
{icon && (
|
||||
<div className="p-2 bg-gray-dark rounded-full">
|
||||
<Icon name={icon} className={iconClassName} />
|
||||
</div>
|
||||
)}
|
||||
<div>{title}</div>
|
||||
</div>
|
||||
{contextMenu}
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
9
packages/app/src/Components/RightWidgets/index.tsx
Normal file
9
packages/app/src/Components/RightWidgets/index.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
export enum RightColumnWidget {
|
||||
TaskList,
|
||||
TrendingNotes,
|
||||
TrendingPeople,
|
||||
TrendingHashtags,
|
||||
TrendingArticls,
|
||||
LiveStreams,
|
||||
InviteFriends,
|
||||
}
|
43
packages/app/src/Components/RightWidgets/invite-friends.tsx
Normal file
43
packages/app/src/Components/RightWidgets/invite-friends.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import SnortApi, { RefCodeResponse } from "@/External/SnortApi";
|
||||
import { useCopy } from "@/Hooks/useCopy";
|
||||
import useEventPublisher from "@/Hooks/useEventPublisher";
|
||||
|
||||
import AsyncButton from "../Button/AsyncButton";
|
||||
import Icon from "../Icons/Icon";
|
||||
import { BaseWidget } from "./base";
|
||||
|
||||
export default function InviteFriendsWidget() {
|
||||
const [refCode, setRefCode] = useState<RefCodeResponse>();
|
||||
const { publisher } = useEventPublisher();
|
||||
const api = new SnortApi(undefined, publisher);
|
||||
const copy = useCopy();
|
||||
|
||||
async function loadRefCode() {
|
||||
const c = await api.getRefCode();
|
||||
setRefCode(c);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
loadRefCode();
|
||||
}, [publisher]);
|
||||
|
||||
return (
|
||||
<BaseWidget
|
||||
title={<FormattedMessage defaultMessage="Invite Friends" />}
|
||||
icon="heart-solid"
|
||||
iconClassName="text-heart">
|
||||
<div className="flex flex-col gap-2">
|
||||
<FormattedMessage defaultMessage="Share a personalized invitation with friends!" />
|
||||
<div>
|
||||
<AsyncButton onClick={() => copy.copy(`https://${window.location.host}?ref=${refCode?.code}`)}>
|
||||
<Icon name="copy" />
|
||||
<FormattedMessage defaultMessage="Copy link" />
|
||||
</AsyncButton>
|
||||
</div>
|
||||
</div>
|
||||
</BaseWidget>
|
||||
);
|
||||
}
|
51
packages/app/src/Components/RightWidgets/mini-stream.tsx
Normal file
51
packages/app/src/Components/RightWidgets/mini-stream.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import { NostrLink } from "@snort/system";
|
||||
import { useUserProfile } from "@snort/system-react";
|
||||
|
||||
import useLiveStreams from "@/Hooks/useLiveStreams";
|
||||
import { findTag, getDisplayName } from "@/Utils";
|
||||
|
||||
import IconButton from "../Button/IconButton";
|
||||
import ZapButton from "../Event/ZapButton";
|
||||
import { ProxyImg } from "../ProxyImg";
|
||||
import Avatar from "../User/Avatar";
|
||||
import { BaseWidget } from "./base";
|
||||
|
||||
export default function MiniStreamWidget() {
|
||||
const streams = useLiveStreams();
|
||||
|
||||
const ev = streams.at(0);
|
||||
const host = ev?.tags.find(a => a[0] === "p" && a.at(3) === "host")?.at(1) ?? ev?.pubkey;
|
||||
const hostProfile = useUserProfile(host);
|
||||
|
||||
if (!ev) return;
|
||||
const link = NostrLink.fromEvent(ev);
|
||||
const image = findTag(ev, "image");
|
||||
const title = findTag(ev, "title");
|
||||
return (
|
||||
<BaseWidget>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="rounded-xl relative aspect-video w-full overflow-hidden">
|
||||
<ProxyImg src={image} className="absolute w-full h-full" />
|
||||
<div className="absolute flex items-center justify-center w-full h-full">
|
||||
<IconButton
|
||||
icon={{
|
||||
name: "play-square-outline",
|
||||
}}
|
||||
onClick={() => window.open(`https://zap.stream/${link.encode()}`, "_blank")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex gap-2">
|
||||
<Avatar pubkey={host ?? ""} user={hostProfile} size={48} />
|
||||
<div className="flex flex-col">
|
||||
<div className="text-lg text-white f-ellipsis font-semibold">{title}</div>
|
||||
<div>{getDisplayName(hostProfile, host!)}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>{host && <ZapButton pubkey={host} event={link} />}</div>
|
||||
</div>
|
||||
</div>
|
||||
</BaseWidget>
|
||||
);
|
||||
}
|
@ -2,13 +2,25 @@ import { HexKey } from "@snort/system";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
import PageSpinner from "@/Components/PageSpinner";
|
||||
import FollowListBase from "@/Components/User/FollowListBase";
|
||||
import FollowListBase, { FollowListBaseProps } from "@/Components/User/FollowListBase";
|
||||
import NostrBandApi from "@/External/NostrBand";
|
||||
import useCachedFetch from "@/Hooks/useCachedFetch";
|
||||
|
||||
import { ErrorOrOffline } from "../ErrorOrOffline";
|
||||
|
||||
export default function TrendingUsers({ title, count = Infinity }: { title?: ReactNode; count?: number }) {
|
||||
export default function TrendingUsers({
|
||||
title,
|
||||
count = Infinity,
|
||||
followAll = true,
|
||||
actions,
|
||||
profileActions,
|
||||
}: {
|
||||
title?: ReactNode;
|
||||
count?: number;
|
||||
followAll?: boolean;
|
||||
actions?: FollowListBaseProps["actions"];
|
||||
profileActions?: FollowListBaseProps["profileActions"];
|
||||
}) {
|
||||
const api = new NostrBandApi();
|
||||
const trendingProfilesUrl = api.trendingProfilesUrl();
|
||||
const storageKey = `nostr-band-${trendingProfilesUrl}`;
|
||||
@ -27,5 +39,14 @@ export default function TrendingUsers({ title, count = Infinity }: { title?: Rea
|
||||
return <PageSpinner />;
|
||||
}
|
||||
|
||||
return <FollowListBase pubkeys={trendingUsersData.slice(0, count) as HexKey[]} showAbout={true} title={title} />;
|
||||
return (
|
||||
<FollowListBase
|
||||
pubkeys={trendingUsersData.slice(0, count) as HexKey[]}
|
||||
showAbout={true}
|
||||
title={title}
|
||||
showFollowAll={followAll}
|
||||
actions={actions}
|
||||
profileActions={profileActions}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import "./ZapModal.css";
|
||||
|
||||
import { LNURLSuccessAction } from "@snort/shared";
|
||||
import { HexKey } from "@snort/system";
|
||||
import React, { ReactNode, useEffect, useState } from "react";
|
||||
import { ReactNode, useEffect, useState } from "react";
|
||||
|
||||
import CloseButton from "@/Components/Button/CloseButton";
|
||||
import Modal from "@/Components/Modal/Modal";
|
||||
@ -23,7 +22,6 @@ export interface SendSatsProps {
|
||||
invoice?: string; // shortcut to invoice qr tab
|
||||
title?: ReactNode;
|
||||
notice?: string;
|
||||
note?: HexKey;
|
||||
allocatePool?: boolean;
|
||||
}
|
||||
|
||||
|
27
packages/app/src/Hooks/useLiveStreams.ts
Normal file
27
packages/app/src/Hooks/useLiveStreams.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { unixNow } from "@snort/shared";
|
||||
import { EventKind, RequestBuilder } from "@snort/system";
|
||||
import { useRequestBuilder } from "@snort/system-react";
|
||||
import { useMemo } from "react";
|
||||
|
||||
import { findTag } from "@/Utils";
|
||||
import { Hour } from "@/Utils/Const";
|
||||
|
||||
export default function useLiveStreams() {
|
||||
const sub = useMemo(() => {
|
||||
const rb = new RequestBuilder("streams");
|
||||
rb.withFilter()
|
||||
.kinds([EventKind.LiveEvent])
|
||||
.since(unixNow() - Hour);
|
||||
return rb;
|
||||
}, []);
|
||||
|
||||
return useRequestBuilder(sub)
|
||||
.filter(a => {
|
||||
return findTag(a, "status") === "live";
|
||||
})
|
||||
.sort((a, b) => {
|
||||
const sA = Number(findTag(a, "starts"));
|
||||
const sB = Number(findTag(b, "starts"));
|
||||
return sA > sB ? -1 : 1;
|
||||
});
|
||||
}
|
@ -1,9 +1,15 @@
|
||||
import classNames from "classnames";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
|
||||
import { RightColumnWidget } from "@/Components/RightWidgets";
|
||||
import { BaseWidget } from "@/Components/RightWidgets/base";
|
||||
import InviteFriendsWidget from "@/Components/RightWidgets/invite-friends";
|
||||
import MiniStreamWidget from "@/Components/RightWidgets/mini-stream";
|
||||
import SearchBox from "@/Components/SearchBox/SearchBox";
|
||||
import { TaskList } from "@/Components/Tasks/TaskList";
|
||||
import TrendingHashtags from "@/Components/Trending/TrendingHashtags";
|
||||
import TrendingNotes from "@/Components/Trending/TrendingPosts";
|
||||
import TrendingUsers from "@/Components/Trending/TrendingUsers";
|
||||
import useLogin from "@/Hooks/useLogin";
|
||||
|
||||
export default function RightColumn() {
|
||||
@ -11,16 +17,44 @@ export default function RightColumn() {
|
||||
const hideRightColumnPaths = ["/login", "/new", "/messages"];
|
||||
const show = !hideRightColumnPaths.some(path => globalThis.location.pathname.startsWith(path));
|
||||
|
||||
const getTitleMessage = () => {
|
||||
return pubkey ? (
|
||||
<FormattedMessage defaultMessage="Trending notes" />
|
||||
) : (
|
||||
<FormattedMessage defaultMessage="Trending hashtags" />
|
||||
);
|
||||
};
|
||||
const widgets = pubkey
|
||||
? [
|
||||
RightColumnWidget.TaskList,
|
||||
RightColumnWidget.InviteFriends,
|
||||
//RightColumnWidget.LiveStreams,
|
||||
RightColumnWidget.TrendingNotes,
|
||||
RightColumnWidget.TrendingPeople,
|
||||
RightColumnWidget.TrendingHashtags,
|
||||
]
|
||||
: [RightColumnWidget.TrendingPeople, RightColumnWidget.TrendingHashtags];
|
||||
|
||||
const getContent = () => {
|
||||
return pubkey ? <TrendingNotes small={true} count={100} /> : <TrendingHashtags short={true} />;
|
||||
const getWidget = (t: RightColumnWidget) => {
|
||||
switch (t) {
|
||||
case RightColumnWidget.TaskList:
|
||||
return <TaskList />;
|
||||
case RightColumnWidget.TrendingNotes:
|
||||
return (
|
||||
<BaseWidget title={<FormattedMessage defaultMessage="Trending Notes" />}>
|
||||
<TrendingNotes small={true} count={6} />
|
||||
</BaseWidget>
|
||||
);
|
||||
case RightColumnWidget.TrendingPeople:
|
||||
return (
|
||||
<BaseWidget title={<FormattedMessage defaultMessage="Trending People" />}>
|
||||
<TrendingUsers count={6} followAll={false} profileActions={pubkey ? () => undefined : () => <></>} />
|
||||
</BaseWidget>
|
||||
);
|
||||
case RightColumnWidget.TrendingHashtags:
|
||||
return (
|
||||
<BaseWidget title={<FormattedMessage defaultMessage="Popular Hashtags" />}>
|
||||
<TrendingHashtags short={true} count={6} />
|
||||
</BaseWidget>
|
||||
);
|
||||
case RightColumnWidget.InviteFriends:
|
||||
return <InviteFriendsWidget />;
|
||||
case RightColumnWidget.LiveStreams:
|
||||
return <MiniStreamWidget />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@ -34,8 +68,7 @@ export default function RightColumn() {
|
||||
<div>
|
||||
<SearchBox />
|
||||
</div>
|
||||
<div className="font-bold text-xs mt-4 mb-2 uppercase tracking-wide">{getTitleMessage()}</div>
|
||||
<div className="overflow-y-auto hide-scrollbar flex-grow rounded-lg">{getContent()}</div>
|
||||
<div className="flex flex-col gap-4 overflow-y-auto">{widgets.map(getWidget)}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,39 +1,17 @@
|
||||
import { EventKind, NostrEvent, RequestBuilder, TaggedNostrEvent } from "@snort/system";
|
||||
import { WorkerRelayInterface } from "@snort/worker-relay";
|
||||
import { memo, useEffect, useMemo, useState } from "react";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { Link, useNavigationType } from "react-router-dom";
|
||||
import { useNavigationType } from "react-router-dom";
|
||||
|
||||
import { Relay } from "@/Cache";
|
||||
import { DisplayAs, DisplayAsSelector } from "@/Components/Feed/DisplayAsSelector";
|
||||
import { TimelineRenderer } from "@/Components/Feed/TimelineRenderer";
|
||||
import { TaskList } from "@/Components/Tasks/TaskList";
|
||||
import useTimelineFeed, { TimelineFeedOptions, TimelineSubject } from "@/Feed/TimelineFeed";
|
||||
import useFollowsControls from "@/Hooks/useFollowControls";
|
||||
import useHistoryState from "@/Hooks/useHistoryState";
|
||||
import useLogin from "@/Hooks/useLogin";
|
||||
import messages from "@/Pages/messages";
|
||||
import { System } from "@/system";
|
||||
|
||||
const FollowsHint = () => {
|
||||
const publicKey = useLogin(s => s.publicKey);
|
||||
const { followList } = useFollowsControls();
|
||||
if (followList.length === 0 && publicKey) {
|
||||
return (
|
||||
<FormattedMessage
|
||||
{...messages.NoFollows}
|
||||
values={{
|
||||
newUsersPage: (
|
||||
<Link to={"/discover"}>
|
||||
<FormattedMessage {...messages.NewUsers} />
|
||||
</Link>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let forYouFeed = {
|
||||
events: [] as NostrEvent[],
|
||||
created_at: 0,
|
||||
@ -180,8 +158,6 @@ export const ForYouTab = memo(function ForYouTab() {
|
||||
return (
|
||||
<>
|
||||
<DisplayAsSelector activeSelection={displayAs} onSelect={a => setDisplayAs(a)} />
|
||||
<FollowsHint />
|
||||
<TaskList />
|
||||
<TimelineRenderer
|
||||
frags={frags}
|
||||
latest={[]}
|
||||
|
@ -2,7 +2,6 @@ import { NostrEvent, NostrLink } from "@snort/system";
|
||||
import { useContext, useMemo } from "react";
|
||||
|
||||
import TimelineFollows from "@/Components/Feed/TimelineFollows";
|
||||
import { TaskList } from "@/Components/Tasks/TaskList";
|
||||
import { DeckContext } from "@/Pages/Deck/DeckLayout";
|
||||
|
||||
export const NotesTab = () => {
|
||||
@ -18,10 +17,5 @@ export const NotesTab = () => {
|
||||
return undefined;
|
||||
}, [deckContext]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<TaskList />
|
||||
<TimelineFollows postsOnly={true} noteOnClick={noteOnClick} />
|
||||
</>
|
||||
);
|
||||
return <TimelineFollows postsOnly={true} noteOnClick={noteOnClick} />;
|
||||
};
|
||||
|
@ -306,9 +306,6 @@
|
||||
"6ewQqw": {
|
||||
"defaultMessage": "Likes ({n})"
|
||||
},
|
||||
"6k7xfM": {
|
||||
"defaultMessage": "Trending notes"
|
||||
},
|
||||
"6mr8WU": {
|
||||
"defaultMessage": "Followed by"
|
||||
},
|
||||
@ -506,9 +503,6 @@
|
||||
"CYkOCI": {
|
||||
"defaultMessage": "and {count} others you follow"
|
||||
},
|
||||
"CbM2hK": {
|
||||
"defaultMessage": "Trending hashtags"
|
||||
},
|
||||
"CmZ9ls": {
|
||||
"defaultMessage": "{n} Muted"
|
||||
},
|
||||
@ -1151,6 +1145,9 @@
|
||||
"UrKTqQ": {
|
||||
"defaultMessage": "You have an active iris.to account"
|
||||
},
|
||||
"UsCzPc": {
|
||||
"defaultMessage": "Share a personalized invitation with friends!"
|
||||
},
|
||||
"UxgyeY": {
|
||||
"defaultMessage": "Your referral code is {code}"
|
||||
},
|
||||
@ -1307,6 +1304,9 @@
|
||||
"abbGKq": {
|
||||
"defaultMessage": "{n} km"
|
||||
},
|
||||
"ak3MTf": {
|
||||
"defaultMessage": "Invite Friends"
|
||||
},
|
||||
"b12Goz": {
|
||||
"defaultMessage": "Mnemonic"
|
||||
},
|
||||
@ -1407,6 +1407,9 @@
|
||||
"dOQCL8": {
|
||||
"defaultMessage": "Display name"
|
||||
},
|
||||
"ddd3JX": {
|
||||
"defaultMessage": "Popular Hashtags"
|
||||
},
|
||||
"deEeEI": {
|
||||
"defaultMessage": "Register"
|
||||
},
|
||||
@ -1701,6 +1704,9 @@
|
||||
"lTbT3s": {
|
||||
"defaultMessage": "Wallet password"
|
||||
},
|
||||
"lbr3Lq": {
|
||||
"defaultMessage": "Copy link"
|
||||
},
|
||||
"lfOesV": {
|
||||
"defaultMessage": "Non-Zap"
|
||||
},
|
||||
|
@ -101,7 +101,6 @@
|
||||
"6WWD34": "Looking for: {noteId}",
|
||||
"6bgpn+": "Not all clients support this, you may still receive some zaps as if zap splits was not configured",
|
||||
"6ewQqw": "Likes ({n})",
|
||||
"6k7xfM": "Trending notes",
|
||||
"6mr8WU": "Followed by",
|
||||
"6pdxsi": "Extra metadata fields and tags",
|
||||
"6uMqL1": "Unpaid",
|
||||
@ -167,7 +166,6 @@
|
||||
"CM0k0d": "Prune follow list",
|
||||
"CVWeJ6": "Trending People",
|
||||
"CYkOCI": "and {count} others you follow",
|
||||
"CbM2hK": "Trending hashtags",
|
||||
"CmZ9ls": "{n} Muted",
|
||||
"CsCUYo": "{n} sats",
|
||||
"Cu/K85": "Translated from {lang}",
|
||||
@ -381,6 +379,7 @@
|
||||
"Up5U7K": "Block",
|
||||
"Ups2/p": "Your application is pending",
|
||||
"UrKTqQ": "You have an active iris.to account",
|
||||
"UsCzPc": "Share a personalized invitation with friends!",
|
||||
"UxgyeY": "Your referral code is {code}",
|
||||
"V20Og0": "Labeling",
|
||||
"VOjC1i": "Pick which upload service you want to upload attachments to",
|
||||
@ -433,6 +432,7 @@
|
||||
"aSGz4J": "Connect to your own LND node with Lightning Node Connect",
|
||||
"aWpBzj": "Show more",
|
||||
"abbGKq": "{n} km",
|
||||
"ak3MTf": "Invite Friends",
|
||||
"b12Goz": "Mnemonic",
|
||||
"b5vAk0": "Your handle will act like a lightning address and will redirect to your chosen LNURL or Lightning address",
|
||||
"bF1MYT": "You are a community leader and are earning <b>{percent}</b> of referred users subscriptions!",
|
||||
@ -466,6 +466,7 @@
|
||||
"d7d0/x": "LN Address",
|
||||
"dK2CcV": "The public key is like your username, you can share it with anyone.",
|
||||
"dOQCL8": "Display name",
|
||||
"ddd3JX": "Popular Hashtags",
|
||||
"deEeEI": "Register",
|
||||
"djLctd": "Amount in sats",
|
||||
"djNL6D": "Read-only",
|
||||
@ -564,6 +565,7 @@
|
||||
"lEnclp": "My events: {n}",
|
||||
"lPWASz": "Snort nostr address",
|
||||
"lTbT3s": "Wallet password",
|
||||
"lbr3Lq": "Copy link",
|
||||
"lfOesV": "Non-Zap",
|
||||
"lgg1KN": "account page",
|
||||
"ll3xBp": "Image proxy service",
|
||||
|
Loading…
Reference in New Issue
Block a user