diff --git a/packages/app/public/icons.svg b/packages/app/public/icons.svg
index 43c7b523..806a5df3 100644
--- a/packages/app/public/icons.svg
+++ b/packages/app/public/icons.svg
@@ -154,5 +154,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/packages/app/src/Element/NoteFooter.tsx b/packages/app/src/Element/NoteFooter.tsx
index a9f523c4..219738bb 100644
--- a/packages/app/src/Element/NoteFooter.tsx
+++ b/packages/app/src/Element/NoteFooter.tsx
@@ -10,7 +10,7 @@ import Spinner from "Icons/Spinner";
import { formatShort } from "Number";
import useEventPublisher from "Feed/EventPublisher";
-import { bech32ToHex, delay, normalizeReaction, unwrap } from "Util";
+import { delay, normalizeReaction, unwrap } from "Util";
import { NoteCreator } from "Element/NoteCreator";
import { ReBroadcaster } from "Element/ReBroadcaster";
import Reactions from "Element/Reactions";
@@ -25,13 +25,13 @@ import {
reset as resetReBroadcast,
} from "State/ReBroadcast";
import useModeration from "Hooks/useModeration";
-import { SnortPubKey, TranslateHost } from "Const";
+import { TranslateHost } from "Const";
import { LNURL } from "LNURL";
-import { DonateLNURL } from "Pages/DonatePage";
import { useWallet } from "Wallet";
import useLogin from "Hooks/useLogin";
import { setBookmarked, setPinned } from "Login";
import { useInteractionCache } from "Hooks/useInteractionCache";
+import { ZapPoolController } from "ZapPoolController";
import messages from "./messages";
@@ -160,7 +160,6 @@ export default function NoteFooter(props: NoteFooterProps) {
setZapping(true);
try {
await fastZapInner(lnurl, prefs.defaultZapAmount, ev.pubkey, ev.id);
- fastZapDonate();
} catch (e) {
console.warn("Fast zap failed", e);
if (!(e instanceof Error) || e.message !== "User rejected") {
@@ -184,26 +183,12 @@ export default function NoteFooter(props: NoteFooterProps) {
const zap = handler.canZap && publisher ? await publisher.zap(amount * 1000, key, zr, id) : undefined;
const invoice = await handler.getInvoice(amount, undefined, zap);
await wallet?.payInvoice(unwrap(invoice.pr));
+ ZapPoolController.allocate(amount);
await interactionCache.zap();
});
}
- function fastZapDonate() {
- queueMicrotask(async () => {
- if (prefs.fastZapDonate > 0) {
- // spin off donate
- const donateAmount = Math.floor(prefs.defaultZapAmount * prefs.fastZapDonate);
- if (donateAmount > 0) {
- console.debug(`Donating ${donateAmount} sats to ${DonateLNURL}`);
- fastZapInner(DonateLNURL, donateAmount, bech32ToHex(SnortPubKey))
- .then(() => console.debug("Donation sent! Thank You!"))
- .catch(() => console.debug("Failed to donate"));
- }
- }
- });
- }
-
useEffect(() => {
if (prefs.autoZap && !didZap && !isMine && !zapping) {
const lnurl = getLNURL();
@@ -212,7 +197,6 @@ export default function NoteFooter(props: NoteFooterProps) {
queueMicrotask(async () => {
try {
await fastZapInner(lnurl, prefs.defaultZapAmount, ev.pubkey, ev.id);
- fastZapDonate();
} catch {
// ignored
} finally {
@@ -457,6 +441,7 @@ export default function NoteFooter(props: NoteFooterProps) {
author={author?.pubkey}
target={getTargetName()}
note={ev.id}
+ allocatePool={true}
/>
diff --git a/packages/app/src/Element/SendSats.tsx b/packages/app/src/Element/SendSats.tsx
index 6228f7bb..60ac0949 100644
--- a/packages/app/src/Element/SendSats.tsx
+++ b/packages/app/src/Element/SendSats.tsx
@@ -16,6 +16,7 @@ import { useWallet } from "Wallet";
import useLogin from "Hooks/useLogin";
import { generateRandomKey } from "Login";
import { EventPublisher } from "System/EventPublisher";
+import { ZapPoolController } from "ZapPoolController";
import messages from "./messages";
@@ -36,6 +37,7 @@ export interface SendSatsProps {
target?: string;
note?: HexKey;
author?: HexKey;
+ allocatePool?: boolean;
}
export default function SendSats(props: SendSatsProps) {
@@ -194,9 +196,12 @@ export default function SendSats(props: SendSatsProps) {
async function payWithWallet(invoice: LNURLInvoice) {
try {
- if (wallet?.isReady) {
+ if (wallet?.isReady()) {
setPaying(true);
const res = await wallet.payInvoice(invoice?.pr ?? "");
+ if (props.allocatePool) {
+ ZapPoolController.allocate(amount);
+ }
console.log(res);
setSuccess(invoice?.successAction ?? {});
}
diff --git a/packages/app/src/Login/Preferences.ts b/packages/app/src/Login/Preferences.ts
index 774817e9..647dc90b 100644
--- a/packages/app/src/Login/Preferences.ts
+++ b/packages/app/src/Login/Preferences.ts
@@ -62,11 +62,6 @@ export interface UserPreferences {
*/
defaultZapAmount: number;
- /**
- * For each fast zap an additional X% will be sent to Snort donate address
- */
- fastZapDonate: number;
-
/**
* Auto-zap every post
*/
@@ -86,6 +81,5 @@ export const DefaultPreferences = {
imgProxyConfig: DefaultImgProxy,
defaultRootTab: "posts",
defaultZapAmount: 50,
- fastZapDonate: 0.0,
autoZap: false,
} as UserPreferences;
diff --git a/packages/app/src/Pages/Layout.tsx b/packages/app/src/Pages/Layout.tsx
index bfe5a0a1..415299a8 100644
--- a/packages/app/src/Pages/Layout.tsx
+++ b/packages/app/src/Pages/Layout.tsx
@@ -25,6 +25,7 @@ import Avatar from "Element/Avatar";
import { useUserProfile } from "Hooks/useUserProfile";
import { profileLink } from "Util";
import { getCurrentSubscription } from "Subscription";
+import Toaster from "Toaster";
export default function Layout() {
const location = useLocation();
@@ -170,6 +171,7 @@ export default function Layout() {
>
)}
{window.localStorage.getItem("debug") && }
+
);
}
diff --git a/packages/app/src/Pages/ZapPool.css b/packages/app/src/Pages/ZapPool.css
new file mode 100644
index 00000000..611dfd07
--- /dev/null
+++ b/packages/app/src/Pages/ZapPool.css
@@ -0,0 +1,3 @@
+.zap-pool input[type="range"] {
+ width: 200px;
+}
diff --git a/packages/app/src/Pages/ZapPool.tsx b/packages/app/src/Pages/ZapPool.tsx
new file mode 100644
index 00000000..c2fe1280
--- /dev/null
+++ b/packages/app/src/Pages/ZapPool.tsx
@@ -0,0 +1,185 @@
+import "./ZapPool.css";
+
+import { useMemo, useSyncExternalStore } from "react";
+import { FormattedMessage, FormattedNumber } from "react-intl";
+
+import { SnortPubKey } from "Const";
+import ProfilePreview from "Element/ProfilePreview";
+import useLogin from "Hooks/useLogin";
+import { System } from "System";
+import { UploaderServices } from "Upload";
+import { bech32ToHex, getRelayName, unwrap } from "Util";
+import { ZapPoolController, ZapPoolRecipient, ZapPoolRecipientType } from "ZapPoolController";
+import { useUserProfile } from "Hooks/useUserProfile";
+import AsyncButton from "Element/AsyncButton";
+import { useWallet } from "Wallet";
+
+function ZapTarget({ target }: { target: ZapPoolRecipient }) {
+ const login = useLogin();
+ const profile = useUserProfile(target.pubkey);
+ const hasAddress = profile?.lud16 || profile?.lud06;
+ const defaultZapMount = Math.ceil(login.preferences.defaultZapAmount * (target.split / 100));
+ return (
+
+
+ % (
+ )
+
+
+ ZapPoolController.set({
+ ...target,
+ split: e.target.valueAsNumber,
+ })
+ }
+ />
+
+ ) : (
+
+ )
+ }
+ />
+ );
+}
+
+export default function ZapPoolPage() {
+ const login = useLogin();
+ const zapPool = useSyncExternalStore(
+ c => ZapPoolController.hook(c),
+ () => ZapPoolController.snapshot()
+ );
+ const { wallet } = useWallet();
+
+ const relayConnections = useMemo(() => {
+ return [...System.Sockets.values()]
+ .map(a => {
+ if (a.Info?.pubkey) {
+ return {
+ address: a.Address,
+ pubkey: a.Info.pubkey,
+ };
+ }
+ })
+ .filter(a => a !== undefined)
+ .map(unwrap);
+ }, [login.relays]);
+
+ const sumPending = zapPool.reduce((acc, v) => acc + v.sum, 0);
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ),
+ }}
+ />
+
+
+
+
+
+ ),
+ nOut: (
+
+
+
+ ),
+ }}
+ />
+
+
+
+
+
+ ),
+ }}
+ />
+
+
+ {wallet && (
+ ZapPoolController.payout(wallet)}>
+
+
+ )}
+
+
+ b.pubkey === bech32ToHex(SnortPubKey) && b.type === ZapPoolRecipientType.Generic) ?? {
+ type: ZapPoolRecipientType.Generic,
+ pubkey: bech32ToHex(SnortPubKey),
+ split: 0,
+ sum: 0,
+ }
+ }
+ />
+
+
+
+
+ {relayConnections.map(a => (
+
+
{getRelayName(a.address)}
+ b.pubkey === a.pubkey && b.type === ZapPoolRecipientType.Relay) ?? {
+ type: ZapPoolRecipientType.Relay,
+ pubkey: a.pubkey,
+ split: 0,
+ sum: 0,
+ }
+ }
+ />
+
+ ))}
+
+
+
+ {UploaderServices.map(a => (
+
+
{a.name}
+ b.pubkey === a.owner && b.type === ZapPoolRecipientType.FileHost) ?? {
+ type: ZapPoolRecipientType.FileHost,
+ pubkey: a.owner,
+ split: 0,
+ sum: 0,
+ }
+ }
+ />
+
+ ))}
+
+ );
+}
diff --git a/packages/app/src/Pages/settings/Index.tsx b/packages/app/src/Pages/settings/Index.tsx
index 7ccc5d02..7c929d41 100644
--- a/packages/app/src/Pages/settings/Index.tsx
+++ b/packages/app/src/Pages/settings/Index.tsx
@@ -83,7 +83,11 @@ const SettingsIndex = () => {
-
+ navigate("/zap-pool")}>
+
+
+
+
diff --git a/packages/app/src/Pages/settings/Preferences.tsx b/packages/app/src/Pages/settings/Preferences.tsx
index 9d98e2c6..47877023 100644
--- a/packages/app/src/Pages/settings/Preferences.tsx
+++ b/packages/app/src/Pages/settings/Preferences.tsx
@@ -1,7 +1,6 @@
import "./Preferences.css";
import { FormattedMessage, useIntl } from "react-intl";
-import { Link } from "react-router-dom";
import emoji from "@jukben/emoji-search";
import useLogin from "Hooks/useLogin";
@@ -165,42 +164,6 @@ const PreferencesPage = () => {
/>
-
-
-
-
-
-
-
-
-
-
-
- ),
- }}
- />
-
-
-
- updatePreferences(login, { ...perf, fastZapDonate: parseInt(e.target.value || "0") / 100 })}
- />
-
-
diff --git a/packages/app/src/Toaster.css b/packages/app/src/Toaster.css
new file mode 100644
index 00000000..a5ada87d
--- /dev/null
+++ b/packages/app/src/Toaster.css
@@ -0,0 +1,12 @@
+.toaster {
+ position: fixed;
+ bottom: 0;
+ left: 0;
+ display: flex;
+ flex-direction: column-reverse;
+ z-index: 9999;
+}
+
+.toaster > .card {
+ border: 1px solid var(--gray);
+}
diff --git a/packages/app/src/Toaster.tsx b/packages/app/src/Toaster.tsx
new file mode 100644
index 00000000..4b48c887
--- /dev/null
+++ b/packages/app/src/Toaster.tsx
@@ -0,0 +1,53 @@
+import ExternalStore from "ExternalStore";
+import Icon from "Icons/Icon";
+import { ReactNode, useSyncExternalStore } from "react";
+import { unixNow } from "Util";
+
+import "./Toaster.css";
+
+interface ToastNotification {
+ element: ReactNode;
+ expire?: number;
+ icon?: string;
+}
+
+class ToasterSlots extends ExternalStore
> {
+ #stack: Array = [];
+ #cleanup = setInterval(() => this.#eatToast(), 1000);
+
+ push(n: ToastNotification) {
+ n.expire ??= unixNow() + 3;
+ this.#stack.push(n);
+ this.notifyChange();
+ }
+
+ takeSnapshot(): ToastNotification[] {
+ return [...this.#stack];
+ }
+
+ #eatToast() {
+ const now = unixNow();
+ this.#stack = this.#stack.filter(a => (a.expire ?? 0) > now);
+ this.notifyChange();
+ }
+}
+
+export const Toastore = new ToasterSlots();
+
+export default function Toaster() {
+ const toast = useSyncExternalStore(
+ c => Toastore.hook(c),
+ () => Toastore.snapshot()
+ );
+
+ return (
+
+ {toast.map(a => (
+
+
+ {a.element}
+
+ ))}
+
+ );
+}
diff --git a/packages/app/src/Upload/index.ts b/packages/app/src/Upload/index.ts
index a93b67ec..9f286009 100644
--- a/packages/app/src/Upload/index.ts
+++ b/packages/app/src/Upload/index.ts
@@ -4,6 +4,8 @@ import { RawEvent } from "@snort/nostr";
import NostrBuild from "Upload/NostrBuild";
import VoidCat from "Upload/VoidCat";
import NostrImg from "Upload/NostrImg";
+import { KieranPubKey } from "Const";
+import { bech32ToHex } from "Util";
export interface UploadResult {
url?: string;
@@ -15,6 +17,24 @@ export interface UploadResult {
header?: RawEvent;
}
+/**
+ * List of supported upload services and their owners on nostr
+ */
+export const UploaderServices = [
+ {
+ name: "void.cat",
+ owner: bech32ToHex(KieranPubKey),
+ },
+ {
+ name: "nostr.build",
+ owner: bech32ToHex("npub1nxy4qpqnld6kmpphjykvx2lqwvxmuxluddwjamm4nc29ds3elyzsm5avr7"),
+ },
+ {
+ name: "nostrimg.com",
+ owner: bech32ToHex("npub1xv6axulxcx6mce5mfvfzpsy89r4gee3zuknulm45cqqpmyw7680q5pxea6"),
+ },
+];
+
export interface Uploader {
upload: (f: File | Blob, filename: string) => Promise;
}
diff --git a/packages/app/src/ZapPoolController.ts b/packages/app/src/ZapPoolController.ts
new file mode 100644
index 00000000..8ee240f2
--- /dev/null
+++ b/packages/app/src/ZapPoolController.ts
@@ -0,0 +1,135 @@
+import { UserCache } from "Cache";
+import { getDisplayName } from "Element/ProfileImage";
+import ExternalStore from "ExternalStore";
+import { LNURL } from "LNURL";
+import { Toastore } from "Toaster";
+import { unixNow } from "Util";
+import { LNWallet, WalletInvoiceState } from "Wallet";
+
+export enum ZapPoolRecipientType {
+ Generic = 0,
+ Relay = 1,
+ FileHost = 2,
+}
+
+export interface ZapPoolRecipient {
+ type: ZapPoolRecipientType;
+ pubkey: string;
+ split: number;
+ sum: number;
+}
+
+class ZapPool extends ExternalStore> {
+ #store: Map;
+ #isPayoutInProgress = false;
+
+ constructor() {
+ super();
+ this.#store = new Map();
+ this.#load();
+ }
+
+ async payout(wallet: LNWallet) {
+ if (this.#isPayoutInProgress) {
+ throw new Error("Payout already in progress");
+ }
+ this.#isPayoutInProgress = true;
+ for (const x of this.#store.values()) {
+ if (x.sum === 0) continue;
+ try {
+ const profile = await UserCache.get(x.pubkey);
+ if (!profile) {
+ throw new Error(`Failed to get profile for ${x.pubkey}`);
+ }
+ const svc = new LNURL(profile.lud16 || profile.lud06 || "");
+ await svc.load();
+ const amtSend = x.sum;
+ const invoice = await svc.getInvoice(amtSend, `SnortZapPool: ${x.split}%`);
+ if (invoice.pr) {
+ const result = await wallet.payInvoice(invoice.pr);
+ if (result.state === WalletInvoiceState.Paid) {
+ x.sum -= amtSend;
+ Toastore.push({
+ element: `Sent ${amtSend.toLocaleString()} sats to ${getDisplayName(
+ profile,
+ x.pubkey
+ )} from your zap pool`,
+ expire: unixNow() + 10,
+ icon: "zap",
+ });
+ } else {
+ throw new Error("Payment failed");
+ }
+ } else {
+ throw new Error(invoice.reason ?? "Failed to get invoice");
+ }
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ this.#save();
+ this.notifyChange();
+ this.#isPayoutInProgress = false;
+ }
+
+ calcAllocation(n: number) {
+ let res = 0;
+ for (const x of this.#store.values()) {
+ res += Math.ceil(n * (x.split / 100));
+ }
+ return res;
+ }
+
+ allocate(n: number) {
+ if (this.#isPayoutInProgress) {
+ throw new Error("Payout is in progress, cannot allocate to pool");
+ }
+ for (const x of this.#store.values()) {
+ x.sum += Math.ceil(n * (x.split / 100));
+ }
+ this.#save();
+ this.notifyChange();
+ }
+
+ getOrDefault(rcpt: ZapPoolRecipient) {
+ const k = this.#key(rcpt);
+ if (this.#store.has(k)) {
+ return { ...this.#store.get(k) };
+ }
+ return rcpt;
+ }
+
+ set(rcpt: ZapPoolRecipient) {
+ const k = this.#key(rcpt);
+ // delete entry if split is 0 and sum is 0
+ if (rcpt.split === 0 && rcpt.sum === 0 && this.#store.has(k)) {
+ this.#store.delete(k);
+ } else {
+ this.#store.set(k, rcpt);
+ }
+ this.#save();
+ this.notifyChange();
+ }
+
+ #key(rcpt: ZapPoolRecipient) {
+ return `${rcpt.pubkey}-${rcpt.type}`;
+ }
+
+ #save() {
+ self.localStorage.setItem("zap-pool", JSON.stringify(this.takeSnapshot()));
+ }
+
+ #load() {
+ const existing = self.localStorage.getItem("zap-pool");
+ if (existing) {
+ const arr = JSON.parse(existing) as Array;
+ this.#store = new Map(arr.map(a => [`${a.pubkey}-${a.type}`, a]));
+ }
+ }
+
+ takeSnapshot(): ZapPoolRecipient[] {
+ return [...this.#store.values()];
+ }
+}
+
+export const ZapPoolController = new ZapPool();
diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx
index 788af705..2268c1fd 100644
--- a/packages/app/src/index.tsx
+++ b/packages/app/src/index.tsx
@@ -30,7 +30,7 @@ import { WalletRoutes } from "Pages/WalletPage";
import NostrLinkHandler from "Pages/NostrLinkHandler";
import Thread from "Element/Thread";
import { SubscribeRoutes } from "Pages/subscribe";
-import Discover from "Pages/Discover";
+import ZapPoolPage from "Pages/ZapPool";
/**
* HTTP query provider
@@ -94,6 +94,10 @@ export const router = createBrowserRouter([
path: "/search/:keyword?",
element: ,
},
+ {
+ path: "/zap-pool",
+ element: ,
+ },
...NewUserRoutes,
...WalletRoutes,
...SubscribeRoutes,
diff --git a/packages/app/src/lang.json b/packages/app/src/lang.json
index b04a7399..19b2cce7 100644
--- a/packages/app/src/lang.json
+++ b/packages/app/src/lang.json
@@ -2,6 +2,9 @@
"+D82kt": {
"defaultMessage": "Are you sure you want to repost: {id}"
},
+ "+PzQ9Y": {
+ "defaultMessage": "Payout Now"
+ },
"+aZY2h": {
"defaultMessage": "Zap Type"
},
@@ -271,6 +274,9 @@
"C81/uG": {
"defaultMessage": "Logout"
},
+ "C8HhVE": {
+ "defaultMessage": "Suggested Follows"
+ },
"CHTbO3": {
"defaultMessage": "Failed to load invoice"
},
@@ -280,6 +286,9 @@
"CmZ9ls": {
"defaultMessage": "{n} Muted"
},
+ "CsCUYo": {
+ "defaultMessage": "{n} sats"
+ },
"Cu/K85": {
"defaultMessage": "Translated from {lang}"
},
@@ -407,9 +416,6 @@
"IEwZvs": {
"defaultMessage": "Are you sure you want to unpin this note?"
},
- "IKOPx/": {
- "defaultMessage": "Donate Page"
- },
"INSqIz": {
"defaultMessage": "Twitter username..."
},
@@ -431,8 +437,8 @@
"JHEHCk": {
"defaultMessage": "Zaps ({n})"
},
- "JXtsQW": {
- "defaultMessage": "Fast Zap Donation"
+ "JPFYIM": {
+ "defaultMessage": "No lightning address"
},
"JkLHGw": {
"defaultMessage": "Website"
@@ -464,9 +470,6 @@
"KoFlZg": {
"defaultMessage": "Enter mint URL"
},
- "L7SZPr": {
- "defaultMessage": "For more information about donations see {link}."
- },
"LF5kYT": {
"defaultMessage": "Other Connections"
},
@@ -476,6 +479,9 @@
"LgbKvU": {
"defaultMessage": "Comment"
},
+ "Lu5/Bj": {
+ "defaultMessage": "Open on Zapstr"
+ },
"M3Oirc": {
"defaultMessage": "Debug Menus"
},
@@ -570,6 +576,9 @@
"QDFTjG": {
"defaultMessage": "{n} Relays"
},
+ "QWhotP": {
+ "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."
},
@@ -577,6 +586,9 @@
"defaultMessage": "Art by {name}",
"description": "Artwork attribution label"
},
+ "Qxv0B2": {
+ "defaultMessage": "You currently have {number} sats in your zap pool."
+ },
"R/6nsx": {
"defaultMessage": "Subscription"
},
@@ -699,9 +711,15 @@
"X7xU8J": {
"defaultMessage": "nsec, npub, nip-05, hex, mnemonic"
},
+ "XICsE8": {
+ "defaultMessage": "File hosts"
+ },
"XgWvGA": {
"defaultMessage": "Reactions"
},
+ "Xopqkl": {
+ "defaultMessage": "Your default zap amount is {number} sats, example values are calculated from this."
+ },
"XrSk2j": {
"defaultMessage": "Redeem",
"description": "Button: Redeem Cashu token"
@@ -770,6 +788,9 @@
"c3g2hL": {
"defaultMessage": "Broadcast Again"
},
+ "cE4Hfw": {
+ "defaultMessage": "Discover"
+ },
"cPIKU2": {
"defaultMessage": "Following"
},
@@ -817,6 +838,9 @@
"eR3YIn": {
"defaultMessage": "Posts"
},
+ "eSzf2G": {
+ "defaultMessage": "A single zap of {nIn} sats will allocate {nOut} sats to the zap pool."
+ },
"fOksnD": {
"defaultMessage": "Can't vote because LNURL service does not support zaps"
},
@@ -877,6 +901,9 @@
"hniz8Z": {
"defaultMessage": "here"
},
+ "i/dBAR": {
+ "defaultMessage": "Zap Pool"
+ },
"iCqGww": {
"defaultMessage": "Reactions ({n})"
},
@@ -1097,9 +1124,6 @@
"rudscU": {
"defaultMessage": "Failed to load follows, please try again later"
},
- "sBz4+I": {
- "defaultMessage": "For each Fast Zap an additional {percentage}% ({amount} sats) of the zap amount will be sent to the Snort developers as a donation."
- },
"sWnYKw": {
"defaultMessage": "Snort is designed to have a similar experience to Twitter."
},
@@ -1177,6 +1201,9 @@
"wvFw6Y": {
"defaultMessage": "Hey, it looks like you dont have a NIP-05 handle yet, you should get one! Check out {link}"
},
+ "x/Fx2P": {
+ "defaultMessage": "Fund the services that you use by splitting a portion of all your zaps into a pool of funds!"
+ },
"x/q8d5": {
"defaultMessage": "This note has been marked as sensitive, click here to reveal"
},
@@ -1189,10 +1216,6 @@
"xJ9n2N": {
"defaultMessage": "Your public key"
},
- "xKdNPm": {
- "defaultMessage": "Send",
- "description": "Send DM button"
- },
"xKflGN": {
"defaultMessage": "{username}''s Follows on Nostr"
},
diff --git a/packages/app/src/translations/en.json b/packages/app/src/translations/en.json
index 22c9f91d..161660e3 100644
--- a/packages/app/src/translations/en.json
+++ b/packages/app/src/translations/en.json
@@ -1,5 +1,6 @@
{
"+D82kt": "Are you sure you want to repost: {id}",
+ "+PzQ9Y": "Payout Now",
"+aZY2h": "Zap Type",
"+vA//S": "Logins",
"+vIQlC": "Please make sure to save the following password in order to manage your handle in the future",
@@ -88,9 +89,11 @@
"BcGMo+": "Notes hold text content, the most popular usage of these notes is to store \"tweet like\" messages.",
"C5xzTC": "Premium",
"C81/uG": "Logout",
+ "C8HhVE": "Suggested Follows",
"CHTbO3": "Failed to load invoice",
"CVWeJ6": "Trending People",
"CmZ9ls": "{n} Muted",
+ "CsCUYo": "{n} sats",
"Cu/K85": "Translated from {lang}",
"D+KzKd": "Automatically zap every note when loaded",
"D3idYv": "Settings",
@@ -133,7 +136,6 @@
"HbefNb": "Open Wallet",
"IDjHJ6": "Thanks for using Snort, please consider donating if you can.",
"IEwZvs": "Are you sure you want to unpin this note?",
- "IKOPx/": "Donate Page",
"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.",
"Iwm6o2": "NIP-05 Shop",
@@ -141,7 +143,7 @@
"J+dIsA": "Subscriptions",
"JCIgkj": "Username",
"JHEHCk": "Zaps ({n})",
- "JXtsQW": "Fast Zap Donation",
+ "JPFYIM": "No lightning address",
"JkLHGw": "Website",
"JymXbw": "Private Key",
"K3r6DQ": "Delete",
@@ -152,10 +154,10 @@
"KWuDfz": "I have saved my keys, continue",
"KahimY": "Unknown event kind: {kind}",
"KoFlZg": "Enter mint URL",
- "L7SZPr": "For more information about donations see {link}.",
"LF5kYT": "Other Connections",
"LXxsbk": "Anonymous",
"LgbKvU": "Comment",
+ "Lu5/Bj": "Open on Zapstr",
"M3Oirc": "Debug Menus",
"MBAYRO": "Shows \"Copy ID\" and \"Copy Event JSON\" in the context menu on each message",
"MI2jkA": "Not available:",
@@ -187,8 +189,10 @@
"Pe0ogR": "Theme",
"PrsIg7": "Reactions will be shown on every page, if disabled no reactions will be shown",
"QDFTjG": "{n} Relays",
+ "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.",
"R/6nsx": "Subscription",
"R1fEdZ": "Forward Zaps",
"R2OqnW": "Delete Account",
@@ -228,7 +232,9 @@
"WONP5O": "Find your twitter follows on nostr (Data provided by {provider})",
"WxthCV": "e.g. Jack",
"X7xU8J": "nsec, npub, nip-05, hex, mnemonic",
+ "XICsE8": "File hosts",
"XgWvGA": "Reactions",
+ "Xopqkl": "Your default zap amount is {number} sats, example values are calculated from this.",
"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:",
"Y31HTH": "Help fund the development of Snort",
@@ -251,6 +257,7 @@
"c+oiJe": "Install Extension",
"c35bj2": "If you have an enquiry about your NIP-05 order please DM {link}",
"c3g2hL": "Broadcast Again",
+ "cE4Hfw": "Discover",
"cPIKU2": "Following",
"cQfLWb": "URL..",
"cWx9t8": "Mute all",
@@ -266,6 +273,7 @@
"eHAneD": "Reaction emoji",
"eJj8HD": "Get Verified",
"eR3YIn": "Posts",
+ "eSzf2G": "A single zap of {nIn} sats will allocate {nOut} sats to the zap pool.",
"fOksnD": "Can't vote because LNURL service does not support zaps",
"fWZYP5": "Pinned",
"filwqD": "Read",
@@ -286,6 +294,7 @@
"hY4lzx": "Supports",
"hicxcO": "Show replies",
"hniz8Z": "here",
+ "i/dBAR": "Zap Pool",
"iCqGww": "Reactions ({n})",
"iDGAbc": "Get a Snort identifier",
"iEoXYx": "DeepL translations",
@@ -358,7 +367,6 @@
"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",
- "sBz4+I": "For each Fast Zap an additional {percentage}% ({amount} sats) of the zap amount will be sent to the Snort developers as a donation.",
"sWnYKw": "Snort is designed to have a similar experience to Twitter.",
"svOoEH": "Name-squatting and impersonation is not allowed. Snort and our partners reserve the right to terminate your handle (not your account - nobody can take that away) for violating this rule.",
"tOdNiY": "Dark",
@@ -384,11 +392,11 @@
"wqyN/i": "Find out more info about {service} at {link}",
"wtLjP6": "Copy ID",
"wvFw6Y": "Hey, it looks like you dont have a NIP-05 handle yet, you should get one! Check out {link}",
+ "x/Fx2P": "Fund the services that you use by splitting a portion of all your zaps into a pool of funds!",
"x/q8d5": "This note has been marked as sensitive, click here to reveal",
"x82IOl": "Mute",
"xIoGG9": "Go to",
"xJ9n2N": "Your public key",
- "xKdNPm": "Send",
"xKflGN": "{username}''s Follows on Nostr",
"xQtL3v": "Unlock",
"xbVgIm": "Automatically load media",
@@ -404,4 +412,4 @@
"zjJZBd": "You're ready!",
"zonsdq": "Failed to load LNURL service",
"zvCDao": "Automatically show latest notes"
-}
+}
\ No newline at end of file