on master help sign in
login.js: add inline toggle input for ticket login
commit615749c435f28375c1b786e543335a3a33e9f528 authorLiam Fitzgerald <liam@urizen.co> dateTue 10 Mar 2020, 11:28 (7 years ago) parent6941c77
9 files changed+176−75
src/assets/secret-hidden.svg+17 src/assets/secret-show.svg+4 src/form/Inputs.js+2−2 src/indigo-react/components/CheckboxInput.js+14−4 src/indigo-react/components/Input.js+9−4 src/indigo-react/components/ToggleInput.js+4−1 src/views/Login.js+33−21 src/views/Login/Other.js+13−9 src/views/Login/Ticket.js+80−34
src/assets/secret-hidden.svgnew file+17
@@ -0,0 +1,17 @@
1+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2+<rect width="16" height="16" fill="white"/>
3+<path fill-rule="evenodd" clip-rule="evenodd" d="M8 13C13.0495 13 16 8 16 8C16 8 13.0495 3 8 3C2.95054 3 0 8 0 8C0 8 2.95054 13 8 13ZM8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10Z" fill="black"/>
4+<g filter="url(#filter0_d)">
5+<path d="M2 2.70588L2.70588 2L14 13.2941L13.2941 14L2 2.70588Z" fill="black"/>
6+</g>
7+<defs>
8+<filter id="filter0_d" x="1" y="2" width="13" height="12" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
9+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
10+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
11+<feOffset dx="-1"/>
12+<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
13+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
14+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
15+</filter>
16+</defs>
17+</svg>
src/assets/secret-show.svgnew file+4
@@ -0,0 +1,4 @@
1+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2+<rect width="16" height="16" fill="white"/>
3+<path fill-rule="evenodd" clip-rule="evenodd" d="M8 13C13.0495 13 16 8 16 8C16 8 13.0495 3 8 3C2.95054 3 0 8 0 8C0 8 2.95054 13 8 13ZM8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10Z" fill="#B1B2B3"/>
4+</svg>
src/form/Inputs.js+2−2
@@ -26,7 +26,7 @@ const PLACEHOLDER_EMAIL = 'email@example.com';
2626
2727const formatPat = buildFormatter([downcase, ensurePatFormat]);
2828
29−export function TicketInput({ name, ...rest }) {
29+export function TicketInput({ name, hidden, ...rest }) {
3030 const {
3131 meta: { valid, error, validating, touched, active },
3232 } = useField(name, {
@@ -41,7 +41,7 @@ export function TicketInput({ name, ...rest }) {
4141
4242 return (
4343 <Input
44− type="text"
44+ type={hidden ? 'password' : 'text'}
4545 name={name}
4646 obscure={value => value.replace(/[^~-]+/g, '••••••')}
4747 placeholder={PLACEHOLDER_TICKET}
src/indigo-react/components/CheckboxInput.js+14−4
@@ -9,6 +9,9 @@ export default function CheckboxInput({
99 name,
1010 label,
1111 className,
12+ style,
13+ inline = false,
14+ white = false,
1215
1316 disabled,
1417}) {
@@ -23,7 +26,8 @@ export default function CheckboxInput({
2326 <Flex
2427 row
2528 align="center"
26− className={cn(className, 'mv2', {
29+ className={cn(className, {
30+ mv2: !inline,
2731 black: !disabled,
2832 gray4: disabled,
2933 })}
@@ -39,19 +43,25 @@ export default function CheckboxInput({
3943 <Flex.Item
4044 flex
4145 as="label"
42− className="f6 mr3 lh-tall us-none pointer flex-row align-center"
46+ className={cn(
47+ { mr3: !inline },
48+ 'f6 lh-tall us-none pointer flex-row align-center'
49+ )}
4350 htmlFor={name}>
4451 <Flex
4552 justify="center"
4653 align="center"
47− className={cn('b1 p1 mr3', {
54+ className={cn('b1 p1', {
55+ mr3: !inline,
56+ mr1: inline,
4857 'bg-gray1': disabled,
49− 'bg-black white b-black': !disabled && input.value,
58+ 'bg-black white b-black': !disabled && (input.value || white),
5059 'bg-white black b-black': !disabled && !input.value,
5160 })}
5261 style={{
5362 height: '14px',
5463 width: '14px',
64+ ...style,
5565 }}>
5666 {input.value && '✓'}
5767 </Flex>
src/indigo-react/components/Input.js+9−4
@@ -11,6 +11,7 @@ export default function Input({
1111 label,
1212 className,
1313 accessory,
14+ labelAccessory,
1415 disabled = false,
1516 mono = false,
1617 obscure,
@@ -65,13 +66,17 @@ export default function Input({
6566 }),
6667 }}>
6768 <Flex.Item
68− as="label"
69+ as={Flex}
70+ justify="between"
71+ align="center"
6972 className={cn('f6 lh-tall', {
7073 black: !disabled,
7174 gray4: disabled,
72− })}
73− htmlFor={name}>
74− {label}
75+ })}>
76+ <Flex.Item as="label" justify htmlFor={name}>
77+ {label}
78+ </Flex.Item>
79+ {labelAccessory && <Flex.Item>{labelAccessory}</Flex.Item>}
7580 </Flex.Item>
7681 <Flex.Item as={Flex} row className="rel">
7782 <Flex.Item
src/indigo-react/components/ToggleInput.js+4−1
@@ -11,6 +11,7 @@ export default function ToggleInput({
1111 label,
1212 inverseLabel,
1313 inverseColor = 'black',
14+ small = false,
1415 className,
1516
1617 //
@@ -55,7 +56,9 @@ export default function ToggleInput({
5556 htmlFor={name}>
5657 <LinkButton
5758 disabled={disabled}
58− className={cn('f5', {
59+ className={cn({
60+ f5: !small,
61+ f6: small,
5962 black: !input.checked,
6063 [inverseColor]: input.checked,
6164 })}>
src/views/Login.js+33−21
@@ -1,5 +1,5 @@
11import React, { useCallback, useState } from 'react';
2−import { P, H4, H5, Grid, Text } from 'indigo-react';
2+import { P, H4, H5, Grid, Text, Button, Flex, LinkButton } from 'indigo-react';
33
44import { version } from '../../package.json';
55
@@ -59,41 +59,53 @@ export default function Login() {
5959 return (
6060 <View pop={pop} inset>
6161 <Grid>
62− <Grid.Item full as={Crumbs} routes={[{ text: 'Bridge' }]} />
63− <Grid.Item full as={Text} className="flex justify-center mt4">
64− <Grid.Item as={Text} className="gray5">
62+ <Grid.Item full as={Text} className="flex justify-center mt9 mb7">
63+ <Grid.Item as={Text} className="gray4">
6564 Urbit ID /&nbsp;
6665 </Grid.Item>
6766 <Grid.Item as={Text}>Login</Grid.Item>
6867 </Grid.Item>
69− {isOther && <Grid.Item full as={Other} />}
70− {!isOther && <Grid.Item full as={Ticket} />}
68+ {isOther && <Grid.Item full as={Other} goHome={goHome} />}
69+ {!isOther && <Grid.Item full as={Ticket} goHome={goHome} />}
7170 {!isOther && (
72− <Grid.Item full as={ForwardButton} onClick={() => setisOther(true)}>
73− Metamask ledger, etc.
74− </Grid.Item>
71+ <>
72+ <Grid.Item full className="t-center mv4 gray4">
73+ or
74+ </Grid.Item>
75+ <Grid.Item
76+ full
77+ as={Button}
78+ className="b-solid b1 b-black"
79+ center
80+ onClick={() => setisOther(true)}>
81+ Metamask, Mnemonic, Hardware Wallet, etc...
82+ </Grid.Item>
83+ <Grid.Item full onClick={goToActivate} className="mv10 t-center f6">
84+ <span className="gray4">New Urbit ID? </span>
85+ <LinkButton>Activate</LinkButton>
86+ </Grid.Item>
87+ </>
7588 )}
7689 {isOther && (
7790 <Grid.Item
7891 onClick={() => setisOther(false)}
79− className="underline gray4">
92+ full
93+ className="t-center underline mt8">
8094 Back
8195 </Grid.Item>
8296 )}
83− <Grid.Item full as={P} className="f6">
84− Version {version}
85− </Grid.Item>
8697 </Grid>
8798
8899 <Footer>
89− <Grid>
90− <Grid.Divider />
91− <Grid.Item full as={ForwardButton} onClick={goToActivate}>
92− Activate
93− </Grid.Item>
94− <Grid.Divider />
95− <Grid.Item full as={OfflineButton} />
96− </Grid>
100+ <Flex className="mb8 f6" justify="between">
101+ <Flex.Item
102+ as="a"
103+ href="https://github.com/urbit/bridge/releases"
104+ className="us-none pointer">
105+ <span className="underline">Offline </span>↗
106+ </Flex.Item>
107+ <Flex.Item className="gray4">Version {version}</Flex.Item>
108+ </Flex>
97109 </Footer>
98110 </View>
99111 );
src/views/Login/Other.js+13−9
@@ -1,4 +1,5 @@
11import React, { useState, useMemo } from 'react';
2+import { Grid } from 'indigo-react';
23
34import useBreakpoints from 'lib/useBreakpoints';
45
@@ -55,14 +56,17 @@ export default function Other({ className, ...rest }) {
5556 [hardwareAllowed]
5657 );
5758 return (
58− <Accordion
59− className={className}
60− views={VIEWS}
61− options={options}
62− currentTab={currentTab}
63− onTabChange={setCurrentTab}
64− //
65− {...rest}
66− />
59+ <>
60+ <Grid.Divider />
61+ <Accordion
62+ className={className}
63+ views={VIEWS}
64+ options={options}
65+ currentTab={currentTab}
66+ onTabChange={setCurrentTab}
67+ //
68+ {...rest}
69+ />
70+ </>
6771 );
6872}
src/views/Login/Ticket.js+80−34
@@ -3,7 +3,13 @@ import { Just } from 'folktale/maybe';
33import cn from 'classnames';
44import * as azimuth from 'azimuth-js';
55import * as kg from 'urbit-key-generation';
6−import { Grid, CheckboxInput, Flex, ToggleInput } from 'indigo-react';
6+import {
7+ Grid,
8+ CheckboxInput,
9+ Flex,
10+ ToggleInput,
11+ AccessoryIcon,
12+} from 'indigo-react';
713import { FORM_ERROR } from 'final-form';
814
915import { useNetwork } from 'store/network';
@@ -31,6 +37,56 @@ import FormError from 'form/FormError';
3137import SubmitButton from 'form/SubmitButton';
3238import { WARNING } from 'form/helpers';
3339
40+import { ReactComponent as SecretShowIcon } from 'assets/secret-show.svg';
41+import { ReactComponent as SecretHideIcon } from 'assets/secret-hidden.svg';
42+
43+function AdvancedOptions() {
44+ return (
45+ <Flex.Item as={Flex}>
46+ <Condition when="useAdvanced" is={true}>
47+ <Flex.Item
48+ as={CheckboxInput}
49+ inline
50+ white
51+ className="mr4"
52+ name="usePassphrase"
53+ label="Passphrase"
54+ style={{ boxSizing: 'border-box' }}
55+ />
56+ <Flex.Item
57+ as={CheckboxInput}
58+ inline
59+ white
60+ className="mr4"
61+ name="useShards"
62+ label="Shards"
63+ style={{ boxSizing: 'border-box' }}
64+ />
65+ </Condition>
66+ <Flex.Item
67+ as={ToggleInput}
68+ name="useAdvanced"
69+ label="Settings"
70+ small
71+ inverseLabel="Close"
72+ />
73+ </Flex.Item>
74+ );
75+}
76+
77+function TicketInputAccessory({ name }) {
78+ return (
79+ <AccessoryIcon>
80+ <ToggleInput
81+ name={name}
82+ className="mt1"
83+ inverseLabel={<SecretHideIcon />}
84+ label={<SecretShowIcon />}
85+ />
86+ </AccessoryIcon>
87+ );
88+}
89+
3490export default function Ticket({ className, goHome }) {
3591 useLoginView(WALLET_TYPES.TICKET);
3692
@@ -124,7 +180,7 @@ export default function Ticket({ className, goHome }) {
124180 shard1: buildPatqValidator(),
125181 shard2: buildPatqValidator(),
126182 shard3: buildPatqValidator(),
127− showTicket: buildCheckboxValidator(),
183+ ticketHidden: buildCheckboxValidator(),
128184 passphrase: buildPassphraseValidator(),
129185 },
130186 validateForm
@@ -137,14 +193,14 @@ export default function Ticket({ className, goHome }) {
137193 point: impliedPoint || '',
138194 usePasshrase: false,
139195 useShards: false,
140− showTicket: true,
196+ ticketHidden: false,
141197 useAdvanced: false,
142198 }),
143199 [impliedPoint]
144200 );
145201
146202 return (
147− <Grid className={cn('mt4', className)}>
203+ <Grid className={className}>
148204 <BridgeForm
149205 validate={validate}
150206 onSubmit={onSubmit}
@@ -158,7 +214,10 @@ export default function Ticket({ className, goHome }) {
158214 <Grid.Item
159215 full
160216 as={TicketInput}
161− type={values.showTicket ? 'text' : 'password'}
217+ hidden={values.ticketHidden}
218+ labelAccessory={<AdvancedOptions />}
219+ accessory={<TicketInputAccessory name="ticketHidden" />}
220+ className="mt3"
162221 name="ticket"
163222 label="Master Ticket"
164223 />
@@ -168,32 +227,38 @@ export default function Ticket({ className, goHome }) {
168227 <Grid.Item
169228 full
170229 as={TicketInput}
171− type={values.showTicket ? 'text' : 'password'}
230+ accessory={<TicketInputAccessory name="ticketHidden" />}
231+ hidden={values.ticketHidden}
232+ labelAccessory={<AdvancedOptions />}
233+ className="mt3"
172234 name="shard1"
173235 label="Shard 1"
174236 />
175237 <Grid.Item
176238 full
177239 as={TicketInput}
178− type={values.showTicket ? 'text' : 'password'}
240+ accessory={<TicketInputAccessory name="ticketHidden" />}
241+ hidden={values.ticketHidden}
242+ className="mt3"
179243 name="shard2"
180244 label="Shard 2"
181245 />
182246 <Grid.Item
183247 full
184248 as={TicketInput}
185− type={values.showTicket ? 'text' : 'password'}
249+ className="mt3"
250+ accessory={<TicketInputAccessory name="ticketHidden" />}
251+ hidden={values.ticketHidden}
186252 name="shard3"
187253 label="Shard 3"
188254 />
189255 </Condition>
190256
191− <Grid.Item full as={CheckboxInput} name="showTicket" label="Show" />
192−
193257 <Condition when="usePassphrase" is={true}>
194258 <Grid.Item
195259 full
196260 as={PassphraseInput}
261+ className="mt3"
197262 name="passphrase"
198263 label="Wallet Passphrase"
199264 />
@@ -201,7 +266,11 @@ export default function Ticket({ className, goHome }) {
201266
202267 <Grid.Item full as={FormError} />
203268
204− <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
269+ <Grid.Item
270+ full
271+ as={SubmitButton}
272+ center
273+ handleSubmit={handleSubmit}>
205274 {isWarning =>
206275 submitting
207276 ? 'Logging in...'
@@ -210,29 +279,6 @@ export default function Ticket({ className, goHome }) {
210279 : 'Continue'
211280 }
212281 </Grid.Item>
213−
214− <Grid.Item full as={Flex} justify="between">
215− <Flex.Item
216− as={ToggleInput}
217− name="useAdvanced"
218− label="Advanced"
219− inverseLabel="Hide"
220− />
221− <Condition when="useAdvanced" is={true}>
222− <Flex.Item as={Flex}>
223− <Flex.Item
224− as={CheckboxInput}
225− name="usePassphrase"
226− label="Passphrase"
227− />
228− <Flex.Item
229− as={CheckboxInput}
230− name="useShards"
231− label="Shards"
232− />
233− </Flex.Item>
234− </Condition>
235− </Grid.Item>
236282 </>
237283 )}
238284 </BridgeForm>