diff --git a/package-lock.json b/package-lock.json index 6c39c94..563be69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wrystr", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "wrystr", - "version": "0.1.0", + "version": "0.1.1", "dependencies": { "@nostr-dev-kit/ndk": "^3.0.3", "@tailwindcss/vite": "^4.2.1", @@ -15,6 +15,7 @@ "marked": "^17.0.4", "react": "^19.1.0", "react-dom": "^19.1.0", + "react-qr-code": "^2.0.18", "tailwindcss": "^4.2.1", "zustand": "^5.0.11" }, @@ -2418,7 +2419,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/jsesc": { @@ -2717,6 +2717,18 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -2968,6 +2980,15 @@ "license": "MIT", "peer": true }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/oniguruma-parser": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz", @@ -3037,6 +3058,17 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, "node_modules/property-information": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", @@ -3047,6 +3079,12 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/qr.js": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/qr.js/-/qr.js-0.0.0.tgz", + "integrity": "sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==", + "license": "MIT" + }, "node_modules/react": { "version": "19.2.4", "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", @@ -3068,6 +3106,25 @@ "react": "^19.2.4" } }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-qr-code": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/react-qr-code/-/react-qr-code-2.0.18.tgz", + "integrity": "sha512-v1Jqz7urLMhkO6jkgJuBYhnqvXagzceg3qJUWayuCK/c6LTIonpWbwxR1f1APGd4xrW/QcQEovNrAojbUz65Tg==", + "license": "MIT", + "dependencies": { + "prop-types": "^15.8.1", + "qr.js": "0.0.0" + }, + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-refresh": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", diff --git a/package.json b/package.json index f26c827..ff263a5 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "marked": "^17.0.4", "react": "^19.1.0", "react-dom": "^19.1.0", + "react-qr-code": "^2.0.18", "tailwindcss": "^4.2.1", "zustand": "^5.0.11" }, diff --git a/src/App.tsx b/src/App.tsx index c5cbcc6..d00cc8a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,6 +8,7 @@ import { ProfileView } from "./components/profile/ProfileView"; import { ThreadView } from "./components/thread/ThreadView"; import { ArticleEditor } from "./components/article/ArticleEditor"; import { OnboardingFlow } from "./components/onboarding/OnboardingFlow"; +import { AboutView } from "./components/shared/AboutView"; import { useUIStore } from "./stores/ui"; function App() { @@ -31,6 +32,7 @@ function App() { {currentView === "profile" && } {currentView === "thread" && } {currentView === "article-editor" && } + {currentView === "about" && } ); diff --git a/src/components/shared/AboutView.tsx b/src/components/shared/AboutView.tsx new file mode 100644 index 0000000..0c2b646 --- /dev/null +++ b/src/components/shared/AboutView.tsx @@ -0,0 +1,142 @@ +import { useState } from "react"; +import QRCode from "react-qr-code"; +import { ZapModal } from "../zap/ZapModal"; + +const DEV_NPUB = "npub1ezt7xcq87ljj65jkjsuagwll4yp75tacgkuyjdhkw6mza8j3azfq2vrvl6"; +const DEV_PUBKEY = "c897e36007f7e52d52569439d43bffa903ea2fb845b84936f676b62e9e51e892"; +const LIGHTNING_ADDRESS = "harpos@getalby.com"; +const BITCOIN_ADDRESS = "bc1qcgaupf80j28ca537xjlcs9dm9s03khezjs7crp"; +const KOFI_URL = "https://ko-fi.com/jure"; +const GITHUB_URL = "https://github.com/hoornet/wrystr"; + +function CopyButton({ text }: { text: string }) { + const [copied, setCopied] = useState(false); + const handle = () => { + navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => setCopied(false), 1500); + }; + return ( + + ); +} + +function QRBlock({ value, label }: { value: string; label: string }) { + return ( +
+
+ +
+
+ {label} + +
+
+ ); +} + +export function AboutView() { + const [showZap, setShowZap] = useState(false); + + return ( +
+
+ {/* Header */} +
+

Support Wrystr

+

+ Wrystr is free, open-source, and built by one person. If it's useful to you, + any support — a zap, a share, a star on GitHub — genuinely helps. +

+
+ + {/* Zap */} +
+

⚡ Zap the developer

+

+ Send sats directly from Wrystr using your connected Lightning wallet. +

+ +

{DEV_NPUB}

+
+ + {/* QR codes */} +
+

Scan to send

+
+
+
Lightning
+ +
+
+
Bitcoin
+ +
+
+
+ + {/* Links */} +
+

Other ways to help

+
+ + +
+
+ + {/* Version / About */} +
+
+
Wrystr v0.1.1 — MIT license
+
+ Built with{" "} + Tauri + {" · "} + NDK + {" · "} + Nostr +
+
+
+
+ + {showZap && ( + setShowZap(false)} + /> + )} +
+ ); +} diff --git a/src/components/sidebar/Sidebar.tsx b/src/components/sidebar/Sidebar.tsx index e4470dd..143fb51 100644 --- a/src/components/sidebar/Sidebar.tsx +++ b/src/components/sidebar/Sidebar.tsx @@ -9,6 +9,7 @@ const NAV_ITEMS = [ { id: "search" as const, label: "search", icon: "⌕" }, { id: "relays" as const, label: "relays", icon: "⟐" }, { id: "settings" as const, label: "settings", icon: "⚙" }, + { id: "about" as const, label: "support", icon: "♥" }, ] as const; export function Sidebar() { diff --git a/src/stores/ui.ts b/src/stores/ui.ts index 8eed72c..c260292 100644 --- a/src/stores/ui.ts +++ b/src/stores/ui.ts @@ -2,7 +2,7 @@ import { create } from "zustand"; import { NDKEvent } from "@nostr-dev-kit/ndk"; -type View = "feed" | "search" | "relays" | "settings" | "profile" | "thread" | "article-editor"; +type View = "feed" | "search" | "relays" | "settings" | "profile" | "thread" | "article-editor" | "about"; interface UIState { currentView: View;