diff --git a/app/soapbox/actions/soapbox.js b/app/soapbox/actions/soapbox.js
index e732b1f40..7e03a1e52 100644
--- a/app/soapbox/actions/soapbox.js
+++ b/app/soapbox/actions/soapbox.js
@@ -43,6 +43,9 @@ export const defaultConfig = ImmutableMap({
allowedEmoji: allowedEmoji,
verifiedCanEditName: false,
displayFqn: true,
+ cryptoDonatePanel: ImmutableMap({
+ limit: 3,
+ }),
});
export function getSoapboxConfig(state) {
diff --git a/app/soapbox/features/crypto_donate/components/crypto_donate_panel.js b/app/soapbox/features/crypto_donate/components/crypto_donate_panel.js
new file mode 100644
index 000000000..b63acdad1
--- /dev/null
+++ b/app/soapbox/features/crypto_donate/components/crypto_donate_panel.js
@@ -0,0 +1,65 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
+import { Link } from 'react-router-dom';
+import { FormattedMessage } from 'react-intl';
+import ImmutablePureComponent from 'react-immutable-pure-component';
+import SiteWallet from './site_wallet';
+import { List as ImmutableList } from 'immutable';
+import classNames from 'classnames';
+
+const mapStateToProps = state => {
+ const addresses = state.getIn(['soapbox', 'crypto_addresses'], ImmutableList());
+ return {
+ total: addresses.size,
+ siteTitle: state.getIn(['instance', 'title']),
+ };
+};
+
+export default @connect(mapStateToProps)
+class CryptoDonatePanel extends ImmutablePureComponent {
+
+ static propTypes = {
+ limit: PropTypes.number,
+ total: PropTypes.number,
+ }
+
+ static defaultProps = {
+ limit: 3,
+ }
+
+ render() {
+ const { limit, total, siteTitle } = this.props;
+ const more = total - limit;
+ const hasMore = more > 0;
+
+ return (
+
+
+
+
+
+
+
+
+ {hasMore &&
+
+ }
+
+ );
+ }
+
+};
diff --git a/app/soapbox/features/crypto_donate/components/site_wallet.js b/app/soapbox/features/crypto_donate/components/site_wallet.js
index 3e5d30bc5..5e5e3fa69 100644
--- a/app/soapbox/features/crypto_donate/components/site_wallet.js
+++ b/app/soapbox/features/crypto_donate/components/site_wallet.js
@@ -1,14 +1,18 @@
import React from 'react';
import { connect } from 'react-redux';
+import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import CryptoAddress from './crypto_address';
-const mapStateToProps = state => {
+const mapStateToProps = (state, ownProps) => {
// Address example:
// {"ticker": "btc", "address": "bc1q9cx35adpm73aq2fw40ye6ts8hfxqzjr5unwg0n", "note": "This is our main address"}
+ const addresses = state.getIn(['soapbox', 'crypto_addresses']);
+ const { limit } = ownProps;
+
return {
- coinList: state.getIn(['soapbox', 'crypto_addresses']),
+ coinList: typeof limit === 'number' ? addresses.take(limit) : addresses,
};
};
@@ -17,6 +21,7 @@ class CoinList extends ImmutablePureComponent {
static propTypes = {
coinList: ImmutablePropTypes.list,
+ limit: PropTypes.number,
}
render() {
diff --git a/app/soapbox/pages/home_page.js b/app/soapbox/pages/home_page.js
index 50233bb70..435752196 100644
--- a/app/soapbox/pages/home_page.js
+++ b/app/soapbox/pages/home_page.js
@@ -8,6 +8,7 @@ import FeaturesPanel from '../features/ui/components/features_panel';
import PromoPanel from '../features/ui/components/promo_panel';
import UserPanel from '../features/ui/components/user_panel';
import FundingPanel from '../features/ui/components/funding_panel';
+import CryptoDonatePanel from 'soapbox/features/crypto_donate/components/crypto_donate_panel';
import ComposeFormContainer from '../features/compose/containers/compose_form_container';
import Avatar from '../components/avatar';
import { getFeatures } from 'soapbox/utils/features';
@@ -16,10 +17,13 @@ import { getSoapboxConfig } from 'soapbox/actions/soapbox';
const mapStateToProps = state => {
const me = state.get('me');
+ const soapbox = getSoapboxConfig(state);
return {
me,
account: state.getIn(['accounts', me]),
- hasPatron: getSoapboxConfig(state).getIn(['extensions', 'patron', 'enabled']),
+ hasPatron: soapbox.getIn(['extensions', 'patron', 'enabled']),
+ hasCrypto: typeof soapbox.getIn(['crypto_addresses', 0, 'ticker']) === 'string',
+ cryptoLimit: soapbox.getIn(['cryptoDonatePanel', 'limit']),
features: getFeatures(state.get('instance')),
};
};
@@ -33,7 +37,7 @@ class HomePage extends ImmutablePureComponent {
}
render() {
- const { me, children, account, hasPatron, features } = this.props;
+ const { me, children, account, hasPatron, features, hasCrypto, cryptoLimit } = this.props;
return (
@@ -44,6 +48,7 @@ class HomePage extends ImmutablePureComponent {
{hasPatron && }
+ {hasCrypto && }
diff --git a/app/styles/components/crypto-donate.scss b/app/styles/components/crypto-donate.scss
index 10289e976..2fd6b7fd6 100644
--- a/app/styles/components/crypto-donate.scss
+++ b/app/styles/components/crypto-donate.scss
@@ -67,3 +67,35 @@
padding: 10px 0;
}
}
+
+.crypto-donate-panel {
+ &__message {
+ margin: 20px 0;
+ margin-top: -12px;
+ font-size: 14px;
+ }
+
+ .site-wallet {
+ display: block;
+ padding-bottom: 10px;
+ }
+
+ .crypto-address {
+ padding: 0;
+ margin: 20px 0;
+
+ &:first-child {
+ margin-top: 0;
+ }
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
+
+ &--has-more {
+ .site-wallet {
+ padding-bottom: 0;
+ }
+ }
+}
diff --git a/app/styles/components/wtf-panel.scss b/app/styles/components/wtf-panel.scss
index bad152f99..ce46a038a 100644
--- a/app/styles/components/wtf-panel.scss
+++ b/app/styles/components/wtf-panel.scss
@@ -129,4 +129,23 @@
}
}
}
+
+ &__expand-btn {
+ display: block;
+ width: 100%;
+ height: 100%;
+ max-height: 46px;
+ position: relative;
+ border-top: 1px solid;
+ border-color: var(--brand-color--faint);
+ transition: max-height 150ms ease;
+ overflow: hidden;
+ opacity: 1;
+ text-align: center;
+ line-height: 46px;
+ font-size: 14px;
+ cursor: pointer;
+ color: var(--primary-text-color);
+ text-decoration: none;
+ }
}