-
Notifications
You must be signed in to change notification settings - Fork 194
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2338 from getAlby/feat/mnemonic
feat: mnemonic and webbtc.getAddress
- Loading branch information
Showing
69 changed files
with
2,205 additions
and
487 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { classNames } from "~/app/utils"; | ||
|
||
type Props = { | ||
type: "warn" | "info"; | ||
children: React.ReactNode; | ||
}; | ||
|
||
export default function Alert({ type, children }: Props) { | ||
return ( | ||
<div | ||
className={classNames( | ||
"rounded-md font-medium p-4", | ||
type == "warn" && | ||
"text-orange-700 bg-orange-50 dark:text-orange-200 dark:bg-orange-900", | ||
type == "info" && | ||
"text-blue-700 bg-blue-50 dark:text-blue-200 dark:bg-blue-900" | ||
)} | ||
> | ||
<p>{children}</p> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import React from "react"; | ||
|
||
export function ContentBox({ children }: React.PropsWithChildren<object>) { | ||
return ( | ||
<div className="mt-12 shadow bg-white rounded-md p-10 divide-black/10 dark:divide-white/10 dark:bg-surface-02dp flex flex-col gap-4"> | ||
{children} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { CopyIcon as CopyFilledIcon } from "@bitcoin-design/bitcoin-icons-react/filled"; | ||
import { CopyIcon } from "@bitcoin-design/bitcoin-icons-react/outline"; | ||
import { useState } from "react"; | ||
import { toast } from "react-toastify"; | ||
import { classNames } from "~/app/utils"; | ||
|
||
type Props = { | ||
value: string; | ||
className?: string; | ||
}; | ||
|
||
function InputCopyButton({ value, className }: Props) { | ||
const [copied, setCopied] = useState(false); | ||
const CurrentIcon = copied ? CopyFilledIcon : CopyIcon; | ||
return ( | ||
<button | ||
type="button" | ||
tabIndex={-1} | ||
className={classNames( | ||
"flex justify-center items-center h-8 w-10", | ||
!!className && className | ||
)} | ||
onClick={async () => { | ||
try { | ||
navigator.clipboard.writeText(value); | ||
setCopied(true); | ||
setTimeout(() => { | ||
setCopied(false); | ||
}, 1000); | ||
} catch (e) { | ||
if (e instanceof Error) { | ||
toast.error(e.message); | ||
} | ||
} | ||
}} | ||
> | ||
<CurrentIcon className="w-6 h-6" /> | ||
</button> | ||
); | ||
} | ||
export default InputCopyButton; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { useEffect } from "react"; | ||
import { useLocation } from "react-router-dom"; | ||
|
||
function ScrollToTop() { | ||
const location = useLocation(); | ||
// Scroll to top if path changes | ||
useEffect(() => { | ||
window.scrollTo(0, 0); | ||
}, [location.pathname]); | ||
|
||
return null; | ||
} | ||
|
||
export default ScrollToTop; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { | ||
HiddenIcon, | ||
VisibleIcon, | ||
} from "@bitcoin-design/bitcoin-icons-react/filled"; | ||
import { wordlist } from "@scure/bip39/wordlists/english"; | ||
import { useState } from "react"; | ||
import { useTranslation } from "react-i18next"; | ||
import Input from "~/app/components/form/Input"; | ||
|
||
type MnemonicInputsProps = { | ||
mnemonic?: string; | ||
setMnemonic?(mnemonic: string): void; | ||
readOnly?: boolean; | ||
}; | ||
|
||
export default function MnemonicInputs({ | ||
mnemonic, | ||
setMnemonic, | ||
readOnly, | ||
children, | ||
}: React.PropsWithChildren<MnemonicInputsProps>) { | ||
const { t } = useTranslation("translation", { | ||
keyPrefix: "accounts.account_view.mnemonic", | ||
}); | ||
const [revealedIndex, setRevealedIndex] = useState<number | undefined>( | ||
undefined | ||
); | ||
|
||
const words = mnemonic?.split(" ") || []; | ||
while (words.length < 12) { | ||
words.push(""); | ||
} | ||
|
||
return ( | ||
<div className="border-[1px] border-gray-200 rounded-lg py-8 px-4 flex flex-col gap-8 items-center justify-center w-[580px] self-center"> | ||
<h3 className="font-semibold dark:text-white">{t("inputs.title")}</h3> | ||
<div className="flex flex-wrap gap-4 justify-center items-center"> | ||
{words.map((word, i) => { | ||
const isRevealed = revealedIndex === i; | ||
const inputId = `mnemonic-word-${i}`; | ||
return ( | ||
<div key={i} className="flex justify-center items-center"> | ||
<span className="w-7 text-gray-500 slashed-zero dark:text-neutral-500"> | ||
{i + 1}. | ||
</span> | ||
<div className="relative"> | ||
<Input | ||
id={inputId} | ||
autoFocus={!readOnly && i === 0} | ||
onFocus={() => setRevealedIndex(i)} | ||
onBlur={() => setRevealedIndex(undefined)} | ||
readOnly={readOnly} | ||
block={false} | ||
className="w-24 text-center" | ||
list={readOnly ? undefined : "wordlist"} | ||
value={isRevealed ? word : word.length ? "•••••" : ""} | ||
onChange={(e) => { | ||
if (revealedIndex !== i) { | ||
return; | ||
} | ||
words[i] = e.target.value; | ||
setMnemonic?.( | ||
words | ||
.map((word) => word.trim()) | ||
.join(" ") | ||
.trim() | ||
); | ||
}} | ||
endAdornment={ | ||
<button | ||
type="button" | ||
tabIndex={-1} | ||
className="mr-2" | ||
onClick={() => document.getElementById(inputId)?.focus()} | ||
> | ||
{isRevealed ? ( | ||
<VisibleIcon className="h-6 w-6" /> | ||
) : ( | ||
<HiddenIcon className="h-6 w-6" /> | ||
)} | ||
</button> | ||
} | ||
/> | ||
</div> | ||
</div> | ||
); | ||
})} | ||
</div> | ||
{!readOnly && ( | ||
<datalist id="wordlist"> | ||
{wordlist.map((word) => ( | ||
<option key={word} value={word} /> | ||
))} | ||
</datalist> | ||
)} | ||
{children} | ||
</div> | ||
); | ||
} |
39 changes: 39 additions & 0 deletions
39
src/app/components/mnemonic/SecretKeyDescription/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { useTranslation } from "react-i18next"; | ||
import NostrIcon from "~/app/icons/NostrIcon"; | ||
|
||
function SecretKeyDescription() { | ||
const { t } = useTranslation("translation", { | ||
keyPrefix: "accounts.account_view.mnemonic", | ||
}); | ||
|
||
return ( | ||
<> | ||
<p className="text-gray-500 dark:text-neutral-500"> | ||
{t("backup.description1")} | ||
</p> | ||
<div className="flex flex-col gap-4"> | ||
<ProtocolListItem | ||
icon={<NostrIcon className="text-gray-500 dark:text-neutral-500" />} | ||
title={t("backup.protocols.nostr")} | ||
/> | ||
</div> | ||
|
||
<p className="mb-8 text-gray-500 dark:text-neutral-500"> | ||
{t("backup.description2")} | ||
</p> | ||
</> | ||
); | ||
} | ||
|
||
export default SecretKeyDescription; | ||
|
||
type ProtocolListItemProps = { icon: React.ReactNode; title: string }; | ||
|
||
function ProtocolListItem({ icon, title }: ProtocolListItemProps) { | ||
return ( | ||
<div className="flex gap-2"> | ||
{icon} | ||
<span className="text-gray-500 dark:text-neutral-500">{title}</span> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.