Bring tabs into apps without (consistency) (#659)

* Bring tabs into apps without (consistency)

* Small signer updates

* Explorer info as label

* Adjust fonts for modals

* Cleanup imports

* .ui.modal base color

* Adjust Account summary opacity

* Bump API (metadata V1 events)

* Update Event.tsx

* Remove order overrides

* Expand isDisabled balance

* Update index.tsx

* Update index.tsx
This commit is contained in:
Jaco Greeff 2019-01-28 20:30:49 +01:00 committed by GitHub
parent ac84a529e4
commit 3ff2053370
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 155 additions and 127 deletions

View File

@ -21,14 +21,14 @@ export default class AccountSelector extends React.PureComponent<Props, State> {
const { accountId } = this.state;
return (
<section className='template--AccountSelector template--2-columns'>
<section className='template--AccountSelector ui--row'>
<InputAddress
className='template--column'
className='medium'
label='my default account'
onChange={this.onChange}
type='account'
/>
<div className='template--column'>
<div className='medium'>
<Bubble color='teal' icon='address card' label='index'>
<AccountIndex value={accountId} />
</Bubble>

View File

@ -26,8 +26,8 @@ export default class Transfer extends React.PureComponent<Props> {
return (
<section>
<h1>transfer</h1>
<div className='template--2-columns'>
<article className='template--column'>
<div className='ui--row'>
<article className='medium'>
<InputAddress
label='recipient address for this transfer'
onChange={this.onChangeRecipient}
@ -46,7 +46,7 @@ export default class Transfer extends React.PureComponent<Props> {
/>
</Button.Group>
</article>
<div className='template--column template--summary'>Make a transfer from any account you control to another account. Transfer fees and per-transaction feed apply.</div>
<div className='template--summary small'>Make a transfer from any account you control to another account. Transfer fees and per-transaction fees apply and will be calculated upon submission.</div>
</div>
</section>
);

View File

@ -2,16 +2,6 @@
/* This software may be modified and distributed under the terms
/* of the Apache-2.0 license. See the LICENSE file for details. */
.template--2-columns {
display: flex;
.template--column {
box-sizing: border-box;
flex: 1;
min-width: 0;
}
}
.template--summary {
opacity: 0.5;
padding: 1rem 1.5rem;
@ -20,7 +10,7 @@
.template--AccountSelector {
align-items: flex-end;
.ui.dropdown {
margin-bottom: 0.25rem;
.summary {
text-align: center;
}
}

View File

@ -2,22 +2,35 @@
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
import { AppProps, BareProps } from '@polkadot/ui-app/types';
import { AppProps, BareProps, I18nProps } from '@polkadot/ui-app/types';
import './index.css';
import React from 'react';
import { Tabs } from '@polkadot/ui-app/index';
import Proposals from './Proposals';
import Referendums from './Referendums';
import Summary from './Summary';
import translate from './translate';
type Props = AppProps & BareProps;
type Props = AppProps & BareProps & I18nProps;
export default class App extends React.PureComponent<Props> {
class App extends React.PureComponent<Props> {
render () {
const { t } = this.props;
return (
<main className='democracy--App'>
<header>
<Tabs
activeItem='overview'
items={[{
name: 'overview',
text: t('Democracy overview')
}]}
/>
</header>
<Summary />
<Referendums />
<Proposals />
@ -25,3 +38,5 @@ export default class App extends React.PureComponent<Props> {
);
}
}
export default translate(App);

View File

@ -8,8 +8,6 @@
}
.explorer--BlockHeader {
animation: fadein 1.5s;
.author {
font-size: 1rem;
text-align: right;
@ -74,16 +72,19 @@
text-overflow: ellipsis;
white-space: nowrap;
> div {
display: inline-block;
padding: 0 0.25em;
vertical-align: middle;
.ui--Labelled {
text-align: center;
}
&.type {
opacity: 0.75;
text-align: right;
width: 10em;
}
> div,
> label {
display: inline-block;
vertical-align: middle;
}
label {
min-width: 10rem;
text-align: right;
}
}
}

View File

@ -51,7 +51,7 @@ export default class BlockHeader extends React.PureComponent<Props> {
<div className='ui--hover'>
<div className='ui--hover-content contains'>
<div className='info'>
<div className='type'>parentHash</div>
<label>parentHash</label>
<div className='hash'>{
value.blockNumber.gtn(1)
? <Link to={`/explorer/hash/${parentHex}`}>{parentHex}</Link>
@ -59,11 +59,11 @@ export default class BlockHeader extends React.PureComponent<Props> {
}</div>
</div>
<div className='info'>
<div className='type'>extrinsicsRoot</div>
<label>extrinsicsRoot</label>
<div className='hash'>{extrinsicsRoot.toHex()}</div>
</div>
<div className='info'>
<div className='type'>stateRoot</div>
<label>stateRoot</label>
<div className='hash'>{stateRoot.toHex()}</div>
</div>
</div>

View File

@ -28,7 +28,7 @@ class Query extends React.PureComponent<Props, State> {
const { hash, isValid } = this.state;
return (
<header>
<summary>
<div className='ui--row'>
<div className='small' />
<div className='storage--actionrow medium'>
@ -47,7 +47,7 @@ class Query extends React.PureComponent<Props, State> {
/>
</div>
</div>
</header>
</summary>
);
}

View File

@ -98,17 +98,3 @@
padding: 0 1em 1em;
}
}
.storage--Query-actionrow {
display: flex;
}
.storage--Query-actionrow-hash {
flex: 1;
min-width: 0;
}
.storage--Query-actionrow-button {
flex: 0;
padding: 0 0.25rem;
}

View File

@ -68,11 +68,13 @@ class Selection extends React.PureComponent<Props, State> {
/>
</Labelled>
</div>
<br></br>
<Extrinsic
defaultValue={defaultExtrinsic}
label={t('submit the following extrinsic')}
onChange={this.onChangeExtrinsic}
/>
<br></br>
<Button.Group>
<Button
isDisabled={!isValid}

View File

@ -10,11 +10,12 @@ import './index.css';
import React from 'react';
import { Link } from 'react-router-dom';
import { QueueConsumer } from '@polkadot/ui-app/Status/Context';
import { Tabs } from '@polkadot/ui-app/index';
import accountsObservable from '@polkadot/ui-keyring/observable/accounts';
import { withMulti, withObservable } from '@polkadot/ui-api/index';
import translate from './translate';
import Selection from './Selection';
import translate from './translate';
type Props = AppProps & I18nProps & {
accountAll?: Array<any>
@ -37,6 +38,15 @@ class ExtrinsicsApp extends React.PureComponent<Props> {
return (
<main className='extrinsics--App'>
<header>
<Tabs
activeItem='create'
items={[{
name: 'create',
text: t('Extrinsic submission')
}]}
/>
</header>
<QueueConsumer>
{({ queueExtrinsic }: QueueProps) => (
<Selection queueExtrinsic={queueExtrinsic} />

View File

@ -9,6 +9,7 @@ import React from 'react';
import { Trans } from 'react-i18next';
import accountObservable from '@polkadot/ui-keyring/observable/accounts';
import { withMulti, withObservable } from '@polkadot/ui-api/index';
import { Tabs } from '@polkadot/ui-app/index';
import './index.css';
@ -29,7 +30,7 @@ class App extends React.PureComponent<Props> {
}
private renderBody () {
const { allAccounts } = this.props;
const { allAccounts, t } = this.props;
if (!allAccounts || !Object.keys(allAccounts).length) {
return (
@ -42,7 +43,18 @@ class App extends React.PureComponent<Props> {
}
return (
<Transfer />
<>
<header>
<Tabs
activeItem='create'
items={[{
name: 'create',
text: t('Balance transfer')
}]}
/>
</header>
<Transfer />
</>
);
}
}

View File

@ -31,8 +31,8 @@
"homepage": "https://github.com/polkadot-js/ui/tree/master/packages/ui-reactive#readme",
"dependencies": {
"@babel/runtime": "^7.2.0",
"@polkadot/api": "^0.41.3",
"@polkadot/types": "^0.41.3",
"@polkadot/api": "^0.41.7",
"@polkadot/types": "^0.41.7",
"rxjs-compat": "^6.3.2"
}
}

View File

@ -11,10 +11,10 @@
"license": "Apache-2.0",
"dependencies": {
"@babel/runtime": "^7.2.0",
"@polkadot/extrinsics": "^0.41.3",
"@polkadot/extrinsics": "^0.41.7",
"@polkadot/keyring": "^0.33.36",
"@polkadot/storage": "^0.41.3",
"@polkadot/types": "^0.41.3",
"@polkadot/storage": "^0.41.7",
"@polkadot/types": "^0.41.7",
"@polkadot/ui-api": "^0.22.53",
"@polkadot/ui-identicon": "^0.25.8",
"@polkadot/ui-keyring": "^0.25.8",

View File

@ -9,3 +9,7 @@
.ui--Button-Group:not(:first-child) {
margin-top: 0.75rem;
}
br+.ui--Button-Group {
margin-top: 0;
}

View File

@ -33,9 +33,11 @@ h3, h4, h5 {
label {
box-sizing: border-box;
color: #4e4e4e;
display: block;
font-family: sans-serif;
font-size: 1rem;
font-weight: normal;
font-weight: 100;
margin: 0.25rem;
opacity: 0.75;
}
@ -46,6 +48,10 @@ a:hover {
}
*/
br {
line-height: 1.5rem;
}
main {
padding: 1em 2em;
min-height: 100vh;
@ -95,12 +101,6 @@ summary {
text-align: center;
}
header+header,
header+summary,
summary+header {
margin-top: -1em;
}
summary {
align-items: stretch;
display: flex;

View File

@ -120,7 +120,8 @@ header .ui--Button-Group {
.ui--Balance,
.ui--AddressSummary-balance,
.ui--AddressSummary-nonce {
opacity: 0.5;
font-weight: 100;
opacity: 0.75;
}
.ui--AddressSummary-balance {

View File

@ -19,6 +19,11 @@
margin: 0.25rem 0;
}
.ui.selection.dropdown,
.ui.input > input {
color: inherit;
}
.ui.dropdown {
&.disabled {
background: #fefefe;
@ -91,6 +96,8 @@
.ui.modal {
background: #fafafa;
color: #4e4e4e;
font-family: sans-serif;
> .actions,
> .content,

View File

@ -23,7 +23,7 @@ class Balance extends React.PureComponent<Props> {
style={style}
>
<InputBalance
className='large'
className={isDisabled ? 'full' : 'large'}
defaultValue={defaultValue}
isDisabled={isDisabled}
isError={isError}

View File

@ -31,8 +31,8 @@
"homepage": "https://github.com/polkadot-js/ui/tree/master/packages/ui-reactive#readme",
"dependencies": {
"@babel/runtime": "^7.2.0",
"@polkadot/api": "^0.41.3",
"@polkadot/types": "^0.41.3",
"@polkadot/api": "^0.41.7",
"@polkadot/types": "^0.41.7",
"rxjs-compat": "^6.3.2"
}
}

View File

@ -141,7 +141,7 @@ class FeeDisplay extends React.PureComponent<Props, State> {
{
hasAvailable
? undefined
: <div><Icon name='ban' />{t('The account does not have the required balance available for this transaction')}</div>
: <div><Icon name='ban' />{t('The selected account does not have the required balance available for this transaction')}</div>
}
{
overLimit

View File

@ -38,10 +38,10 @@ class Transaction extends React.PureComponent<Props> {
}</label>
</Modal.Header>
<Modal.Content className='ui--signer-Signer-Content'>
<Call value={extrinsic} />
{this.renderAccount()}
{children}
<Call value={extrinsic} />
{this.renderChecks()}
{children}
</Modal.Content>
</>
);
@ -60,7 +60,7 @@ class Transaction extends React.PureComponent<Props> {
defaultValue={accountId}
isDisabled
isInput
label={t('from my account')}
label={t('sending from my account')}
withLabel
/>
);

View File

@ -55,7 +55,7 @@ class Unlock extends React.PureComponent<Props, State> {
<Password
autoFocus={autoFocus}
isError={isError}
label={label || t('unlocked using password')}
label={label || t('unlock account with password')}
onChange={onChange}
onKeyDown={onKeyDown}
tabIndex={tabIndex}

104
yarn.lock
View File

@ -1385,31 +1385,31 @@
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
"@polkadot/api-derive@^0.41.3":
version "0.41.3"
resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-0.41.3.tgz#b124cd005a144366bf3f6e742f93461c5ec5b78d"
integrity sha512-JxnhhdtU5FzrsMty518+QGwNrNk9QHe3HoQbf4ITVIgPQLb3BAnOb2QBv14XAI9HJ+UgD9e40oPeMR7xcy/mCg==
"@polkadot/api-derive@^0.41.7":
version "0.41.7"
resolved "https://registry.yarnpkg.com/@polkadot/api-derive/-/api-derive-0.41.7.tgz#fec5994f74d81a97bcd42874d29dc8620f04e496"
integrity sha512-EaIHphOJkl+tadB7+2QRxsmL0d6a9JGa7ffxKolVtIXGkyrMQpm33I+zL714KZH5zZzwAybt948eunWkrTDvYw==
dependencies:
"@babel/runtime" "^7.2.0"
"@polkadot/api" "^0.41.3"
"@polkadot/types" "^0.41.3"
"@polkadot/api" "^0.41.7"
"@polkadot/types" "^0.41.7"
"@types/memoizee" "^0.4.2"
"@types/rx" "^4.1.1"
memoizee "^0.4.14"
rxjs "^6.3.3"
"@polkadot/api@^0.41.3":
version "0.41.3"
resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-0.41.3.tgz#c763a5b2c354bae9a88c4dc843ebd127fd4d897b"
integrity sha512-ZT750O8ylwFrLDN+B7Kq9inAWFoAK/XtAtzH98U1t5FwJs1ys+tkw9JyZobCrQfj67Bw7wSAIjWU16KT6yDVKg==
"@polkadot/api@^0.41.7":
version "0.41.7"
resolved "https://registry.yarnpkg.com/@polkadot/api/-/api-0.41.7.tgz#e65d620d9effc9b9754d82d1f533d71d8f3912cd"
integrity sha512-G7oGcnBTZX1Sk2kl2fcW+BBAwrnOh+iCw84MvziCEiczfEFeWO7HuZcv5INnOxf1qy7m6MfQNlKIXfqAdoEs2g==
dependencies:
"@babel/runtime" "^7.2.0"
"@polkadot/api-derive" "^0.41.3"
"@polkadot/extrinsics" "^0.41.3"
"@polkadot/rpc-provider" "^0.41.3"
"@polkadot/rpc-rx" "^0.41.3"
"@polkadot/storage" "^0.41.3"
"@polkadot/types" "^0.41.3"
"@polkadot/api-derive" "^0.41.7"
"@polkadot/extrinsics" "^0.41.7"
"@polkadot/rpc-provider" "^0.41.7"
"@polkadot/rpc-rx" "^0.41.7"
"@polkadot/storage" "^0.41.7"
"@polkadot/types" "^0.41.7"
"@types/rx" "^4.1.1"
rxjs "^6.3.3"
@ -1489,19 +1489,19 @@
typedoc-plugin-no-inherit "^1.1.2"
typescript "^3.2.2"
"@polkadot/extrinsics@^0.41.3":
version "0.41.3"
resolved "https://registry.yarnpkg.com/@polkadot/extrinsics/-/extrinsics-0.41.3.tgz#51d3189c33f006b2f78e1db8d74e8dc0408ede51"
integrity sha512-zK6JuiE7gyxRHJZit/CQCACsehpBiGr+dUhOKE4lqOfFiqI/oy7ypdWVeEXSIvII4ZZbo4Uakch4D2+GmWTNpQ==
"@polkadot/extrinsics@^0.41.7":
version "0.41.7"
resolved "https://registry.yarnpkg.com/@polkadot/extrinsics/-/extrinsics-0.41.7.tgz#01f698f01d223a3847b7cf72eab4ebdee15e0596"
integrity sha512-RMPQEIXSk633FDOo1XV74ocyAI8UfDOYnrVb71xko5qspsyRsE8/Km+DkId3Y4PoCKiSE7Ns1+ZqUpvFnNnvJw==
dependencies:
"@babel/runtime" "^7.2.0"
"@polkadot/types" "^0.41.3"
"@polkadot/types" "^0.41.7"
"@polkadot/util" "^0.33.36"
"@polkadot/jsonrpc@^0.41.3":
version "0.41.3"
resolved "https://registry.yarnpkg.com/@polkadot/jsonrpc/-/jsonrpc-0.41.3.tgz#3fe9c9021d22da6d028c702ef0405690ed8aaf2c"
integrity sha512-YoVSUbWkzel5YOzyTVqZJkVNqMjZO9AiZHmYBM/Ndsjp0wtyjUDLDknaSzziNClUbLit6+g1TZ0bexkWb5UKeA==
"@polkadot/jsonrpc@^0.41.7":
version "0.41.7"
resolved "https://registry.yarnpkg.com/@polkadot/jsonrpc/-/jsonrpc-0.41.7.tgz#d33156bf599c184adcd134774e9f9e6b60f3d8f1"
integrity sha512-+Xwd50rDvJqMKkR0Jl/vqJwyLXuGyFAui/44xPf1hlp4kUuGmEd2DWWwXT9bNWqYPsmjIlfIU+CjIZ6fB2u3zA==
dependencies:
"@babel/runtime" "^7.2.0"
@ -1516,25 +1516,25 @@
"@types/bs58" "^4.0.0"
bs58 "^4.0.1"
"@polkadot/rpc-core@^0.41.3":
version "0.41.3"
resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-0.41.3.tgz#2a20d6d652341ca043ccdda791ce40271b2cf4cb"
integrity sha512-lSi+CkxVHEHrfPdcWzfoM+GHyX9nKq1ix7CdaOCo+H7WiEBUIqd4aTdWF/Ph5KElxRSO6xADmSLCdYXuwo6XBw==
"@polkadot/rpc-core@^0.41.7":
version "0.41.7"
resolved "https://registry.yarnpkg.com/@polkadot/rpc-core/-/rpc-core-0.41.7.tgz#09990d72aaa8c034b872f6b525fcf8633799fff1"
integrity sha512-XFo2nV0A2lBTdMqcHoAqHfzk0og2/jTp7vSu95K4nXp867IrgRc0C4p1rk9u0Mq+pYs2LxQEXyQzw8FxuQM7Zw==
dependencies:
"@babel/runtime" "^7.2.0"
"@polkadot/jsonrpc" "^0.41.3"
"@polkadot/rpc-provider" "^0.41.3"
"@polkadot/types" "^0.41.3"
"@polkadot/jsonrpc" "^0.41.7"
"@polkadot/rpc-provider" "^0.41.7"
"@polkadot/types" "^0.41.7"
"@polkadot/util" "^0.33.36"
"@polkadot/rpc-provider@^0.41.3":
version "0.41.3"
resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-0.41.3.tgz#51b0cea3cd13b33030a9f009ec7c10e77f487660"
integrity sha512-QBYVjykZwngM2HkyDH5M2M5x5G6z0kVkpKqdowMd3bgK0RflYoXhbpAvWOVwY00Buo6mi+r9szzKtvroqr1Ueg==
"@polkadot/rpc-provider@^0.41.7":
version "0.41.7"
resolved "https://registry.yarnpkg.com/@polkadot/rpc-provider/-/rpc-provider-0.41.7.tgz#878c9138d65efecbf3295c8b6401235dd2bae160"
integrity sha512-sCOJFb+9ezqwTFum+RFEhPw5EHLrZnJk09NTAPngd0+Q9ItZXTUy1htR/7/0u8KUFM3+4B+ZkGVsWJYbw2NOnQ==
dependencies:
"@babel/runtime" "^7.2.0"
"@polkadot/keyring" "^0.33.36"
"@polkadot/storage" "^0.41.3"
"@polkadot/storage" "^0.41.7"
"@polkadot/util" "^0.33.36"
"@polkadot/util-crypto" "^0.33.36"
"@types/nock" "^9.3.0"
@ -1542,25 +1542,25 @@
isomorphic-fetch "^2.2.1"
websocket "^1.0.28"
"@polkadot/rpc-rx@^0.41.3":
version "0.41.3"
resolved "https://registry.yarnpkg.com/@polkadot/rpc-rx/-/rpc-rx-0.41.3.tgz#40ff568f04d1630d41c5ea8b21075965373094ff"
integrity sha512-SPMSz3TmzqRacRP5MYoPUn7NNp5c824cALraf0+53Ne2V3uSbHyRsdTrfaN9uPE6S6iLlbJ2AtlBTzqmZST0sQ==
"@polkadot/rpc-rx@^0.41.7":
version "0.41.7"
resolved "https://registry.yarnpkg.com/@polkadot/rpc-rx/-/rpc-rx-0.41.7.tgz#e1ac6c2573703041f5e95503c6ca1f9c8a3c027e"
integrity sha512-aZoCam1MgKU8pFqbLI+gF0lmoQn7W3cXWUNkPOSpql16V1YQFETVzhZgGq11Egs0UnTQq4mf+JgyWhcx9QmH8w==
dependencies:
"@babel/runtime" "^7.2.0"
"@polkadot/rpc-core" "^0.41.3"
"@polkadot/rpc-provider" "^0.41.3"
"@polkadot/rpc-core" "^0.41.7"
"@polkadot/rpc-provider" "^0.41.7"
"@types/rx" "^4.1.1"
rxjs "^6.3.3"
"@polkadot/storage@^0.41.3":
version "0.41.3"
resolved "https://registry.yarnpkg.com/@polkadot/storage/-/storage-0.41.3.tgz#c4c0fb63c6b122943a459373b918f40e38742982"
integrity sha512-awGiAv0k2CG7Fe4u9bQWC8IDv+mtxO4WCxVIwmwFoFWO5Tgnx/cNXcTKzfCRZDxuZyJzFsTPpsoTRDy0/Xmm2g==
"@polkadot/storage@^0.41.7":
version "0.41.7"
resolved "https://registry.yarnpkg.com/@polkadot/storage/-/storage-0.41.7.tgz#cb01d8f5ec44d540052436cc1ff4c8003e62eff6"
integrity sha512-esK5WdKZU2ej1X3tdor2uY9AUD3l7upA+09OprGxkW8/wmXzy0IRV7zJv42B66AcGRtnpXccBWIfxf/GI62IOQ==
dependencies:
"@babel/runtime" "^7.2.0"
"@polkadot/keyring" "^0.33.36"
"@polkadot/types" "^0.41.3"
"@polkadot/types" "^0.41.7"
"@polkadot/util" "^0.33.36"
"@polkadot/util-crypto" "^0.33.36"
@ -1569,10 +1569,10 @@
resolved "https://registry.yarnpkg.com/@polkadot/ts/-/ts-0.1.52.tgz#6fb09e494d244dad4b3a9ca581bfe13beec66565"
integrity sha512-sij1O0x4CY51A394RYD4/aQwDPwIxIeTOpYI4AZgdF/vq5nvF14b4XFq9vAcSnblaIosf0sYKoz1f3dkN3QqLw==
"@polkadot/types@^0.41.3":
version "0.41.3"
resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-0.41.3.tgz#79b063765ee720e7298e90e007a72f8bb875e204"
integrity sha512-KnjHZs+Z4WytLFWBh8V3BmDsEfOXWP+jZKlyysN2lTxvmIr8OelAowDx7WjSrGRefqltT5q3cz+61NFZJwMBcg==
"@polkadot/types@^0.41.7":
version "0.41.7"
resolved "https://registry.yarnpkg.com/@polkadot/types/-/types-0.41.7.tgz#50a74aa7b91ea8c381016d716a8edfdc7fffb447"
integrity sha512-i4rtuPUl+T6LJR0nri0pzPee16MfsPojvxtrtyBowgr2oCEMwPvGUZXhHQsv8Baep21/MwjeBCQao2UYserhCA==
dependencies:
"@babel/runtime" "^7.2.0"
"@polkadot/keyring" "^0.33.36"