diff --git a/src/components/ArticleView.tsx b/src/components/ArticleView.tsx
index 3c1ccba..9a4b9a6 100644
--- a/src/components/ArticleView.tsx
+++ b/src/components/ArticleView.tsx
@@ -58,6 +58,21 @@ export function ArticleView({ post }: ArticleViewProps) {
.filter(([name]) => name === 't')
.map(([, value]) => value);
+ // Parse zap splits from tags (community convention under NIP-57)
+ const zapSplits = post.tags
+ .filter(([n]) => n === 'zap')
+ .map((t) => {
+ const pub = t[1] ?? '';
+ let weight = 0;
+ const idx = t.findIndex((x) => x === 'weight');
+ if (idx >= 0 && t[idx + 1]) weight = parseInt(t[idx + 1] as string) || 0;
+ else if (t[2]) {
+ const n = parseInt(t[2] as string); if (!Number.isNaN(n)) weight = n;
+ }
+ return { pubkey: pub, weight };
+ })
+ .filter((s) => s.pubkey && s.weight > 0);
+
const date = publishedAt
? new Date(parseInt(publishedAt) * 1000)
: new Date(post.created_at * 1000);
@@ -202,6 +217,20 @@ export function ArticleView({ post }: ArticleViewProps) {
+ {zapSplits.length > 0 && (
+
+
Zap revenue splits
+
+ {zapSplits.map((s, i) => (
+
+
{genUserName(s.pubkey)}
+
{s.weight}%
+
+ ))}
+
+
+ )}
+
)}
+
+ {/* Zap revenue split (fixed recipient, adjustable percentage) */}
+ {HOUSE_SPLIT_ENABLED && (
+
+
+
+
setSplitPercent(v[0] ?? 0)}
+ />
+
+ {splitPercent}% goes to the platform. {100 - splitPercent}% goes to you.
+
+
+
+ )}
)}
diff --git a/src/config.tsx b/src/config.tsx
new file mode 100644
index 0000000..c4b9a1e
--- /dev/null
+++ b/src/config.tsx
@@ -0,0 +1,15 @@
+// Global app configuration
+// Central place to store static keys and app-level constants
+
+// Hex-encoded public key for platform revenue share (house account)
+// Note: Keep this in hex to avoid decoding at runtime.
+export const HOUSE_PUBKEY_HEX =
+ '1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef';
+
+// Toggle showing and applying the house zap split on the article creation page
+export const HOUSE_SPLIT_ENABLED = true;
+
+export default {
+ HOUSE_PUBKEY_HEX,
+ HOUSE_SPLIT_ENABLED,
+};
diff --git a/src/hooks/usePublishBlogPost.ts b/src/hooks/usePublishBlogPost.ts
index 26fdeab..936b287 100644
--- a/src/hooks/usePublishBlogPost.ts
+++ b/src/hooks/usePublishBlogPost.ts
@@ -11,6 +11,12 @@ interface BlogPostData {
content: string;
hashtags?: string[];
publishedAt?: number;
+ /** Optional zap revenue splits. Weights are integers (percent). */
+ splits?: Array<{
+ pubkey: string; // hex or npub1
+ weight: number; // 1..100
+ relays?: string[];
+ }>;
}
/**
@@ -51,6 +57,32 @@ export function usePublishBlogPost() {
});
}
+ // Zap splits (NIP-57 community convention): add one `zap` tag per recipient.
+ // Tag shape we emit: ["zap", , "weight", "", "relays", , ...]
+ if (data.splits && data.splits.length > 0) {
+ for (const split of data.splits) {
+ // Normalize pubkey: accept npub or hex; if npub, decode to hex
+ let hexPub = split.pubkey;
+ try {
+ if (hexPub.startsWith('npub1')) {
+ const { nip19 } = await import('nostr-tools');
+ const decoded = nip19.decode(hexPub);
+ if (decoded.type === 'npub') {
+ hexPub = decoded.data as string;
+ }
+ }
+ } catch {
+ // keep as-is; signer/relays may ignore invalid entries
+ }
+
+ const parts: string[] = ['zap', hexPub, 'weight', String(Math.max(0, Math.min(100, Math.trunc(split.weight || 0))))];
+ if (split.relays && split.relays.length > 0) {
+ parts.push('relays', ...split.relays);
+ }
+ tags.push(parts);
+ }
+ }
+
// Add client tag
// tags.push(['client', 'zelo.news']);
diff --git a/src/hooks/useZaps.ts b/src/hooks/useZaps.ts
index 4ed7162..7a2db7e 100644
--- a/src/hooks/useZaps.ts
+++ b/src/hooks/useZaps.ts
@@ -209,6 +209,21 @@ export function useZaps(
comment
});
+ // If target event contains zap split tags, include them in the zap request,
+ // so compatible zap servers can honor the split distribution.
+ try {
+ if (Array.isArray(actualTarget.tags)) {
+ const splitTags = actualTarget.tags.filter((t) => t[0] === 'zap');
+ if (splitTags.length > 0) {
+ const zr = zapRequest as unknown as { tags?: string[][] };
+ zr.tags = Array.isArray(zr.tags) ? zr.tags : [];
+ zr.tags.push(...splitTags);
+ }
+ }
+ } catch (e) {
+ console.debug('Failed to include zap split tags in zap request', e);
+ }
+
// Sign the zap request (but don't publish to relays - only send to LNURL endpoint)
if (!user.signer) {
throw new Error('No signer available');