From da190423bc55f42d1ca58453e0d4c2cea8e97171 Mon Sep 17 00:00:00 2001 From: Kieran Date: Thu, 20 Jul 2023 15:40:47 +0100 Subject: [PATCH] Account menu --- package.json | 3 + public/icons.svg | 13 +++- src/element/login-signup.tsx | 1 + src/element/profile.tsx | 4 +- src/index.css | 50 ++++++++++++---- src/index.tsx | 3 +- src/login.ts | 21 +++++-- src/pages/layout.tsx | 112 +++++++++++++++++++++++------------ yarn.lock | 48 ++++++++++++++- 9 files changed, 195 insertions(+), 60 deletions(-) diff --git a/package.json b/package.json index 0e62b77..14b4654 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@snort/shared": "^1.0.4", "@snort/system": "^1.0.16", "@snort/system-react": "^1.0.11", + "@szhsin/react-menu": "^4.0.2", "@testing-library/jest-dom": "^5.14.1", "@testing-library/react": "^13.0.0", "@testing-library/user-event": "^13.2.1", @@ -78,6 +79,8 @@ "@testing-library/dom": "^9.3.1", "@types/lodash": "^4.14.195", "@types/lodash.uniqby": "^4.7.7", + "@types/react": "^18.2.15", + "@types/react-dom": "^18.2.7", "@typescript-eslint/eslint-plugin": "^6.1.0", "@typescript-eslint/parser": "^6.1.0", "@webbtc/webln-types": "^1.0.12", diff --git a/public/icons.svg b/public/icons.svg index 94c70f7..f683e4f 100644 --- a/public/icons.svg +++ b/public/icons.svg @@ -9,8 +9,11 @@ - - + + + + + @@ -41,5 +44,11 @@ + + + + + + diff --git a/src/element/login-signup.tsx b/src/element/login-signup.tsx index 0f0152c..bf87b30 100644 --- a/src/element/login-signup.tsx +++ b/src/element/login-signup.tsx @@ -30,6 +30,7 @@ export function LoginSignup({ close }: { close: () => void }) { const pub = await EventPublisher.nip7(); if (pub) { Login.loginWithPubkey(pub.pubKey, LoginType.Nip7); + close(); } } catch (e) { console.error(e); diff --git a/src/element/profile.tsx b/src/element/profile.tsx index bdedd95..a36fba2 100644 --- a/src/element/profile.tsx +++ b/src/element/profile.tsx @@ -33,12 +33,14 @@ export function Profile({ avatarClassname, options, profile, + linkToProfile, }: { pubkey: string; icon?: ReactNode; avatarClassname?: string; options?: ProfileOptions; profile?: UserMetadata; + linkToProfile?: boolean; }) { const { inView, ref } = useInView(); const pLoaded = @@ -69,7 +71,7 @@ export function Profile({ ); - return pubkey === "anon" ? ( + return pubkey === "anon" || linkToProfile === false ? (
{content}
diff --git a/src/index.css b/src/index.css index 8ff23ef..e31f23e 100644 --- a/src/index.css +++ b/src/index.css @@ -1,14 +1,14 @@ body { margin: 0; - font-family: 'Outfit', sans-serif; + font-family: "Outfit", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - background-color: #0A0A0A; + background-color: #0a0a0a; color: white; } code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', + font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", monospace; } @@ -50,7 +50,7 @@ a { } .pill.live { - background: #F838D9; + background: #f838d9; color: white; } @@ -77,7 +77,7 @@ a { border: 1px solid transparent; color: inherit; background: linear-gradient(black, black) padding-box, - linear-gradient(94.73deg, #2BD9FF 0%, #F838D9 100%) border-box; + linear-gradient(94.73deg, #2bd9ff 0%, #f838d9 100%) border-box; transition: 0.3s; } @@ -87,7 +87,7 @@ a { } .btn-primary { - background: #FFF; + background: #fff; color: #0a0a0a; } @@ -96,11 +96,11 @@ a { } .btn-warning { - background: #FF563F; + background: #ff563f; color: white; } -.btn>span { +.btn > span { display: flex; align-items: center; justify-content: center; @@ -133,7 +133,7 @@ input[type="checkbox"] { } input[type="checkbox"]:after { - content: ' '; + content: " "; position: relative; left: 40%; top: 20%; @@ -164,11 +164,11 @@ div.paper { } .warning { - color: #FF563F; + color: #ff563f; } .border-warning { - border: 1px solid #FF563F; + border: 1px solid #ff563f; } .dialog-content { @@ -191,4 +191,30 @@ div.paper { display: block; color: #868686; margin: 6px; -} \ No newline at end of file +} + +.ctx-menu { + font-size: 16px; + font-weight: 700; + line-height: 20px; + border-radius: 12px; + background: #434343; + padding: 12px 0px; + color: white; + display: flex; + flex-direction: column; +} + +.ctx-menu li { + padding: 12px 24px; + display: flex; + gap: 16px; +} + +.ctx-menu li:hover { + background: #505050; +} + +.szh-menu__item--hover { + background-color: unset; +} diff --git a/src/index.tsx b/src/index.tsx index b033c29..7fbd356 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,3 +1,4 @@ +import "@szhsin/react-menu/dist/index.css"; import "./index.css"; import React from "react"; @@ -49,7 +50,7 @@ const router = createBrowserRouter([ }, { path: "/nsfw", - element: + element: , }, { path: "/:id", diff --git a/src/login.ts b/src/login.ts index 435e26e..1a46871 100644 --- a/src/login.ts +++ b/src/login.ts @@ -5,7 +5,7 @@ import { EventPublisher, Nip7Signer, PrivateKeySigner } from "@snort/system"; export enum LoginType { Nip7 = "nip7", - PrivateKey = "private-key" + PrivateKey = "private-key", } export interface LoginSession { @@ -25,7 +25,6 @@ export class LoginStore extends ExternalStore { this.#session = JSON.parse(json); if (this.#session) { this.#session.type ??= LoginType.Nip7; - } } } @@ -49,12 +48,21 @@ export class LoginStore extends ExternalStore { this.#save(); } + logout() { + this.#session = undefined; + this.#save(); + } + takeSnapshot() { return this.#session ? { ...this.#session } : undefined; } #save() { - window.localStorage.setItem("session", JSON.stringify(this.#session)); + if (this.#session) { + window.localStorage.setItem("session", JSON.stringify(this.#session)); + } else { + window.localStorage.removeItem("session"); + } this.notifyChange(); } } @@ -65,7 +73,10 @@ export function getPublisher(session: LoginSession) { return new EventPublisher(new Nip7Signer(), session.pubkey); } case LoginType.PrivateKey: { - return new EventPublisher(new PrivateKeySigner(session.privateKey!), session.pubkey); + return new EventPublisher( + new PrivateKeySigner(session.privateKey!), + session.pubkey + ); } } -} \ No newline at end of file +} diff --git a/src/pages/layout.tsx b/src/pages/layout.tsx index a46f30f..a54eaf6 100644 --- a/src/pages/layout.tsx +++ b/src/pages/layout.tsx @@ -8,6 +8,9 @@ import { useLogin } from "hooks/login"; import { Profile } from "element/profile"; import { NewStreamDialog } from "element/new-stream"; import { LoginSignup } from "element/login-signup"; +import { Menu, MenuItem } from "@szhsin/react-menu"; +import { hexToBech32 } from "@snort/shared"; +import { Login } from "index"; export function LayoutPage() { const navigate = useNavigate(); @@ -21,13 +24,34 @@ export function LayoutPage() { return ( <> - + + + + } + align="end" + gap={5} + > + navigate(`/p/${hexToBech32("npub", login.pubkey)}`)} + > + + Profile + + Login.logout()}> + + Logout + + ); } @@ -35,31 +59,40 @@ export function LayoutPage() { function loggedOut() { if (login) return; - return - - - - - - - setShowLogin(false)} /> - - - + return ( + + + + + + + + setShowLogin(false)} /> + + + + ); } const isNsfw = window.location.pathname === "/nsfw"; return (
@@ -81,14 +114,15 @@ export function LayoutPage() {
{isNsfw && } -
); } function ContentWarningOverlay() { const navigate = useNavigate(); - const [is18Plus, setIs18Plus] = useState(Boolean(window.localStorage.getItem("accepted-content-warning"))); + const [is18Plus, setIs18Plus] = useState( + Boolean(window.localStorage.getItem("accepted-content-warning")) + ); if (is18Plus) return null; function grownUp() { @@ -96,16 +130,18 @@ function ContentWarningOverlay() { setIs18Plus(true); } - return
-

Sexually explicit material ahead!

-

Confirm your age

-
- - + return ( +
+

Sexually explicit material ahead!

+

Confirm your age

+
+ + +
-
-} \ No newline at end of file + ); +} diff --git a/yarn.lock b/yarn.lock index a62fed7..240286d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2579,6 +2579,19 @@ __metadata: languageName: node linkType: hard +"@szhsin/react-menu@npm:^4.0.2": + version: 4.0.2 + resolution: "@szhsin/react-menu@npm:4.0.2" + dependencies: + prop-types: ^15.7.2 + react-transition-state: ^2.1.0 + peerDependencies: + react: ">=16.14.0" + react-dom: ">=16.14.0" + checksum: ac84a6f84b2671044d96667011ae747e8962a1b90507080155e5aec7807a705cbd7020f6a6396df34d68cd6b9de87b979af785916eeb29eb683d0da3fd0aa8dd + languageName: node + linkType: hard + "@testing-library/dom@npm:^8.5.0": version: 8.20.1 resolution: "@testing-library/dom@npm:8.20.1" @@ -2966,6 +2979,15 @@ __metadata: languageName: node linkType: hard +"@types/react-dom@npm:^18.2.7": + version: 18.2.7 + resolution: "@types/react-dom@npm:18.2.7" + dependencies: + "@types/react": "*" + checksum: e02ea908289a7ad26053308248d2b87f6aeafd73d0e2de2a3d435947bcea0422599016ffd1c3e38ff36c42f5e1c87c7417f05b0a157e48649e4a02f21727d54f + languageName: node + linkType: hard + "@types/react@npm:*": version: 18.2.13 resolution: "@types/react@npm:18.2.13" @@ -2977,6 +2999,17 @@ __metadata: languageName: node linkType: hard +"@types/react@npm:^18.2.15": + version: 18.2.15 + resolution: "@types/react@npm:18.2.15" + dependencies: + "@types/prop-types": "*" + "@types/scheduler": "*" + csstype: ^3.0.2 + checksum: 36989f638201bfe2f4110b06c119180f6df9c0e13d7060481e82e7a745f81745a01ae543c478a25b61e0767cb52e82da2ad5b0dedacabf99339e523d06176705 + languageName: node + linkType: hard + "@types/resolve@npm:1.17.1": version: 1.17.1 resolution: "@types/resolve@npm:1.17.1" @@ -8279,7 +8312,7 @@ __metadata: languageName: node linkType: hard -"prop-types@npm:^15.8.1": +"prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": version: 15.8.1 resolution: "prop-types@npm:15.8.1" dependencies: @@ -8506,6 +8539,16 @@ __metadata: languageName: node linkType: hard +"react-transition-state@npm:^2.1.0": + version: 2.1.1 + resolution: "react-transition-state@npm:2.1.1" + peerDependencies: + react: ">=16.8.0" + react-dom: ">=16.8.0" + checksum: 6091d0c59a255b9ec47b6bfc8f766737bdb1a21bb15f0c738e0feef9efd20df5a3209699029cab2fcb18c99fa8ad97cdbce95ceabee9fe6c6dd8b98a11af00b5 + languageName: node + linkType: hard + "react@npm:^18.2.0": version: 18.2.0 resolution: "react@npm:18.2.0" @@ -9313,12 +9356,15 @@ __metadata: "@snort/shared": ^1.0.4 "@snort/system": ^1.0.16 "@snort/system-react": ^1.0.11 + "@szhsin/react-menu": ^4.0.2 "@testing-library/dom": ^9.3.1 "@testing-library/jest-dom": ^5.14.1 "@testing-library/react": ^13.0.0 "@testing-library/user-event": ^13.2.1 "@types/lodash": ^4.14.195 "@types/lodash.uniqby": ^4.7.7 + "@types/react": ^18.2.15 + "@types/react-dom": ^18.2.7 "@types/webscopeio__react-textarea-autocomplete": ^4.7.2 "@typescript-eslint/eslint-plugin": ^6.1.0 "@typescript-eslint/parser": ^6.1.0