forked from Kieran/snort
feat: sign up flow v2
This commit is contained in:
parent
a2bcb936ef
commit
d119a5f626
@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from "react";
|
import { ReactNode, useEffect, useState } from "react";
|
||||||
import { HexKey } from "@snort/system";
|
import { HexKey } from "@snort/system";
|
||||||
|
|
||||||
import FollowListBase from "Element/User/FollowListBase";
|
import FollowListBase from "Element/User/FollowListBase";
|
||||||
@ -6,7 +6,7 @@ import PageSpinner from "Element/PageSpinner";
|
|||||||
import NostrBandApi from "External/NostrBand";
|
import NostrBandApi from "External/NostrBand";
|
||||||
import { ErrorOrOffline } from "./ErrorOrOffline";
|
import { ErrorOrOffline } from "./ErrorOrOffline";
|
||||||
|
|
||||||
export default function TrendingUsers() {
|
export default function TrendingUsers({ title }: { title?: ReactNode }) {
|
||||||
const [userList, setUserList] = useState<HexKey[]>();
|
const [userList, setUserList] = useState<HexKey[]>();
|
||||||
const [error, setError] = useState<Error>();
|
const [error, setError] = useState<Error>();
|
||||||
|
|
||||||
@ -28,5 +28,5 @@ export default function TrendingUsers() {
|
|||||||
if (error) return <ErrorOrOffline error={error} onRetry={loadTrendingUsers} className="p" />;
|
if (error) return <ErrorOrOffline error={error} onRetry={loadTrendingUsers} className="p" />;
|
||||||
if (!userList) return <PageSpinner />;
|
if (!userList) return <PageSpinner />;
|
||||||
|
|
||||||
return <FollowListBase pubkeys={userList} showAbout={true} />;
|
return <FollowListBase pubkeys={userList} showAbout={true} title={title} />;
|
||||||
}
|
}
|
||||||
|
@ -45,19 +45,21 @@ export default function FollowListBase({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className="flex flex-col g8">
|
||||||
{(showFollowAll ?? true) && (
|
{(showFollowAll ?? true) && (
|
||||||
<div className="flex mt10 mb10">
|
<div className="flex items-center">
|
||||||
<div className="grow bold">{title}</div>
|
<div className="grow font-bold">{title}</div>
|
||||||
{actions}
|
{actions}
|
||||||
<AsyncButton className="transparent" type="button" onClick={() => followAll()} disabled={login.readonly}>
|
<AsyncButton className="transparent" type="button" onClick={() => followAll()} disabled={login.readonly}>
|
||||||
<FormattedMessage {...messages.FollowAll} />
|
<FormattedMessage {...messages.FollowAll} />
|
||||||
</AsyncButton>
|
</AsyncButton>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<div className={className}>
|
||||||
{pubkeys?.map(a => (
|
{pubkeys?.map(a => (
|
||||||
<ProfilePreview pubkey={a} key={a} options={{ about: showAbout }} actions={profileActions?.(a)} />
|
<ProfilePreview pubkey={a} key={a} options={{ about: showAbout }} actions={profileActions?.(a)} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ export default function ProfilePreview(props: ProfilePreviewProps) {
|
|||||||
showProfileCard={options.profileCards}
|
showProfileCard={options.profileCards}
|
||||||
/>
|
/>
|
||||||
{props.actions ?? (
|
{props.actions ?? (
|
||||||
<div className="follow-button-container">
|
<div className="whitespace-nowrap">
|
||||||
<FollowButton pubkey={pubkey} />
|
<FollowButton pubkey={pubkey} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { useEffect, useState, type ReactNode } from "react";
|
import { useEffect, useState, type ReactNode, useSyncExternalStore } from "react";
|
||||||
import { IntlProvider as ReactIntlProvider } from "react-intl";
|
import { IntlProvider as ReactIntlProvider } from "react-intl";
|
||||||
|
|
||||||
import enMessages from "translations/en.json";
|
import enMessages from "translations/en.json";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
|
import { ExternalStore } from "@snort/shared";
|
||||||
|
|
||||||
const DefaultLocale = "en-US";
|
const DefaultLocale = "en-US";
|
||||||
|
|
||||||
@ -80,9 +81,35 @@ const getMessages = (locale: string) => {
|
|||||||
return matchLang(locale) ?? matchLang(truncatedLocale) ?? Promise.resolve(enMessages);
|
return matchLang(locale) ?? matchLang(truncatedLocale) ?? Promise.resolve(enMessages);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IntlProvider = ({ children }: { children: ReactNode }) => {
|
class LangStore extends ExternalStore<string> {
|
||||||
|
setLang(s: string) {
|
||||||
|
localStorage.setItem("lang", s);
|
||||||
|
this.notifyChange();
|
||||||
|
}
|
||||||
|
|
||||||
|
takeSnapshot(): string {
|
||||||
|
return localStorage.getItem("lang") ?? DefaultLocale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const LangOverride = new LangStore();
|
||||||
|
|
||||||
|
export function useLocale() {
|
||||||
const { language } = useLogin(s => ({ language: s.preferences.language }));
|
const { language } = useLogin(s => ({ language: s.preferences.language }));
|
||||||
const locale = language ?? getLocale();
|
const loggedOutLang = useSyncExternalStore(
|
||||||
|
c => LangOverride.hook(c),
|
||||||
|
() => LangOverride.snapshot(),
|
||||||
|
);
|
||||||
|
const locale = language ?? loggedOutLang ?? getLocale();
|
||||||
|
return {
|
||||||
|
locale,
|
||||||
|
lang: locale.toLowerCase().split(/[_-]+/)[0],
|
||||||
|
setOverride: (s: string) => LangOverride.setLang(s),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const IntlProvider = ({ children }: { children: ReactNode }) => {
|
||||||
|
const { locale } = useLocale();
|
||||||
const [messages, setMessages] = useState<Record<string, string>>(enMessages);
|
const [messages, setMessages] = useState<Record<string, string>>(enMessages);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -93,7 +120,7 @@ export const IntlProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
}, [language]);
|
}, [locale]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactIntlProvider locale={locale} messages={messages}>
|
<ReactIntlProvider locale={locale} messages={messages}>
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
PrivateKeySigner,
|
PrivateKeySigner,
|
||||||
KeyStorage,
|
KeyStorage,
|
||||||
SystemInterface,
|
SystemInterface,
|
||||||
|
UserMetadata,
|
||||||
} from "@snort/system";
|
} from "@snort/system";
|
||||||
import { unixNowMs } from "@snort/shared";
|
import { unixNowMs } from "@snort/shared";
|
||||||
import * as secp from "@noble/curves/secp256k1";
|
import * as secp from "@noble/curves/secp256k1";
|
||||||
@ -79,7 +80,11 @@ export function clearEntropy(state: LoginSession) {
|
|||||||
/**
|
/**
|
||||||
* Generate a new key and login with this generated key
|
* Generate a new key and login with this generated key
|
||||||
*/
|
*/
|
||||||
export async function generateNewLogin(system: SystemInterface, pin: (key: string) => Promise<KeyStorage>) {
|
export async function generateNewLogin(
|
||||||
|
system: SystemInterface,
|
||||||
|
pin: (key: string) => Promise<KeyStorage>,
|
||||||
|
profile: UserMetadata,
|
||||||
|
) {
|
||||||
const ent = generateBip39Entropy();
|
const ent = generateBip39Entropy();
|
||||||
const entropy = utils.bytesToHex(ent);
|
const entropy = utils.bytesToHex(ent);
|
||||||
const privateKey = entropyToPrivateKey(ent);
|
const privateKey = entropyToPrivateKey(ent);
|
||||||
@ -99,6 +104,10 @@ export async function generateNewLogin(system: SystemInterface, pin: (key: strin
|
|||||||
const ev2 = await publisher.relayList(newRelays);
|
const ev2 = await publisher.relayList(newRelays);
|
||||||
await system.BroadcastEvent(ev2);
|
await system.BroadcastEvent(ev2);
|
||||||
|
|
||||||
|
// Publish new profile
|
||||||
|
const ev3 = await publisher.metadata(profile);
|
||||||
|
await system.BroadcastEvent(ev3);
|
||||||
|
|
||||||
LoginStore.loginWithPrivateKey(await pin(privateKey), entropy, newRelays);
|
LoginStore.loginWithPrivateKey(await pin(privateKey), entropy, newRelays);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,388 +0,0 @@
|
|||||||
import "./LoginPage.css";
|
|
||||||
|
|
||||||
import { CSSProperties, useEffect, useState } from "react";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import { useIntl, FormattedMessage } from "react-intl";
|
|
||||||
import { HexKey, Nip46Signer, NotEncrypted, PinEncrypted, PrivateKeySigner } from "@snort/system";
|
|
||||||
|
|
||||||
import { bech32ToHex, getPublicKey, unwrap } from "SnortUtils";
|
|
||||||
import ZapButton from "Element/Event/ZapButton";
|
|
||||||
import useImgProxy from "Hooks/useImgProxy";
|
|
||||||
import Icon from "Icons/Icon";
|
|
||||||
import { generateNewLogin, LoginSessionType, LoginStore } from "Login";
|
|
||||||
import AsyncButton from "Element/AsyncButton";
|
|
||||||
import useLoginHandler from "Hooks/useLoginHandler";
|
|
||||||
import { secp256k1 } from "@noble/curves/secp256k1";
|
|
||||||
import { bytesToHex } from "@noble/curves/abstract/utils";
|
|
||||||
import Modal from "Element/Modal";
|
|
||||||
import QrCode from "Element/QrCode";
|
|
||||||
import Copy from "Element/Copy";
|
|
||||||
import { delay } from "SnortUtils";
|
|
||||||
import { PinPrompt } from "Element/PinPrompt";
|
|
||||||
import useEventPublisher from "Hooks/useEventPublisher";
|
|
||||||
import { isHex } from "@snort/shared";
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
interface Window {
|
|
||||||
plausible?: (tag: string) => void;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ArtworkEntry {
|
|
||||||
name: string;
|
|
||||||
pubkey: HexKey;
|
|
||||||
link: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const KarnageKey = bech32ToHex("npub1r0rs5q2gk0e3dk3nlc7gnu378ec6cnlenqp8a3cjhyzu6f8k5sgs4sq9ac");
|
|
||||||
|
|
||||||
// todo: fill more
|
|
||||||
const Artwork: Array<ArtworkEntry> = [
|
|
||||||
{
|
|
||||||
name: "",
|
|
||||||
pubkey: KarnageKey,
|
|
||||||
link: "https://void.cat/d/VKhPayp9ekeXYZGzAL9CxP",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "",
|
|
||||||
pubkey: KarnageKey,
|
|
||||||
link: "https://void.cat/d/3H2h8xxc3aEN6EVeobd8tw",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "",
|
|
||||||
pubkey: KarnageKey,
|
|
||||||
link: "https://void.cat/d/7i9W9PXn3TV86C4RUefNC9",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "",
|
|
||||||
pubkey: KarnageKey,
|
|
||||||
link: "https://void.cat/d/KtoX4ei6RYHY7HESg3Ve3k",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function LoginPage() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const [key, setKey] = useState("");
|
|
||||||
const [nip46Key, setNip46Key] = useState("");
|
|
||||||
const [error, setError] = useState("");
|
|
||||||
const [pin, setPin] = useState(false);
|
|
||||||
const [art, setArt] = useState<ArtworkEntry>();
|
|
||||||
const [isMasking, setMasking] = useState(true);
|
|
||||||
const { formatMessage } = useIntl();
|
|
||||||
const { proxy } = useImgProxy();
|
|
||||||
const loginHandler = useLoginHandler();
|
|
||||||
const hasNip7 = "nostr" in window;
|
|
||||||
const { system } = useEventPublisher();
|
|
||||||
const hasSubtleCrypto = window.crypto.subtle !== undefined;
|
|
||||||
const [nostrConnect, setNostrConnect] = useState("");
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const ret = unwrap(Artwork.at(Artwork.length * Math.random()));
|
|
||||||
const url = proxy(ret.link);
|
|
||||||
setArt({ ...ret, link: url });
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
async function makeKeyStore(key: string, pin?: string) {
|
|
||||||
if (pin) {
|
|
||||||
return await PinEncrypted.create(key, pin);
|
|
||||||
} else {
|
|
||||||
return new NotEncrypted(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function doLogin(pin?: string) {
|
|
||||||
setError("");
|
|
||||||
try {
|
|
||||||
await loginHandler.doLogin(key, key => makeKeyStore(key, pin));
|
|
||||||
navigate("/");
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof Error) {
|
|
||||||
setError(e.message);
|
|
||||||
} else {
|
|
||||||
setError(
|
|
||||||
formatMessage({
|
|
||||||
defaultMessage: "Unknown login error",
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function makeRandomKey(pin?: string) {
|
|
||||||
try {
|
|
||||||
await generateNewLogin(system, key => makeKeyStore(key, pin));
|
|
||||||
window.plausible?.("Generate Account");
|
|
||||||
navigate("/new");
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof Error) {
|
|
||||||
setError(e.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function doNip07Login() {
|
|
||||||
const relays =
|
|
||||||
"getRelays" in unwrap(window.nostr) ? await unwrap(window.nostr?.getRelays).call(window.nostr) : undefined;
|
|
||||||
const pubKey = await unwrap(window.nostr).getPublicKey();
|
|
||||||
LoginStore.loginWithPubkey(pubKey, LoginSessionType.Nip7, relays);
|
|
||||||
navigate("/");
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateNip46() {
|
|
||||||
const meta = {
|
|
||||||
name: CONFIG.appNameCapitalized,
|
|
||||||
url: window.location.href,
|
|
||||||
};
|
|
||||||
|
|
||||||
const newKey = bytesToHex(secp256k1.utils.randomPrivateKey());
|
|
||||||
const relays = ["wss://relay.damus.io"].map(a => `relay=${encodeURIComponent(a)}`);
|
|
||||||
const connectUrl = `nostrconnect://${getPublicKey(newKey)}?${[
|
|
||||||
...relays,
|
|
||||||
`metadata=${encodeURIComponent(JSON.stringify(meta))}`,
|
|
||||||
].join("&")}`;
|
|
||||||
setNostrConnect(connectUrl);
|
|
||||||
setNip46Key(newKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function startNip46(pin?: string) {
|
|
||||||
if (!nostrConnect || !nip46Key) return;
|
|
||||||
|
|
||||||
const signer = new Nip46Signer(nostrConnect, new PrivateKeySigner(nip46Key));
|
|
||||||
await signer.init();
|
|
||||||
await delay(500);
|
|
||||||
await signer.describe();
|
|
||||||
LoginStore.loginWithPubkey(
|
|
||||||
await signer.getPubKey(),
|
|
||||||
LoginSessionType.Nip46,
|
|
||||||
undefined,
|
|
||||||
["wss://relay.damus.io"],
|
|
||||||
await makeKeyStore(nip46Key, pin),
|
|
||||||
);
|
|
||||||
navigate("/");
|
|
||||||
}
|
|
||||||
|
|
||||||
function nip46Buttons() {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<AsyncButton
|
|
||||||
type="button"
|
|
||||||
onClick={() => {
|
|
||||||
generateNip46();
|
|
||||||
setPin(true);
|
|
||||||
}}>
|
|
||||||
<FormattedMessage defaultMessage="Nostr Connect" description="Login button for NIP-46 signer app" />
|
|
||||||
</AsyncButton>
|
|
||||||
{nostrConnect && !pin && (
|
|
||||||
<Modal id="nostr-connect" onClose={() => setNostrConnect("")}>
|
|
||||||
<>
|
|
||||||
<h2>
|
|
||||||
<FormattedMessage defaultMessage="Nostr Connect" />
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage defaultMessage="Scan this QR code with your signer app to get started" />
|
|
||||||
</p>
|
|
||||||
<div className="flex flex-col items-center g12">
|
|
||||||
<QrCode data={nostrConnect} />
|
|
||||||
<Copy text={nostrConnect} />
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
</Modal>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function altLogins() {
|
|
||||||
if (!hasNip7) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<AsyncButton type="button" onClick={doNip07Login}>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Nostr Extension"
|
|
||||||
description="Login button for NIP7 key manager extension"
|
|
||||||
/>
|
|
||||||
</AsyncButton>
|
|
||||||
{nip46Buttons()}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function installExtension() {
|
|
||||||
if (hasSubtleCrypto) return;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="flex login-or">
|
|
||||||
<FormattedMessage defaultMessage="OR" description="Seperator text for Login / Generate Key" />
|
|
||||||
<div className="divider w-max"></div>
|
|
||||||
</div>
|
|
||||||
<h1 dir="auto">
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Install Extension"
|
|
||||||
description="Heading for install key manager extension"
|
|
||||||
/>
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage defaultMessage="Key manager extensions are more secure and allow you to easily login to any Nostr client, here are some well known extensions:" />
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="https://getalby.com/" target="_blank" rel="noreferrer">
|
|
||||||
Alby
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="https://chrome.google.com/webstore/detail/nos2x/kpgefcfmnafjgpblomihpgmejjdanjjp"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer">
|
|
||||||
nos2x
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="If you want to try out some others, check out {link} for more!"
|
|
||||||
values={{
|
|
||||||
link: <a href="https://github.com/aljazceru/awesome-nostr#browser-extensions">awesome-nostr</a>,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage defaultMessage="Once you setup your key manager extension and generated a key, you can follow our new users flow to setup your profile and help you find some interesting people on Nostr to follow." />
|
|
||||||
</p>
|
|
||||||
{hasNip7 ? (
|
|
||||||
<div className="login-actions">
|
|
||||||
<button type="button" onClick={() => doNip07Login().then(() => navigate("/new/username"))}>
|
|
||||||
<FormattedMessage defaultMessage="Setup Profile" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<b className="error">
|
|
||||||
<FormattedMessage defaultMessage="Hmm, can't find a key manager extension.. try reloading the page." />
|
|
||||||
</b>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="login">
|
|
||||||
<div>
|
|
||||||
<div className="login-container">
|
|
||||||
<h1 className="logo" onClick={() => navigate("/")}>
|
|
||||||
{CONFIG.appName}
|
|
||||||
</h1>
|
|
||||||
<h1 dir="auto">
|
|
||||||
<FormattedMessage defaultMessage="Login" description="Login header" />
|
|
||||||
</h1>
|
|
||||||
<p dir="auto">
|
|
||||||
<FormattedMessage defaultMessage="Your key" description="Label for key input" />
|
|
||||||
</p>
|
|
||||||
<div className="flex items-center g8">
|
|
||||||
<input
|
|
||||||
dir="auto"
|
|
||||||
type={isMasking ? "password" : "text"}
|
|
||||||
placeholder={formatMessage({
|
|
||||||
defaultMessage: "nsec, npub, nip-05, hex, mnemonic",
|
|
||||||
})}
|
|
||||||
className="grow"
|
|
||||||
onChange={e => setKey(e.target.value)}
|
|
||||||
/>
|
|
||||||
<Icon
|
|
||||||
name={isMasking ? "openeye" : "closedeye"}
|
|
||||||
size={30}
|
|
||||||
className="highlight pointer"
|
|
||||||
onClick={() => setMasking(!isMasking)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{error.length > 0 ? <b className="error">{error}</b> : null}
|
|
||||||
<p>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Only the secret key can be used to publish (sign events), everything else logs you in read-only mode."
|
|
||||||
description="Explanation for public key only login is read-only"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
<div dir="auto" className="login-actions">
|
|
||||||
<AsyncButton
|
|
||||||
type="button"
|
|
||||||
onClick={async () => {
|
|
||||||
if (key.startsWith("nsec") || (key.length === 64 && isHex(key))) {
|
|
||||||
setPin(true);
|
|
||||||
} else {
|
|
||||||
await doLogin();
|
|
||||||
}
|
|
||||||
}}>
|
|
||||||
<FormattedMessage defaultMessage="Login" description="Login button" />
|
|
||||||
</AsyncButton>
|
|
||||||
<AsyncButton onClick={() => setPin(true)}>
|
|
||||||
<FormattedMessage defaultMessage="Create Account" />
|
|
||||||
</AsyncButton>
|
|
||||||
{pin && (
|
|
||||||
<PinPrompt
|
|
||||||
subTitle={
|
|
||||||
<>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Secure your private key with a PIN, ensuring enhanced protection on {site}. You'll be prompted to enter this PIN each time you access the site."
|
|
||||||
values={{
|
|
||||||
site: CONFIG.appNameCapitalized,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage defaultMessage="Alternatively, you may choose to store your private key without a PIN by selecting 'Cancel.'" />
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage defaultMessage="After submitting the pin there may be a slight delay as we encrypt the key." />
|
|
||||||
</p>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
onResult={async pin => {
|
|
||||||
setPin(false);
|
|
||||||
if (key) {
|
|
||||||
await doLogin(pin);
|
|
||||||
} else if (nostrConnect) {
|
|
||||||
await startNip46(pin);
|
|
||||||
} else {
|
|
||||||
await makeRandomKey(pin);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onCancel={async () => {
|
|
||||||
setPin(false);
|
|
||||||
if (key) {
|
|
||||||
await doLogin();
|
|
||||||
} else if (nostrConnect) {
|
|
||||||
await startNip46();
|
|
||||||
} else {
|
|
||||||
await makeRandomKey();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{altLogins()}
|
|
||||||
</div>
|
|
||||||
{installExtension()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div className="artwork" style={{ ["--img-src"]: `url('${art?.link}')` } as CSSProperties}>
|
|
||||||
<div className="attribution">
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Art by {name}"
|
|
||||||
description="Artwork attribution label"
|
|
||||||
values={{
|
|
||||||
name: <span className="artist">Karnage</span>,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<ZapButton pubkey={art?.pubkey ?? ""} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,55 +0,0 @@
|
|||||||
import { useIntl, FormattedMessage } from "react-intl";
|
|
||||||
import { useNavigate, Link } from "react-router-dom";
|
|
||||||
|
|
||||||
import { DeveloperAccounts } from "Const";
|
|
||||||
import Logo from "Element/Logo";
|
|
||||||
import FollowListBase from "Element/User/FollowListBase";
|
|
||||||
import { clearEntropy } from "Login";
|
|
||||||
import useLogin from "Hooks/useLogin";
|
|
||||||
import TrendingUsers from "Element/TrendingUsers";
|
|
||||||
|
|
||||||
import messages from "./messages";
|
|
||||||
|
|
||||||
export default function DiscoverFollows() {
|
|
||||||
const { formatMessage } = useIntl();
|
|
||||||
const login = useLogin();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
async function clearEntropyAndGo() {
|
|
||||||
clearEntropy(login);
|
|
||||||
navigate("/");
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="main-content new-user p" dir="auto">
|
|
||||||
<Logo />
|
|
||||||
<div className="progress-bar">
|
|
||||||
<div className="progress"></div>
|
|
||||||
</div>
|
|
||||||
<h1>
|
|
||||||
<FormattedMessage {...messages.Ready} />
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage {...messages.Share} values={{ link: <Link to="/">{formatMessage(messages.World)}</Link> }} />
|
|
||||||
</p>
|
|
||||||
<div className="next-actions continue-actions">
|
|
||||||
<button type="button" onClick={() => clearEntropyAndGo()}>
|
|
||||||
<FormattedMessage {...messages.Done} />{" "}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<h3>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="{site_name} Developers"
|
|
||||||
values={{
|
|
||||||
site_name: CONFIG.appNameCapitalized,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</h3>
|
|
||||||
{DeveloperAccounts.length > 0 && <FollowListBase pubkeys={DeveloperAccounts} showAbout={true} />}
|
|
||||||
<h3>
|
|
||||||
<FormattedMessage defaultMessage="Trending Users" />
|
|
||||||
</h3>
|
|
||||||
<TrendingUsers />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,115 +0,0 @@
|
|||||||
import { useState } from "react";
|
|
||||||
import { FormattedMessage } from "react-intl";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import { useUserProfile } from "@snort/system-react";
|
|
||||||
|
|
||||||
import Logo from "Element/Logo";
|
|
||||||
import { Nip5Services } from "Pages/NostrAddressPage";
|
|
||||||
import Nip5Service from "Element/Nip5Service";
|
|
||||||
import ProfileImage from "Element/User/ProfileImage";
|
|
||||||
import useLogin from "Hooks/useLogin";
|
|
||||||
|
|
||||||
import messages from "./messages";
|
|
||||||
|
|
||||||
export default function GetVerified() {
|
|
||||||
const navigate = useNavigate();
|
|
||||||
const { publicKey } = useLogin();
|
|
||||||
const user = useUserProfile(publicKey);
|
|
||||||
const [isVerified, setIsVerified] = useState(false);
|
|
||||||
const name = user?.name || "nostrich";
|
|
||||||
const [nip05, setNip05] = useState(`${name}@snort.social`);
|
|
||||||
|
|
||||||
const onNext = async () => {
|
|
||||||
navigate("/new/import");
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="main-content new-user" dir="auto">
|
|
||||||
<Logo />
|
|
||||||
<div className="progress-bar">
|
|
||||||
<div className="progress progress-third"></div>
|
|
||||||
</div>
|
|
||||||
<h1>
|
|
||||||
<FormattedMessage {...messages.Identifier} />
|
|
||||||
</h1>
|
|
||||||
<div className="next-actions continue-actions">
|
|
||||||
<button className="secondary" type="button" onClick={onNext}>
|
|
||||||
<FormattedMessage {...messages.Skip} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<h4>
|
|
||||||
<FormattedMessage {...messages.PreviewOnSnort} />
|
|
||||||
</h4>
|
|
||||||
<div className="profile-preview-nip">
|
|
||||||
{publicKey && <ProfileImage pubkey={publicKey} defaultNip={nip05} verifyNip={false} />}
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage {...messages.IdentifierHelp} />
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<FormattedMessage {...messages.PreventFakes} />
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<FormattedMessage {...messages.EasierToFind} />
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<FormattedMessage {...messages.Funding} />
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p className="warning">
|
|
||||||
<FormattedMessage {...messages.NameSquatting} />
|
|
||||||
</p>
|
|
||||||
{!isVerified && (
|
|
||||||
<>
|
|
||||||
<h2>
|
|
||||||
<FormattedMessage {...messages.GetSnortId} />
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage {...messages.GetSnortIdHelp} />
|
|
||||||
</p>
|
|
||||||
<div className="nip-container">
|
|
||||||
<Nip5Service
|
|
||||||
key="snort"
|
|
||||||
{...Nip5Services[0]}
|
|
||||||
helpText={false}
|
|
||||||
onChange={setNip05}
|
|
||||||
onSuccess={() => setIsVerified(true)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{!isVerified && (
|
|
||||||
<>
|
|
||||||
<h2>
|
|
||||||
<FormattedMessage {...messages.GetPartnerId} />
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage {...messages.GetPartnerIdHelp} />
|
|
||||||
</p>
|
|
||||||
<div className="nip-container">
|
|
||||||
<Nip5Service
|
|
||||||
key="nostrplebs"
|
|
||||||
{...Nip5Services[1]}
|
|
||||||
helpText={false}
|
|
||||||
onChange={setNip05}
|
|
||||||
onSuccess={() => setIsVerified(true)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<div className="next-actions">
|
|
||||||
{!isVerified && (
|
|
||||||
<button type="button" className="transparent" onClick={onNext}>
|
|
||||||
<FormattedMessage {...messages.Skip} />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{isVerified && (
|
|
||||||
<button type="button" onClick={onNext}>
|
|
||||||
<FormattedMessage {...messages.Next} />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,147 +0,0 @@
|
|||||||
import { FormattedMessage } from "react-intl";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
|
|
||||||
import Logo from "Element/Logo";
|
|
||||||
import { CollapsedSection } from "Element/Collapsed";
|
|
||||||
import useLogin from "Hooks/useLogin";
|
|
||||||
import { PROFILE } from ".";
|
|
||||||
import { DefaultPreferences, LoginStore, updatePreferences } from "Login";
|
|
||||||
import { AllLanguageCodes } from "Pages/settings/Preferences";
|
|
||||||
|
|
||||||
import messages from "./messages";
|
|
||||||
import ExportKeys from "Pages/settings/Keys";
|
|
||||||
|
|
||||||
const WhatIsSnort = () => {
|
|
||||||
return (
|
|
||||||
<CollapsedSection
|
|
||||||
title={
|
|
||||||
<h3>
|
|
||||||
<FormattedMessage {...messages.WhatIsSnort} />
|
|
||||||
</h3>
|
|
||||||
}>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage {...messages.WhatIsSnortIntro} />
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage {...messages.WhatIsSnortNotes} />
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage {...messages.WhatIsSnortExperience} />
|
|
||||||
</p>
|
|
||||||
</CollapsedSection>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const HowDoKeysWork = () => {
|
|
||||||
return (
|
|
||||||
<CollapsedSection
|
|
||||||
title={
|
|
||||||
<h3>
|
|
||||||
<FormattedMessage {...messages.HowKeysWork} />
|
|
||||||
</h3>
|
|
||||||
}>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage {...messages.DigitalSignatures} />
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage {...messages.TamperProof} />
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage {...messages.Bitcoin} />
|
|
||||||
</p>
|
|
||||||
</CollapsedSection>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Extensions = () => {
|
|
||||||
const { preferences } = useLogin();
|
|
||||||
return (
|
|
||||||
<CollapsedSection
|
|
||||||
title={
|
|
||||||
<h3>
|
|
||||||
<FormattedMessage {...messages.ImproveSecurity} />
|
|
||||||
</h3>
|
|
||||||
}>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage {...messages.Extensions} />
|
|
||||||
</p>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a href="https://getalby.com/" target="_blank" rel="noreferrer">
|
|
||||||
Alby
|
|
||||||
</a>
|
|
||||||
{(preferences.language === "ru" || preferences.language === "ru-RU") && (
|
|
||||||
<a href="https://nostr.21ideas.org/docs/guides/Alby.html" target="_blank" rel="noreferrer">
|
|
||||||
(Tony's Guide)
|
|
||||||
</a>
|
|
||||||
)}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://github.com/fiatjaf/nos2x" target="_blank" rel="noreferrer">
|
|
||||||
nos2x
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage {...messages.ExtensionsNostr} />
|
|
||||||
</p>
|
|
||||||
</CollapsedSection>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function NewUserFlow() {
|
|
||||||
const login = useLogin();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="main-content new-user p" dir="auto">
|
|
||||||
<Logo />
|
|
||||||
<div className="progress-bar">
|
|
||||||
<div className="progress progress-first"></div>
|
|
||||||
</div>
|
|
||||||
<h1>
|
|
||||||
<FormattedMessage {...messages.SaveKeys} />
|
|
||||||
</h1>
|
|
||||||
<div className="flex justify-between">
|
|
||||||
<FormattedMessage defaultMessage="Language" />
|
|
||||||
<select
|
|
||||||
value={login.preferences.language || DefaultPreferences.language}
|
|
||||||
onChange={e =>
|
|
||||||
updatePreferences(login, {
|
|
||||||
...login.preferences,
|
|
||||||
language: e.target.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
style={{ textTransform: "capitalize" }}>
|
|
||||||
{AllLanguageCodes.sort().map(a => (
|
|
||||||
<option value={a}>
|
|
||||||
{new Intl.DisplayNames([a], {
|
|
||||||
type: "language",
|
|
||||||
}).of(a)}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<FormattedMessage {...messages.SaveKeysHelp} />
|
|
||||||
</p>
|
|
||||||
<ExportKeys />
|
|
||||||
<div className="next-actions">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => {
|
|
||||||
LoginStore.updateSession({
|
|
||||||
...login,
|
|
||||||
generatedEntropy: undefined,
|
|
||||||
});
|
|
||||||
navigate(PROFILE);
|
|
||||||
}}>
|
|
||||||
<FormattedMessage {...messages.KeysSaved} />{" "}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<WhatIsSnort />
|
|
||||||
<HowDoKeysWork />
|
|
||||||
<Extensions />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
import { useEffect, useState } from "react";
|
|
||||||
import { useIntl, FormattedMessage } from "react-intl";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import { mapEventToProfile } from "@snort/system";
|
|
||||||
import { useUserProfile } from "@snort/system-react";
|
|
||||||
|
|
||||||
import Logo from "Element/Logo";
|
|
||||||
import useEventPublisher from "Hooks/useEventPublisher";
|
|
||||||
import useLogin from "Hooks/useLogin";
|
|
||||||
import { UserCache } from "Cache";
|
|
||||||
import AvatarEditor from "Element/User/AvatarEditor";
|
|
||||||
import { DISCOVER } from ".";
|
|
||||||
|
|
||||||
import messages from "./messages";
|
|
||||||
|
|
||||||
export default function ProfileSetup() {
|
|
||||||
const login = useLogin();
|
|
||||||
const myProfile = useUserProfile(login.publicKey);
|
|
||||||
const [username, setUsername] = useState("");
|
|
||||||
const [picture, setPicture] = useState("");
|
|
||||||
const { formatMessage } = useIntl();
|
|
||||||
const { publisher, system } = useEventPublisher();
|
|
||||||
const navigate = useNavigate();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (myProfile) {
|
|
||||||
setUsername(myProfile.name ?? "");
|
|
||||||
setPicture(myProfile.picture ?? "");
|
|
||||||
}
|
|
||||||
}, [myProfile]);
|
|
||||||
|
|
||||||
const onNext = async () => {
|
|
||||||
if ((username.length > 0 || picture.length > 0) && publisher) {
|
|
||||||
const ev = await publisher.metadata({
|
|
||||||
...myProfile,
|
|
||||||
name: username,
|
|
||||||
picture,
|
|
||||||
});
|
|
||||||
system.BroadcastEvent(ev);
|
|
||||||
const profile = mapEventToProfile(ev);
|
|
||||||
if (profile) {
|
|
||||||
UserCache.set(profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
navigate(DISCOVER);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="main-content new-user p" dir="auto">
|
|
||||||
<Logo />
|
|
||||||
<div className="progress-bar">
|
|
||||||
<div className="progress progress-second"></div>
|
|
||||||
</div>
|
|
||||||
<h1>
|
|
||||||
<FormattedMessage defaultMessage="Setup profile" />
|
|
||||||
</h1>
|
|
||||||
<h2>
|
|
||||||
<FormattedMessage defaultMessage="Profile picture" />
|
|
||||||
</h2>
|
|
||||||
<AvatarEditor picture={picture} onPictureChange={p => setPicture(p)} />
|
|
||||||
<h2>
|
|
||||||
<FormattedMessage defaultMessage="Username" />
|
|
||||||
</h2>
|
|
||||||
<input
|
|
||||||
className="username"
|
|
||||||
placeholder={formatMessage(messages.UsernamePlaceholder)}
|
|
||||||
type="text"
|
|
||||||
value={username}
|
|
||||||
onChange={ev => setUsername(ev.target.value)}
|
|
||||||
/>
|
|
||||||
<div className="help-text">
|
|
||||||
<FormattedMessage defaultMessage="You can change your username at any point." />
|
|
||||||
</div>
|
|
||||||
<div className="next-actions">
|
|
||||||
<button type="button" className="transparent" onClick={() => navigate(DISCOVER)}>
|
|
||||||
<FormattedMessage {...messages.Skip} />
|
|
||||||
</button>
|
|
||||||
<button type="button" onClick={onNext}>
|
|
||||||
<FormattedMessage {...messages.Next} />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,179 +0,0 @@
|
|||||||
.new-user {
|
|
||||||
color: var(--font-secondary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user input {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user p {
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user p > a {
|
|
||||||
color: var(--highlight);
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user li {
|
|
||||||
line-height: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user li > a {
|
|
||||||
color: var(--highlight);
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user .nip-handle {
|
|
||||||
max-width: 120px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user h1 {
|
|
||||||
color: var(--font-color);
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 32px;
|
|
||||||
line-height: 39px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user h2 {
|
|
||||||
margin-top: 24px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
color: var(--font-color);
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 19px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user h3 {
|
|
||||||
color: var(--font-color);
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 21px;
|
|
||||||
line-height: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user h4 {
|
|
||||||
color: var(--font-secondary-color);
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 19px;
|
|
||||||
letter-spacing: 0.08em;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar {
|
|
||||||
width: 100%;
|
|
||||||
height: 7px;
|
|
||||||
background: var(--gray-secondary);
|
|
||||||
border-radius: 53px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar .progress {
|
|
||||||
height: 7px;
|
|
||||||
background: var(--snort-gradient);
|
|
||||||
border-radius: 53px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress.progress-first {
|
|
||||||
width: 20%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress.progress-second {
|
|
||||||
width: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress.progress-third {
|
|
||||||
width: 75%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress.progress-last {
|
|
||||||
width: 95%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user .next-actions {
|
|
||||||
margin-top: 32px;
|
|
||||||
margin-bottom: 64px;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user .next-actions button:not(:last-child) {
|
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user .next-actions.continue-actions {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user > .copy {
|
|
||||||
padding: 12px 16px;
|
|
||||||
border: 2px dashed #222222;
|
|
||||||
border-radius: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.light .new-user > .copy {
|
|
||||||
border: 2px dashed #aaaaaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user > .copy .body {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
@media (max-width: 520px) {
|
|
||||||
.new-user > .copy .body {
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user > .copy .icon {
|
|
||||||
margin-left: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user > .copy .icon svg {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user input {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 568px;
|
|
||||||
background: #222;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 720px) {
|
|
||||||
.new-user input {
|
|
||||||
width: calc(100vw - 40px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.light .new-user input {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user .warning {
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 19px;
|
|
||||||
color: #fc6e1e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.profile-preview-nip {
|
|
||||||
padding: 12px 16px;
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
||||||
border-radius: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.light .profile-preview-nip {
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user .nip-container input[type="text"] {
|
|
||||||
width: 166px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-user .help-text {
|
|
||||||
margin-top: 6px;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 24px;
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
import "./index.css";
|
|
||||||
import { RouteObject } from "react-router-dom";
|
|
||||||
|
|
||||||
import GetVerified from "Pages/new/GetVerified";
|
|
||||||
import ProfileSetup from "Pages/new/ProfileSetup";
|
|
||||||
import NewUserFlow from "Pages/new/NewUserFlow";
|
|
||||||
import DiscoverFollows from "Pages/new/DiscoverFollows";
|
|
||||||
|
|
||||||
export const PROFILE = "/new/profile";
|
|
||||||
export const DISCOVER = "/new/discover";
|
|
||||||
export const VERIFY = "/new/verify";
|
|
||||||
|
|
||||||
export const NewUserRoutes: RouteObject[] = [
|
|
||||||
{
|
|
||||||
path: "/new",
|
|
||||||
element: <NewUserFlow />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: PROFILE,
|
|
||||||
element: <ProfileSetup />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: VERIFY,
|
|
||||||
element: <GetVerified />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: DISCOVER,
|
|
||||||
element: <DiscoverFollows />,
|
|
||||||
},
|
|
||||||
];
|
|
@ -1,86 +0,0 @@
|
|||||||
import { defineMessages } from "react-intl";
|
|
||||||
|
|
||||||
export default defineMessages({
|
|
||||||
SaveKeys: {
|
|
||||||
defaultMessage: "Save your keys!",
|
|
||||||
},
|
|
||||||
SaveKeysHelp: {
|
|
||||||
defaultMessage:
|
|
||||||
"Your private key is your password. If you lose this key, you will lose access to your account! Copy it and keep it in a safe place. There is no way to reset your private key.",
|
|
||||||
},
|
|
||||||
YourPubkey: { defaultMessage: "Your public key" },
|
|
||||||
YourPrivkey: { defaultMessage: "Your private key" },
|
|
||||||
YourMnemonic: { defaultMessage: "Your mnemonic phrase" },
|
|
||||||
KeysSaved: { defaultMessage: "I have saved my keys, continue" },
|
|
||||||
WhatIsSnort: {
|
|
||||||
defaultMessage: "What is {site} and how does it work?",
|
|
||||||
values: { site: CONFIG.appNameCapitalized },
|
|
||||||
},
|
|
||||||
WhatIsSnortIntro: {
|
|
||||||
defaultMessage: `{site} is a Nostr UI, nostr is a decentralised protocol for saving and distributing "notes".`,
|
|
||||||
values: { site: CONFIG.appNameCapitalized },
|
|
||||||
},
|
|
||||||
WhatIsSnortNotes: {
|
|
||||||
defaultMessage: `Notes hold text content, the most popular usage of these notes is to store "tweet like" messages.`,
|
|
||||||
},
|
|
||||||
|
|
||||||
WhatIsSnortExperience: {
|
|
||||||
defaultMessage: "{site} is designed to have a similar experience to Twitter.",
|
|
||||||
values: { site: CONFIG.appNameCapitalized },
|
|
||||||
},
|
|
||||||
HowKeysWork: { defaultMessage: "How do keys work?" },
|
|
||||||
DigitalSignatures: {
|
|
||||||
defaultMessage: `Nostr uses digital signature technology to provide tamper proof notes which can safely be replicated to many relays to provide redundant storage of your content.`,
|
|
||||||
},
|
|
||||||
TamperProof: {
|
|
||||||
defaultMessage: `This means that nobody can modify notes which you have created and everybody can easily verify that the notes they are reading are created by you.`,
|
|
||||||
},
|
|
||||||
Bitcoin: {
|
|
||||||
defaultMessage: `This is the same technology which is used by Bitcoin and has been proven to be extremely secure.`,
|
|
||||||
},
|
|
||||||
Extensions: {
|
|
||||||
defaultMessage: `It is recommended to use one of the following browser extensions if you are on a desktop computer to secure your key:`,
|
|
||||||
},
|
|
||||||
ExtensionsNostr: { defaultMessage: `You can also use these extensions to login to most Nostr sites.` },
|
|
||||||
ImproveSecurity: { defaultMessage: "Improve login security with browser extensions" },
|
|
||||||
PickUsername: { defaultMessage: "Pick a username" },
|
|
||||||
Username: { defaultMessage: "Username" },
|
|
||||||
UsernamePlaceholder: { defaultMessage: "e.g. Jack" },
|
|
||||||
PopularAccounts: { defaultMessage: "Follow some popular accounts" },
|
|
||||||
Skip: { defaultMessage: "Skip" },
|
|
||||||
Done: { defaultMessage: "Done!" },
|
|
||||||
ImportTwitter: { defaultMessage: "Import Twitter Follows" },
|
|
||||||
TwitterPlaceholder: { defaultMessage: "Twitter username..." },
|
|
||||||
FindYourFollows: { defaultMessage: "Find your twitter follows on nostr (Data provided by {provider})" },
|
|
||||||
TwitterUsername: { defaultMessage: "Twitter username" },
|
|
||||||
FollowsOnNostr: { defaultMessage: "{username}'s Follows on Nostr" },
|
|
||||||
NoUsersFound: { defaultMessage: "No nostr users found for {twitterUsername}" },
|
|
||||||
FailedToLoad: { defaultMessage: "Failed to load follows, please try again later" },
|
|
||||||
Check: { defaultMessage: "Check" },
|
|
||||||
Next: { defaultMessage: "Next" },
|
|
||||||
SetupProfile: { defaultMessage: "Setup your Profile" },
|
|
||||||
Identifier: { defaultMessage: "Get an identifier" },
|
|
||||||
IdentifierHelp: {
|
|
||||||
defaultMessage:
|
|
||||||
"Getting an identifier helps confirm the real you to people who know you. Many people can have a username @jack, but there is only one jack@cash.app.",
|
|
||||||
},
|
|
||||||
PreventFakes: { defaultMessage: "Prevent fake accounts from imitating you" },
|
|
||||||
EasierToFind: { defaultMessage: "Make your profile easier to find and share" },
|
|
||||||
Funding: { defaultMessage: "Fund developers and platforms providing NIP-05 verification services" },
|
|
||||||
NameSquatting: {
|
|
||||||
defaultMessage:
|
|
||||||
"Name-squatting and impersonation is not allowed. {site} and our partners reserve the right to terminate your handle (not your account - nobody can take that away) for violating this rule.",
|
|
||||||
values: { site: CONFIG.appNameCapitalized },
|
|
||||||
},
|
|
||||||
PreviewOnSnort: { defaultMessage: "Preview on {site}", values: { site: CONFIG.appNameCapitalized } },
|
|
||||||
GetSnortId: { defaultMessage: "Get a Snort identifier" },
|
|
||||||
GetSnortIdHelp: {
|
|
||||||
defaultMessage:
|
|
||||||
"Only Snort and our integration partner identifier gives you a colorful domain name, but you are welcome to use other services too.",
|
|
||||||
},
|
|
||||||
GetPartnerId: { defaultMessage: "Get a partner identifier" },
|
|
||||||
GetPartnerIdHelp: { defaultMessage: "We have also partnered with nostrplebs.com to give you more options" },
|
|
||||||
Ready: { defaultMessage: "You're ready!" },
|
|
||||||
Share: { defaultMessage: "Share your thoughts with {link}" },
|
|
||||||
World: { defaultMessage: "the world" },
|
|
||||||
});
|
|
42
packages/app/src/Pages/onboarding/discover.tsx
Normal file
42
packages/app/src/Pages/onboarding/discover.tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
|
import AsyncButton from "Element/AsyncButton";
|
||||||
|
import { NewUserState } from ".";
|
||||||
|
import TrendingUsers from "Element/TrendingUsers";
|
||||||
|
|
||||||
|
export function Discover() {
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const state = location.state as NewUserState;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col g24">
|
||||||
|
<h1 className="text-center">
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="{site} is more fun together!"
|
||||||
|
values={{
|
||||||
|
site: CONFIG.appNameCapitalized,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</h1>
|
||||||
|
<div className="new-trending">
|
||||||
|
<TrendingUsers
|
||||||
|
title={
|
||||||
|
<h3>
|
||||||
|
<FormattedMessage defaultMessage="Trending Users" />
|
||||||
|
</h3>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<AsyncButton
|
||||||
|
className="primary"
|
||||||
|
onClick={() =>
|
||||||
|
navigate("/login/sign-up/moderation", {
|
||||||
|
state,
|
||||||
|
})
|
||||||
|
}>
|
||||||
|
<FormattedMessage defaultMessage="Next" />
|
||||||
|
</AsyncButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
50
packages/app/src/Pages/onboarding/index.css
Normal file
50
packages/app/src/Pages/onboarding/index.css
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
.onboarding-modal {
|
||||||
|
clear: both;
|
||||||
|
margin-top: 10vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
.onboarding-modal {
|
||||||
|
padding: 40px 48px;
|
||||||
|
border-radius: 24px;
|
||||||
|
background-color: var(--gray-superdark);
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-top: 10vh;
|
||||||
|
width: 460px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.onboarding-modal h1,
|
||||||
|
.onboarding-modal h2,
|
||||||
|
.onboarding-modal h3,
|
||||||
|
.onboarding-modal h4,
|
||||||
|
.onboarding-modal h5 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.onboarding-modal button.secondary:hover {
|
||||||
|
background-color: var(--gray-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
.onboarding-modal {
|
||||||
|
--border-color: #3a3a3a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-username {
|
||||||
|
padding: 10px 16px !important;
|
||||||
|
align-self: stretch;
|
||||||
|
border-radius: 100px !important;
|
||||||
|
background-color: var(--gray-superlight) !important;
|
||||||
|
box-shadow: 0px 0px 0px 4px transparent !important;
|
||||||
|
color: var(--gray-ultradark) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-username:focus {
|
||||||
|
box-shadow: 0px 0px 0px 4px rgba(172, 136, 255, 0.8) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-trending {
|
||||||
|
max-height: 30vh;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
74
packages/app/src/Pages/onboarding/index.tsx
Normal file
74
packages/app/src/Pages/onboarding/index.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import "./index.css";
|
||||||
|
import { Outlet, RouteObject } from "react-router-dom";
|
||||||
|
import { SignIn, SignUp } from "./start";
|
||||||
|
import { AllLanguageCodes } from "Pages/settings/Preferences";
|
||||||
|
import Icon from "Icons/Icon";
|
||||||
|
import { Profile } from "./profile";
|
||||||
|
import { Topics } from "./topics";
|
||||||
|
import { Discover } from "./discover";
|
||||||
|
import { useLocale } from "IntlProvider";
|
||||||
|
import { Moderation } from "./moderation";
|
||||||
|
|
||||||
|
export interface NewUserState {
|
||||||
|
name?: string;
|
||||||
|
picture?: string;
|
||||||
|
topics?: Array<string>;
|
||||||
|
muteLists?: Array<string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function OnboardingLayout() {
|
||||||
|
const { lang, setOverride } = useLocale();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="p24">
|
||||||
|
<div className="float-right flex g8 items-center">
|
||||||
|
<Icon name="translate" />
|
||||||
|
<select value={lang} onChange={e => setOverride(e.target.value)} className="capitalize">
|
||||||
|
{AllLanguageCodes.sort().map(a => (
|
||||||
|
<option value={a}>
|
||||||
|
{new Intl.DisplayNames([a], {
|
||||||
|
type: "language",
|
||||||
|
}).of(a)}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="onboarding-modal">
|
||||||
|
<Outlet />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const OnboardingRoutes = [
|
||||||
|
{
|
||||||
|
path: "/login",
|
||||||
|
element: <OnboardingLayout />,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "",
|
||||||
|
element: <SignIn />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "sign-up",
|
||||||
|
element: <SignUp />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "sign-up/profile",
|
||||||
|
element: <Profile />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "sign-up/topics",
|
||||||
|
element: <Topics />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "sign-up/discover",
|
||||||
|
element: <Discover />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "sign-up/moderation",
|
||||||
|
element: <Moderation />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
] as Array<RouteObject>;
|
156
packages/app/src/Pages/onboarding/moderation.tsx
Normal file
156
packages/app/src/Pages/onboarding/moderation.tsx
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||||
|
import { ReactNode, useState } from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import AsyncButton from "Element/AsyncButton";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import { appendDedupe } from "SnortUtils";
|
||||||
|
import useEventPublisher from "Hooks/useEventPublisher";
|
||||||
|
import { setMuted } from "Login";
|
||||||
|
import { ToggleSwitch } from "Icons/Toggle";
|
||||||
|
|
||||||
|
export const FixedModeration = {
|
||||||
|
hateSpeech: {
|
||||||
|
title: <FormattedMessage defaultMessage="Hate Speech" />,
|
||||||
|
words: [],
|
||||||
|
canEdit: false,
|
||||||
|
},
|
||||||
|
derogatory: {
|
||||||
|
title: <FormattedMessage defaultMessage="Derogatory" />,
|
||||||
|
words: [],
|
||||||
|
canEdit: false,
|
||||||
|
},
|
||||||
|
nsfw: {
|
||||||
|
title: <FormattedMessage defaultMessage="NSFW" />,
|
||||||
|
words: [
|
||||||
|
"adult content",
|
||||||
|
"explicit",
|
||||||
|
"mature audiences",
|
||||||
|
"18+",
|
||||||
|
"sensitive content",
|
||||||
|
"graphic content",
|
||||||
|
"age-restricted",
|
||||||
|
"explicit material",
|
||||||
|
"adult material",
|
||||||
|
"nsfw",
|
||||||
|
"explicit images",
|
||||||
|
"adult film",
|
||||||
|
"adult video",
|
||||||
|
"mature themes",
|
||||||
|
"sexual content",
|
||||||
|
"graphic violence",
|
||||||
|
"strong language",
|
||||||
|
"explicit language",
|
||||||
|
"adult-only",
|
||||||
|
"mature language",
|
||||||
|
],
|
||||||
|
canEdit: false,
|
||||||
|
},
|
||||||
|
crypto: {
|
||||||
|
title: <FormattedMessage defaultMessage="Crypto" />,
|
||||||
|
words: [
|
||||||
|
"bitcoin",
|
||||||
|
"btc",
|
||||||
|
"satoshi",
|
||||||
|
"crypto",
|
||||||
|
"blockchain",
|
||||||
|
"mining",
|
||||||
|
"wallet",
|
||||||
|
"exchange",
|
||||||
|
"halving",
|
||||||
|
"hash rate",
|
||||||
|
"ledger",
|
||||||
|
"crypto trading",
|
||||||
|
"digital currency",
|
||||||
|
"virtual currency",
|
||||||
|
"cryptocurrency investment",
|
||||||
|
"altcoin",
|
||||||
|
"decentralized finance",
|
||||||
|
"defi",
|
||||||
|
"token",
|
||||||
|
"ico",
|
||||||
|
"crypto wallet",
|
||||||
|
"satoshi nakamoto",
|
||||||
|
],
|
||||||
|
canEdit: true,
|
||||||
|
},
|
||||||
|
politics: {
|
||||||
|
title: <FormattedMessage defaultMessage="Politics" />,
|
||||||
|
words: [],
|
||||||
|
canEdit: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function Moderation() {
|
||||||
|
const { publisher, system } = useEventPublisher();
|
||||||
|
const [topics, setTopics] = useState<Array<string>>(Object.keys(FixedModeration));
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col g24">
|
||||||
|
<div className="flex flex-col g8 text-center">
|
||||||
|
<h1>
|
||||||
|
<FormattedMessage defaultMessage="Clean up your feed" />
|
||||||
|
</h1>
|
||||||
|
<FormattedMessage defaultMessage="Your space the way you want it 😌" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col g8">
|
||||||
|
<div className="flex g8 items-center">
|
||||||
|
<small className="grow uppercase font-semibold">
|
||||||
|
<FormattedMessage defaultMessage="Lists to mute:" />
|
||||||
|
</small>
|
||||||
|
<span className="font-medium">
|
||||||
|
<FormattedMessage defaultMessage="Toggle all" />
|
||||||
|
</span>
|
||||||
|
<ToggleSwitch
|
||||||
|
size={50}
|
||||||
|
onClick={() =>
|
||||||
|
topics.length === Object.keys(FixedModeration).length
|
||||||
|
? setTopics([])
|
||||||
|
: setTopics(Object.keys(FixedModeration))
|
||||||
|
}
|
||||||
|
className={topics.length === Object.keys(FixedModeration).length ? "active" : ""}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{Object.entries(FixedModeration).map(([k, v]) => (
|
||||||
|
<div className="flex g8 items-center bb" key={k}>
|
||||||
|
<div className="font-semibold grow">{v.title}</div>
|
||||||
|
{v.canEdit && (
|
||||||
|
<div>
|
||||||
|
<FormattedMessage defaultMessage="edit" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<ToggleSwitch
|
||||||
|
size={50}
|
||||||
|
className={topics.includes(k) ? "active" : ""}
|
||||||
|
onClick={() => setTopics(s => (topics.includes(k) ? s.filter(a => a !== k) : appendDedupe(s, [k])))}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col g8">
|
||||||
|
<span className="font-semibold">
|
||||||
|
<FormattedMessage defaultMessage="Additional Terms:" />
|
||||||
|
</span>
|
||||||
|
<small className="font-medium">
|
||||||
|
<FormattedMessage defaultMessage="Use commas to separate words e.g. word1, word2, word3" />
|
||||||
|
</small>
|
||||||
|
<textarea></textarea>
|
||||||
|
</div>
|
||||||
|
<AsyncButton
|
||||||
|
className="primary"
|
||||||
|
onClick={async () => {
|
||||||
|
const words = Object.entries(FixedModeration)
|
||||||
|
.filter(([k]) => topics.includes(k))
|
||||||
|
.map(([, v]) => v.words)
|
||||||
|
.flat();
|
||||||
|
if (words.length > 0) {
|
||||||
|
// no
|
||||||
|
}
|
||||||
|
navigate("/");
|
||||||
|
}}>
|
||||||
|
<FormattedMessage defaultMessage="Finish" />
|
||||||
|
</AsyncButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
47
packages/app/src/Pages/onboarding/profile.tsx
Normal file
47
packages/app/src/Pages/onboarding/profile.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import AsyncButton from "Element/AsyncButton";
|
||||||
|
import AvatarEditor from "Element/User/AvatarEditor";
|
||||||
|
import { useContext, useState } from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
|
import { generateNewLogin } from "Login";
|
||||||
|
import { SnortContext } from "@snort/system-react";
|
||||||
|
import { NotEncrypted } from "@snort/system";
|
||||||
|
import { NewUserState } from ".";
|
||||||
|
|
||||||
|
export function Profile() {
|
||||||
|
const system = useContext(SnortContext);
|
||||||
|
const [picture, setPicture] = useState<string>();
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
|
const state = location.state as NewUserState;
|
||||||
|
|
||||||
|
async function makeRandomKey() {
|
||||||
|
try {
|
||||||
|
setError("");
|
||||||
|
await generateNewLogin(system, key => Promise.resolve(new NotEncrypted(key)), {
|
||||||
|
name: state.name,
|
||||||
|
picture,
|
||||||
|
});
|
||||||
|
window.plausible?.("Generate Account");
|
||||||
|
navigate("/login/sign-up/topics");
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
|
setError(e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col g24 text-center">
|
||||||
|
<h1>
|
||||||
|
<FormattedMessage defaultMessage="Profile Image" />
|
||||||
|
</h1>
|
||||||
|
<AvatarEditor picture={picture} onPictureChange={p => setPicture(p)} />
|
||||||
|
<AsyncButton className="primary" onClick={() => makeRandomKey()}>
|
||||||
|
<FormattedMessage defaultMessage="Next" />
|
||||||
|
</AsyncButton>
|
||||||
|
{error && <b className="error">{error}</b>}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
151
packages/app/src/Pages/onboarding/start.tsx
Normal file
151
packages/app/src/Pages/onboarding/start.tsx
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
|
import { unwrap } from "@snort/shared";
|
||||||
|
|
||||||
|
import AsyncButton from "Element/AsyncButton";
|
||||||
|
import Icon from "Icons/Icon";
|
||||||
|
import { NewUserState } from ".";
|
||||||
|
import { LoginSessionType, LoginStore } from "Login";
|
||||||
|
import useLoginHandler from "Hooks/useLoginHandler";
|
||||||
|
import { NotEncrypted } from "@snort/system";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
export function SignIn() {
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
const [key, setKey] = useState("");
|
||||||
|
const [error, setError] = useState("");
|
||||||
|
const [useKey, setUseKey] = useState(false);
|
||||||
|
const loginHandler = useLoginHandler();
|
||||||
|
|
||||||
|
const hasNip7 = "nostr" in window;
|
||||||
|
async function doNip07Login() {
|
||||||
|
const relays =
|
||||||
|
"getRelays" in unwrap(window.nostr) ? await unwrap(window.nostr?.getRelays).call(window.nostr) : undefined;
|
||||||
|
const pubKey = await unwrap(window.nostr).getPublicKey();
|
||||||
|
LoginStore.loginWithPubkey(pubKey, LoginSessionType.Nip7, relays);
|
||||||
|
navigate("/");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doLogin() {
|
||||||
|
setError("");
|
||||||
|
try {
|
||||||
|
await loginHandler.doLogin(key, key => Promise.resolve(new NotEncrypted(key)));
|
||||||
|
navigate("/");
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
|
setError(e.message);
|
||||||
|
} else {
|
||||||
|
setError(
|
||||||
|
formatMessage({
|
||||||
|
defaultMessage: "Unknown login error",
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const nip7Login = hasNip7 && !useKey;
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col g24">
|
||||||
|
<img src={CONFIG.appleTouchIconUrl} width={48} height={48} className="br mr-auto ml-auto" />
|
||||||
|
<div className="flex flex-col g16 items-center">
|
||||||
|
<h1>
|
||||||
|
<FormattedMessage defaultMessage="Sign In" />
|
||||||
|
</h1>
|
||||||
|
{nip7Login && <FormattedMessage defaultMessage="Use a nostr signer extension to sign in" />}
|
||||||
|
</div>
|
||||||
|
<div className={classNames("flex flex-col g16", { "items-center": nip7Login })}>
|
||||||
|
{hasNip7 && !useKey && (
|
||||||
|
<>
|
||||||
|
<AsyncButton onClick={doNip07Login}>
|
||||||
|
<div className="circle bg-warning p12 text-white">
|
||||||
|
<Icon name="key" />
|
||||||
|
</div>
|
||||||
|
<FormattedMessage defaultMessage="Sign in with Nostr Extension" />
|
||||||
|
</AsyncButton>
|
||||||
|
<Link to="" className="highlight">
|
||||||
|
<FormattedMessage defaultMessage="Supported Extensions" />
|
||||||
|
</Link>
|
||||||
|
<AsyncButton onClick={() => setUseKey(true)}>
|
||||||
|
<FormattedMessage defaultMessage="Sign in with key" />
|
||||||
|
</AsyncButton>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{(!hasNip7 || useKey) && (
|
||||||
|
<>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder={formatMessage({
|
||||||
|
defaultMessage: "nsec, npub, nip-05, hex, mnemonic",
|
||||||
|
})}
|
||||||
|
value={key}
|
||||||
|
onChange={e => setKey(e.target.value)}
|
||||||
|
className="new-username"
|
||||||
|
/>
|
||||||
|
{error && <b className="error">{error}</b>}
|
||||||
|
<AsyncButton onClick={doLogin} className="primary">
|
||||||
|
<FormattedMessage defaultMessage="Login" />
|
||||||
|
</AsyncButton>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col g16 items-center">
|
||||||
|
<FormattedMessage defaultMessage="Don't have an account?" />
|
||||||
|
<AsyncButton className="secondary" onClick={() => navigate("/login/sign-up")}>
|
||||||
|
<FormattedMessage defaultMessage="Sign Up" />
|
||||||
|
</AsyncButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SignUp() {
|
||||||
|
const { formatMessage } = useIntl();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [name, setName] = useState("");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col g24">
|
||||||
|
<img src={CONFIG.appleTouchIconUrl} width={48} height={48} className="br mr-auto ml-auto" />
|
||||||
|
<div className="flex flex-col g16 items-center">
|
||||||
|
<h1>
|
||||||
|
<FormattedMessage defaultMessage="Sign Up" />
|
||||||
|
</h1>
|
||||||
|
<FormattedMessage defaultMessage="What should we call you?" />
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col g16">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
autoFocus={true}
|
||||||
|
placeholder={formatMessage({
|
||||||
|
defaultMessage: "Name or nym",
|
||||||
|
})}
|
||||||
|
value={name}
|
||||||
|
onChange={e => setName(e.target.value)}
|
||||||
|
className="new-username"
|
||||||
|
/>
|
||||||
|
<AsyncButton
|
||||||
|
className="primary"
|
||||||
|
disabled={name.length === 0}
|
||||||
|
onClick={() =>
|
||||||
|
navigate("/login/sign-up/profile", {
|
||||||
|
state: {
|
||||||
|
name: name,
|
||||||
|
} as NewUserState,
|
||||||
|
})
|
||||||
|
}>
|
||||||
|
<FormattedMessage defaultMessage="Next" />
|
||||||
|
</AsyncButton>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col g16 items-center">
|
||||||
|
<FormattedMessage defaultMessage="Already have an account?" />
|
||||||
|
<AsyncButton className="secondary" onClick={() => navigate("/login")}>
|
||||||
|
<FormattedMessage defaultMessage="Sign In" />
|
||||||
|
</AsyncButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
85
packages/app/src/Pages/onboarding/topics.tsx
Normal file
85
packages/app/src/Pages/onboarding/topics.tsx
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { ReactNode, useState } from "react";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import AsyncButton from "Element/AsyncButton";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import { appendDedupe } from "SnortUtils";
|
||||||
|
import useEventPublisher from "Hooks/useEventPublisher";
|
||||||
|
|
||||||
|
export const FixedTopics = {
|
||||||
|
life: {
|
||||||
|
text: <FormattedMessage defaultMessage="Life" />,
|
||||||
|
tags: ["life"],
|
||||||
|
},
|
||||||
|
science: {
|
||||||
|
text: <FormattedMessage defaultMessage="Science" />,
|
||||||
|
tags: ["science"],
|
||||||
|
},
|
||||||
|
nature: {
|
||||||
|
text: <FormattedMessage defaultMessage="Nature" />,
|
||||||
|
tags: ["nature"],
|
||||||
|
},
|
||||||
|
business: {
|
||||||
|
text: <FormattedMessage defaultMessage="Business" />,
|
||||||
|
tags: ["business"],
|
||||||
|
},
|
||||||
|
game: {
|
||||||
|
text: <FormattedMessage defaultMessage="Game" />,
|
||||||
|
tags: ["game", "gaming"],
|
||||||
|
},
|
||||||
|
sport: {
|
||||||
|
text: <FormattedMessage defaultMessage="Sport" />,
|
||||||
|
tags: ["sport"],
|
||||||
|
},
|
||||||
|
photography: {
|
||||||
|
text: <FormattedMessage defaultMessage="Photography" />,
|
||||||
|
tags: ["photography"],
|
||||||
|
},
|
||||||
|
bitcoin: {
|
||||||
|
text: <FormattedMessage defaultMessage="Bitcoin" />,
|
||||||
|
tags: ["bitcoin"],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function Topics() {
|
||||||
|
const { publisher, system } = useEventPublisher();
|
||||||
|
const [topics, setTopics] = useState<Array<string>>([]);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
function tab(name: string, text: ReactNode) {
|
||||||
|
const active = topics.includes(name);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames("tab", { active })}
|
||||||
|
onClick={() => setTopics(s => (active ? s.filter(a => a !== name) : appendDedupe(s, [name])))}>
|
||||||
|
{text}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col g24 text-center">
|
||||||
|
<h1>
|
||||||
|
<FormattedMessage defaultMessage="Pick a few topics of interest" />
|
||||||
|
</h1>
|
||||||
|
<div className="tabs flex-wrap justify-center">{Object.entries(FixedTopics).map(([k, v]) => tab(k, v.text))}</div>
|
||||||
|
<AsyncButton
|
||||||
|
className="primary"
|
||||||
|
onClick={async () => {
|
||||||
|
const tags = Object.entries(FixedTopics)
|
||||||
|
.filter(([k]) => topics.includes(k))
|
||||||
|
.map(([, v]) => v.tags)
|
||||||
|
.flat();
|
||||||
|
if (tags.length > 0) {
|
||||||
|
const ev = await publisher?.tags(tags);
|
||||||
|
if (ev) {
|
||||||
|
await system.BroadcastEvent(ev);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
navigate("/login/sign-up/discover");
|
||||||
|
}}>
|
||||||
|
<FormattedMessage defaultMessage="Next" />
|
||||||
|
</AsyncButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -2,9 +2,10 @@ import "./Preferences.css";
|
|||||||
|
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import useLogin from "Hooks/useLogin";
|
import useLogin from "Hooks/useLogin";
|
||||||
import { DefaultPreferences, updatePreferences, UserPreferences } from "Login";
|
import { updatePreferences, UserPreferences } from "Login";
|
||||||
import { DefaultImgProxy } from "Const";
|
import { DefaultImgProxy } from "Const";
|
||||||
import { unwrap } from "SnortUtils";
|
import { unwrap } from "SnortUtils";
|
||||||
|
import { useLocale } from "IntlProvider";
|
||||||
|
|
||||||
import messages from "./messages";
|
import messages from "./messages";
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ const PreferencesPage = () => {
|
|||||||
const { formatMessage } = useIntl();
|
const { formatMessage } = useIntl();
|
||||||
const login = useLogin();
|
const login = useLogin();
|
||||||
const perf = login.preferences;
|
const perf = login.preferences;
|
||||||
|
const { lang } = useLocale();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="preferences flex flex-col g24">
|
<div className="preferences flex flex-col g24">
|
||||||
@ -49,7 +51,7 @@ const PreferencesPage = () => {
|
|||||||
</h4>
|
</h4>
|
||||||
<div>
|
<div>
|
||||||
<select
|
<select
|
||||||
value={perf.language || DefaultPreferences.language}
|
value={lang}
|
||||||
onChange={e =>
|
onChange={e =>
|
||||||
updatePreferences(login, {
|
updatePreferences(login, {
|
||||||
...perf,
|
...perf,
|
||||||
|
@ -660,6 +660,10 @@ div.form-col {
|
|||||||
color: var(--warning);
|
color: var(--warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bg-warning {
|
||||||
|
background-color: var(--warning);
|
||||||
|
}
|
||||||
|
|
||||||
.bg-error {
|
.bg-error {
|
||||||
background-color: var(--error);
|
background-color: var(--error);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ import * as serviceWorkerRegistration from "serviceWorkerRegistration";
|
|||||||
import { IntlProvider } from "IntlProvider";
|
import { IntlProvider } from "IntlProvider";
|
||||||
import { getCountry, unwrap } from "SnortUtils";
|
import { getCountry, unwrap } from "SnortUtils";
|
||||||
import Layout from "Pages/Layout";
|
import Layout from "Pages/Layout";
|
||||||
import LoginPage from "Pages/LoginPage";
|
|
||||||
import ProfilePage from "Pages/Profile/ProfilePage";
|
import ProfilePage from "Pages/Profile/ProfilePage";
|
||||||
import { RootRoutes, RootTabRoutes } from "Pages/Root";
|
import { RootRoutes, RootTabRoutes } from "Pages/Root";
|
||||||
import NotificationsPage from "Pages/Notifications";
|
import NotificationsPage from "Pages/Notifications";
|
||||||
@ -37,7 +36,6 @@ import MessagesPage from "Pages/MessagesPage";
|
|||||||
import DonatePage from "Pages/DonatePage";
|
import DonatePage from "Pages/DonatePage";
|
||||||
import SearchPage from "Pages/SearchPage";
|
import SearchPage from "Pages/SearchPage";
|
||||||
import HelpPage from "Pages/HelpPage";
|
import HelpPage from "Pages/HelpPage";
|
||||||
import { NewUserRoutes } from "Pages/new";
|
|
||||||
import { WalletRoutes } from "Pages/WalletPage";
|
import { WalletRoutes } from "Pages/WalletPage";
|
||||||
import NostrLinkHandler from "Pages/NostrLinkHandler";
|
import NostrLinkHandler from "Pages/NostrLinkHandler";
|
||||||
import { ThreadRoute } from "Element/Event/Thread";
|
import { ThreadRoute } from "Element/Event/Thread";
|
||||||
@ -51,6 +49,13 @@ import FreeNostrAddressPage from "./Pages/FreeNostrAddressPage";
|
|||||||
import { ListFeedPage } from "Pages/ListFeedPage";
|
import { ListFeedPage } from "Pages/ListFeedPage";
|
||||||
import { updateRelayConnections } from "Hooks/useLoginRelays";
|
import { updateRelayConnections } from "Hooks/useLoginRelays";
|
||||||
import { AboutPage } from "Pages/About";
|
import { AboutPage } from "Pages/About";
|
||||||
|
import { OnboardingRoutes } from "Pages/onboarding";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
plausible?: (tag: string) => void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const WasmQueryOptimizer = {
|
const WasmQueryOptimizer = {
|
||||||
expandFilter: (f: ReqFilter) => {
|
expandFilter: (f: ReqFilter) => {
|
||||||
@ -165,10 +170,6 @@ async function initSite() {
|
|||||||
let didInit = false;
|
let didInit = false;
|
||||||
const mainRoutes = [
|
const mainRoutes = [
|
||||||
...RootRoutes,
|
...RootRoutes,
|
||||||
{
|
|
||||||
path: "/login",
|
|
||||||
element: <LoginPage />,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: "/help",
|
path: "/help",
|
||||||
element: <HelpPage />,
|
element: <HelpPage />,
|
||||||
@ -218,7 +219,7 @@ const mainRoutes = [
|
|||||||
path: "/about",
|
path: "/about",
|
||||||
element: <AboutPage />,
|
element: <AboutPage />,
|
||||||
},
|
},
|
||||||
...NewUserRoutes,
|
...OnboardingRoutes,
|
||||||
...WalletRoutes,
|
...WalletRoutes,
|
||||||
] as Array<RouteObject>;
|
] as Array<RouteObject>;
|
||||||
|
|
||||||
|
@ -23,11 +23,14 @@
|
|||||||
"+vVZ/G": {
|
"+vVZ/G": {
|
||||||
"defaultMessage": "Connect"
|
"defaultMessage": "Connect"
|
||||||
},
|
},
|
||||||
|
"+vj0U3": {
|
||||||
|
"defaultMessage": "edit"
|
||||||
|
},
|
||||||
"+xliwN": {
|
"+xliwN": {
|
||||||
"defaultMessage": "{name} reposted"
|
"defaultMessage": "{name} reposted"
|
||||||
},
|
},
|
||||||
"/4tOwT": {
|
"/B8zwF": {
|
||||||
"defaultMessage": "Skip"
|
"defaultMessage": "Your space the way you want it 😌"
|
||||||
},
|
},
|
||||||
"/GCoTA": {
|
"/GCoTA": {
|
||||||
"defaultMessage": "Clear"
|
"defaultMessage": "Clear"
|
||||||
@ -39,9 +42,6 @@
|
|||||||
"defaultMessage": "Public",
|
"defaultMessage": "Public",
|
||||||
"description": "Public Zap"
|
"description": "Public Zap"
|
||||||
},
|
},
|
||||||
"/RD0e2": {
|
|
||||||
"defaultMessage": "Nostr uses digital signature technology to provide tamper proof notes which can safely be replicated to many relays to provide redundant storage of your content."
|
|
||||||
},
|
|
||||||
"/Xf4UW": {
|
"/Xf4UW": {
|
||||||
"defaultMessage": "Send anonymous usage metrics"
|
"defaultMessage": "Send anonymous usage metrics"
|
||||||
},
|
},
|
||||||
@ -72,6 +72,9 @@
|
|||||||
"0mch2Y": {
|
"0mch2Y": {
|
||||||
"defaultMessage": "name has disallowed characters"
|
"defaultMessage": "name has disallowed characters"
|
||||||
},
|
},
|
||||||
|
"0siT4z": {
|
||||||
|
"defaultMessage": "Politics"
|
||||||
|
},
|
||||||
"0uoY11": {
|
"0uoY11": {
|
||||||
"defaultMessage": "Show Status"
|
"defaultMessage": "Show Status"
|
||||||
},
|
},
|
||||||
@ -93,6 +96,9 @@
|
|||||||
"1o2BgB": {
|
"1o2BgB": {
|
||||||
"defaultMessage": "Check Signatures"
|
"defaultMessage": "Check Signatures"
|
||||||
},
|
},
|
||||||
|
"1ozeyg": {
|
||||||
|
"defaultMessage": "Nature"
|
||||||
|
},
|
||||||
"1udzha": {
|
"1udzha": {
|
||||||
"defaultMessage": "Conversations"
|
"defaultMessage": "Conversations"
|
||||||
},
|
},
|
||||||
@ -102,12 +108,18 @@
|
|||||||
"25V4l1": {
|
"25V4l1": {
|
||||||
"defaultMessage": "Banner"
|
"defaultMessage": "Banner"
|
||||||
},
|
},
|
||||||
|
"25WwxF": {
|
||||||
|
"defaultMessage": "Don't have an account?"
|
||||||
|
},
|
||||||
"2IFGap": {
|
"2IFGap": {
|
||||||
"defaultMessage": "Donate"
|
"defaultMessage": "Donate"
|
||||||
},
|
},
|
||||||
"2LbrkB": {
|
"2LbrkB": {
|
||||||
"defaultMessage": "Enter password"
|
"defaultMessage": "Enter password"
|
||||||
},
|
},
|
||||||
|
"2O2sfp": {
|
||||||
|
"defaultMessage": "Finish"
|
||||||
|
},
|
||||||
"2a2YiP": {
|
"2a2YiP": {
|
||||||
"defaultMessage": "{n} Bookmarks"
|
"defaultMessage": "{n} Bookmarks"
|
||||||
},
|
},
|
||||||
@ -120,6 +132,9 @@
|
|||||||
"2zJXeA": {
|
"2zJXeA": {
|
||||||
"defaultMessage": "Profiles"
|
"defaultMessage": "Profiles"
|
||||||
},
|
},
|
||||||
|
"39AHJm": {
|
||||||
|
"defaultMessage": "Sign Up"
|
||||||
|
},
|
||||||
"3KNMbJ": {
|
"3KNMbJ": {
|
||||||
"defaultMessage": "Articles"
|
"defaultMessage": "Articles"
|
||||||
},
|
},
|
||||||
@ -138,16 +153,9 @@
|
|||||||
"3tVy+Z": {
|
"3tVy+Z": {
|
||||||
"defaultMessage": "{n} Followers"
|
"defaultMessage": "{n} Followers"
|
||||||
},
|
},
|
||||||
"3xCwbZ": {
|
|
||||||
"defaultMessage": "OR",
|
|
||||||
"description": "Seperator text for Login / Generate Key"
|
|
||||||
},
|
|
||||||
"3yk8fB": {
|
"3yk8fB": {
|
||||||
"defaultMessage": "Wallet"
|
"defaultMessage": "Wallet"
|
||||||
},
|
},
|
||||||
"40VR6s": {
|
|
||||||
"defaultMessage": "Nostr Connect"
|
|
||||||
},
|
|
||||||
"450Fty": {
|
"450Fty": {
|
||||||
"defaultMessage": "None"
|
"defaultMessage": "None"
|
||||||
},
|
},
|
||||||
@ -163,6 +171,9 @@
|
|||||||
"4MBtMa": {
|
"4MBtMa": {
|
||||||
"defaultMessage": "Name must be between 1 and 32 characters"
|
"defaultMessage": "Name must be between 1 and 32 characters"
|
||||||
},
|
},
|
||||||
|
"4MjsHk": {
|
||||||
|
"defaultMessage": "Life"
|
||||||
|
},
|
||||||
"4OB335": {
|
"4OB335": {
|
||||||
"defaultMessage": "Dislike"
|
"defaultMessage": "Dislike"
|
||||||
},
|
},
|
||||||
@ -181,15 +192,9 @@
|
|||||||
"5CB6zB": {
|
"5CB6zB": {
|
||||||
"defaultMessage": "Zap Splits"
|
"defaultMessage": "Zap Splits"
|
||||||
},
|
},
|
||||||
"5JcXdV": {
|
|
||||||
"defaultMessage": "Create Account"
|
|
||||||
},
|
|
||||||
"5oTnfy": {
|
"5oTnfy": {
|
||||||
"defaultMessage": "Buy Handle"
|
"defaultMessage": "Buy Handle"
|
||||||
},
|
},
|
||||||
"5rOdPG": {
|
|
||||||
"defaultMessage": "Once you setup your key manager extension and generated a key, you can follow our new users flow to setup your profile and help you find some interesting people on Nostr to follow."
|
|
||||||
},
|
|
||||||
"5u6iEc": {
|
"5u6iEc": {
|
||||||
"defaultMessage": "Transfer to Pubkey"
|
"defaultMessage": "Transfer to Pubkey"
|
||||||
},
|
},
|
||||||
@ -217,9 +222,6 @@
|
|||||||
"6TfgXX": {
|
"6TfgXX": {
|
||||||
"defaultMessage": "{site} is an open source project built by passionate people in their free time"
|
"defaultMessage": "{site} is an open source project built by passionate people in their free time"
|
||||||
},
|
},
|
||||||
"6Yfvvp": {
|
|
||||||
"defaultMessage": "Get an identifier"
|
|
||||||
},
|
|
||||||
"6bgpn+": {
|
"6bgpn+": {
|
||||||
"defaultMessage": "Not all clients support this, you may still receive some zaps as if zap splits was not configured"
|
"defaultMessage": "Not all clients support this, you may still receive some zaps as if zap splits was not configured"
|
||||||
},
|
},
|
||||||
@ -232,9 +234,6 @@
|
|||||||
"7+Domh": {
|
"7+Domh": {
|
||||||
"defaultMessage": "Notes"
|
"defaultMessage": "Notes"
|
||||||
},
|
},
|
||||||
"7/h1jn": {
|
|
||||||
"defaultMessage": "After submitting the pin there may be a slight delay as we encrypt the key."
|
|
||||||
},
|
|
||||||
"712i26": {
|
"712i26": {
|
||||||
"defaultMessage": "Proxy uses HODL invoices to forward the payment, which hides the pubkey of your node"
|
"defaultMessage": "Proxy uses HODL invoices to forward the payment, which hides the pubkey of your node"
|
||||||
},
|
},
|
||||||
@ -256,9 +255,6 @@
|
|||||||
"8ED/4u": {
|
"8ED/4u": {
|
||||||
"defaultMessage": "Reply To"
|
"defaultMessage": "Reply To"
|
||||||
},
|
},
|
||||||
"8Kboo2": {
|
|
||||||
"defaultMessage": "Scan this QR code with your signer app to get started"
|
|
||||||
},
|
|
||||||
"8QDesP": {
|
"8QDesP": {
|
||||||
"defaultMessage": "Zap {n} sats"
|
"defaultMessage": "Zap {n} sats"
|
||||||
},
|
},
|
||||||
@ -274,10 +270,6 @@
|
|||||||
"8v1NN+": {
|
"8v1NN+": {
|
||||||
"defaultMessage": "Pairing phrase"
|
"defaultMessage": "Pairing phrase"
|
||||||
},
|
},
|
||||||
"8xNnhi": {
|
|
||||||
"defaultMessage": "Nostr Extension",
|
|
||||||
"description": "Login button for NIP7 key manager extension"
|
|
||||||
},
|
|
||||||
"9+Ddtu": {
|
"9+Ddtu": {
|
||||||
"defaultMessage": "Next"
|
"defaultMessage": "Next"
|
||||||
},
|
},
|
||||||
@ -290,10 +282,6 @@
|
|||||||
"9WRlF4": {
|
"9WRlF4": {
|
||||||
"defaultMessage": "Send"
|
"defaultMessage": "Send"
|
||||||
},
|
},
|
||||||
"9gqH2W": {
|
|
||||||
"defaultMessage": "Login",
|
|
||||||
"description": "Login button"
|
|
||||||
},
|
|
||||||
"9kSari": {
|
"9kSari": {
|
||||||
"defaultMessage": "Retry publishing"
|
"defaultMessage": "Retry publishing"
|
||||||
},
|
},
|
||||||
@ -316,15 +304,15 @@
|
|||||||
"ASRK0S": {
|
"ASRK0S": {
|
||||||
"defaultMessage": "This author has been muted"
|
"defaultMessage": "This author has been muted"
|
||||||
},
|
},
|
||||||
"Adk34V": {
|
|
||||||
"defaultMessage": "Setup your Profile"
|
|
||||||
},
|
|
||||||
"Ai8VHU": {
|
"Ai8VHU": {
|
||||||
"defaultMessage": "Unlimited note retention on Snort relay"
|
"defaultMessage": "Unlimited note retention on Snort relay"
|
||||||
},
|
},
|
||||||
"AkCxS/": {
|
"AkCxS/": {
|
||||||
"defaultMessage": "Reason"
|
"defaultMessage": "Reason"
|
||||||
},
|
},
|
||||||
|
"Am8glJ": {
|
||||||
|
"defaultMessage": "Game"
|
||||||
|
},
|
||||||
"AnLrRC": {
|
"AnLrRC": {
|
||||||
"defaultMessage": "Non-Zap",
|
"defaultMessage": "Non-Zap",
|
||||||
"description": "Non-Zap, Regular LN payment"
|
"description": "Non-Zap, Regular LN payment"
|
||||||
@ -347,15 +335,9 @@
|
|||||||
"BGCM48": {
|
"BGCM48": {
|
||||||
"defaultMessage": "Write access to Snort relay, with 1 year of event retention"
|
"defaultMessage": "Write access to Snort relay, with 1 year of event retention"
|
||||||
},
|
},
|
||||||
"BOUMjw": {
|
|
||||||
"defaultMessage": "No nostr users found for {twitterUsername}"
|
|
||||||
},
|
|
||||||
"BWpuKl": {
|
"BWpuKl": {
|
||||||
"defaultMessage": "Update"
|
"defaultMessage": "Update"
|
||||||
},
|
},
|
||||||
"BcGMo+": {
|
|
||||||
"defaultMessage": "Notes hold text content, the most popular usage of these notes is to store \"tweet like\" messages."
|
|
||||||
},
|
|
||||||
"BjNwZW": {
|
"BjNwZW": {
|
||||||
"defaultMessage": "Nostr address (nip05)"
|
"defaultMessage": "Nostr address (nip05)"
|
||||||
},
|
},
|
||||||
@ -380,9 +362,6 @@
|
|||||||
"CmZ9ls": {
|
"CmZ9ls": {
|
||||||
"defaultMessage": "{n} Muted"
|
"defaultMessage": "{n} Muted"
|
||||||
},
|
},
|
||||||
"CoVXRS": {
|
|
||||||
"defaultMessage": "Alternatively, you may choose to store your private key without a PIN by selecting 'Cancel.'"
|
|
||||||
},
|
|
||||||
"CsCUYo": {
|
"CsCUYo": {
|
||||||
"defaultMessage": "{n} sats"
|
"defaultMessage": "{n} sats"
|
||||||
},
|
},
|
||||||
@ -416,8 +395,8 @@
|
|||||||
"DtYelJ": {
|
"DtYelJ": {
|
||||||
"defaultMessage": "Transfer"
|
"defaultMessage": "Transfer"
|
||||||
},
|
},
|
||||||
"E8a4yq": {
|
"Dx4ey3": {
|
||||||
"defaultMessage": "Follow some popular accounts"
|
"defaultMessage": "Toggle all"
|
||||||
},
|
},
|
||||||
"EJbFi7": {
|
"EJbFi7": {
|
||||||
"defaultMessage": "Search notes"
|
"defaultMessage": "Search notes"
|
||||||
@ -425,9 +404,6 @@
|
|||||||
"ELbg9p": {
|
"ELbg9p": {
|
||||||
"defaultMessage": "Data Providers"
|
"defaultMessage": "Data Providers"
|
||||||
},
|
},
|
||||||
"EPYwm7": {
|
|
||||||
"defaultMessage": "Your private key is your password. If you lose this key, you will lose access to your account! Copy it and keep it in a safe place. There is no way to reset your private key."
|
|
||||||
},
|
|
||||||
"EQKRE4": {
|
"EQKRE4": {
|
||||||
"defaultMessage": "Show badges on profile pages"
|
"defaultMessage": "Show badges on profile pages"
|
||||||
},
|
},
|
||||||
@ -452,12 +428,6 @@
|
|||||||
"EnCOBJ": {
|
"EnCOBJ": {
|
||||||
"defaultMessage": "Buy"
|
"defaultMessage": "Buy"
|
||||||
},
|
},
|
||||||
"Eqjl5K": {
|
|
||||||
"defaultMessage": "Only Snort and our integration partner identifier gives you a colorful domain name, but you are welcome to use other services too."
|
|
||||||
},
|
|
||||||
"F+B3x1": {
|
|
||||||
"defaultMessage": "We have also partnered with nostrplebs.com to give you more options"
|
|
||||||
},
|
|
||||||
"F3l7xL": {
|
"F3l7xL": {
|
||||||
"defaultMessage": "Add Account"
|
"defaultMessage": "Add Account"
|
||||||
},
|
},
|
||||||
@ -467,9 +437,6 @@
|
|||||||
"FMfjrl": {
|
"FMfjrl": {
|
||||||
"defaultMessage": "Show status messages on profile pages"
|
"defaultMessage": "Show status messages on profile pages"
|
||||||
},
|
},
|
||||||
"FS3b54": {
|
|
||||||
"defaultMessage": "Done!"
|
|
||||||
},
|
|
||||||
"FSYL8G": {
|
"FSYL8G": {
|
||||||
"defaultMessage": "Trending Users"
|
"defaultMessage": "Trending Users"
|
||||||
},
|
},
|
||||||
@ -549,12 +516,6 @@
|
|||||||
"IKKHqV": {
|
"IKKHqV": {
|
||||||
"defaultMessage": "Follows"
|
"defaultMessage": "Follows"
|
||||||
},
|
},
|
||||||
"INSqIz": {
|
|
||||||
"defaultMessage": "Twitter username..."
|
|
||||||
},
|
|
||||||
"IUZC+0": {
|
|
||||||
"defaultMessage": "This means that nobody can modify notes which you have created and everybody can easily verify that the notes they are reading are created by you."
|
|
||||||
},
|
|
||||||
"IVbtTS": {
|
"IVbtTS": {
|
||||||
"defaultMessage": "Zap all {n} sats"
|
"defaultMessage": "Zap all {n} sats"
|
||||||
},
|
},
|
||||||
@ -573,6 +534,9 @@
|
|||||||
"J+dIsA": {
|
"J+dIsA": {
|
||||||
"defaultMessage": "Subscriptions"
|
"defaultMessage": "Subscriptions"
|
||||||
},
|
},
|
||||||
|
"J2HeQ+": {
|
||||||
|
"defaultMessage": "Use commas to separate words e.g. word1, word2, word3"
|
||||||
|
},
|
||||||
"JCIgkj": {
|
"JCIgkj": {
|
||||||
"defaultMessage": "Username"
|
"defaultMessage": "Username"
|
||||||
},
|
},
|
||||||
@ -582,6 +546,9 @@
|
|||||||
"JHEHCk": {
|
"JHEHCk": {
|
||||||
"defaultMessage": "Zaps ({n})"
|
"defaultMessage": "Zaps ({n})"
|
||||||
},
|
},
|
||||||
|
"JIVWWA": {
|
||||||
|
"defaultMessage": "Sport"
|
||||||
|
},
|
||||||
"JPFYIM": {
|
"JPFYIM": {
|
||||||
"defaultMessage": "No lightning address"
|
"defaultMessage": "No lightning address"
|
||||||
},
|
},
|
||||||
@ -616,9 +583,6 @@
|
|||||||
"KQvWvD": {
|
"KQvWvD": {
|
||||||
"defaultMessage": "Deleted"
|
"defaultMessage": "Deleted"
|
||||||
},
|
},
|
||||||
"KWuDfz": {
|
|
||||||
"defaultMessage": "I have saved my keys, continue"
|
|
||||||
},
|
|
||||||
"KahimY": {
|
"KahimY": {
|
||||||
"defaultMessage": "Unknown event kind: {kind}"
|
"defaultMessage": "Unknown event kind: {kind}"
|
||||||
},
|
},
|
||||||
@ -649,10 +613,6 @@
|
|||||||
"LwYmVi": {
|
"LwYmVi": {
|
||||||
"defaultMessage": "Zaps on this note will be split to the following users."
|
"defaultMessage": "Zaps on this note will be split to the following users."
|
||||||
},
|
},
|
||||||
"M10zFV": {
|
|
||||||
"defaultMessage": "Nostr Connect",
|
|
||||||
"description": "Login button for NIP-46 signer app"
|
|
||||||
},
|
|
||||||
"M3Oirc": {
|
"M3Oirc": {
|
||||||
"defaultMessage": "Debug Menus"
|
"defaultMessage": "Debug Menus"
|
||||||
},
|
},
|
||||||
@ -666,9 +626,6 @@
|
|||||||
"defaultMessage": "Wallet password",
|
"defaultMessage": "Wallet password",
|
||||||
"description": "Wallet password input placeholder"
|
"description": "Wallet password input placeholder"
|
||||||
},
|
},
|
||||||
"MRp6Ly": {
|
|
||||||
"defaultMessage": "Twitter username"
|
|
||||||
},
|
|
||||||
"MWTx65": {
|
"MWTx65": {
|
||||||
"defaultMessage": "Default Page"
|
"defaultMessage": "Default Page"
|
||||||
},
|
},
|
||||||
@ -696,27 +653,18 @@
|
|||||||
"NAuFNH": {
|
"NAuFNH": {
|
||||||
"defaultMessage": "You already have a subscription of this type, please renew or pay"
|
"defaultMessage": "You already have a subscription of this type, please renew or pay"
|
||||||
},
|
},
|
||||||
"NNSu3d": {
|
|
||||||
"defaultMessage": "Import Twitter Follows"
|
|
||||||
},
|
|
||||||
"NdOYJJ": {
|
"NdOYJJ": {
|
||||||
"defaultMessage": "Hmm nothing here.. Checkout {newUsersPage} to follow some recommended nostrich's!"
|
"defaultMessage": "Hmm nothing here.. Checkout {newUsersPage} to follow some recommended nostrich's!"
|
||||||
},
|
},
|
||||||
"NepkXH": {
|
"NepkXH": {
|
||||||
"defaultMessage": "Can't vote with {amount} sats, please set a different default zap amount"
|
"defaultMessage": "Can't vote with {amount} sats, please set a different default zap amount"
|
||||||
},
|
},
|
||||||
"NfNk2V": {
|
|
||||||
"defaultMessage": "Your private key"
|
|
||||||
},
|
|
||||||
"NndBJE": {
|
"NndBJE": {
|
||||||
"defaultMessage": "New users page"
|
"defaultMessage": "New users page"
|
||||||
},
|
},
|
||||||
"O8Z8t9": {
|
"O8Z8t9": {
|
||||||
"defaultMessage": "Show More"
|
"defaultMessage": "Show More"
|
||||||
},
|
},
|
||||||
"O9GTIc": {
|
|
||||||
"defaultMessage": "Profile picture"
|
|
||||||
},
|
|
||||||
"OEW7yJ": {
|
"OEW7yJ": {
|
||||||
"defaultMessage": "Zaps"
|
"defaultMessage": "Zaps"
|
||||||
},
|
},
|
||||||
@ -735,12 +683,6 @@
|
|||||||
"ORGv1Q": {
|
"ORGv1Q": {
|
||||||
"defaultMessage": "Created"
|
"defaultMessage": "Created"
|
||||||
},
|
},
|
||||||
"Oq/kVn": {
|
|
||||||
"defaultMessage": "Name-squatting and impersonation is not allowed. {site} and our partners reserve the right to terminate your handle (not your account - nobody can take that away) for violating this rule."
|
|
||||||
},
|
|
||||||
"P/xrLk": {
|
|
||||||
"defaultMessage": "Secure your private key with a PIN, ensuring enhanced protection on {site}. You'll be prompted to enter this PIN each time you access the site."
|
|
||||||
},
|
|
||||||
"P61BTu": {
|
"P61BTu": {
|
||||||
"defaultMessage": "Copy Event JSON"
|
"defaultMessage": "Copy Event JSON"
|
||||||
},
|
},
|
||||||
@ -757,12 +699,6 @@
|
|||||||
"defaultMessage": "Summary",
|
"defaultMessage": "Summary",
|
||||||
"description": "Notifications summary"
|
"description": "Notifications summary"
|
||||||
},
|
},
|
||||||
"PLSbmL": {
|
|
||||||
"defaultMessage": "Your mnemonic phrase"
|
|
||||||
},
|
|
||||||
"PaN7t3": {
|
|
||||||
"defaultMessage": "Preview on {site}"
|
|
||||||
},
|
|
||||||
"PamNxw": {
|
"PamNxw": {
|
||||||
"defaultMessage": "Unknown file header: {name}"
|
"defaultMessage": "Unknown file header: {name}"
|
||||||
},
|
},
|
||||||
@ -778,13 +714,6 @@
|
|||||||
"QWhotP": {
|
"QWhotP": {
|
||||||
"defaultMessage": "Zap Pool only works if you use one of the supported wallet connections (WebLN, LNC, LNDHub or Nostr Wallet Connect)"
|
"defaultMessage": "Zap Pool only works if you use one of the supported wallet connections (WebLN, LNC, LNDHub or Nostr Wallet Connect)"
|
||||||
},
|
},
|
||||||
"QawghE": {
|
|
||||||
"defaultMessage": "You can change your username at any point."
|
|
||||||
},
|
|
||||||
"QxCuTo": {
|
|
||||||
"defaultMessage": "Art by {name}",
|
|
||||||
"description": "Artwork attribution label"
|
|
||||||
},
|
|
||||||
"Qxv0B2": {
|
"Qxv0B2": {
|
||||||
"defaultMessage": "You currently have {number} sats in your zap pool."
|
"defaultMessage": "You currently have {number} sats in your zap pool."
|
||||||
},
|
},
|
||||||
@ -794,9 +723,6 @@
|
|||||||
"R81upa": {
|
"R81upa": {
|
||||||
"defaultMessage": "People you follow"
|
"defaultMessage": "People you follow"
|
||||||
},
|
},
|
||||||
"RDZVQL": {
|
|
||||||
"defaultMessage": "Check"
|
|
||||||
},
|
|
||||||
"RSr2uB": {
|
"RSr2uB": {
|
||||||
"defaultMessage": "Username must only contain lowercase letters and numbers"
|
"defaultMessage": "Username must only contain lowercase letters and numbers"
|
||||||
},
|
},
|
||||||
@ -813,6 +739,9 @@
|
|||||||
"defaultMessage": "Recent",
|
"defaultMessage": "Recent",
|
||||||
"description": "Sort order name"
|
"description": "Sort order name"
|
||||||
},
|
},
|
||||||
|
"RkW5we": {
|
||||||
|
"defaultMessage": "Bitcoin"
|
||||||
|
},
|
||||||
"RoOyAh": {
|
"RoOyAh": {
|
||||||
"defaultMessage": "Relays"
|
"defaultMessage": "Relays"
|
||||||
},
|
},
|
||||||
@ -844,6 +773,9 @@
|
|||||||
"Sjo1P4": {
|
"Sjo1P4": {
|
||||||
"defaultMessage": "Custom"
|
"defaultMessage": "Custom"
|
||||||
},
|
},
|
||||||
|
"SmuYUd": {
|
||||||
|
"defaultMessage": "What should we call you?"
|
||||||
|
},
|
||||||
"Ss0sWu": {
|
"Ss0sWu": {
|
||||||
"defaultMessage": "Pay Now"
|
"defaultMessage": "Pay Now"
|
||||||
},
|
},
|
||||||
@ -859,6 +791,12 @@
|
|||||||
"TP/cMX": {
|
"TP/cMX": {
|
||||||
"defaultMessage": "Ended"
|
"defaultMessage": "Ended"
|
||||||
},
|
},
|
||||||
|
"TaeBqw": {
|
||||||
|
"defaultMessage": "Sign in with Nostr Extension"
|
||||||
|
},
|
||||||
|
"TdtZQ5": {
|
||||||
|
"defaultMessage": "Crypto"
|
||||||
|
},
|
||||||
"TpgeGw": {
|
"TpgeGw": {
|
||||||
"defaultMessage": "Hex Salt..",
|
"defaultMessage": "Hex Salt..",
|
||||||
"description": "Hexidecimal 'salt' input for imgproxy"
|
"description": "Hexidecimal 'salt' input for imgproxy"
|
||||||
@ -884,15 +822,15 @@
|
|||||||
"UUPFlt": {
|
"UUPFlt": {
|
||||||
"defaultMessage": "Users must accept the content warning to show the content of your note."
|
"defaultMessage": "Users must accept the content warning to show the content of your note."
|
||||||
},
|
},
|
||||||
|
"Ub+AGc": {
|
||||||
|
"defaultMessage": "Sign In"
|
||||||
|
},
|
||||||
"Up5U7K": {
|
"Up5U7K": {
|
||||||
"defaultMessage": "Block"
|
"defaultMessage": "Block"
|
||||||
},
|
},
|
||||||
"UrKTqQ": {
|
"UrKTqQ": {
|
||||||
"defaultMessage": "You have an active iris.to account"
|
"defaultMessage": "You have an active iris.to account"
|
||||||
},
|
},
|
||||||
"VBadwB": {
|
|
||||||
"defaultMessage": "Hmm, can't find a key manager extension.. try reloading the page."
|
|
||||||
},
|
|
||||||
"VN0+Fz": {
|
"VN0+Fz": {
|
||||||
"defaultMessage": "Balance: {amount} sats"
|
"defaultMessage": "Balance: {amount} sats"
|
||||||
},
|
},
|
||||||
@ -914,9 +852,6 @@
|
|||||||
"VvaJst": {
|
"VvaJst": {
|
||||||
"defaultMessage": "View Wallets"
|
"defaultMessage": "View Wallets"
|
||||||
},
|
},
|
||||||
"Vx7Zm2": {
|
|
||||||
"defaultMessage": "How do keys work?"
|
|
||||||
},
|
|
||||||
"W1yoZY": {
|
"W1yoZY": {
|
||||||
"defaultMessage": "It looks like you dont have any subscriptions, you can get one {link}"
|
"defaultMessage": "It looks like you dont have any subscriptions, you can get one {link}"
|
||||||
},
|
},
|
||||||
@ -926,17 +861,14 @@
|
|||||||
"W9355R": {
|
"W9355R": {
|
||||||
"defaultMessage": "Unmute"
|
"defaultMessage": "Unmute"
|
||||||
},
|
},
|
||||||
"WONP5O": {
|
|
||||||
"defaultMessage": "Find your twitter follows on nostr (Data provided by {provider})"
|
|
||||||
},
|
|
||||||
"WmZhfL": {
|
"WmZhfL": {
|
||||||
"defaultMessage": "Automatically translate notes to your local language"
|
"defaultMessage": "Automatically translate notes to your local language"
|
||||||
},
|
},
|
||||||
"WvGmZT": {
|
"WvGmZT": {
|
||||||
"defaultMessage": "npub / nprofile / nostr address"
|
"defaultMessage": "npub / nprofile / nostr address"
|
||||||
},
|
},
|
||||||
"WxthCV": {
|
"X6tipZ": {
|
||||||
"defaultMessage": "e.g. Jack"
|
"defaultMessage": "Sign in with key"
|
||||||
},
|
},
|
||||||
"X7xU8J": {
|
"X7xU8J": {
|
||||||
"defaultMessage": "nsec, npub, nip-05, hex, mnemonic"
|
"defaultMessage": "nsec, npub, nip-05, hex, mnemonic"
|
||||||
@ -957,9 +889,6 @@
|
|||||||
"defaultMessage": "Redeem",
|
"defaultMessage": "Redeem",
|
||||||
"description": "Button: Redeem Cashu token"
|
"description": "Button: Redeem Cashu token"
|
||||||
},
|
},
|
||||||
"XzF0aC": {
|
|
||||||
"defaultMessage": "Key manager extensions are more secure and allow you to easily login to any Nostr client, here are some well known extensions:"
|
|
||||||
},
|
|
||||||
"YDURw6": {
|
"YDURw6": {
|
||||||
"defaultMessage": "Service URL"
|
"defaultMessage": "Service URL"
|
||||||
},
|
},
|
||||||
@ -981,8 +910,8 @@
|
|||||||
"Zff6lu": {
|
"Zff6lu": {
|
||||||
"defaultMessage": "Username iris.to/<b>{name}</b> is reserved for you!"
|
"defaultMessage": "Username iris.to/<b>{name}</b> is reserved for you!"
|
||||||
},
|
},
|
||||||
"Zr5TMx": {
|
"a+6cHB": {
|
||||||
"defaultMessage": "Setup profile"
|
"defaultMessage": "Derogatory"
|
||||||
},
|
},
|
||||||
"a5UPxh": {
|
"a5UPxh": {
|
||||||
"defaultMessage": "Fund developers and platforms providing NIP-05 verification services"
|
"defaultMessage": "Fund developers and platforms providing NIP-05 verification services"
|
||||||
@ -990,6 +919,12 @@
|
|||||||
"a7TDNm": {
|
"a7TDNm": {
|
||||||
"defaultMessage": "Notes will stream in real time into global and notes tab"
|
"defaultMessage": "Notes will stream in real time into global and notes tab"
|
||||||
},
|
},
|
||||||
|
"aHje0o": {
|
||||||
|
"defaultMessage": "Name or nym"
|
||||||
|
},
|
||||||
|
"aMaLBK": {
|
||||||
|
"defaultMessage": "Supported Extensions"
|
||||||
|
},
|
||||||
"aWpBzj": {
|
"aWpBzj": {
|
||||||
"defaultMessage": "Show more"
|
"defaultMessage": "Show more"
|
||||||
},
|
},
|
||||||
@ -1011,19 +946,12 @@
|
|||||||
"bfvyfs": {
|
"bfvyfs": {
|
||||||
"defaultMessage": "Anon"
|
"defaultMessage": "Anon"
|
||||||
},
|
},
|
||||||
"brAXSu": {
|
|
||||||
"defaultMessage": "Pick a username"
|
|
||||||
},
|
|
||||||
"bxv59V": {
|
"bxv59V": {
|
||||||
"defaultMessage": "Just now"
|
"defaultMessage": "Just now"
|
||||||
},
|
},
|
||||||
"c+JYNI": {
|
"c+JYNI": {
|
||||||
"defaultMessage": "No thanks"
|
"defaultMessage": "No thanks"
|
||||||
},
|
},
|
||||||
"c+oiJe": {
|
|
||||||
"defaultMessage": "Install Extension",
|
|
||||||
"description": "Heading for install key manager extension"
|
|
||||||
},
|
|
||||||
"c35bj2": {
|
"c35bj2": {
|
||||||
"defaultMessage": "If you have an enquiry about your NIP-05 order please DM {link}"
|
"defaultMessage": "If you have an enquiry about your NIP-05 order please DM {link}"
|
||||||
},
|
},
|
||||||
@ -1033,6 +961,9 @@
|
|||||||
"cFbU1B": {
|
"cFbU1B": {
|
||||||
"defaultMessage": "Using Alby? Go to {link} to get your NWC config!"
|
"defaultMessage": "Using Alby? Go to {link} to get your NWC config!"
|
||||||
},
|
},
|
||||||
|
"cHCwbF": {
|
||||||
|
"defaultMessage": "Photography"
|
||||||
|
},
|
||||||
"cPIKU2": {
|
"cPIKU2": {
|
||||||
"defaultMessage": "Following"
|
"defaultMessage": "Following"
|
||||||
},
|
},
|
||||||
@ -1055,6 +986,9 @@
|
|||||||
"cyR7Kh": {
|
"cyR7Kh": {
|
||||||
"defaultMessage": "Back"
|
"defaultMessage": "Back"
|
||||||
},
|
},
|
||||||
|
"d+6YsV": {
|
||||||
|
"defaultMessage": "Lists to mute:"
|
||||||
|
},
|
||||||
"d6CyG5": {
|
"d6CyG5": {
|
||||||
"defaultMessage": "History",
|
"defaultMessage": "History",
|
||||||
"description": "Wallet transation history"
|
"description": "Wallet transation history"
|
||||||
@ -1080,6 +1014,9 @@
|
|||||||
"e7qqly": {
|
"e7qqly": {
|
||||||
"defaultMessage": "Mark All Read"
|
"defaultMessage": "Mark All Read"
|
||||||
},
|
},
|
||||||
|
"eF0Re7": {
|
||||||
|
"defaultMessage": "Use a nostr signer extension to sign in"
|
||||||
|
},
|
||||||
"eHAneD": {
|
"eHAneD": {
|
||||||
"defaultMessage": "Reaction emoji"
|
"defaultMessage": "Reaction emoji"
|
||||||
},
|
},
|
||||||
@ -1104,6 +1041,9 @@
|
|||||||
"fWZYP5": {
|
"fWZYP5": {
|
||||||
"defaultMessage": "Pinned"
|
"defaultMessage": "Pinned"
|
||||||
},
|
},
|
||||||
|
"fX5RYm": {
|
||||||
|
"defaultMessage": "Pick a few topics of interest"
|
||||||
|
},
|
||||||
"filwqD": {
|
"filwqD": {
|
||||||
"defaultMessage": "Read"
|
"defaultMessage": "Read"
|
||||||
},
|
},
|
||||||
@ -1125,9 +1065,6 @@
|
|||||||
"g985Wp": {
|
"g985Wp": {
|
||||||
"defaultMessage": "Failed to send vote"
|
"defaultMessage": "Failed to send vote"
|
||||||
},
|
},
|
||||||
"gBdUXk": {
|
|
||||||
"defaultMessage": "Save your keys!"
|
|
||||||
},
|
|
||||||
"gDzDRs": {
|
"gDzDRs": {
|
||||||
"defaultMessage": "Emoji to send when reactiong to a note"
|
"defaultMessage": "Emoji to send when reactiong to a note"
|
||||||
},
|
},
|
||||||
@ -1146,12 +1083,12 @@
|
|||||||
"grQ+mI": {
|
"grQ+mI": {
|
||||||
"defaultMessage": "Proof of Work"
|
"defaultMessage": "Proof of Work"
|
||||||
},
|
},
|
||||||
|
"h7jvCs": {
|
||||||
|
"defaultMessage": "{site} is more fun together!"
|
||||||
|
},
|
||||||
"h8XMJL": {
|
"h8XMJL": {
|
||||||
"defaultMessage": "Badges"
|
"defaultMessage": "Badges"
|
||||||
},
|
},
|
||||||
"hK5ZDk": {
|
|
||||||
"defaultMessage": "the world"
|
|
||||||
},
|
|
||||||
"hMzcSq": {
|
"hMzcSq": {
|
||||||
"defaultMessage": "Messages"
|
"defaultMessage": "Messages"
|
||||||
},
|
},
|
||||||
@ -1176,9 +1113,6 @@
|
|||||||
"iCqGww": {
|
"iCqGww": {
|
||||||
"defaultMessage": "Reactions ({n})"
|
"defaultMessage": "Reactions ({n})"
|
||||||
},
|
},
|
||||||
"iDGAbc": {
|
|
||||||
"defaultMessage": "Get a Snort identifier"
|
|
||||||
},
|
|
||||||
"iEoXYx": {
|
"iEoXYx": {
|
||||||
"defaultMessage": "DeepL translations"
|
"defaultMessage": "DeepL translations"
|
||||||
},
|
},
|
||||||
@ -1209,6 +1143,9 @@
|
|||||||
"jAmfGl": {
|
"jAmfGl": {
|
||||||
"defaultMessage": "Your {site_name} subscription is expired"
|
"defaultMessage": "Your {site_name} subscription is expired"
|
||||||
},
|
},
|
||||||
|
"jHa/ko": {
|
||||||
|
"defaultMessage": "Clean up your feed"
|
||||||
|
},
|
||||||
"jMzO1S": {
|
"jMzO1S": {
|
||||||
"defaultMessage": "Internal error: {msg}"
|
"defaultMessage": "Internal error: {msg}"
|
||||||
},
|
},
|
||||||
@ -1216,9 +1153,6 @@
|
|||||||
"defaultMessage": "Back",
|
"defaultMessage": "Back",
|
||||||
"description": "Navigate back button on threads view"
|
"description": "Navigate back button on threads view"
|
||||||
},
|
},
|
||||||
"juhqvW": {
|
|
||||||
"defaultMessage": "Improve login security with browser extensions"
|
|
||||||
},
|
|
||||||
"jvo0vs": {
|
"jvo0vs": {
|
||||||
"defaultMessage": "Save"
|
"defaultMessage": "Save"
|
||||||
},
|
},
|
||||||
@ -1228,6 +1162,9 @@
|
|||||||
"k2veDA": {
|
"k2veDA": {
|
||||||
"defaultMessage": "Write"
|
"defaultMessage": "Write"
|
||||||
},
|
},
|
||||||
|
"k7+5Ny": {
|
||||||
|
"defaultMessage": "Hate Speech"
|
||||||
|
},
|
||||||
"k7sKNy": {
|
"k7sKNy": {
|
||||||
"defaultMessage": "Our very own NIP-05 verification service, help support the development of this site and get a shiny special badge on our site!"
|
"defaultMessage": "Our very own NIP-05 verification service, help support the development of this site and get a shiny special badge on our site!"
|
||||||
},
|
},
|
||||||
@ -1237,9 +1174,6 @@
|
|||||||
"kJYo0u": {
|
"kJYo0u": {
|
||||||
"defaultMessage": "{n,plural,=0{{name} reposted} other{{name} & {n} others reposted}}"
|
"defaultMessage": "{n,plural,=0{{name} reposted} other{{name} & {n} others reposted}}"
|
||||||
},
|
},
|
||||||
"kTLGM2": {
|
|
||||||
"defaultMessage": "{site} is designed to have a similar experience to Twitter."
|
|
||||||
},
|
|
||||||
"kaaf1E": {
|
"kaaf1E": {
|
||||||
"defaultMessage": "now"
|
"defaultMessage": "now"
|
||||||
},
|
},
|
||||||
@ -1249,9 +1183,6 @@
|
|||||||
"l+ikU1": {
|
"l+ikU1": {
|
||||||
"defaultMessage": "Everything in {plan}"
|
"defaultMessage": "Everything in {plan}"
|
||||||
},
|
},
|
||||||
"lBboHo": {
|
|
||||||
"defaultMessage": "If you want to try out some others, check out {link} for more!"
|
|
||||||
},
|
|
||||||
"lCILNz": {
|
"lCILNz": {
|
||||||
"defaultMessage": "Buy Now"
|
"defaultMessage": "Buy Now"
|
||||||
},
|
},
|
||||||
@ -1264,9 +1195,6 @@
|
|||||||
"lTbT3s": {
|
"lTbT3s": {
|
||||||
"defaultMessage": "Wallet password"
|
"defaultMessage": "Wallet password"
|
||||||
},
|
},
|
||||||
"lVKH7C": {
|
|
||||||
"defaultMessage": "What is {site} and how does it work?"
|
|
||||||
},
|
|
||||||
"lgg1KN": {
|
"lgg1KN": {
|
||||||
"defaultMessage": "account page"
|
"defaultMessage": "account page"
|
||||||
},
|
},
|
||||||
@ -1313,15 +1241,6 @@
|
|||||||
"nGBrvw": {
|
"nGBrvw": {
|
||||||
"defaultMessage": "Bookmarks"
|
"defaultMessage": "Bookmarks"
|
||||||
},
|
},
|
||||||
"nN9XTz": {
|
|
||||||
"defaultMessage": "Share your thoughts with {link}"
|
|
||||||
},
|
|
||||||
"nOaArs": {
|
|
||||||
"defaultMessage": "Setup Profile"
|
|
||||||
},
|
|
||||||
"ncbgUU": {
|
|
||||||
"defaultMessage": "{site} is a Nostr UI, nostr is a decentralised protocol for saving and distributing \"notes\"."
|
|
||||||
},
|
|
||||||
"nihgfo": {
|
"nihgfo": {
|
||||||
"defaultMessage": "Listen to this article"
|
"defaultMessage": "Listen to this article"
|
||||||
},
|
},
|
||||||
@ -1331,10 +1250,6 @@
|
|||||||
"nwZXeh": {
|
"nwZXeh": {
|
||||||
"defaultMessage": "{n} blocked"
|
"defaultMessage": "{n} blocked"
|
||||||
},
|
},
|
||||||
"o6Uy3d": {
|
|
||||||
"defaultMessage": "Only the secret key can be used to publish (sign events), everything else logs you in read-only mode.",
|
|
||||||
"description": "Explanation for public key only login is read-only"
|
|
||||||
},
|
|
||||||
"o7e+nJ": {
|
"o7e+nJ": {
|
||||||
"defaultMessage": "{n} followers"
|
"defaultMessage": "{n} followers"
|
||||||
},
|
},
|
||||||
@ -1344,19 +1259,9 @@
|
|||||||
"odFwjL": {
|
"odFwjL": {
|
||||||
"defaultMessage": "Follows only"
|
"defaultMessage": "Follows only"
|
||||||
},
|
},
|
||||||
"odhABf": {
|
|
||||||
"defaultMessage": "Login",
|
|
||||||
"description": "Login header"
|
|
||||||
},
|
|
||||||
"ojzbwv": {
|
"ojzbwv": {
|
||||||
"defaultMessage": "Hey, it looks like you dont have a Nostr Address yet, you should get one! Check out {link}"
|
"defaultMessage": "Hey, it looks like you dont have a Nostr Address yet, you should get one! Check out {link}"
|
||||||
},
|
},
|
||||||
"osUr8O": {
|
|
||||||
"defaultMessage": "You can also use these extensions to login to most Nostr sites."
|
|
||||||
},
|
|
||||||
"oxCa4R": {
|
|
||||||
"defaultMessage": "Getting an identifier helps confirm the real you to people who know you. Many people can have a username @jack, but there is only one jack@cash.app."
|
|
||||||
},
|
|
||||||
"p4N05H": {
|
"p4N05H": {
|
||||||
"defaultMessage": "Upload"
|
"defaultMessage": "Upload"
|
||||||
},
|
},
|
||||||
@ -1402,6 +1307,9 @@
|
|||||||
"qtWLmt": {
|
"qtWLmt": {
|
||||||
"defaultMessage": "Like"
|
"defaultMessage": "Like"
|
||||||
},
|
},
|
||||||
|
"qydxOd": {
|
||||||
|
"defaultMessage": "Science"
|
||||||
|
},
|
||||||
"qz9fty": {
|
"qz9fty": {
|
||||||
"defaultMessage": "Incorrect pin"
|
"defaultMessage": "Incorrect pin"
|
||||||
},
|
},
|
||||||
@ -1417,21 +1325,12 @@
|
|||||||
"rbrahO": {
|
"rbrahO": {
|
||||||
"defaultMessage": "Close"
|
"defaultMessage": "Close"
|
||||||
},
|
},
|
||||||
"reJ6SM": {
|
|
||||||
"defaultMessage": "It is recommended to use one of the following browser extensions if you are on a desktop computer to secure your key:"
|
|
||||||
},
|
|
||||||
"rfuMjE": {
|
"rfuMjE": {
|
||||||
"defaultMessage": "(Default)"
|
"defaultMessage": "(Default)"
|
||||||
},
|
},
|
||||||
"rmdsT4": {
|
"rmdsT4": {
|
||||||
"defaultMessage": "{n} days"
|
"defaultMessage": "{n} days"
|
||||||
},
|
},
|
||||||
"rrfdTe": {
|
|
||||||
"defaultMessage": "This is the same technology which is used by Bitcoin and has been proven to be extremely secure."
|
|
||||||
},
|
|
||||||
"rudscU": {
|
|
||||||
"defaultMessage": "Failed to load follows, please try again later"
|
|
||||||
},
|
|
||||||
"rx1i0i": {
|
"rx1i0i": {
|
||||||
"defaultMessage": "Short link"
|
"defaultMessage": "Short link"
|
||||||
},
|
},
|
||||||
@ -1471,6 +1370,9 @@
|
|||||||
"u4bHcR": {
|
"u4bHcR": {
|
||||||
"defaultMessage": "Check out the code here: {link}"
|
"defaultMessage": "Check out the code here: {link}"
|
||||||
},
|
},
|
||||||
|
"uCk8r+": {
|
||||||
|
"defaultMessage": "Already have an account?"
|
||||||
|
},
|
||||||
"uKqSN+": {
|
"uKqSN+": {
|
||||||
"defaultMessage": "Follows Feed"
|
"defaultMessage": "Follows Feed"
|
||||||
},
|
},
|
||||||
@ -1486,15 +1388,15 @@
|
|||||||
"usAvMr": {
|
"usAvMr": {
|
||||||
"defaultMessage": "Edit Profile"
|
"defaultMessage": "Edit Profile"
|
||||||
},
|
},
|
||||||
"ut+2Cd": {
|
|
||||||
"defaultMessage": "Get a partner identifier"
|
|
||||||
},
|
|
||||||
"v8lolG": {
|
"v8lolG": {
|
||||||
"defaultMessage": "Start chat"
|
"defaultMessage": "Start chat"
|
||||||
},
|
},
|
||||||
"vB3oQ/": {
|
"vB3oQ/": {
|
||||||
"defaultMessage": "Must be a contact list or pubkey list"
|
"defaultMessage": "Must be a contact list or pubkey list"
|
||||||
},
|
},
|
||||||
|
"vN5UH8": {
|
||||||
|
"defaultMessage": "Profile Image"
|
||||||
|
},
|
||||||
"vOKedj": {
|
"vOKedj": {
|
||||||
"defaultMessage": "{n,plural,=1{& {n} other} other{& {n} others}}"
|
"defaultMessage": "{n,plural,=1{& {n} other} other{& {n} others}}"
|
||||||
},
|
},
|
||||||
@ -1513,13 +1415,15 @@
|
|||||||
"vxwnbh": {
|
"vxwnbh": {
|
||||||
"defaultMessage": "Amount of work to apply to all published events"
|
"defaultMessage": "Amount of work to apply to all published events"
|
||||||
},
|
},
|
||||||
|
"w1Fanr": {
|
||||||
|
"defaultMessage": "Business"
|
||||||
|
},
|
||||||
|
"w6qrwX": {
|
||||||
|
"defaultMessage": "NSFW"
|
||||||
|
},
|
||||||
"wEQDC6": {
|
"wEQDC6": {
|
||||||
"defaultMessage": "Edit"
|
"defaultMessage": "Edit"
|
||||||
},
|
},
|
||||||
"wLtRCF": {
|
|
||||||
"defaultMessage": "Your key",
|
|
||||||
"description": "Label for key input"
|
|
||||||
},
|
|
||||||
"wSZR47": {
|
"wSZR47": {
|
||||||
"defaultMessage": "Submit"
|
"defaultMessage": "Submit"
|
||||||
},
|
},
|
||||||
@ -1539,9 +1443,6 @@
|
|||||||
"wtLjP6": {
|
"wtLjP6": {
|
||||||
"defaultMessage": "Copy ID"
|
"defaultMessage": "Copy ID"
|
||||||
},
|
},
|
||||||
"wuMvI5": {
|
|
||||||
"defaultMessage": "{site_name} Developers"
|
|
||||||
},
|
|
||||||
"x/Fx2P": {
|
"x/Fx2P": {
|
||||||
"defaultMessage": "Fund the services that you use by splitting a portion of all your zaps into a pool of funds!"
|
"defaultMessage": "Fund the services that you use by splitting a portion of all your zaps into a pool of funds!"
|
||||||
},
|
},
|
||||||
@ -1554,12 +1455,6 @@
|
|||||||
"xIoGG9": {
|
"xIoGG9": {
|
||||||
"defaultMessage": "Go to"
|
"defaultMessage": "Go to"
|
||||||
},
|
},
|
||||||
"xJ9n2N": {
|
|
||||||
"defaultMessage": "Your public key"
|
|
||||||
},
|
|
||||||
"xKflGN": {
|
|
||||||
"defaultMessage": "{username}''s Follows on Nostr"
|
|
||||||
},
|
|
||||||
"xQtL3v": {
|
"xQtL3v": {
|
||||||
"defaultMessage": "Unlock",
|
"defaultMessage": "Unlock",
|
||||||
"description": "Unlock wallet"
|
"description": "Unlock wallet"
|
||||||
@ -1573,6 +1468,9 @@
|
|||||||
"xhQMeQ": {
|
"xhQMeQ": {
|
||||||
"defaultMessage": "Expires"
|
"defaultMessage": "Expires"
|
||||||
},
|
},
|
||||||
|
"xl4s/X": {
|
||||||
|
"defaultMessage": "Additional Terms:"
|
||||||
|
},
|
||||||
"xmcVZ0": {
|
"xmcVZ0": {
|
||||||
"defaultMessage": "Search"
|
"defaultMessage": "Search"
|
||||||
},
|
},
|
||||||
@ -1600,9 +1498,6 @@
|
|||||||
"zcaOTs": {
|
"zcaOTs": {
|
||||||
"defaultMessage": "Zap amount in sats"
|
"defaultMessage": "Zap amount in sats"
|
||||||
},
|
},
|
||||||
"zjJZBd": {
|
|
||||||
"defaultMessage": "You're ready!"
|
|
||||||
},
|
|
||||||
"zm6qS1": {
|
"zm6qS1": {
|
||||||
"defaultMessage": "{n} mins to read"
|
"defaultMessage": "{n} mins to read"
|
||||||
},
|
},
|
||||||
|
@ -7,12 +7,12 @@
|
|||||||
"+vA//S": "Logins",
|
"+vA//S": "Logins",
|
||||||
"+vIQlC": "Please make sure to save the following password in order to manage your handle in the future",
|
"+vIQlC": "Please make sure to save the following password in order to manage your handle in the future",
|
||||||
"+vVZ/G": "Connect",
|
"+vVZ/G": "Connect",
|
||||||
|
"+vj0U3": "edit",
|
||||||
"+xliwN": "{name} reposted",
|
"+xliwN": "{name} reposted",
|
||||||
"/4tOwT": "Skip",
|
"/B8zwF": "Your space the way you want it 😌",
|
||||||
"/GCoTA": "Clear",
|
"/GCoTA": "Clear",
|
||||||
"/JE/X+": "Account Support",
|
"/JE/X+": "Account Support",
|
||||||
"/PCavi": "Public",
|
"/PCavi": "Public",
|
||||||
"/RD0e2": "Nostr uses digital signature technology to provide tamper proof notes which can safely be replicated to many relays to provide redundant storage of your content.",
|
|
||||||
"/Xf4UW": "Send anonymous usage metrics",
|
"/Xf4UW": "Send anonymous usage metrics",
|
||||||
"/clOBU": "Weekly",
|
"/clOBU": "Weekly",
|
||||||
"/d6vEc": "Make your profile easier to find and share",
|
"/d6vEc": "Make your profile easier to find and share",
|
||||||
@ -23,6 +23,7 @@
|
|||||||
"0BUTMv": "Search...",
|
"0BUTMv": "Search...",
|
||||||
"0jOEtS": "Invalid LNURL",
|
"0jOEtS": "Invalid LNURL",
|
||||||
"0mch2Y": "name has disallowed characters",
|
"0mch2Y": "name has disallowed characters",
|
||||||
|
"0siT4z": "Politics",
|
||||||
"0uoY11": "Show Status",
|
"0uoY11": "Show Status",
|
||||||
"0yO7wF": "{n} secs",
|
"0yO7wF": "{n} secs",
|
||||||
"1Mo59U": "Are you sure you want to remove this note from bookmarks?",
|
"1Mo59U": "Are you sure you want to remove this note from bookmarks?",
|
||||||
@ -30,38 +31,39 @@
|
|||||||
"1c4YST": "Connected to: {node} 🎉",
|
"1c4YST": "Connected to: {node} 🎉",
|
||||||
"1nYUGC": "{n} Following",
|
"1nYUGC": "{n} Following",
|
||||||
"1o2BgB": "Check Signatures",
|
"1o2BgB": "Check Signatures",
|
||||||
|
"1ozeyg": "Nature",
|
||||||
"1udzha": "Conversations",
|
"1udzha": "Conversations",
|
||||||
"2/2yg+": "Add",
|
"2/2yg+": "Add",
|
||||||
"25V4l1": "Banner",
|
"25V4l1": "Banner",
|
||||||
|
"25WwxF": "Don't have an account?",
|
||||||
"2IFGap": "Donate",
|
"2IFGap": "Donate",
|
||||||
"2LbrkB": "Enter password",
|
"2LbrkB": "Enter password",
|
||||||
|
"2O2sfp": "Finish",
|
||||||
"2a2YiP": "{n} Bookmarks",
|
"2a2YiP": "{n} Bookmarks",
|
||||||
"2k0Cv+": "Dislikes ({n})",
|
"2k0Cv+": "Dislikes ({n})",
|
||||||
"2ukA4d": "{n} hours",
|
"2ukA4d": "{n} hours",
|
||||||
"2zJXeA": "Profiles",
|
"2zJXeA": "Profiles",
|
||||||
|
"39AHJm": "Sign Up",
|
||||||
"3KNMbJ": "Articles",
|
"3KNMbJ": "Articles",
|
||||||
"3cc4Ct": "Light",
|
"3cc4Ct": "Light",
|
||||||
"3gOsZq": "Translators",
|
"3gOsZq": "Translators",
|
||||||
"3qnJlS": "You are voting with {amount} sats",
|
"3qnJlS": "You are voting with {amount} sats",
|
||||||
"3t3kok": "{n,plural,=1{{n} new note} other{{n} new notes}}",
|
"3t3kok": "{n,plural,=1{{n} new note} other{{n} new notes}}",
|
||||||
"3tVy+Z": "{n} Followers",
|
"3tVy+Z": "{n} Followers",
|
||||||
"3xCwbZ": "OR",
|
|
||||||
"3yk8fB": "Wallet",
|
"3yk8fB": "Wallet",
|
||||||
"40VR6s": "Nostr Connect",
|
|
||||||
"450Fty": "None",
|
"450Fty": "None",
|
||||||
"47FYwb": "Cancel",
|
"47FYwb": "Cancel",
|
||||||
"4IPzdn": "Primary Developers",
|
"4IPzdn": "Primary Developers",
|
||||||
"4L2vUY": "Your new NIP-05 handle is:",
|
"4L2vUY": "Your new NIP-05 handle is:",
|
||||||
"4MBtMa": "Name must be between 1 and 32 characters",
|
"4MBtMa": "Name must be between 1 and 32 characters",
|
||||||
|
"4MjsHk": "Life",
|
||||||
"4OB335": "Dislike",
|
"4OB335": "Dislike",
|
||||||
"4Vmpt4": "Nostr Plebs is one of the first NIP-05 providers in the space and offers a good collection of domains at reasonable prices",
|
"4Vmpt4": "Nostr Plebs is one of the first NIP-05 providers in the space and offers a good collection of domains at reasonable prices",
|
||||||
"4Z3t5i": "Use imgproxy to compress images",
|
"4Z3t5i": "Use imgproxy to compress images",
|
||||||
"4rYCjn": "Note to Self",
|
"4rYCjn": "Note to Self",
|
||||||
"5BVs2e": "zap",
|
"5BVs2e": "zap",
|
||||||
"5CB6zB": "Zap Splits",
|
"5CB6zB": "Zap Splits",
|
||||||
"5JcXdV": "Create Account",
|
|
||||||
"5oTnfy": "Buy Handle",
|
"5oTnfy": "Buy Handle",
|
||||||
"5rOdPG": "Once you setup your key manager extension and generated a key, you can follow our new users flow to setup your profile and help you find some interesting people on Nostr to follow.",
|
|
||||||
"5u6iEc": "Transfer to Pubkey",
|
"5u6iEc": "Transfer to Pubkey",
|
||||||
"5vMmmR": "Usernames are not unique on Nostr. The nostr address is your unique human-readable address that is unique to you upon registration.",
|
"5vMmmR": "Usernames are not unique on Nostr. The nostr address is your unique human-readable address that is unique to you upon registration.",
|
||||||
"5ykRmX": "Send zap",
|
"5ykRmX": "Send zap",
|
||||||
@ -71,12 +73,10 @@
|
|||||||
"65BmHb": "Failed to proxy image from {host}, click here to load directly",
|
"65BmHb": "Failed to proxy image from {host}, click here to load directly",
|
||||||
"6OSOXl": "Reason: <i>{reason}</i>",
|
"6OSOXl": "Reason: <i>{reason}</i>",
|
||||||
"6TfgXX": "{site} is an open source project built by passionate people in their free time",
|
"6TfgXX": "{site} is an open source project built by passionate people in their free time",
|
||||||
"6Yfvvp": "Get an identifier",
|
|
||||||
"6bgpn+": "Not all clients support this, you may still receive some zaps as if zap splits was not configured",
|
"6bgpn+": "Not all clients support this, you may still receive some zaps as if zap splits was not configured",
|
||||||
"6ewQqw": "Likes ({n})",
|
"6ewQqw": "Likes ({n})",
|
||||||
"6uMqL1": "Unpaid",
|
"6uMqL1": "Unpaid",
|
||||||
"7+Domh": "Notes",
|
"7+Domh": "Notes",
|
||||||
"7/h1jn": "After submitting the pin there may be a slight delay as we encrypt the key.",
|
|
||||||
"712i26": "Proxy uses HODL invoices to forward the payment, which hides the pubkey of your node",
|
"712i26": "Proxy uses HODL invoices to forward the payment, which hides the pubkey of your node",
|
||||||
"7BX/yC": "Account Switcher",
|
"7BX/yC": "Account Switcher",
|
||||||
"7UOvbT": "Offline",
|
"7UOvbT": "Offline",
|
||||||
@ -84,18 +84,15 @@
|
|||||||
"8/vBbP": "Reposts ({n})",
|
"8/vBbP": "Reposts ({n})",
|
||||||
"89q5wc": "Confirm Reposts",
|
"89q5wc": "Confirm Reposts",
|
||||||
"8ED/4u": "Reply To",
|
"8ED/4u": "Reply To",
|
||||||
"8Kboo2": "Scan this QR code with your signer app to get started",
|
|
||||||
"8QDesP": "Zap {n} sats",
|
"8QDesP": "Zap {n} sats",
|
||||||
"8Rkoyb": "Recipient",
|
"8Rkoyb": "Recipient",
|
||||||
"8Y6bZQ": "Invalid zap split: {input}",
|
"8Y6bZQ": "Invalid zap split: {input}",
|
||||||
"8g2vyB": "name too long",
|
"8g2vyB": "name too long",
|
||||||
"8v1NN+": "Pairing phrase",
|
"8v1NN+": "Pairing phrase",
|
||||||
"8xNnhi": "Nostr Extension",
|
|
||||||
"9+Ddtu": "Next",
|
"9+Ddtu": "Next",
|
||||||
"9HU8vw": "Reply",
|
"9HU8vw": "Reply",
|
||||||
"9SvQep": "Follows {n}",
|
"9SvQep": "Follows {n}",
|
||||||
"9WRlF4": "Send",
|
"9WRlF4": "Send",
|
||||||
"9gqH2W": "Login",
|
|
||||||
"9kSari": "Retry publishing",
|
"9kSari": "Retry publishing",
|
||||||
"9pMqYs": "Nostr Address",
|
"9pMqYs": "Nostr Address",
|
||||||
"9wO4wJ": "Lightning Invoice",
|
"9wO4wJ": "Lightning Invoice",
|
||||||
@ -103,9 +100,9 @@
|
|||||||
"ADmfQT": "Parent",
|
"ADmfQT": "Parent",
|
||||||
"AN0Z7Q": "Muted Words",
|
"AN0Z7Q": "Muted Words",
|
||||||
"ASRK0S": "This author has been muted",
|
"ASRK0S": "This author has been muted",
|
||||||
"Adk34V": "Setup your Profile",
|
|
||||||
"Ai8VHU": "Unlimited note retention on Snort relay",
|
"Ai8VHU": "Unlimited note retention on Snort relay",
|
||||||
"AkCxS/": "Reason",
|
"AkCxS/": "Reason",
|
||||||
|
"Am8glJ": "Game",
|
||||||
"AnLrRC": "Non-Zap",
|
"AnLrRC": "Non-Zap",
|
||||||
"AxDOiG": "Months",
|
"AxDOiG": "Months",
|
||||||
"AyGauy": "Login",
|
"AyGauy": "Login",
|
||||||
@ -113,9 +110,7 @@
|
|||||||
"B6+XJy": "zapped",
|
"B6+XJy": "zapped",
|
||||||
"B6H7eJ": "nsec, npub, nip-05, hex",
|
"B6H7eJ": "nsec, npub, nip-05, hex",
|
||||||
"BGCM48": "Write access to Snort relay, with 1 year of event retention",
|
"BGCM48": "Write access to Snort relay, with 1 year of event retention",
|
||||||
"BOUMjw": "No nostr users found for {twitterUsername}",
|
|
||||||
"BWpuKl": "Update",
|
"BWpuKl": "Update",
|
||||||
"BcGMo+": "Notes hold text content, the most popular usage of these notes is to store \"tweet like\" messages.",
|
|
||||||
"BjNwZW": "Nostr address (nip05)",
|
"BjNwZW": "Nostr address (nip05)",
|
||||||
"C1LjMx": "Lightning Donation",
|
"C1LjMx": "Lightning Donation",
|
||||||
"C7642/": "Quote Repost",
|
"C7642/": "Quote Repost",
|
||||||
@ -124,7 +119,6 @@
|
|||||||
"CHTbO3": "Failed to load invoice",
|
"CHTbO3": "Failed to load invoice",
|
||||||
"CVWeJ6": "Trending People",
|
"CVWeJ6": "Trending People",
|
||||||
"CmZ9ls": "{n} Muted",
|
"CmZ9ls": "{n} Muted",
|
||||||
"CoVXRS": "Alternatively, you may choose to store your private key without a PIN by selecting 'Cancel.'",
|
|
||||||
"CsCUYo": "{n} sats",
|
"CsCUYo": "{n} sats",
|
||||||
"Cu/K85": "Translated from {lang}",
|
"Cu/K85": "Translated from {lang}",
|
||||||
"D+KzKd": "Automatically zap every note when loaded",
|
"D+KzKd": "Automatically zap every note when loaded",
|
||||||
@ -136,10 +130,9 @@
|
|||||||
"Dh3hbq": "Auto Zap",
|
"Dh3hbq": "Auto Zap",
|
||||||
"Dn82AL": "Live",
|
"Dn82AL": "Live",
|
||||||
"DtYelJ": "Transfer",
|
"DtYelJ": "Transfer",
|
||||||
"E8a4yq": "Follow some popular accounts",
|
"Dx4ey3": "Toggle all",
|
||||||
"EJbFi7": "Search notes",
|
"EJbFi7": "Search notes",
|
||||||
"ELbg9p": "Data Providers",
|
"ELbg9p": "Data Providers",
|
||||||
"EPYwm7": "Your private key is your password. If you lose this key, you will lose access to your account! Copy it and keep it in a safe place. There is no way to reset your private key.",
|
|
||||||
"EQKRE4": "Show badges on profile pages",
|
"EQKRE4": "Show badges on profile pages",
|
||||||
"EWyQH5": "Global",
|
"EWyQH5": "Global",
|
||||||
"Ebl/B2": "Translate to {lang}",
|
"Ebl/B2": "Translate to {lang}",
|
||||||
@ -148,12 +141,9 @@
|
|||||||
"EcglP9": "Key",
|
"EcglP9": "Key",
|
||||||
"EjFyoR": "On-chain Donation Address",
|
"EjFyoR": "On-chain Donation Address",
|
||||||
"EnCOBJ": "Buy",
|
"EnCOBJ": "Buy",
|
||||||
"Eqjl5K": "Only Snort and our integration partner identifier gives you a colorful domain name, but you are welcome to use other services too.",
|
|
||||||
"F+B3x1": "We have also partnered with nostrplebs.com to give you more options",
|
|
||||||
"F3l7xL": "Add Account",
|
"F3l7xL": "Add Account",
|
||||||
"FDguSC": "{n} Zaps",
|
"FDguSC": "{n} Zaps",
|
||||||
"FMfjrl": "Show status messages on profile pages",
|
"FMfjrl": "Show status messages on profile pages",
|
||||||
"FS3b54": "Done!",
|
|
||||||
"FSYL8G": "Trending Users",
|
"FSYL8G": "Trending Users",
|
||||||
"FcNSft": "Redirect issues HTTP redirect to the supplied lightning address",
|
"FcNSft": "Redirect issues HTTP redirect to the supplied lightning address",
|
||||||
"FdhSU2": "Claim Now",
|
"FdhSU2": "Claim Now",
|
||||||
@ -180,17 +170,17 @@
|
|||||||
"HhcAVH": "You don't follow this person, click here to load media from <i>{link}</i>, or update <a><i>your preferences</i></a> to always load media from everybody.",
|
"HhcAVH": "You don't follow this person, click here to load media from <i>{link}</i>, or update <a><i>your preferences</i></a> to always load media from everybody.",
|
||||||
"IEwZvs": "Are you sure you want to unpin this note?",
|
"IEwZvs": "Are you sure you want to unpin this note?",
|
||||||
"IKKHqV": "Follows",
|
"IKKHqV": "Follows",
|
||||||
"INSqIz": "Twitter username...",
|
|
||||||
"IUZC+0": "This means that nobody can modify notes which you have created and everybody can easily verify that the notes they are reading are created by you.",
|
|
||||||
"IVbtTS": "Zap all {n} sats",
|
"IVbtTS": "Zap all {n} sats",
|
||||||
"IWz1ta": "Auto Translate",
|
"IWz1ta": "Auto Translate",
|
||||||
"Ig9/a1": "Sent {n} sats to {name}",
|
"Ig9/a1": "Sent {n} sats to {name}",
|
||||||
"IoQq+a": "Click here to load anyway",
|
"IoQq+a": "Click here to load anyway",
|
||||||
"Ix8l+B": "Trending Notes",
|
"Ix8l+B": "Trending Notes",
|
||||||
"J+dIsA": "Subscriptions",
|
"J+dIsA": "Subscriptions",
|
||||||
|
"J2HeQ+": "Use commas to separate words e.g. word1, word2, word3",
|
||||||
"JCIgkj": "Username",
|
"JCIgkj": "Username",
|
||||||
"JGrt9q": "Send sats to {name}",
|
"JGrt9q": "Send sats to {name}",
|
||||||
"JHEHCk": "Zaps ({n})",
|
"JHEHCk": "Zaps ({n})",
|
||||||
|
"JIVWWA": "Sport",
|
||||||
"JPFYIM": "No lightning address",
|
"JPFYIM": "No lightning address",
|
||||||
"JSx7y9": "Subscribe to {site_name} {plan} for {price} and receive the following rewards",
|
"JSx7y9": "Subscribe to {site_name} {plan} for {price} and receive the following rewards",
|
||||||
"JeoS4y": "Repost",
|
"JeoS4y": "Repost",
|
||||||
@ -202,7 +192,6 @@
|
|||||||
"KAhAcM": "Enter LNDHub config",
|
"KAhAcM": "Enter LNDHub config",
|
||||||
"KHK8B9": "Relay",
|
"KHK8B9": "Relay",
|
||||||
"KQvWvD": "Deleted",
|
"KQvWvD": "Deleted",
|
||||||
"KWuDfz": "I have saved my keys, continue",
|
|
||||||
"KahimY": "Unknown event kind: {kind}",
|
"KahimY": "Unknown event kind: {kind}",
|
||||||
"KoFlZg": "Enter mint URL",
|
"KoFlZg": "Enter mint URL",
|
||||||
"KtsyO0": "Enter Pin",
|
"KtsyO0": "Enter Pin",
|
||||||
@ -213,12 +202,10 @@
|
|||||||
"Lu5/Bj": "Open on Zapstr",
|
"Lu5/Bj": "Open on Zapstr",
|
||||||
"Lw+I+J": "{n,plural,=0{{name} zapped} other{{name} & {n} others zapped}}",
|
"Lw+I+J": "{n,plural,=0{{name} zapped} other{{name} & {n} others zapped}}",
|
||||||
"LwYmVi": "Zaps on this note will be split to the following users.",
|
"LwYmVi": "Zaps on this note will be split to the following users.",
|
||||||
"M10zFV": "Nostr Connect",
|
|
||||||
"M3Oirc": "Debug Menus",
|
"M3Oirc": "Debug Menus",
|
||||||
"MBAYRO": "Shows \"Copy ID\" and \"Copy Event JSON\" in the context menu on each message",
|
"MBAYRO": "Shows \"Copy ID\" and \"Copy Event JSON\" in the context menu on each message",
|
||||||
"MI2jkA": "Not available:",
|
"MI2jkA": "Not available:",
|
||||||
"MP54GY": "Wallet password",
|
"MP54GY": "Wallet password",
|
||||||
"MRp6Ly": "Twitter username",
|
|
||||||
"MWTx65": "Default Page",
|
"MWTx65": "Default Page",
|
||||||
"MiMipu": "Set as primary Nostr address (nip05)",
|
"MiMipu": "Set as primary Nostr address (nip05)",
|
||||||
"Mrpkot": "Pay for subscription",
|
"Mrpkot": "Pay for subscription",
|
||||||
@ -228,44 +215,35 @@
|
|||||||
"N2IrpM": "Confirm",
|
"N2IrpM": "Confirm",
|
||||||
"NAidKb": "Notifications",
|
"NAidKb": "Notifications",
|
||||||
"NAuFNH": "You already have a subscription of this type, please renew or pay",
|
"NAuFNH": "You already have a subscription of this type, please renew or pay",
|
||||||
"NNSu3d": "Import Twitter Follows",
|
|
||||||
"NdOYJJ": "Hmm nothing here.. Checkout {newUsersPage} to follow some recommended nostrich's!",
|
"NdOYJJ": "Hmm nothing here.. Checkout {newUsersPage} to follow some recommended nostrich's!",
|
||||||
"NepkXH": "Can't vote with {amount} sats, please set a different default zap amount",
|
"NepkXH": "Can't vote with {amount} sats, please set a different default zap amount",
|
||||||
"NfNk2V": "Your private key",
|
|
||||||
"NndBJE": "New users page",
|
"NndBJE": "New users page",
|
||||||
"O8Z8t9": "Show More",
|
"O8Z8t9": "Show More",
|
||||||
"O9GTIc": "Profile picture",
|
|
||||||
"OEW7yJ": "Zaps",
|
"OEW7yJ": "Zaps",
|
||||||
"OKhRC6": "Share",
|
"OKhRC6": "Share",
|
||||||
"OLEm6z": "Unknown login error",
|
"OLEm6z": "Unknown login error",
|
||||||
"OQSOJF": "Get a free nostr address",
|
"OQSOJF": "Get a free nostr address",
|
||||||
"OQXnew": "You subscription is still active, you can't renew yet",
|
"OQXnew": "You subscription is still active, you can't renew yet",
|
||||||
"ORGv1Q": "Created",
|
"ORGv1Q": "Created",
|
||||||
"Oq/kVn": "Name-squatting and impersonation is not allowed. {site} and our partners reserve the right to terminate your handle (not your account - nobody can take that away) for violating this rule.",
|
|
||||||
"P/xrLk": "Secure your private key with a PIN, ensuring enhanced protection on {site}. You'll be prompted to enter this PIN each time you access the site.",
|
|
||||||
"P61BTu": "Copy Event JSON",
|
"P61BTu": "Copy Event JSON",
|
||||||
"P7FD0F": "System (Default)",
|
"P7FD0F": "System (Default)",
|
||||||
"P7nJT9": "Total today (UTC): {amount} sats",
|
"P7nJT9": "Total today (UTC): {amount} sats",
|
||||||
"PCSt5T": "Preferences",
|
"PCSt5T": "Preferences",
|
||||||
"PJeJFc": "Summary",
|
"PJeJFc": "Summary",
|
||||||
"PLSbmL": "Your mnemonic phrase",
|
|
||||||
"PaN7t3": "Preview on {site}",
|
|
||||||
"PamNxw": "Unknown file header: {name}",
|
"PamNxw": "Unknown file header: {name}",
|
||||||
"Pe0ogR": "Theme",
|
"Pe0ogR": "Theme",
|
||||||
"PrsIg7": "Reactions will be shown on every page, if disabled no reactions will be shown",
|
"PrsIg7": "Reactions will be shown on every page, if disabled no reactions will be shown",
|
||||||
"QDFTjG": "{n} Relays",
|
"QDFTjG": "{n} Relays",
|
||||||
"QWhotP": "Zap Pool only works if you use one of the supported wallet connections (WebLN, LNC, LNDHub or Nostr Wallet Connect)",
|
"QWhotP": "Zap Pool only works if you use one of the supported wallet connections (WebLN, LNC, LNDHub or Nostr Wallet Connect)",
|
||||||
"QawghE": "You can change your username at any point.",
|
|
||||||
"QxCuTo": "Art by {name}",
|
|
||||||
"Qxv0B2": "You currently have {number} sats in your zap pool.",
|
"Qxv0B2": "You currently have {number} sats in your zap pool.",
|
||||||
"R/6nsx": "Subscription",
|
"R/6nsx": "Subscription",
|
||||||
"R81upa": "People you follow",
|
"R81upa": "People you follow",
|
||||||
"RDZVQL": "Check",
|
|
||||||
"RSr2uB": "Username must only contain lowercase letters and numbers",
|
"RSr2uB": "Username must only contain lowercase letters and numbers",
|
||||||
"RahCRH": "Expired",
|
"RahCRH": "Expired",
|
||||||
"RfhLwC": "By: {author}",
|
"RfhLwC": "By: {author}",
|
||||||
"RhDAoS": "Are you sure you want to delete {id}",
|
"RhDAoS": "Are you sure you want to delete {id}",
|
||||||
"RjpoYG": "Recent",
|
"RjpoYG": "Recent",
|
||||||
|
"RkW5we": "Bitcoin",
|
||||||
"RoOyAh": "Relays",
|
"RoOyAh": "Relays",
|
||||||
"Rs4kCE": "Bookmark",
|
"Rs4kCE": "Bookmark",
|
||||||
"RwFaYs": "Sort",
|
"RwFaYs": "Sort",
|
||||||
@ -276,11 +254,14 @@
|
|||||||
"SYQtZ7": "LN Address Proxy",
|
"SYQtZ7": "LN Address Proxy",
|
||||||
"ShdEie": "Mark all read",
|
"ShdEie": "Mark all read",
|
||||||
"Sjo1P4": "Custom",
|
"Sjo1P4": "Custom",
|
||||||
|
"SmuYUd": "What should we call you?",
|
||||||
"Ss0sWu": "Pay Now",
|
"Ss0sWu": "Pay Now",
|
||||||
"StKzTE": "The author has marked this note as a <i>sensitive topic</i>",
|
"StKzTE": "The author has marked this note as a <i>sensitive topic</i>",
|
||||||
"TDR5ge": "Media in notes will automatically be shown for selected people, otherwise only the link will show",
|
"TDR5ge": "Media in notes will automatically be shown for selected people, otherwise only the link will show",
|
||||||
"TJo5E6": "Preview",
|
"TJo5E6": "Preview",
|
||||||
"TP/cMX": "Ended",
|
"TP/cMX": "Ended",
|
||||||
|
"TaeBqw": "Sign in with Nostr Extension",
|
||||||
|
"TdtZQ5": "Crypto",
|
||||||
"TpgeGw": "Hex Salt..",
|
"TpgeGw": "Hex Salt..",
|
||||||
"Tpy00S": "People",
|
"Tpy00S": "People",
|
||||||
"U1aPPi": "Stop listening",
|
"U1aPPi": "Stop listening",
|
||||||
@ -289,9 +270,9 @@
|
|||||||
"UNjfWJ": "Check all event signatures received from relays",
|
"UNjfWJ": "Check all event signatures received from relays",
|
||||||
"UT7Nkj": "New Chat",
|
"UT7Nkj": "New Chat",
|
||||||
"UUPFlt": "Users must accept the content warning to show the content of your note.",
|
"UUPFlt": "Users must accept the content warning to show the content of your note.",
|
||||||
|
"Ub+AGc": "Sign In",
|
||||||
"Up5U7K": "Block",
|
"Up5U7K": "Block",
|
||||||
"UrKTqQ": "You have an active iris.to account",
|
"UrKTqQ": "You have an active iris.to account",
|
||||||
"VBadwB": "Hmm, can't find a key manager extension.. try reloading the page.",
|
|
||||||
"VN0+Fz": "Balance: {amount} sats",
|
"VN0+Fz": "Balance: {amount} sats",
|
||||||
"VOjC1i": "Pick which upload service you want to upload attachments to",
|
"VOjC1i": "Pick which upload service you want to upload attachments to",
|
||||||
"VR5eHw": "Public key (npub/nprofile)",
|
"VR5eHw": "Public key (npub/nprofile)",
|
||||||
@ -299,21 +280,18 @@
|
|||||||
"VlJkSk": "{n} muted",
|
"VlJkSk": "{n} muted",
|
||||||
"VnXp8Z": "Avatar",
|
"VnXp8Z": "Avatar",
|
||||||
"VvaJst": "View Wallets",
|
"VvaJst": "View Wallets",
|
||||||
"Vx7Zm2": "How do keys work?",
|
|
||||||
"W1yoZY": "It looks like you dont have any subscriptions, you can get one {link}",
|
"W1yoZY": "It looks like you dont have any subscriptions, you can get one {link}",
|
||||||
"W2PiAr": "{n} Blocked",
|
"W2PiAr": "{n} Blocked",
|
||||||
"W9355R": "Unmute",
|
"W9355R": "Unmute",
|
||||||
"WONP5O": "Find your twitter follows on nostr (Data provided by {provider})",
|
|
||||||
"WmZhfL": "Automatically translate notes to your local language",
|
"WmZhfL": "Automatically translate notes to your local language",
|
||||||
"WvGmZT": "npub / nprofile / nostr address",
|
"WvGmZT": "npub / nprofile / nostr address",
|
||||||
"WxthCV": "e.g. Jack",
|
"X6tipZ": "Sign in with key",
|
||||||
"X7xU8J": "nsec, npub, nip-05, hex, mnemonic",
|
"X7xU8J": "nsec, npub, nip-05, hex, mnemonic",
|
||||||
"XECMfW": "Send usage metrics",
|
"XECMfW": "Send usage metrics",
|
||||||
"XICsE8": "File hosts",
|
"XICsE8": "File hosts",
|
||||||
"XgWvGA": "Reactions",
|
"XgWvGA": "Reactions",
|
||||||
"Xopqkl": "Your default zap amount is {number} sats, example values are calculated from this.",
|
"Xopqkl": "Your default zap amount is {number} sats, example values are calculated from this.",
|
||||||
"XrSk2j": "Redeem",
|
"XrSk2j": "Redeem",
|
||||||
"XzF0aC": "Key manager extensions are more secure and allow you to easily login to any Nostr client, here are some well known extensions:",
|
|
||||||
"YDURw6": "Service URL",
|
"YDURw6": "Service URL",
|
||||||
"YXA3AH": "Enable reactions",
|
"YXA3AH": "Enable reactions",
|
||||||
"Z4BMCZ": "Enter pairing phrase",
|
"Z4BMCZ": "Enter pairing phrase",
|
||||||
@ -321,9 +299,11 @@
|
|||||||
"ZLmyG9": "Contributors",
|
"ZLmyG9": "Contributors",
|
||||||
"ZS+jRE": "Send zap splits to",
|
"ZS+jRE": "Send zap splits to",
|
||||||
"Zff6lu": "Username iris.to/<b>{name}</b> is reserved for you!",
|
"Zff6lu": "Username iris.to/<b>{name}</b> is reserved for you!",
|
||||||
"Zr5TMx": "Setup profile",
|
"a+6cHB": "Derogatory",
|
||||||
"a5UPxh": "Fund developers and platforms providing NIP-05 verification services",
|
"a5UPxh": "Fund developers and platforms providing NIP-05 verification services",
|
||||||
"a7TDNm": "Notes will stream in real time into global and notes tab",
|
"a7TDNm": "Notes will stream in real time into global and notes tab",
|
||||||
|
"aHje0o": "Name or nym",
|
||||||
|
"aMaLBK": "Supported Extensions",
|
||||||
"aWpBzj": "Show more",
|
"aWpBzj": "Show more",
|
||||||
"b12Goz": "Mnemonic",
|
"b12Goz": "Mnemonic",
|
||||||
"b5vAk0": "Your handle will act like a lightning address and will redirect to your chosen LNURL or Lightning address",
|
"b5vAk0": "Your handle will act like a lightning address and will redirect to your chosen LNURL or Lightning address",
|
||||||
@ -331,13 +311,12 @@
|
|||||||
"bQdA2k": "Sensitive Content",
|
"bQdA2k": "Sensitive Content",
|
||||||
"bep9C3": "Public Key",
|
"bep9C3": "Public Key",
|
||||||
"bfvyfs": "Anon",
|
"bfvyfs": "Anon",
|
||||||
"brAXSu": "Pick a username",
|
|
||||||
"bxv59V": "Just now",
|
"bxv59V": "Just now",
|
||||||
"c+JYNI": "No thanks",
|
"c+JYNI": "No thanks",
|
||||||
"c+oiJe": "Install Extension",
|
|
||||||
"c35bj2": "If you have an enquiry about your NIP-05 order please DM {link}",
|
"c35bj2": "If you have an enquiry about your NIP-05 order please DM {link}",
|
||||||
"c3g2hL": "Broadcast Again",
|
"c3g2hL": "Broadcast Again",
|
||||||
"cFbU1B": "Using Alby? Go to {link} to get your NWC config!",
|
"cFbU1B": "Using Alby? Go to {link} to get your NWC config!",
|
||||||
|
"cHCwbF": "Photography",
|
||||||
"cPIKU2": "Following",
|
"cPIKU2": "Following",
|
||||||
"cQfLWb": "URL..",
|
"cQfLWb": "URL..",
|
||||||
"cWx9t8": "Mute all",
|
"cWx9t8": "Mute all",
|
||||||
@ -345,6 +324,7 @@
|
|||||||
"cuP16y": "Multi account support",
|
"cuP16y": "Multi account support",
|
||||||
"cuV2gK": "name is registered",
|
"cuV2gK": "name is registered",
|
||||||
"cyR7Kh": "Back",
|
"cyR7Kh": "Back",
|
||||||
|
"d+6YsV": "Lists to mute:",
|
||||||
"d6CyG5": "History",
|
"d6CyG5": "History",
|
||||||
"d7d0/x": "LN Address",
|
"d7d0/x": "LN Address",
|
||||||
"dOQCL8": "Display name",
|
"dOQCL8": "Display name",
|
||||||
@ -353,6 +333,7 @@
|
|||||||
"e61Jf3": "Coming soon",
|
"e61Jf3": "Coming soon",
|
||||||
"e7VmYP": "Enter pin to unlock your private key",
|
"e7VmYP": "Enter pin to unlock your private key",
|
||||||
"e7qqly": "Mark All Read",
|
"e7qqly": "Mark All Read",
|
||||||
|
"eF0Re7": "Use a nostr signer extension to sign in",
|
||||||
"eHAneD": "Reaction emoji",
|
"eHAneD": "Reaction emoji",
|
||||||
"eJj8HD": "Get Verified",
|
"eJj8HD": "Get Verified",
|
||||||
"eSzf2G": "A single zap of {nIn} sats will allocate {nOut} sats to the zap pool.",
|
"eSzf2G": "A single zap of {nIn} sats will allocate {nOut} sats to the zap pool.",
|
||||||
@ -361,6 +342,7 @@
|
|||||||
"fBlba3": "Thanks for using {site}, please consider donating if you can.",
|
"fBlba3": "Thanks for using {site}, please consider donating if you can.",
|
||||||
"fOksnD": "Can't vote because LNURL service does not support zaps",
|
"fOksnD": "Can't vote because LNURL service does not support zaps",
|
||||||
"fWZYP5": "Pinned",
|
"fWZYP5": "Pinned",
|
||||||
|
"fX5RYm": "Pick a few topics of interest",
|
||||||
"filwqD": "Read",
|
"filwqD": "Read",
|
||||||
"fjAcWo": "Gift Wraps",
|
"fjAcWo": "Gift Wraps",
|
||||||
"flnGvv": "What's on your mind?",
|
"flnGvv": "What's on your mind?",
|
||||||
@ -368,15 +350,14 @@
|
|||||||
"fsB/4p": "Saved",
|
"fsB/4p": "Saved",
|
||||||
"g5pX+a": "About",
|
"g5pX+a": "About",
|
||||||
"g985Wp": "Failed to send vote",
|
"g985Wp": "Failed to send vote",
|
||||||
"gBdUXk": "Save your keys!",
|
|
||||||
"gDzDRs": "Emoji to send when reactiong to a note",
|
"gDzDRs": "Emoji to send when reactiong to a note",
|
||||||
"gXgY3+": "Not all clients support this yet",
|
"gXgY3+": "Not all clients support this yet",
|
||||||
"gczcC5": "Subscribe",
|
"gczcC5": "Subscribe",
|
||||||
"geppt8": "{count} ({count2} in memory)",
|
"geppt8": "{count} ({count2} in memory)",
|
||||||
"gjBiyj": "Loading...",
|
"gjBiyj": "Loading...",
|
||||||
"grQ+mI": "Proof of Work",
|
"grQ+mI": "Proof of Work",
|
||||||
|
"h7jvCs": "{site} is more fun together!",
|
||||||
"h8XMJL": "Badges",
|
"h8XMJL": "Badges",
|
||||||
"hK5ZDk": "the world",
|
|
||||||
"hMzcSq": "Messages",
|
"hMzcSq": "Messages",
|
||||||
"hRTfTR": "PRO",
|
"hRTfTR": "PRO",
|
||||||
"hY4lzx": "Supports",
|
"hY4lzx": "Supports",
|
||||||
@ -385,7 +366,6 @@
|
|||||||
"hniz8Z": "here",
|
"hniz8Z": "here",
|
||||||
"i/dBAR": "Zap Pool",
|
"i/dBAR": "Zap Pool",
|
||||||
"iCqGww": "Reactions ({n})",
|
"iCqGww": "Reactions ({n})",
|
||||||
"iDGAbc": "Get a Snort identifier",
|
|
||||||
"iEoXYx": "DeepL translations",
|
"iEoXYx": "DeepL translations",
|
||||||
"iGT1eE": "Prevent fake accounts from imitating you",
|
"iGT1eE": "Prevent fake accounts from imitating you",
|
||||||
"iNWbVV": "Handle",
|
"iNWbVV": "Handle",
|
||||||
@ -396,25 +376,23 @@
|
|||||||
"izWS4J": "Unfollow",
|
"izWS4J": "Unfollow",
|
||||||
"jA3OE/": "{n,plural,=1{{n} sat} other{{n} sats}}",
|
"jA3OE/": "{n,plural,=1{{n} sat} other{{n} sats}}",
|
||||||
"jAmfGl": "Your {site_name} subscription is expired",
|
"jAmfGl": "Your {site_name} subscription is expired",
|
||||||
|
"jHa/ko": "Clean up your feed",
|
||||||
"jMzO1S": "Internal error: {msg}",
|
"jMzO1S": "Internal error: {msg}",
|
||||||
"jfV8Wr": "Back",
|
"jfV8Wr": "Back",
|
||||||
"juhqvW": "Improve login security with browser extensions",
|
|
||||||
"jvo0vs": "Save",
|
"jvo0vs": "Save",
|
||||||
"jzgQ2z": "{n} Reactions",
|
"jzgQ2z": "{n} Reactions",
|
||||||
"k2veDA": "Write",
|
"k2veDA": "Write",
|
||||||
|
"k7+5Ny": "Hate Speech",
|
||||||
"k7sKNy": "Our very own NIP-05 verification service, help support the development of this site and get a shiny special badge on our site!",
|
"k7sKNy": "Our very own NIP-05 verification service, help support the development of this site and get a shiny special badge on our site!",
|
||||||
"kEZUR8": "Register an Iris username",
|
"kEZUR8": "Register an Iris username",
|
||||||
"kJYo0u": "{n,plural,=0{{name} reposted} other{{name} & {n} others reposted}}",
|
"kJYo0u": "{n,plural,=0{{name} reposted} other{{name} & {n} others reposted}}",
|
||||||
"kTLGM2": "{site} is designed to have a similar experience to Twitter.",
|
|
||||||
"kaaf1E": "now",
|
"kaaf1E": "now",
|
||||||
"kuPHYE": "{n,plural,=0{{name} liked} other{{name} & {n} others liked}}",
|
"kuPHYE": "{n,plural,=0{{name} liked} other{{name} & {n} others liked}}",
|
||||||
"l+ikU1": "Everything in {plan}",
|
"l+ikU1": "Everything in {plan}",
|
||||||
"lBboHo": "If you want to try out some others, check out {link} for more!",
|
|
||||||
"lCILNz": "Buy Now",
|
"lCILNz": "Buy Now",
|
||||||
"lD3+8a": "Pay",
|
"lD3+8a": "Pay",
|
||||||
"lPWASz": "Snort nostr address",
|
"lPWASz": "Snort nostr address",
|
||||||
"lTbT3s": "Wallet password",
|
"lTbT3s": "Wallet password",
|
||||||
"lVKH7C": "What is {site} and how does it work?",
|
|
||||||
"lgg1KN": "account page",
|
"lgg1KN": "account page",
|
||||||
"ll3xBp": "Image proxy service",
|
"ll3xBp": "Image proxy service",
|
||||||
"lnaT9F": "Following {n}",
|
"lnaT9F": "Following {n}",
|
||||||
@ -430,20 +408,13 @@
|
|||||||
"n1Whvj": "Switch",
|
"n1Whvj": "Switch",
|
||||||
"nDejmx": "Unblock",
|
"nDejmx": "Unblock",
|
||||||
"nGBrvw": "Bookmarks",
|
"nGBrvw": "Bookmarks",
|
||||||
"nN9XTz": "Share your thoughts with {link}",
|
|
||||||
"nOaArs": "Setup Profile",
|
|
||||||
"ncbgUU": "{site} is a Nostr UI, nostr is a decentralised protocol for saving and distributing \"notes\".",
|
|
||||||
"nihgfo": "Listen to this article",
|
"nihgfo": "Listen to this article",
|
||||||
"nn1qb3": "Your donations are greatly appreciated",
|
"nn1qb3": "Your donations are greatly appreciated",
|
||||||
"nwZXeh": "{n} blocked",
|
"nwZXeh": "{n} blocked",
|
||||||
"o6Uy3d": "Only the secret key can be used to publish (sign events), everything else logs you in read-only mode.",
|
|
||||||
"o7e+nJ": "{n} followers",
|
"o7e+nJ": "{n} followers",
|
||||||
"oJ+JJN": "Nothing found :/",
|
"oJ+JJN": "Nothing found :/",
|
||||||
"odFwjL": "Follows only",
|
"odFwjL": "Follows only",
|
||||||
"odhABf": "Login",
|
|
||||||
"ojzbwv": "Hey, it looks like you dont have a Nostr Address yet, you should get one! Check out {link}",
|
"ojzbwv": "Hey, it looks like you dont have a Nostr Address yet, you should get one! Check out {link}",
|
||||||
"osUr8O": "You can also use these extensions to login to most Nostr sites.",
|
|
||||||
"oxCa4R": "Getting an identifier helps confirm the real you to people who know you. Many people can have a username @jack, but there is only one jack@cash.app.",
|
|
||||||
"p4N05H": "Upload",
|
"p4N05H": "Upload",
|
||||||
"p85Uwy": "Active Subscriptions",
|
"p85Uwy": "Active Subscriptions",
|
||||||
"pI+77w": "Downloadable backups from Snort relay",
|
"pI+77w": "Downloadable backups from Snort relay",
|
||||||
@ -459,16 +430,14 @@
|
|||||||
"qkvYUb": "Add to Profile",
|
"qkvYUb": "Add to Profile",
|
||||||
"qmJ8kD": "Translation failed",
|
"qmJ8kD": "Translation failed",
|
||||||
"qtWLmt": "Like",
|
"qtWLmt": "Like",
|
||||||
|
"qydxOd": "Science",
|
||||||
"qz9fty": "Incorrect pin",
|
"qz9fty": "Incorrect pin",
|
||||||
"r3C4x/": "Software",
|
"r3C4x/": "Software",
|
||||||
"r5srDR": "Enter wallet password",
|
"r5srDR": "Enter wallet password",
|
||||||
"rT14Ow": "Add Relays",
|
"rT14Ow": "Add Relays",
|
||||||
"rbrahO": "Close",
|
"rbrahO": "Close",
|
||||||
"reJ6SM": "It is recommended to use one of the following browser extensions if you are on a desktop computer to secure your key:",
|
|
||||||
"rfuMjE": "(Default)",
|
"rfuMjE": "(Default)",
|
||||||
"rmdsT4": "{n} days",
|
"rmdsT4": "{n} days",
|
||||||
"rrfdTe": "This is the same technology which is used by Bitcoin and has been proven to be extremely secure.",
|
|
||||||
"rudscU": "Failed to load follows, please try again later",
|
|
||||||
"rx1i0i": "Short link",
|
"rx1i0i": "Short link",
|
||||||
"sKDn4e": "Show Badges",
|
"sKDn4e": "Show Badges",
|
||||||
"sUNhQE": "user",
|
"sUNhQE": "user",
|
||||||
@ -482,39 +451,39 @@
|
|||||||
"u+LyXc": "Interactions",
|
"u+LyXc": "Interactions",
|
||||||
"u/vOPu": "Paid",
|
"u/vOPu": "Paid",
|
||||||
"u4bHcR": "Check out the code here: {link}",
|
"u4bHcR": "Check out the code here: {link}",
|
||||||
|
"uCk8r+": "Already have an account?",
|
||||||
"uKqSN+": "Follows Feed",
|
"uKqSN+": "Follows Feed",
|
||||||
"uSV4Ti": "Reposts need to be manually confirmed",
|
"uSV4Ti": "Reposts need to be manually confirmed",
|
||||||
"uc0din": "Send sats splits to",
|
"uc0din": "Send sats splits to",
|
||||||
"ugyJnE": "Sending notes and other stuff",
|
"ugyJnE": "Sending notes and other stuff",
|
||||||
"usAvMr": "Edit Profile",
|
"usAvMr": "Edit Profile",
|
||||||
"ut+2Cd": "Get a partner identifier",
|
|
||||||
"v8lolG": "Start chat",
|
"v8lolG": "Start chat",
|
||||||
"vB3oQ/": "Must be a contact list or pubkey list",
|
"vB3oQ/": "Must be a contact list or pubkey list",
|
||||||
|
"vN5UH8": "Profile Image",
|
||||||
"vOKedj": "{n,plural,=1{& {n} other} other{& {n} others}}",
|
"vOKedj": "{n,plural,=1{& {n} other} other{& {n} others}}",
|
||||||
"vZ4quW": "NIP-05 is a DNS based verification spec which helps to validate you as a real user.",
|
"vZ4quW": "NIP-05 is a DNS based verification spec which helps to validate you as a real user.",
|
||||||
"vhlWFg": "Poll Options",
|
"vhlWFg": "Poll Options",
|
||||||
"vlbWtt": "Get a free one",
|
"vlbWtt": "Get a free one",
|
||||||
"vrTOHJ": "{amount} sats",
|
"vrTOHJ": "{amount} sats",
|
||||||
"vxwnbh": "Amount of work to apply to all published events",
|
"vxwnbh": "Amount of work to apply to all published events",
|
||||||
|
"w1Fanr": "Business",
|
||||||
|
"w6qrwX": "NSFW",
|
||||||
"wEQDC6": "Edit",
|
"wEQDC6": "Edit",
|
||||||
"wLtRCF": "Your key",
|
|
||||||
"wSZR47": "Submit",
|
"wSZR47": "Submit",
|
||||||
"wWLwvh": "Anon",
|
"wWLwvh": "Anon",
|
||||||
"wih7iJ": "name is blocked",
|
"wih7iJ": "name is blocked",
|
||||||
"wofVHy": "Moderation",
|
"wofVHy": "Moderation",
|
||||||
"wqyN/i": "Find out more info about {service} at {link}",
|
"wqyN/i": "Find out more info about {service} at {link}",
|
||||||
"wtLjP6": "Copy ID",
|
"wtLjP6": "Copy ID",
|
||||||
"wuMvI5": "{site_name} Developers",
|
|
||||||
"x/Fx2P": "Fund the services that you use by splitting a portion of all your zaps into a pool of funds!",
|
"x/Fx2P": "Fund the services that you use by splitting a portion of all your zaps into a pool of funds!",
|
||||||
"x82IOl": "Mute",
|
"x82IOl": "Mute",
|
||||||
"xIcAOU": "Votes by {type}",
|
"xIcAOU": "Votes by {type}",
|
||||||
"xIoGG9": "Go to",
|
"xIoGG9": "Go to",
|
||||||
"xJ9n2N": "Your public key",
|
|
||||||
"xKflGN": "{username}''s Follows on Nostr",
|
|
||||||
"xQtL3v": "Unlock",
|
"xQtL3v": "Unlock",
|
||||||
"xaj9Ba": "Provider",
|
"xaj9Ba": "Provider",
|
||||||
"xbVgIm": "Automatically load media",
|
"xbVgIm": "Automatically load media",
|
||||||
"xhQMeQ": "Expires",
|
"xhQMeQ": "Expires",
|
||||||
|
"xl4s/X": "Additional Terms:",
|
||||||
"xmcVZ0": "Search",
|
"xmcVZ0": "Search",
|
||||||
"y1Z3or": "Language",
|
"y1Z3or": "Language",
|
||||||
"yCLnBC": "LNURL or Lightning Address",
|
"yCLnBC": "LNURL or Lightning Address",
|
||||||
@ -524,7 +493,6 @@
|
|||||||
"zINlao": "Owner",
|
"zINlao": "Owner",
|
||||||
"zQvVDJ": "All",
|
"zQvVDJ": "All",
|
||||||
"zcaOTs": "Zap amount in sats",
|
"zcaOTs": "Zap amount in sats",
|
||||||
"zjJZBd": "You're ready!",
|
|
||||||
"zm6qS1": "{n} mins to read",
|
"zm6qS1": "{n} mins to read",
|
||||||
"zonsdq": "Failed to load LNURL service",
|
"zonsdq": "Failed to load LNURL service",
|
||||||
"zvCDao": "Automatically show latest notes",
|
"zvCDao": "Automatically show latest notes",
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
"@snort/shared": "^1.0.7",
|
"@snort/shared": "^1.0.7",
|
||||||
"@stablelib/xchacha20": "^1.0.1",
|
"@stablelib/xchacha20": "^1.0.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"events": "^3.3.0",
|
"eventemitter3": "^5.0.1",
|
||||||
"isomorphic-ws": "^5.0.0",
|
"isomorphic-ws": "^5.0.0",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"ws": "^8.14.0"
|
"ws": "^8.14.0"
|
||||||
|
@ -3243,7 +3243,7 @@ __metadata:
|
|||||||
"@types/uuid": ^9.0.2
|
"@types/uuid": ^9.0.2
|
||||||
"@types/ws": ^8.5.5
|
"@types/ws": ^8.5.5
|
||||||
debug: ^4.3.4
|
debug: ^4.3.4
|
||||||
events: ^3.3.0
|
eventemitter3: ^5.0.1
|
||||||
isomorphic-ws: ^5.0.0
|
isomorphic-ws: ^5.0.0
|
||||||
jest: ^29.5.0
|
jest: ^29.5.0
|
||||||
jest-environment-jsdom: ^29.5.0
|
jest-environment-jsdom: ^29.5.0
|
||||||
@ -7272,6 +7272,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"eventemitter3@npm:^5.0.1":
|
||||||
|
version: 5.0.1
|
||||||
|
resolution: "eventemitter3@npm:5.0.1"
|
||||||
|
checksum: 543d6c858ab699303c3c32e0f0f47fc64d360bf73c3daf0ac0b5079710e340d6fe9f15487f94e66c629f5f82cd1a8678d692f3dbb6f6fcd1190e1b97fcad36f8
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"events@npm:^3.2.0, events@npm:^3.3.0":
|
"events@npm:^3.2.0, events@npm:^3.3.0":
|
||||||
version: 3.3.0
|
version: 3.3.0
|
||||||
resolution: "events@npm:3.3.0"
|
resolution: "events@npm:3.3.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user