Skip to content
This repository has been archived by the owner on Oct 10, 2023. It is now read-only.

Introduce Tailwind (part 1) #2337

Merged
merged 2 commits into from
Jul 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
"@types/secp256k1": "^4.0.3",
"@types/styled-components": "^5.1.25",
"assert": "^2.0.0",
"autoprefixer": "^10.4.8",
"browserify-fs": "^1.0.0",
"buffer": "^6.0.3",
"chalk": "^5.0.1",
Expand All @@ -177,13 +178,15 @@
"nodemon": "^2.0.16",
"os-browserify": "^0.3.0",
"path-browserify": "^1.0.1",
"postcss": "^8.4.14",
"prettier": "^2.6.2",
"process": "^0.11.10",
"react-error-overlay": "^6.0.11",
"rimraf": "^3.0.2",
"source-map-explorer": "^2.5.2",
"storybook": "^7.0.0-alpha.13",
"stream-browserify": "^3.0.0",
"tailwindcss": "^3.1.7",
"testcafe": "^1.18.6",
"testcafe-browser-provider-electron": "^0.0.18",
"testcafe-react-selectors": "^4.1.5",
Expand Down
6 changes: 6 additions & 0 deletions postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {}
}
}
6 changes: 3 additions & 3 deletions src/main/api/keystore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ export const loadKeystore = async () => {
const migrateLegacyAccount = (): TE.TaskEither<Error, KeystoreAccounts> =>
FP.pipe(
exists(LEGACY_KEYSTORE_FILE),
// Switch to error if no file exists
// Switch to error if file does not exists
TE.fromPredicate(
(v) => !!v,
() => Error('Keystore file does not exist')
() => Error(`${LEGACY_KEYSTORE_FILE} file does not exist`)
),
// get keystore content
// read keystore from disc
TE.chain(() => readJSON(LEGACY_KEYSTORE_FILE)),
// decode keystore content
TE.chain(FP.flow(keystoreIO.decode, E.mapLeft(mapIOErrors), TE.fromEither)),
Expand Down
17 changes: 13 additions & 4 deletions src/main/utils/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export const readFile: (path: string, encoding: string) => TE.TaskEither<Error,
/**
* Reads a JSON file.
*/
export const readJSON: (path: string, options?: fs.ReadOptions) => TE.TaskEither<Error, string> = TE.taskify<
export const readJSON: (path: string, options?: fs.ReadOptions) => TE.TaskEither<Error, unknown> = TE.taskify<
string,
fs.ReadOptions | undefined,
Error,
string
unknown
>(fs.readJSON)

/**
Expand All @@ -47,8 +47,17 @@ export const writeFile: (path: string, data: string, options?: fs.WriteFileOptio
* Writes a JSON file.
* If the parent directory does not exist, it will be created.
*/
export const writeJSON: (path: string, data: object, options?: fs.WriteOptions) => TE.TaskEither<Error, void> =
TE.taskify<string, object, fs.WriteOptions | undefined, Error, void>(fs.outputJSON)
export const writeJSON: (
path: string,
data: boolean | number | string | object | null,
options?: fs.WriteOptions
) => TE.TaskEither<Error, void> = TE.taskify<
string,
boolean | number | string | object | null,
fs.WriteOptions | undefined,
Error,
void
>(fs.outputJSON)

export const exists: (path: string) => TE.TaskEither<Error, boolean> = TE.taskify<string, Error, boolean>(fs.pathExists)

Expand Down
15 changes: 5 additions & 10 deletions src/renderer/components/wallet/keystore/ImportKeystore.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as RD from '@devexperts/remote-data-ts'
import { ComponentMeta, StoryFn } from '@storybook/react'
import { Keystore } from '@xchainjs/xchain-crypto'
import * as Rx from 'rxjs'

import { MOCK_KEYSTORE } from '../../../../shared/mock/wallet'
import { ImportKeystore as Component, Props } from './ImportKeystore'

const initialImportKeystore = () => Rx.of(RD.initial)
Expand All @@ -15,7 +15,7 @@ export const Default = Template.bind({})

const meta: ComponentMeta<typeof Component> = {
component: Component,
title: 'Wallet/Keystore',
title: 'Wallet/ImportKeystore',
argTypes: {
loadKeystore$: {
control: {
Expand All @@ -25,7 +25,7 @@ const meta: ComponentMeta<typeof Component> = {
intitial: initialLoadKeystore,
loading: () => Rx.of(RD.pending),
error: () => Rx.of(RD.failure(Error('load keystore error'))),
success: () => Rx.of(RD.success({} as Keystore))
success: () => Rx.of(RD.success(MOCK_KEYSTORE))
}
}
},
Expand All @@ -37,7 +37,7 @@ const meta: ComponentMeta<typeof Component> = {
intitial: initialImportKeystore,
loading: () => Rx.of(RD.pending),
error: () => Rx.of(RD.failure(Error('import keystore error'))),
success: () => Rx.of(RD.success({}))
success: () => Rx.of(RD.success(undefined))
}
}
}
Expand All @@ -48,12 +48,7 @@ const meta: ComponentMeta<typeof Component> = {
},
decorators: [
(Story) => (
<div
style={{
display: 'flex',
flexDirection: 'column',
width: '300px'
}}>
<div className="flex items-center w-full">
<Story />
</div>
)
Expand Down
85 changes: 59 additions & 26 deletions src/renderer/components/wallet/keystore/ImportKeystore.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import { useIntl } from 'react-intl'
import { KeystoreClientStates } from '../../../hooks/useKeystoreClientStates'
import { useSubscriptionState } from '../../../hooks/useSubscriptionState'
import { ImportKeystoreLD, ImportKeystoreParams, LoadKeystoreLD } from '../../../services/wallet/types'
import { InnerForm } from '../../shared/form/Form.styles'
import { Spin } from '../../shared/loading'
import { InputPassword } from '../../uielements/input'
import * as Styled from './Keystore.styles'
import { Button } from '../../uielements/button'
import { InputPassword, Input } from '../../uielements/input'
import { Label } from '../../uielements/label'

export type Props = {
clientStates: KeystoreClientStates
Expand All @@ -36,27 +38,30 @@ export const ImportKeystore: React.FC<Props> = (props): JSX.Element => {
RD.RemoteData<Error, void>
>(RD.initial)

const walletId = useMemo(() => new Date().getTime(), [])

const submitForm = useCallback(
({ password }: Store) => {
FP.pipe(
loadKeystoreState,
RD.map((keystore) => {
const id = new Date().getTime()
// TODO (@veado) Get name from form
const name = `wallet-${id}`
subscribeImportKeystoreState(importKeystore$({ keystore, password, id, name }))
const name = `wallet-${walletId}`
subscribeImportKeystoreState(importKeystore$({ keystore, password, id: walletId, name }))
return true
})
)
},
[importKeystore$, loadKeystoreState, subscribeImportKeystoreState]
[importKeystore$, loadKeystoreState, subscribeImportKeystoreState, walletId]
)

const uploadKeystore = () => {
subscribeLoadKeystoreState(loadKeystore$())
}

const renderError = useCallback((msg: string) => <Styled.ErrorLabel>{msg}</Styled.ErrorLabel>, [])
const renderError = (msg: string) => (
<Label className="mb-[20px] uppercase text-error0 dark:text-error0 text-center">{msg}</Label>
)

const renderImportError = useMemo(
() =>
Expand All @@ -69,7 +74,7 @@ export const ImportKeystore: React.FC<Props> = (props): JSX.Element => {
() => <></>
)
),
[importKeystoreState, intl, renderError]
[importKeystoreState, intl]
)

const renderLoadError = useMemo(
Expand All @@ -83,7 +88,7 @@ export const ImportKeystore: React.FC<Props> = (props): JSX.Element => {
() => <></>
)
),
[loadKeystoreState, intl, renderError]
[loadKeystoreState, intl]
)

const renderClientError = useMemo(
Expand All @@ -97,37 +102,65 @@ export const ImportKeystore: React.FC<Props> = (props): JSX.Element => {
() => <></>
)
),
[clientStates, renderError]
[clientStates]
)

return (
<>
<Styled.Form form={form} onFinish={submitForm} labelCol={{ span: 24 }}>
<InnerForm className="w-full p-[30px] pt-[15px]" labelCol={{ span: 24 }} form={form} onFinish={submitForm}>
{renderLoadError}
{renderImportError}
{renderClientError}
<Spin
spinning={RD.isPending(importKeystoreState) || RD.isPending(loadKeystoreState)}
tip={intl.formatMessage({ id: 'common.loading' })}>
<Form.Item>
<Styled.Title>{intl.formatMessage({ id: 'wallet.imports.keystore.title' })}</Styled.Title>
<Styled.KeystoreButton onClick={uploadKeystore}>
<div className="flex flex-col items-center">
{/* title */}
<Label className="w-full mb-10" size="big" align="center" textTransform="uppercase">
{intl.formatMessage({ id: 'wallet.imports.keystore.title' })}
</Label>
{/* import button */}
<Button
className="mw-[100%] py-[5xp] px-[10px] mb-[50px] h-[35px] cursor-pointer text-[14px]"
typevalue="outline"
sizevalue="normal"
onClick={uploadKeystore}>
{RD.isSuccess(loadKeystoreState) ? <CheckCircleTwoTone twoToneColor="#50e3c2" /> : <UploadOutlined />}
{intl.formatMessage({ id: 'wallet.imports.keystore.select' })}
</Styled.KeystoreButton>
</Form.Item>
<Styled.PasswordContainer>
<Styled.PasswordItem name="password">
<InputPassword size="large" placeholder={intl.formatMessage({ id: 'common.password' }).toUpperCase()} />
</Styled.PasswordItem>
</Styled.PasswordContainer>
</Button>
{/* password */}
<div className="w-full flex flex-col items-center">
<Form.Item
className="w-full !max-w-[380px] uppercase text-text0 dark:text-text0d"
name="password"
label={intl.formatMessage({ id: 'common.password' })}>
<InputPassword className="!text-[16px]" size="large" />
</Form.Item>
</div>
{/* name */}
<div className="w-full flex flex-col items-center">
<Form.Item
className="w-full !max-w-[380px] uppercase text-text0 dark:text-text0d"
name="name"
label={'wallet name'}>
<Input className="!text-[16px]" size="large" placeholder={`wallet-${walletId}`} />
</Form.Item>
</div>
</div>
</Spin>
<Form.Item style={{ display: 'grid', justifyContent: 'flex-end' }}>
<Styled.SubmitButton disabled={!RD.isSuccess(loadKeystoreState) || RD.isPending(importKeystoreState)}>
{/* submit button */}
<div className="flex flex-col items-center">
<Button
className="min-w-[150px] mt-[50px]"
sizevalue="xnormal"
type="primary"
htmlType="submit"
round="true"
disabled={!RD.isSuccess(loadKeystoreState) || RD.isPending(importKeystoreState)}>
{intl.formatMessage({ id: 'wallet.action.import' })}
</Styled.SubmitButton>
</Form.Item>
</Styled.Form>
</Button>
</div>
</InnerForm>
</>
)
}
62 changes: 0 additions & 62 deletions src/renderer/components/wallet/keystore/Keystore.styles.ts

This file was deleted.

6 changes: 5 additions & 1 deletion src/renderer/index.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

/*
Since `createGlobalStyle` of `styled-components` re-loads fonts in some cases (and for unknown reasons),
which ends up in flickering texts, we do defined all fonts and other "global" styles here
Expand All @@ -7,7 +11,7 @@ which ends up in flickering texts, we do defined all fonts and other "global" st
font-family: 'MainFontRegular';
font-style: normal;
font-weight: normal;
src: local('MainFontBold'), url(./assets/fonts/Exo2-Regular.otf) format('opentype');
src: local('MainFontRegular'), url(./assets/fonts/Exo2-Regular.otf) format('opentype');
}
@font-face {
font-family: 'MainFontBold';
Expand Down
13 changes: 13 additions & 0 deletions src/renderer/views/app/AppView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { useWalletContext } from '../../contexts/WalletContext'
import { unionChains } from '../../helpers/fp/array'
import { rdAltOnPending } from '../../helpers/fpHelpers'
import { useMimirHalt } from '../../hooks/useMimirHalt'
import { useTheme } from '../../hooks/useTheme'
import { DEFAULT_MIMIR_HALT } from '../../services/thorchain/const'
import { MimirHalt, MimirHaltRD } from '../../services/thorchain/types'
import { View } from '../View'
Expand All @@ -39,11 +40,23 @@ export const AppView: React.FC = (): JSX.Element => {
const { locale$ } = useI18nContext()
const currentLocale = useObservableState(locale$, DEFAULT_LOCALE)

const { isLight } = useTheme()

// locale
useEffect(() => {
// Needed to update Electron native menu according to the selected locale
window.apiLang.update(currentLocale)
}, [currentLocale])

// Add/remove `dark` selector depending on selected theme (needed for tailwind)
useEffect(() => {
if (isLight) {
document.documentElement.classList.remove('dark')
} else {
document.documentElement.classList.add('dark')
}
}, [isLight])

const {
service: {
apiEndpoint$,
Expand Down
Loading