feat: export keys & new settings page

This commit is contained in:
Kieran 2023-04-21 21:55:04 +01:00
parent e6daf6536e
commit 45ca273064
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
9 changed files with 152 additions and 47 deletions

View File

@ -139,5 +139,11 @@
<symbol id="code-circle" viewBox="0 0 22 22" fill="none">
<path d="M13 16L16 13L13 10M9 6L6 9L9 12M21 11C21 16.5228 16.5228 21 11 21C5.47715 21 1 16.5228 1 11C1 5.47715 5.47715 1 11 1C16.5228 1 21 5.47715 21 11Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</symbol>
<symbol id="key" viewBox="0 0 20 20" fill="none">
<path d="M15 6.99994C15 6.48812 14.8047 5.9763 14.4142 5.58579C14.0237 5.19526 13.5118 5 13 5M13 13C16.3137 13 19 10.3137 19 7C19 3.68629 16.3137 1 13 1C9.68629 1 7 3.68629 7 7C7 7.27368 7.01832 7.54308 7.05381 7.80704C7.11218 8.24118 7.14136 8.45825 7.12172 8.59559C7.10125 8.73865 7.0752 8.81575 7.00469 8.9419C6.937 9.063 6.81771 9.18229 6.57913 9.42087L1.46863 14.5314C1.29568 14.7043 1.2092 14.7908 1.14736 14.8917C1.09253 14.9812 1.05213 15.0787 1.02763 15.1808C1 15.2959 1 15.4182 1 15.6627V17.4C1 17.9601 1 18.2401 1.10899 18.454C1.20487 18.6422 1.35785 18.7951 1.54601 18.891C1.75992 19 2.03995 19 2.6 19H5V17H7V15H9L10.5791 13.4209C10.8177 13.1823 10.937 13.063 11.0581 12.9953C11.1843 12.9248 11.2613 12.8987 11.4044 12.8783C11.5417 12.8586 11.7588 12.8878 12.193 12.9462C12.4569 12.9817 12.7263 13 13 13Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</symbol>
<symbol id="user" viewBox="0 0 18 20" fill="none">
<path d="M17 19C17 17.6044 17 16.9067 16.8278 16.3389C16.44 15.0605 15.4395 14.06 14.1611 13.6722C13.5933 13.5 12.8956 13.5 11.5 13.5H6.5C5.10444 13.5 4.40665 13.5 3.83886 13.6722C2.56045 14.06 1.56004 15.0605 1.17224 16.3389C1 16.9067 1 17.6044 1 19M13.5 5.5C13.5 7.98528 11.4853 10 9 10C6.51472 10 4.5 7.98528 4.5 5.5C4.5 3.01472 6.51472 1 9 1C11.4853 1 13.5 3.01472 13.5 5.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</symbol>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -32,23 +32,25 @@ export const CollapsedIcon = ({ icon, collapsed }: CollapsedIconProps) => {
interface CollapsedSectionProps {
title: ReactNode;
children: ReactNode;
className?: string;
}
export const CollapsedSection = ({ title, children }: CollapsedSectionProps) => {
export const CollapsedSection = ({ title, children, className }: CollapsedSectionProps) => {
const [collapsed, setCollapsed] = useState(true);
const icon = (
<div className={`collapse-icon ${collapsed ? "" : "flip"}`} onClick={() => setCollapsed(!collapsed)}>
<Icon name="chevronDown" />
<div className={`collapse-icon ${collapsed ? "" : "flip"}`}>
<Icon name="arrowFront" />
</div>
);
return (
<>
<div className="collapsable-section">
<h3 onClick={() => setCollapsed(!collapsed)}>{title}</h3>
<div
className={`collapsable-section${className ? ` ${className}` : ""}`}
onClick={() => setCollapsed(!collapsed)}>
{title}
<CollapsedIcon icon={icon} collapsed={collapsed} />
</div>
{collapsed ? null : children}
{!collapsed && children}
</>
);
};

View File

@ -8,6 +8,7 @@ import RelayInfo from "Pages/settings/RelayInfo";
import AccountsPage from "Pages/settings/Accounts";
import { WalletSettingsRoutes } from "Pages/settings/WalletSettings";
import { ManageHandleRoutes } from "Pages/settings/handle";
import ExportKeys from "Pages/settings/Keys";
import messages from "./messages";
@ -49,6 +50,10 @@ export const SettingsRoutes: RouteObject[] = [
path: "accounts",
element: <AccountsPage />,
},
{
path: "keys",
element: <ExportKeys />,
},
...ManageHandleRoutes,
...WalletSettingsRoutes,
];

