diff --git a/UI/app.tsx b/UI/app.tsx index 6398529..13190c4 100644 --- a/UI/app.tsx +++ b/UI/app.tsx @@ -43,7 +43,6 @@ export async function Start(database: DexieDatabase) { const ctx = await getCurrentSignInCtx(); if (ctx instanceof Error) { console.error(ctx); - model.signIn.warningString = "Please add your private key to your NIP-7 extension"; } else if (ctx) { const dbView = await Database_Contextual_View.New(database); if (dbView instanceof Error) { @@ -386,13 +385,7 @@ export function AppComponent(props: { if (model.app == undefined) { console.log("render sign in page"); - return ( - - ); + return ; } const app = model.app; diff --git a/UI/app_model.ts b/UI/app_model.ts index ffea6e4..ffd65ca 100644 --- a/UI/app_model.ts +++ b/UI/app_model.ts @@ -3,7 +3,6 @@ import { SearchInitModel, SearchModel } from "./search_model.ts"; import { ProfileData } from "../features/profile.ts"; import { RightPanelModel } from "./message-panel.tsx"; import { App } from "./app.tsx"; -import { SignInModel } from "./signIn.tsx"; import { EditorModel } from "./editor.tsx"; import { DM_Model } from "./dm.tsx"; @@ -25,9 +24,6 @@ export type Model = { // UI navigationModel: NavigationModel; rightPanelModel: RightPanelModel; - - // sign in - signIn: SignInModel; }; export function initialModel(): Model { @@ -53,8 +49,5 @@ export function initialModel(): Model { show: false, }, myProfile: undefined, - signIn: { - privateKey: "", - }, }; } diff --git a/UI/app_update.tsx b/UI/app_update.tsx index 28c7037..8c50dac 100644 --- a/UI/app_update.tsx +++ b/UI/app_update.tsx @@ -18,7 +18,7 @@ import { NavigationUpdate } from "./nav.tsx"; import { Model } from "./app_model.ts"; import { SearchUpdate, SelectConversation } from "./search_model.ts"; import { LamportTime } from "../time.ts"; -import { SignInEvent, signInWithExtension, signInWithPrivateKey } from "./signIn.tsx"; +import { SignInEvent } from "./signIn.tsx"; import { Encrypted_Event, getTags, @@ -84,26 +84,8 @@ export async function* UI_Interaction_Update(args: { for await (const event of events) { console.log(event); switch (event.type) { - case "editSignInPrivateKey": - model.signIn.privateKey = event.privateKey; - yield model; - continue; - break; - case "signin": - let ctx; - if (event.privateKey) { - ctx = signInWithPrivateKey(event.privateKey); - } else { - const ctx2 = await signInWithExtension(); - console.log(ctx2); - if (typeof ctx2 == "string") { - model.signIn.warningString = ctx2; - } else if (ctx2 instanceof Error) { - model.signIn.warningString = ctx2.message; - } else { - ctx = ctx2; - } - } + case "SignInEvent": + const ctx = event.ctx; if (ctx) { console.log("sign in as", ctx.publicKey.bech32()); const dbView = await Database_Contextual_View.New(dexieDB); diff --git a/UI/components/tw.ts b/UI/components/tw.ts index c79442c..ac3dfed 100644 --- a/UI/components/tw.ts +++ b/UI/components/tw.ts @@ -3,7 +3,7 @@ import { DividerBackgroundColor, PlaceholderColor, PrimaryTextColor } from "../s export const CenterClass = "flex items-center justify-center"; export const NoOutlineClass = "focus:outline-none focus-visible:outline-none"; export const inputBorderClass = `border-[2px] border-[${DividerBackgroundColor}]`; -export const DividerClass = `h-[0.0625rem] bg-[${DividerBackgroundColor}] my-[1.5rem]`; +export const DividerClass = `h-[0.0625rem] bg-[${DividerBackgroundColor}] my-[1.5rem] w-full`; export const LinearGradientsClass = "bg-gradient-to-r from-[#FF762C] via-[#FF3A5E] to-[#FF01A9]"; export const InputClass = `w-full px-4 py-3 rounded-lg resize-y bg-transparent ${NoOutlineClass} ${inputBorderClass} placeholder-[${PlaceholderColor}] text-[${PrimaryTextColor}]`; diff --git a/UI/deploy/index-extension.html b/UI/deploy/index-extension.html index e525ef0..b14c9de 100644 --- a/UI/deploy/index-extension.html +++ b/UI/deploy/index-extension.html @@ -43,7 +43,7 @@ @media screen and (max-width: 1024px) { html { - font-size: calc(1.618em * (1920 / 2560)); + font-size: 1em; } } diff --git a/UI/deploy/index.html b/UI/deploy/index.html index 89cc095..d33c7d3 100644 --- a/UI/deploy/index.html +++ b/UI/deploy/index.html @@ -43,7 +43,7 @@ @media screen and (max-width: 1024px) { html { - font-size: calc(1.618em * (1920 / 2560)); + font-size: 1em; } } diff --git a/UI/signIn.test.tsx b/UI/signIn.test.tsx index c9a8b72..e31fe56 100644 --- a/UI/signIn.test.tsx +++ b/UI/signIn.test.tsx @@ -7,8 +7,7 @@ import { SignIn } from "./signIn.tsx"; render( , document.body, ); diff --git a/UI/signIn.tsx b/UI/signIn.tsx index 1738fb2..e1228c5 100644 --- a/UI/signIn.tsx +++ b/UI/signIn.tsx @@ -2,18 +2,24 @@ import { Component, h } from "https://esm.sh/preact@10.17.1"; import { tw } from "https://esm.sh/twind@0.16.16"; import { GetLocalStorageAccountContext, Nip7ExtensionContext } from "./account-context.ts"; -import { ButtonClass, CenterClass, DividerClass } from "./components/tw.ts"; +import { ButtonClass, CenterClass, LinearGradientsClass, NoOutlineClass } from "./components/tw.ts"; import KeyView from "./key-view.tsx"; import { PrivateKey } from "../lib/nostr-ts/key.ts"; -import { InMemoryAccountContext } from "../lib/nostr-ts/nostr.ts"; -import { emitFunc, EventEmitter } from "../event-bus.ts"; +import { InMemoryAccountContext, NostrAccountContext } from "../lib/nostr-ts/nostr.ts"; +import { emitFunc } from "../event-bus.ts"; +import { + ErrorColor, + HintLinkColor, + HintTextColor, + HoverButtonBackgroudColor, + PrimaryBackgroundColor, + PrimaryTextColor, + SecondaryBackgroundColor, +} from "./style/colors.ts"; export type SignInEvent = { - type: "signin"; - privateKey?: PrivateKey; // undefined means sign in with extentions -} | { - type: "editSignInPrivateKey"; - privateKey: string; + type: "SignInEvent"; + ctx: NostrAccountContext; }; const AlbyURL = "https://getalby.com/"; @@ -37,14 +43,14 @@ export function setSignInState(state: SignInState) { //////////////////////// export async function getCurrentSignInCtx() { if (getSignInState() === "nip07") { - const albyCtx = await Nip7ExtensionContext.New(); - if (albyCtx instanceof Error) { - return albyCtx; + const nip07Ctx = await Nip7ExtensionContext.New(); + if (nip07Ctx instanceof Error) { + return nip07Ctx; } - if (albyCtx === undefined) { + if (nip07Ctx === undefined) { setSignInState("none"); } - return albyCtx; + return nip07Ctx; } if (getSignInState() === "local") { const ctx = GetLocalStorageAccountContext(); @@ -60,174 +66,184 @@ export async function getCurrentSignInCtx() { return undefined; } -export async function signInWithExtension() { - const albyCtx = await Nip7ExtensionContext.New(); - if (albyCtx instanceof Error) { - return albyCtx; - } - if (albyCtx === undefined) { - open(AlbyURL); - } - return albyCtx; -} - -export function signInWithPrivateKey(privateKey: PrivateKey) { - const ctx = InMemoryAccountContext.New(privateKey); - if (ctx instanceof Error) { - throw ctx; - } - localStorage.setItem("MPK", privateKey.hex); - setSignInState("local"); - return ctx; -} - type Props = { - eventBus: EventEmitter; -} & SignInModel; - -export type SignInModel = { - privateKey: string; - warningString?: string; + emit: emitFunc; }; -type State = { state: "newAccount" | "enterPrivateKey" }; +type State = { + state: "newAccount" | "enterPrivateKey"; + privateKey: PrivateKey; + privateKeyError: string; + nip07Error: string; +}; export class SignIn extends Component { - render() { - const props = this.props; + styles = { + container: + tw`h-screen w-screen bg-[${PrimaryBackgroundColor}] flex items-center justify-center p-4 overflow-y-auto`, + form: tw`w-[30rem] flex flex-col h-full py-8`, + logo: tw`w-32 h-32 mx-auto`, + title: tw`text-[${PrimaryTextColor}] text-center text-4xl`, + subTitle: tw`text-[${HintTextColor}] text-center`, + input: tw`w-full px-4 py-2 focus-visible:outline-none rounded-lg mt-8`, + hint: tw`text-[${HintTextColor}] text-sm mt-2`, + block: tw`flex-1 desktop:hidden`, + signInButton: + tw`w-full mt-4 ${ButtonClass} ${LinearGradientsClass} hover:bg-gradient-to-l mobile:rounded-full font-bold`, + ablyButton: + tw`${ButtonClass} ${CenterClass} mt-4 bg-[#F8C455] text-[#313338] hover:bg-[#FFDF6F] py-0 mobile:rounded-full`, + cancelButton: + tw`${ButtonClass} ${CenterClass} mt-4 bg-[${SecondaryBackgroundColor}] text-[${PrimaryTextColor}] hover:bg-[${HoverButtonBackgroudColor}] mobile:rounded-full`, + newButton: + tw`text-[${HintLinkColor}] hover:underline mobile:text-[${PrimaryTextColor}] mobile:bg-[${HintLinkColor}] mobile:rounded mobile:px-2 mobile:py-1 ${NoOutlineClass}`, + ablyIcon: tw`h-10`, + isError: (error: string) => error ? tw`text-[${ErrorColor}]` : "", + }; + signInWithPrivateKey = () => { + if (!this.state.privateKey) { + this.setState({ + privateKeyError: "Invilid Private Key", + }); + return; + } + + const ctx = InMemoryAccountContext.New(this.state.privateKey); + localStorage.setItem("MPK", this.state.privateKey.hex); + setSignInState("local"); + + this.props.emit({ + type: "SignInEvent", + ctx: ctx, + }); + }; + + signInWithExtension = async () => { + const nip07Ctx = await Nip7ExtensionContext.New(); + if (nip07Ctx === undefined) { + open(AlbyURL); + return; + } + if (typeof nip07Ctx == "string") { + this.setState({ + nip07Error: nip07Ctx, + }); + } else if (nip07Ctx instanceof Error) { + this.setState({ + nip07Error: nip07Ctx.message, + }); + } else { + this.props.emit({ + type: "SignInEvent", + ctx: nip07Ctx, + }); + } + }; + + newAccount = () => { + this.setState({ + privateKey: PrivateKey.Generate(), + privateKeyError: "", + state: "newAccount", + }); + }; + + cancelNew = () => { + this.setState({ + state: "enterPrivateKey", + privateKey: undefined, + }); + }; + + inputPrivateKey = (privateKeyStr: string) => { + let privateKey = PrivateKey.FromHex(privateKeyStr); + if (privateKey instanceof Error) { + privateKey = PrivateKey.FromBech32(privateKeyStr); + + if (privateKey instanceof Error) { + this.setState({ + privateKeyError: "Invilid Private Key", + }); + return; + } + } + this.setState({ + privateKeyError: "", + privateKey: privateKey, + }); + }; + + render() { if (this.state.state == "newAccount") { - const privateKey = PrivateKey.Generate(); return ( -
-
+
+
+

+ Please back up your Private Key +

+
); } - let privateKey = PrivateKey.FromHex(props.privateKey); - if (privateKey instanceof Error) { - privateKey = PrivateKey.FromBech32(props.privateKey); - } - return ( -
-
- Logo -

- Welcome to Blowater -

+
+
+ Logo +

Blowater

+

A delightful Nostr client that focuses on DM

this.inputPrivateKey(e.currentTarget.value)} placeholder="Input your private key here" type="password" - class={tw`w-full px-4 py-2 focus-visible:outline-none rounded-lg mt-8`} + class={this.styles.input} + autofocus /> - {privateKey instanceof Error - ? ( -

- Private Key has to be 64 letters hex-decimal or 63 letters nsec string -

- ) - : undefined} +

+ + Private Key has to be 64 letters hex-decimal or{" "} + 63 letters nsec string. + {" "} + Don't have an account yet?{" "} + +

+
- -
-
-
- Or you can -
-
- - - - {props.warningString - ?

{props.warningString}

- : undefined} +

+ + {this.state.nip07Error} + +

); } } - -const on_CreateAccount_clicked = (setState: (state: State) => void) => () => { - setState({ state: "newAccount" }); -}; - -const on_SignIn_clicked = (privateKey: PrivateKey | Error, emit: emitFunc) => () => { - if (privateKey instanceof PrivateKey) { - emit({ - type: "signin", - privateKey: privateKey, - }); - } -}; - -const on_EditSignInPrivateKey_clicked = - (emit: emitFunc) => (e: h.JSX.TargetedEvent) => { - emit({ - type: "editSignInPrivateKey", - privateKey: e.currentTarget.value, - }); - }; - -const on_BackToSignInPage_click = (setState: (state: State) => void) => () => { - setState({ state: "enterPrivateKey" }); -};