/** @jsx h */ 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, LinearGradientsClass, NoOutlineClass } from "./components/tw.ts"; import KeyView from "./key-view.tsx"; import { PrivateKey } from "../lib/nostr-ts/key.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: "SignInEvent"; ctx: NostrAccountContext; }; const AlbyURL = "https://getalby.com/"; type SignInState = "none" | "nip07" | "local"; export function getSignInState(): SignInState { const state = localStorage.getItem("SignInState"); if (state === null) { return "none"; } return state as SignInState; } export function setSignInState(state: SignInState) { localStorage.setItem("SignInState", state); } //////////////////////// // Check Login Status // //////////////////////// export async function getCurrentSignInCtx() { if (getSignInState() === "nip07") { const nip07Ctx = await Nip7ExtensionContext.New(); if (nip07Ctx instanceof Error) { return nip07Ctx; } if (nip07Ctx === undefined) { setSignInState("none"); } return nip07Ctx; } if (getSignInState() === "local") { const ctx = GetLocalStorageAccountContext(); if (ctx instanceof Error) { throw ctx; } if (ctx === undefined) { console.log("GetLocalStorageAccountContext is undefined"); setSignInState("none"); } return ctx; } return undefined; } type Props = { emit: emitFunc; }; type State = { state: "newAccount" | "enterPrivateKey"; privateKey: PrivateKey; privateKeyError: string; nip07Error: string; }; export class SignIn extends Component { 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") { return (

Please back up your Private Key

); } return (
Logo

Blowater

A delightful Nostr client that focuses on DM

this.inputPrivateKey(e.currentTarget.value)} placeholder="Input your private key here" type="password" class={this.styles.input} autofocus />

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

{this.state.nip07Error}

); } }