View File

@ -12,7 +12,12 @@ import messages from "./messages";
const WhatIsSnort = () => {
return (
<CollapsedSection title={<FormattedMessage {...messages.WhatIsSnort} />}>
<CollapsedSection
title={
<h3>
<FormattedMessage {...messages.WhatIsSnort} />
</h3>
}>
<p>
<FormattedMessage {...messages.WhatIsSnortIntro} />
</p>
@ -28,7 +33,12 @@ const WhatIsSnort = () => {
const HowDoKeysWork = () => {
return (
<CollapsedSection title={<FormattedMessage {...messages.HowKeysWork} />}>
<CollapsedSection
title={
<h3>
<FormattedMessage {...messages.HowKeysWork} />
</h3>
}>
<p>
<FormattedMessage {...messages.DigitalSignatures} />
</p>
@ -44,7 +54,12 @@ const HowDoKeysWork = () => {
const Extensions = () => {
return (
<CollapsedSection title={<FormattedMessage {...messages.ImproveSecurity} />}>
<CollapsedSection
title={
<h3>
<FormattedMessage {...messages.ImproveSecurity} />
</h3>
}>
<p>
<FormattedMessage {...messages.Extensions} />
</p>

View File

@ -13,16 +13,30 @@
border-radius: 10px;
cursor: pointer;
gap: 10px;
margin-bottom: 5px;
}
.settings-row:hover {
.settings-row.inner {
padding: 0.8em 0;
background-color: unset;
border-radius: unset;
margin: 0;
}
.settings-group-header {
font-weight: 600;
font-size: 16px;
padding: 0.8em 1em;
background-color: var(--note-bg);
border-radius: 10px;
margin-bottom: 5px;
}
.settings-row:hover,
.settings-group-header:hover {
color: var(--highlight);
}
.settings-row + .settings-row {
margin-top: 10px;
}
.align-end {
margin-left: auto;
}
@ -31,3 +45,7 @@
width: 100%;
height: 100%;
}
.settings-group-header .collapse-icon > svg {
width: 8px;
}

View File

@ -6,6 +6,7 @@ import { LoginStore, logout } from "Login";
import useLogin from "Hooks/useLogin";
import { unwrap } from "Util";
import { getCurrentSubscription } from "Subscription";
import { CollapsedSection } from "Element/Collapsed";
import messages from "./messages";
@ -22,21 +23,56 @@ const SettingsIndex = () => {
return (
<>
<div className="settings-nav">
<div className="settings-row" onClick={() => navigate("profile")}>
<Icon name="profile" />
<FormattedMessage {...messages.Profile} />
<Icon name="arrowFront" />
</div>
<div className="settings-row" onClick={() => navigate("relays")}>
<Icon name="relay" />
<FormattedMessage {...messages.Relays} />
<Icon name="arrowFront" />
</div>
<CollapsedSection
title={
<div className="flex">
<Icon name="user" className="mr10" />
<FormattedMessage defaultMessage="Account" />
</div>
}
className="settings-group-header">
<div className="card">
<div className="settings-row inner" onClick={() => navigate("profile")}>
<Icon name="profile" />
<FormattedMessage {...messages.Profile} />
<Icon name="arrowFront" />
</div>
<div className="settings-row inner" onClick={() => navigate("relays")}>
<Icon name="relay" />
<FormattedMessage {...messages.Relays} />
<Icon name="arrowFront" />
</div>
<div className="settings-row inner" onClick={() => navigate("keys")}>
<Icon name="key" />
<FormattedMessage defaultMessage="Export Keys" />
<Icon name="arrowFront" />
</div>
<div className="settings-row inner" onClick={() => navigate("handle")}>
<Icon name="badge" />
<FormattedMessage defaultMessage="Nostr Adddress" />
<Icon name="arrowFront" />
</div>
<div className="settings-row inner" onClick={() => navigate("/subscribe/manage")}>
<Icon name="diamond" />
<FormattedMessage defaultMessage="Subscription" />
<Icon name="arrowFront" />
</div>
{sub && (
<div className="settings-row inner" onClick={() => navigate("accounts")}>
<Icon name="code-circle" />
<FormattedMessage defaultMessage="Account Switcher" />
<Icon name="arrowFront" />
</div>
)}
</div>
</CollapsedSection>
<div className="settings-row" onClick={() => navigate("preferences")}>
<Icon name="gear" />
<FormattedMessage {...messages.Preferences} />
<Icon name="arrowFront" />
</div>
<div className="settings-row" onClick={() => navigate("wallet")}>
<Icon name="wallet" />
<FormattedMessage defaultMessage="Wallet" />
@ -47,23 +83,7 @@ const SettingsIndex = () => {
<FormattedMessage {...messages.Donate} />
<Icon name="arrowFront" />
</div>
<div className="settings-row" onClick={() => navigate("handle")}>
<Icon name="badge" />
<FormattedMessage defaultMessage="Snort Nostr Adddress" />
<Icon name="arrowFront" />
</div>
<div className="settings-row" onClick={() => navigate("/subscribe/manage")}>
<Icon name="diamond" />
<FormattedMessage defaultMessage="Snort Subscription" />
<Icon name="arrowFront" />
</div>
{sub && (
<div className="settings-row" onClick={() => navigate("accounts")}>
<Icon name="code-circle" />
<FormattedMessage defaultMessage="Accounts" />
<Icon name="arrowFront" />
</div>
)}
<div className="settings-row" onClick={handleLogout}>
<Icon name="logout" />
<FormattedMessage {...messages.LogOut} />

View File

@ -0,0 +1,5 @@
.export-keys > .copy {
padding: 12px 16px;
border: 2px dashed #222222;
border-radius: 16px;
}

View File

@ -0,0 +1,37 @@
import "./Keys.css";
import { FormattedMessage } from "react-intl";
import { encodeTLV, NostrPrefix } from "@snort/nostr";
import Copy from "Element/Copy";
import useLogin from "Hooks/useLogin";
import { hexToMnemonic } from "nip6";
import { hexToBech32 } from "Util";
export default function ExportKeys() {
const { publicKey, privateKey, generatedEntropy } = useLogin();
return (
<div className="export-keys">
<h3>
<FormattedMessage defaultMessage="Public Key" />
</h3>
<Copy text={hexToBech32("npub", publicKey ?? "")} maxSize={48} className="mb10" />
<Copy text={encodeTLV(publicKey ?? "", NostrPrefix.Profile)} maxSize={48} />
{privateKey && (
<>
<h3>
<FormattedMessage defaultMessage="Private Key" />
</h3>
<Copy text={hexToBech32("nsec", privateKey)} maxSize={48} />
</>
)}
{generatedEntropy && (
<>
<h3>
<FormattedMessage defaultMessage="Mnemonic" />
</h3>
<Copy text={hexToMnemonic(generatedEntropy ?? "")} maxSize={48} />
</>
)}
</div>
);
}

View File

@ -581,19 +581,16 @@ button.tall {
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.collapsable-section h3,
.collapsable-section svg {
cursor: pointer;
}
.collapsable-section .collapse-icon {
transform: rotate(90deg);
transition: transform 300ms ease-in-out;
}
.collapsable-section .collapse-icon.flip {
transform: rotate(180deg);
transform: rotate(270deg);
transition: transform 300ms ease-in-out;
}