kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
Merge branch 'crypto-donate' into 'develop'
Crypto donations See merge request soapbox-pub/soapbox-fe!521datepicker-css
commit
a3ee5789bc
|
@ -0,0 +1,55 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import Icon from 'soapbox/components/icon';
|
||||||
|
import CoinDB from '../utils/coin_db';
|
||||||
|
import { getCoinIcon } from '../utils/coin_icons';
|
||||||
|
import { openModal } from 'soapbox/actions/modal';
|
||||||
|
import { CopyableInput } from 'soapbox/features/forms';
|
||||||
|
import { getExplorerUrl } from '../utils/block_explorer';
|
||||||
|
|
||||||
|
export default @connect()
|
||||||
|
class CryptoAddress extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
address: PropTypes.string.isRequired,
|
||||||
|
ticker: PropTypes.string.isRequired,
|
||||||
|
note: PropTypes.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
handleModalClick = e => {
|
||||||
|
this.props.dispatch(openModal('CRYPTO_DONATE', this.props));
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { address, ticker, note } = this.props;
|
||||||
|
const title = CoinDB.getIn([ticker, 'name']);
|
||||||
|
const explorerUrl = getExplorerUrl(ticker, address);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='crypto-address'>
|
||||||
|
<div className='crypto-address__head'>
|
||||||
|
<div className='crypto-address__icon'>
|
||||||
|
<img src={getCoinIcon(ticker)} alt={title} />
|
||||||
|
</div>
|
||||||
|
<div className='crypto-address__title'>{title || ticker.toUpperCase()}</div>
|
||||||
|
<div className='crypto-address__actions'>
|
||||||
|
<a href='' onClick={this.handleModalClick}>
|
||||||
|
<Icon id='qrcode' />
|
||||||
|
</a>
|
||||||
|
{explorerUrl && <a href={explorerUrl} target='_blank'>
|
||||||
|
<Icon id='external-link' />
|
||||||
|
</a>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{note && <div className='crypto-address__note'>{note}</div>}
|
||||||
|
<div className='crypto-address__address simple_form'>
|
||||||
|
<CopyableInput value={address} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import Icon from 'soapbox/components/icon';
|
||||||
|
import QRCode from 'qrcode.react';
|
||||||
|
import CoinDB from '../utils/coin_db';
|
||||||
|
import { getCoinIcon } from '../utils/coin_icons';
|
||||||
|
import { CopyableInput } from 'soapbox/features/forms';
|
||||||
|
import { getExplorerUrl } from '../utils/block_explorer';
|
||||||
|
|
||||||
|
export default @connect()
|
||||||
|
class DetailedCryptoAddress extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
address: PropTypes.string.isRequired,
|
||||||
|
ticker: PropTypes.string.isRequired,
|
||||||
|
note: PropTypes.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { address, ticker, note } = this.props;
|
||||||
|
const title = CoinDB.getIn([ticker, 'name']);
|
||||||
|
const explorerUrl = getExplorerUrl(ticker, address);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='crypto-address'>
|
||||||
|
<div className='crypto-address__head'>
|
||||||
|
<div className='crypto-address__icon'>
|
||||||
|
<img src={getCoinIcon(ticker)} alt={title} />
|
||||||
|
</div>
|
||||||
|
<div className='crypto-address__title'>{title || ticker.toUpperCase()}</div>
|
||||||
|
<div className='crypto-address__actions'>
|
||||||
|
{explorerUrl && <a href={explorerUrl} target='_blank'>
|
||||||
|
<Icon id='external-link' />
|
||||||
|
</a>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{note && <div className='crypto-address__note'>{note}</div>}
|
||||||
|
<div className='crypto-address__qrcode'>
|
||||||
|
<QRCode value={address} />
|
||||||
|
</div>
|
||||||
|
<div className='crypto-address__address simple_form'>
|
||||||
|
<CopyableInput value={address} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import CryptoAddress from './crypto_address';
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
// Address example:
|
||||||
|
// {"ticker": "btc", "address": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n", "note": "This is our main address"}
|
||||||
|
return {
|
||||||
|
coinList: state.getIn(['soapbox', 'crypto_addresses']),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default @connect(mapStateToProps)
|
||||||
|
class CoinList extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
coinList: ImmutablePropTypes.list,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { coinList } = this.props;
|
||||||
|
if (!coinList) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='site-wallet'>
|
||||||
|
{coinList.map(coin => (
|
||||||
|
<CryptoAddress
|
||||||
|
key={coin.get('ticker')}
|
||||||
|
{...coin.toJS()}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import Column from '../ui/components/column';
|
||||||
|
import SiteWallet from './components/site_wallet';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
heading: { id: 'column.crypto_donate', defaultMessage: 'Donate Cryptocurrency' },
|
||||||
|
});
|
||||||
|
|
||||||
|
export default
|
||||||
|
@injectIntl
|
||||||
|
class CryptoDonate extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { intl } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column icon='bitcoin' heading={intl.formatMessage(messages.heading)} backBtnSlim>
|
||||||
|
<div className='crypto-donate'>
|
||||||
|
<SiteWallet />
|
||||||
|
</div>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import blockExplorers from './block_explorers.json';
|
||||||
|
|
||||||
|
export const getExplorerUrl = (ticker, address) => {
|
||||||
|
const template = blockExplorers[ticker];
|
||||||
|
if (!template) return false;
|
||||||
|
return template.replace('{address}', address);
|
||||||
|
};
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"bch": "https://explorer.bitcoin.com/bch/address/{address}",
|
||||||
|
"btc": "https://explorer.bitcoin.com/btc/address/{address}",
|
||||||
|
"doge": "https://dogechain.info/address/{address}",
|
||||||
|
"eth": "https://etherscan.io/address/{address}",
|
||||||
|
"ubq": "https://ubiqscan.io/address/{address}",
|
||||||
|
"xmr": "https://monerohash.com/explorer/search?value={address}"
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { fromJS } from 'immutable';
|
||||||
|
import manifestMap from './manifest_map';
|
||||||
|
|
||||||
|
// All this does is converts the result from manifest_map.js into an ImmutableMap
|
||||||
|
const coinDB = fromJS(manifestMap);
|
||||||
|
export default coinDB;
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Does some trickery to import all the icons into the project
|
||||||
|
// See: https://stackoverflow.com/questions/42118296/dynamically-import-images-from-a-directory-using-webpack
|
||||||
|
|
||||||
|
const icons = {};
|
||||||
|
|
||||||
|
function importAll(r) {
|
||||||
|
const pathRegex = /\.\/(.*)\.svg/i;
|
||||||
|
|
||||||
|
r.keys().forEach((key) => {
|
||||||
|
const ticker = pathRegex.exec(key)[1];
|
||||||
|
return icons[ticker] = r(key).default;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
importAll(require.context('cryptocurrency-icons/svg/color/', true, /\.svg$/));
|
||||||
|
|
||||||
|
export default icons;
|
||||||
|
|
||||||
|
// For getting the icon
|
||||||
|
export const getCoinIcon = ticker => icons[ticker] || icons.generic || null;
|
|
@ -0,0 +1,12 @@
|
||||||
|
// @preval
|
||||||
|
// Converts cryptocurrency-icon's manifest file from a list to a map.
|
||||||
|
// See: https://github.com/spothq/cryptocurrency-icons/blob/master/manifest.json
|
||||||
|
|
||||||
|
const manifest = require('cryptocurrency-icons/manifest.json');
|
||||||
|
const { Map: ImmutableMap, fromJS } = require('immutable');
|
||||||
|
|
||||||
|
const manifestMap = fromJS(manifest).reduce((acc, entry) => {
|
||||||
|
return acc.set(entry.get('symbol').toLowerCase(), entry);
|
||||||
|
}, ImmutableMap());
|
||||||
|
|
||||||
|
module.exports = manifestMap.toJS();
|
|
@ -1,5 +1,6 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
@ -264,3 +265,38 @@ export const FileChooserLogo = props => (
|
||||||
FileChooserLogo.defaultProps = {
|
FileChooserLogo.defaultProps = {
|
||||||
accept: ['image/svg', 'image/png'],
|
accept: ['image/svg', 'image/png'],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export class CopyableInput extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
value: PropTypes.string,
|
||||||
|
}
|
||||||
|
|
||||||
|
setInputRef = c => {
|
||||||
|
this.input = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleCopyClick = e => {
|
||||||
|
if (!this.input) return;
|
||||||
|
|
||||||
|
this.input.select();
|
||||||
|
this.input.setSelectionRange(0, 99999);
|
||||||
|
|
||||||
|
document.execCommand('copy');
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { value } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='copyable-input'>
|
||||||
|
<input ref={this.setInputRef} type='text' value={value} readOnly />
|
||||||
|
<button onClick={this.handleCopyClick}>
|
||||||
|
<FormattedMessage id='forms.copy' defaultMessage='Copy' />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import DetailedCryptoAddress from 'soapbox/features/crypto_donate/components/detailed_crypto_address';
|
||||||
|
|
||||||
|
export default class CryptoDonateModal extends React.PureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
address: PropTypes.string.isRequired,
|
||||||
|
ticker: PropTypes.string.isRequired,
|
||||||
|
note: PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className='modal-root__modal crypto-donate-modal'>
|
||||||
|
<DetailedCryptoAddress {...this.props} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ import FocalPointModal from './focal_point_modal';
|
||||||
import HotkeysModal from './hotkeys_modal';
|
import HotkeysModal from './hotkeys_modal';
|
||||||
import ComposeModal from './compose_modal';
|
import ComposeModal from './compose_modal';
|
||||||
import UnauthorizedModal from './unauthorized_modal';
|
import UnauthorizedModal from './unauthorized_modal';
|
||||||
|
import CryptoDonateModal from './crypto_donate_modal';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
MuteModal,
|
MuteModal,
|
||||||
|
@ -37,6 +38,7 @@ const MODAL_COMPONENTS = {
|
||||||
'HOTKEYS': () => Promise.resolve({ default: HotkeysModal }),
|
'HOTKEYS': () => Promise.resolve({ default: HotkeysModal }),
|
||||||
'COMPOSE': () => Promise.resolve({ default: ComposeModal }),
|
'COMPOSE': () => Promise.resolve({ default: ComposeModal }),
|
||||||
'UNAUTHORIZED': () => Promise.resolve({ default: UnauthorizedModal }),
|
'UNAUTHORIZED': () => Promise.resolve({ default: UnauthorizedModal }),
|
||||||
|
'CRYPTO_DONATE': () => Promise.resolve({ default: CryptoDonateModal }),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class ModalRoot extends React.PureComponent {
|
export default class ModalRoot extends React.PureComponent {
|
||||||
|
|
|
@ -13,6 +13,12 @@ import { List as ImmutableList } from 'immutable';
|
||||||
import { getAcct, isAdmin, isModerator } from 'soapbox/utils/accounts';
|
import { getAcct, isAdmin, isModerator } from 'soapbox/utils/accounts';
|
||||||
import { displayFqn } from 'soapbox/utils/state';
|
import { displayFqn } from 'soapbox/utils/state';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import CryptoAddress from 'soapbox/features/crypto_donate/components/crypto_address';
|
||||||
|
|
||||||
|
const TICKER_REGEX = /\$([a-zA-Z]*)/i;
|
||||||
|
|
||||||
|
const getTicker = value => (value.match(TICKER_REGEX) || [])[1];
|
||||||
|
const isTicker = value => Boolean(getTicker(value));
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
linkVerifiedOn: { id: 'account.link_verified_on', defaultMessage: 'Ownership of this link was checked on {date}' },
|
linkVerifiedOn: { id: 'account.link_verified_on', defaultMessage: 'Ownership of this link was checked on {date}' },
|
||||||
|
@ -123,15 +129,19 @@ class ProfileInfoPanel extends ImmutablePureComponent {
|
||||||
</dl>
|
</dl>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
{fields.map((pair, i) => (
|
{fields.map((pair, i) =>
|
||||||
<dl className='profile-info-panel-content__fields__item' key={i}>
|
isTicker(pair.get('name', '')) ? (
|
||||||
<dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />
|
<CryptoAddress ticker={getTicker(pair.get('name')).toLowerCase()} address={pair.get('value_plain')} />
|
||||||
|
) : (
|
||||||
|
<dl className='profile-info-panel-content__fields__item' key={i}>
|
||||||
|
<dt dangerouslySetInnerHTML={{ __html: pair.get('name_emojified') }} title={pair.get('name')} />
|
||||||
|
|
||||||
<dd className={pair.get('verified_at') && 'verified'} title={pair.get('value_plain')}>
|
<dd className={pair.get('verified_at') && 'verified'} title={pair.get('value_plain')}>
|
||||||
{pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} />
|
{pair.get('verified_at') && <span title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(pair.get('verified_at'), dateFormatOptions) })}><Icon id='check' className='verified__mark' /></span>} <span dangerouslySetInnerHTML={{ __html: pair.get('value_emojified') }} />
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
))}
|
),
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -92,6 +92,7 @@ import {
|
||||||
AwaitingApproval,
|
AwaitingApproval,
|
||||||
Reports,
|
Reports,
|
||||||
ModerationLog,
|
ModerationLog,
|
||||||
|
CryptoDonate,
|
||||||
} from './util/async-components';
|
} from './util/async-components';
|
||||||
|
|
||||||
// Dummy import, to make sure that <Status /> ends up in the application bundle.
|
// Dummy import, to make sure that <Status /> ends up in the application bundle.
|
||||||
|
@ -289,6 +290,8 @@ class SwitchingColumnsArea extends React.PureComponent {
|
||||||
<WrappedRoute path='/admin/log' page={AdminPage} component={ModerationLog} content={children} exact />
|
<WrappedRoute path='/admin/log' page={AdminPage} component={ModerationLog} content={children} exact />
|
||||||
<WrappedRoute path='/info' layout={LAYOUT.EMPTY} component={ServerInfo} content={children} />
|
<WrappedRoute path='/info' layout={LAYOUT.EMPTY} component={ServerInfo} content={children} />
|
||||||
|
|
||||||
|
<WrappedRoute path='/donate/crypto' layout={LAYOUT.DEFAULT} component={CryptoDonate} content={children} />
|
||||||
|
|
||||||
<WrappedRoute layout={LAYOUT.EMPTY} component={GenericNotFound} content={children} />
|
<WrappedRoute layout={LAYOUT.EMPTY} component={GenericNotFound} content={children} />
|
||||||
</Switch>
|
</Switch>
|
||||||
);
|
);
|
||||||
|
|
|
@ -229,3 +229,7 @@ export function Reports() {
|
||||||
export function ModerationLog() {
|
export function ModerationLog() {
|
||||||
return import(/* webpackChunkName: "features/admin/moderation_log" */'../../admin/moderation_log');
|
return import(/* webpackChunkName: "features/admin/moderation_log" */'../../admin/moderation_log');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function CryptoDonate() {
|
||||||
|
return import(/* webpackChunkName: "features/crypto_donate" */'../../crypto_donate');
|
||||||
|
}
|
||||||
|
|
|
@ -81,6 +81,7 @@
|
||||||
@import 'components/server-info';
|
@import 'components/server-info';
|
||||||
@import 'components/admin';
|
@import 'components/admin';
|
||||||
@import 'components/backups';
|
@import 'components/backups';
|
||||||
|
@import 'components/crypto-donate';
|
||||||
|
|
||||||
// Holiday
|
// Holiday
|
||||||
@import 'holiday/halloween';
|
@import 'holiday/halloween';
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
.crypto-address {
|
||||||
|
padding: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&__head {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
width: 24px;
|
||||||
|
margin-right: 10px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__actions {
|
||||||
|
margin-left: auto;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--primary-text-color--faint);
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__note {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__qrcode {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
padding: 10px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__address {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-wallet {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
|
.crypto-donate-modal {
|
||||||
|
background: var(--foreground-color);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding-bottom: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-info-panel-content__fields {
|
||||||
|
.crypto-address {
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -788,3 +788,23 @@ code {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.copyable-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
input {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 14px !important;
|
||||||
|
border-radius: 4px 0 0 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
width: auto;
|
||||||
|
font-size: 14px;
|
||||||
|
margin: 0;
|
||||||
|
padding-bottom: 9px;
|
||||||
|
border-radius: 0 4px 4px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
"classnames": "^2.2.5",
|
"classnames": "^2.2.5",
|
||||||
"compression-webpack-plugin": "^6.0.2",
|
"compression-webpack-plugin": "^6.0.2",
|
||||||
"copy-webpack-plugin": "6.4.0",
|
"copy-webpack-plugin": "6.4.0",
|
||||||
|
"cryptocurrency-icons": "^0.17.2",
|
||||||
"css-loader": "^4.3.0",
|
"css-loader": "^4.3.0",
|
||||||
"cssnano": "^4.1.10",
|
"cssnano": "^4.1.10",
|
||||||
"detect-passive-events": "^2.0.0",
|
"detect-passive-events": "^2.0.0",
|
||||||
|
|
|
@ -3866,6 +3866,11 @@ crypto-browserify@^3.11.0:
|
||||||
randombytes "^2.0.0"
|
randombytes "^2.0.0"
|
||||||
randomfill "^1.0.3"
|
randomfill "^1.0.3"
|
||||||
|
|
||||||
|
cryptocurrency-icons@^0.17.2:
|
||||||
|
version "0.17.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/cryptocurrency-icons/-/cryptocurrency-icons-0.17.2.tgz#25811b450d8698e7985bc91005d89555f13e6686"
|
||||||
|
integrity sha512-301lellubLNhxkySIBNNG3VD05rWfMR+CFgo9LoLfuNybG2OLy0mpWduxv65WZkJpLl9hhpaVAxCV5SYbG5o9A==
|
||||||
|
|
||||||
css-color-names@0.0.4, css-color-names@^0.0.4:
|
css-color-names@0.0.4, css-color-names@^0.0.4:
|
||||||
version "0.0.4"
|
version "0.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
|
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
|
||||||
|
|
Ładowanie…
Reference in New Issue