diff --git a/package.json b/package.json
index 3b6aa22..d65c76d 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
- "@snort/system-react": "^1.0.2",
+ "@snort/system-react": "^1.0.3",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^13.0.0",
"@testing-library/user-event": "^13.2.1",
@@ -39,6 +39,7 @@
]
},
"devDependencies": {
+ "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"typescript": "^5.1.3"
}
}
diff --git a/src/element/live-chat.tsx b/src/element/live-chat.tsx
index 1e37d03..ee48d2d 100644
--- a/src/element/live-chat.tsx
+++ b/src/element/live-chat.tsx
@@ -8,6 +8,7 @@ import AsyncButton from "./async-button";
import { Profile } from "./profile";
import { Icon } from "./icon";
import Spinner from "./spinner";
+import { useLogin } from "hooks/login";
export interface LiveChatOptions {
canWrite?: boolean,
@@ -17,6 +18,7 @@ export interface LiveChatOptions {
export function LiveChat({ link, options }: { link: NostrLink, options?: LiveChatOptions }) {
const [chat, setChat] = useState("");
const messages = useLiveChatFeed(link);
+ const login = useLogin();
async function sendChatMessage() {
const pub = await EventPublisher.nip7();
@@ -35,6 +37,31 @@ export function LiveChat({ link, options }: { link: NostrLink, options?: LiveCha
setChat("");
}
}
+
+ function writeMessage() {
+ return <>
+
+ setChat(v.target.value)}
+ value={chat}
+ placeholder="Message"
+ onKeyDown={async e => {
+ if (e.code === "Enter") {
+ e.preventDefault();
+ await sendChatMessage();
+ }
+ }}
+ />
+
+
+
+ Send
+
+ >
+ }
+
return (
{(options?.showHeader ?? true) &&
@@ -49,25 +76,7 @@ export function LiveChat({ link, options }: { link: NostrLink, options?: LiveCha
{messages.data === undefined && }
{(options?.canWrite ?? true) &&
-
- setChat(v.target.value)}
- value={chat}
- placeholder="Message"
- onKeyDown={async e => {
- if (e.code === "Enter") {
- e.preventDefault();
- await sendChatMessage();
- }
- }}
- />
-
-
-
- Send
-
+ {login ? writeMessage() :
Please login to write messages!
}
}
);
diff --git a/src/element/profile.tsx b/src/element/profile.tsx
index e58bbef..f97d9ff 100644
--- a/src/element/profile.tsx
+++ b/src/element/profile.tsx
@@ -1,12 +1,24 @@
import "./profile.css";
import { useUserProfile } from "@snort/system-react";
+import { UserMetadata } from "@snort/system";
+import { hexToBech32 } from "@snort/shared";
import { System } from "index";
-export function Profile({ pubkey }: { pubkey: string }) {
+export interface ProfileOptions {
+ showName?: boolean,
+ suffix?: string
+}
+
+export function getName(pk: string, user?: UserMetadata) {
+ const shortPubkey = hexToBech32("npub", pk).slice(0, 12);
+ return user?.display_name ?? user?.name ?? shortPubkey
+}
+
+export function Profile({ pubkey, options }: { pubkey: string, options?: ProfileOptions }) {
const profile = useUserProfile(System, pubkey);
return
- {profile?.display_name ?? profile?.name}
+ {(options?.showName ?? true) && getName(pubkey, profile)}
}
\ No newline at end of file
diff --git a/src/hooks/login.ts b/src/hooks/login.ts
new file mode 100644
index 0000000..1829200
--- /dev/null
+++ b/src/hooks/login.ts
@@ -0,0 +1,6 @@
+import { Login } from "index";
+import { useSyncExternalStore } from "react";
+
+export function useLogin() {
+ return useSyncExternalStore(c => Login.hook(c), () => Login.snapshot());
+}
\ No newline at end of file
diff --git a/src/index.css b/src/index.css
index fa42c31..964974a 100644
--- a/src/index.css
+++ b/src/index.css
@@ -65,4 +65,10 @@ a {
.btn-primary {
background: linear-gradient(94.73deg, #2BD9FF 0%, #8C8DED 47.4%, #F838D9 100%);
color: white;
+}
+
+.btn>span {
+ display: flex;
+ align-items: center;
+ gap: 8px;
}
\ No newline at end of file
diff --git a/src/index.tsx b/src/index.tsx
index 5cdbe1d..e3e9dca 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -7,10 +7,12 @@ import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import { LayoutPage } from 'pages/layout';
import { StreamPage } from 'pages/stream-page';
import { ChatPopout } from 'pages/chat-popout';
+import { LoginStore } from 'login';
export const System = new NostrSystem({
});
+export const Login = new LoginStore();
[
"wss://relay.snort.social",
diff --git a/src/login.ts b/src/login.ts
new file mode 100644
index 0000000..c856704
--- /dev/null
+++ b/src/login.ts
@@ -0,0 +1,29 @@
+import { ExternalStore } from "@snort/shared";
+
+export interface LoginSession {
+ pubkey: string
+}
+
+export class LoginStore extends ExternalStore {
+ #session?: LoginSession;
+
+ constructor() {
+ super();
+ const json = window.localStorage.getItem("session");
+ if (json) {
+ this.#session = JSON.parse(json);
+ }
+ }
+
+ loginWithPubkey(pk: string) {
+ this.#session = {
+ pubkey: pk
+ };
+ window.localStorage.setItem("session", JSON.stringify(this.#session));
+ this.notifyChange();
+ }
+
+ takeSnapshot() {
+ return this.#session ? { ...this.#session } : undefined;
+ }
+}
\ No newline at end of file
diff --git a/src/pages/layout.css b/src/pages/layout.css
index 1de7348..0419167 100644
--- a/src/pages/layout.css
+++ b/src/pages/layout.css
@@ -54,4 +54,9 @@ header button {
display: flex;
align-items: center;
gap: 8px;
+}
+
+header .profile img {
+ width: 48px;
+ height: 48px;
}
\ No newline at end of file
diff --git a/src/pages/layout.tsx b/src/pages/layout.tsx
index 659445d..603ce17 100644
--- a/src/pages/layout.tsx
+++ b/src/pages/layout.tsx
@@ -1,9 +1,48 @@
import { Icon } from "element/icon";
import "./layout.css";
+import { EventPublisher } from "@snort/system";
import { Outlet, useNavigate } from "react-router-dom";
+import AsyncButton from "element/async-button";
+import { Login } from "index";
+import { useLogin } from "hooks/login";
+import { Profile } from "element/profile";
export function LayoutPage() {
const navigate = useNavigate();
+ const login = useLogin();
+
+ async function doLogin() {
+ const pub = await EventPublisher.nip7();
+ if (pub) {
+ Login.loginWithPubkey(pub.pubKey);
+ }
+ }
+
+ function loggedIn() {
+ if (!login) return;
+
+ return <>
+
+
+ >
+ }
+
+ function loggedOut() {
+ if (login) return;
+
+ return <>
+
+ Login
+
+
+ >
+ }
+
return <>
navigate("/")}>
@@ -14,14 +53,8 @@ export function LayoutPage() {
-
-
+ {loggedIn()}
+ {loggedOut()}
diff --git a/src/pages/stream-page.css b/src/pages/stream-page.css
index 8c8c99c..b4e1c3f 100644
--- a/src/pages/stream-page.css
+++ b/src/pages/stream-page.css
@@ -50,10 +50,4 @@
.live-page .tags {
display: flex;
gap: 8px;
-}
-
-.live-page .btn-primary>span {
- display: flex;
- align-items: center;
- gap: 8px;
}
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index f933419..be013d0 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -81,7 +81,7 @@
"@jridgewell/trace-mapping" "^0.3.17"
jsesc "^2.5.1"
-"@babel/helper-annotate-as-pure@^7.22.5":
+"@babel/helper-annotate-as-pure@^7.18.6", "@babel/helper-annotate-as-pure@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882"
integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==
@@ -106,7 +106,7 @@
lru-cache "^5.1.1"
semver "^6.3.0"
-"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.22.5":
+"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.21.0", "@babel/helper-create-class-features-plugin@^7.22.5":
version "7.22.5"
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.5.tgz#2192a1970ece4685fbff85b48da2c32fcb130b7c"
integrity sha512-xkb58MyOYIslxu3gKmVXmjTtUPvBU4odYzbiIQbWwLKIHCsx6UGZGX6F1IznMFVnDdirseUZopzN+ZRt8Xb33Q==
@@ -366,6 +366,16 @@
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703"
integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==
+"@babel/plugin-proposal-private-property-in-object@^7.21.11":
+ version "7.21.11"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz#69d597086b6760c4126525cfa154f34631ff272c"
+ integrity sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.18.6"
+ "@babel/helper-create-class-features-plugin" "^7.21.0"
+ "@babel/helper-plugin-utils" "^7.20.2"
+ "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
+
"@babel/plugin-proposal-unicode-property-regex@^7.4.4":
version "7.18.6"
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e"
@@ -1771,19 +1781,19 @@
debug "^4.3.4"
dexie "^3.2.4"
-"@snort/system-react@^1.0.2":
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/@snort/system-react/-/system-react-1.0.2.tgz#980069bfeba1b6a0ea80cee7a9f4d5522b487191"
- integrity sha512-K0tCf31SHOeIvmxBhNs1gl4IMZLb+jcKwbm39qv+MLHfYkKonMVjMXV5fTNJ0UFkVdnui9YXZjE/ORAaHHu/Qw==
+"@snort/system-react@^1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@snort/system-react/-/system-react-1.0.3.tgz#a64ac4b96f084faab6b19264c4699d523d543927"
+ integrity sha512-7ZoYtmzThjOwJpM1I2UWBKfWRSdXfdZK+r59LSZFuqp5gTzAYKeqF97toQKG+PKbcNlNnqpifTIeNaZHnXkOhw==
dependencies:
"@snort/shared" "^1.0.1"
- "@snort/system" "^1.0.7"
+ "@snort/system" "^1.0.8"
react "^18.2.0"
-"@snort/system@^1.0.7":
- version "1.0.7"
- resolved "https://registry.yarnpkg.com/@snort/system/-/system-1.0.7.tgz#1542e17c3e880e41734e2937a819d460b832c320"
- integrity sha512-PQqeR794pNlYAaDETO7Ab2mtFQz16bMeObb2eb/F09BtMalfwa3SymjZ0VqkEiT1TgGn+NkTu7bNfOEQOA+/Rg==
+"@snort/system@^1.0.8":
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/@snort/system/-/system-1.0.8.tgz#c4a7000320ebf65374298cc1ed5a0d42103a6557"
+ integrity sha512-IxiD4q3cnW8YEA43a42yxq/OmIeCbXR8Wd1kO59JqZA0xwhhASJQHXxWSuKPXNt6LgkEENPkmlTKY2BIkLvTfg==
dependencies:
"@noble/curves" "^1.0.0"
"@scure/base" "^1.1.1"