diff --git a/ui/js/actions/claims.js b/ui/js/actions/claims.js deleted file mode 100644 index 51c50785d..000000000 --- a/ui/js/actions/claims.js +++ /dev/null @@ -1,56 +0,0 @@ -import lbry from "lbry"; -import { selectBalance } from "selectors/wallet"; -import { doOpenModal, doShowSnackBar } from "actions/app"; -import * as types from "constants/action_types"; -import * as modals from "constants/modal_types"; - -export function doSendSupport(amount, claim_id) { - return function(dispatch, getState) { - const state = getState(); - const balance = selectBalance(state); - - if (balance - amount <= 0) { - return dispatch(doOpenModal(modals.INSUFFICIENT_BALANCE)); - } - - dispatch({ - type: types.SUPPORT_TRANSACTION_STARTED, - }); - - const successCallback = results => { - if (results.txid) { - dispatch({ - type: types.SUPPORT_TRANSACTION_COMPLETED, - }); - dispatch( - doShowSnackBar({ - message: __(`You sent ${amount} LBC as support, Mahalo!`), - linkText: __("History"), - linkTarget: __("/wallet"), - }) - ); - } else { - dispatch({ - type: types.SUPPORT_TRANSACTION_FAILED, - data: { error: results.code }, - }); - dispatch(doOpenModal(modals.TRANSACTION_FAILED)); - } - }; - - const errorCallback = error => { - dispatch({ - type: types.SUPPORT_TRANSACTION_FAILED, - data: { error: error.code }, - }); - dispatch(doOpenModal(modals.TRANSACTION_FAILED)); - }; - - lbry - .wallet_send({ - claim_id: claim_id, - amount: amount, - }) - .then(successCallback, errorCallback); - }; -} diff --git a/ui/js/actions/wallet.js b/ui/js/actions/wallet.js index 025cb1def..0e90266fb 100644 --- a/ui/js/actions/wallet.js +++ b/ui/js/actions/wallet.js @@ -6,6 +6,7 @@ import { selectBalance, } from "selectors/wallet"; import { doOpenModal, doShowSnackBar } from "actions/app"; +import { doNavigate } from "actions/navigation"; import * as modals from "constants/modal_types"; export function doUpdateBalance(balance) { @@ -143,3 +144,55 @@ export function doSetDraftTransactionAddress(address) { data: { address }, }; } + +export function doSendSupport(amount, claim_id, uri) { + return function(dispatch, getState) { + const state = getState(); + const balance = selectBalance(state); + + if (balance - amount <= 0) { + return dispatch(doOpenModal(modals.INSUFFICIENT_BALANCE)); + } + + dispatch({ + type: types.SUPPORT_TRANSACTION_STARTED, + }); + + const successCallback = results => { + if (results.txid) { + dispatch({ + type: types.SUPPORT_TRANSACTION_COMPLETED, + }); + dispatch( + doShowSnackBar({ + message: __(`You sent ${amount} LBC as support, Mahalo!`), + linkText: __("History"), + linkTarget: __("/wallet"), + }) + ); + dispatch(doNavigate("/show", { uri })); + } else { + dispatch({ + type: types.SUPPORT_TRANSACTION_FAILED, + data: { error: results.code }, + }); + dispatch(doOpenModal(modals.TRANSACTION_FAILED)); + } + }; + + const errorCallback = error => { + dispatch({ + type: types.SUPPORT_TRANSACTION_FAILED, + data: { error: error.code }, + }); + dispatch(doOpenModal(modals.TRANSACTION_FAILED)); + }; + + lbry + .wallet_send({ + claim_id: claim_id, + amount: amount, + }) + .then(successCallback, errorCallback); + }; +} diff --git a/ui/js/component/fileDetails/index.js b/ui/js/component/fileDetails/index.js new file mode 100644 index 000000000..385959ed2 --- /dev/null +++ b/ui/js/component/fileDetails/index.js @@ -0,0 +1,16 @@ +import React from "react"; +import { connect } from "react-redux"; +import { + makeSelectClaimForUri, + makeSelectContentTypeForUri, + makeSelectMetadataForUri, +} from "selectors/claims"; +import FileDetails from "./view"; + +const select = (state, props) => ({ + claim: makeSelectClaimForUri(props.uri)(state), + contentType: makeSelectContentTypeForUri(props.uri)(state), + metadata: makeSelectMetadataForUri(props.uri)(state), +}); + +export default connect(select, null)(FileDetails); diff --git a/ui/js/component/fileDetails/view.jsx b/ui/js/component/fileDetails/view.jsx new file mode 100644 index 000000000..dfcc47699 --- /dev/null +++ b/ui/js/component/fileDetails/view.jsx @@ -0,0 +1,64 @@ +import React from "react"; +import ReactMarkdown from "react-markdown"; +import lbry from "lbry.js"; +import FileActions from "component/fileActions"; +import Link from "component/link"; +import DateTime from "component/dateTime"; + +class FileDetails extends React.PureComponent { + render() { + const { claim, contentType, metadata, uri } = this.props; + + if (!claim || !metadata) { + return ( +
+ {__("Empty claim or metadata info.")} +
+ ); + } + + const { description, language, license } = metadata; + const { height } = claim; + const mediaType = lbry.getMediaType(contentType); + + return ( +
+ +
+ +
+
+ + + + + + + + + + + + + + + + +
{__("Published on")}
{__("Content-Type")}{mediaType}
{__("Language")}{language}
{__("License")}{license}
+

+ +

+
+
+ ); + } +} + +export default FileDetails; diff --git a/ui/js/component/tipLink/index.js b/ui/js/component/tipLink/index.js deleted file mode 100644 index b43f225ac..000000000 --- a/ui/js/component/tipLink/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from "react"; -import { connect } from "react-redux"; -import { doSendSupport } from "actions/claims"; -import TipLink from "./view"; - -const select = state => ({}); - -const perform = dispatch => ({ - sendSupport: (amount, claim_id) => dispatch(doSendSupport(amount, claim_id)), -}); - -export default connect(select, perform)(TipLink); diff --git a/ui/js/component/tipLink/view.jsx b/ui/js/component/tipLink/view.jsx deleted file mode 100644 index 81e0aa31a..000000000 --- a/ui/js/component/tipLink/view.jsx +++ /dev/null @@ -1,69 +0,0 @@ -import React from "react"; -import Link from "component/link"; -import { FormRow } from "component/form"; - -class TipLink extends React.PureComponent { - constructor(props) { - super(props); - - this.state = { - tipAmount: 0.0, - }; - } - - handleSendButtonClicked() { - let claim_id = this.props.claim_id; - let amount = this.state.tipAmount; - this.props.sendSupport(amount, claim_id); - } - - handleSupportPriceChange(event) { - this.setState({ - tipAmount: Number(event.target.value), - }); - } - - render() { - const { uri } = this.props; - - return ( -
-
-

{__("Support")}

-
-
- {__( - "Support the creator and the success of their content by sending a tip. " - )} - -
-
- this.handleSupportPriceChange(event)} - /> -
-
- - -
-
- ); - } -} - -export default TipLink; diff --git a/ui/js/component/uriIndicator/view.jsx b/ui/js/component/uriIndicator/view.jsx index b69abd591..a6dcb1a50 100644 --- a/ui/js/component/uriIndicator/view.jsx +++ b/ui/js/component/uriIndicator/view.jsx @@ -1,5 +1,7 @@ import React from "react"; import { Icon } from "component/common"; +import Link from "component/link"; +import lbryuri from "lbryuri.js"; class UriIndicator extends React.PureComponent { componentWillMount() { @@ -19,7 +21,7 @@ class UriIndicator extends React.PureComponent { } render() { - const { claim, uri, isResolvingUri } = this.props; + const { claim, link, uri, isResolvingUri } = this.props; if (isResolvingUri && !claim) { return Validating...; @@ -33,21 +35,30 @@ class UriIndicator extends React.PureComponent { channel_name: channelName, has_signature: hasSignature, signature_is_valid: signatureIsValid, + value, } = claim; + const channelClaimId = + value && + value.publisherSignature && + value.publisherSignature.certificateId; if (!hasSignature || !channelName) { return Anonymous; } - let icon, modifier; + let icon, channelLink, modifier; + if (signatureIsValid) { modifier = "valid"; + channelLink = link + ? lbryuri.build({ channelName, claimId: channelClaimId }, false) + : false; } else { icon = "icon-times-circle"; modifier = "invalid"; } - return ( + const inner = ( {channelName} {" "} {!signatureIsValid @@ -58,6 +69,16 @@ class UriIndicator extends React.PureComponent { : ""} ); + + if (!channelLink) { + return inner; + } + + return ( + + {inner} + + ); } } diff --git a/ui/js/component/walletSendTip/index.js b/ui/js/component/walletSendTip/index.js new file mode 100644 index 000000000..6d3275321 --- /dev/null +++ b/ui/js/component/walletSendTip/index.js @@ -0,0 +1,18 @@ +import React from "react"; +import { connect } from "react-redux"; +import { doSendSupport } from "actions/wallet"; +import WalletSendTip from "./view"; +import { makeSelectTitleForUri } from "selectors/claims"; +import { selectIsSendingSupport } from "selectors/wallet"; + +const select = (state, props) => ({ + isPending: selectIsSendingSupport(state), + title: makeSelectTitleForUri(props.uri)(state), +}); + +const perform = dispatch => ({ + sendSupport: (amount, claim_id, uri) => + dispatch(doSendSupport(amount, claim_id, uri)), +}); + +export default connect(select, perform)(WalletSendTip); diff --git a/ui/js/component/walletSendTip/view.jsx b/ui/js/component/walletSendTip/view.jsx new file mode 100644 index 000000000..9b8ce0338 --- /dev/null +++ b/ui/js/component/walletSendTip/view.jsx @@ -0,0 +1,79 @@ +import React from "react"; +import Link from "component/link"; +import { FormRow } from "component/form"; +import UriIndicator from "component/uriIndicator"; + +class WalletSendTip extends React.PureComponent { + constructor(props) { + super(props); + + this.state = { + amount: 0.0, + }; + } + + handleSendButtonClicked() { + const { claim_id, uri } = this.props; + let amount = this.state.amount; + this.props.sendSupport(amount, claim_id, uri); + } + + handleSupportPriceChange(event) { + this.setState({ + amount: Number(event.target.value), + }); + } + + render() { + const { errorMessage, isPending, title, uri } = this.props; + + return ( +
+
+

{__("Support")}

+
+
+ + {__( + 'This will appear as a tip for "%s" located at %s.', + title, + uri + ) + " "} + + + } + placeholder="1.00" + onChange={event => this.handleSupportPriceChange(event)} + /> +
+ + +
+
+
+ ); + } +} + +export default WalletSendTip; diff --git a/ui/js/constants/action_types.js b/ui/js/constants/action_types.js index d1c75403d..a4cb1afaa 100644 --- a/ui/js/constants/action_types.js +++ b/ui/js/constants/action_types.js @@ -39,8 +39,11 @@ export const SEND_TRANSACTION_STARTED = "SEND_TRANSACTION_STARTED"; export const SEND_TRANSACTION_COMPLETED = "SEND_TRANSACTION_COMPLETED"; export const SEND_TRANSACTION_FAILED = "SEND_TRANSACTION_FAILED"; export const FETCH_BLOCK_SUCCESS = "FETCH_BLOCK_SUCCESS"; +export const SUPPORT_TRANSACTION_STARTED = "SUPPORT_TRANSACTION_STARTED"; +export const SUPPORT_TRANSACTION_COMPLETED = "SUPPORT_TRANSACTION_COMPLETED"; +export const SUPPORT_TRANSACTION_FAILED = "SUPPORT_TRANSACTION_FAILED"; -// Content +// Claims export const FETCH_FEATURED_CONTENT_STARTED = "FETCH_FEATURED_CONTENT_STARTED"; export const FETCH_FEATURED_CONTENT_COMPLETED = "FETCH_FEATURED_CONTENT_COMPLETED"; @@ -56,6 +59,19 @@ export const FETCH_CHANNEL_CLAIM_COUNT_COMPLETED = export const FETCH_CLAIM_LIST_MINE_STARTED = "FETCH_CLAIM_LIST_MINE_STARTED"; export const FETCH_CLAIM_LIST_MINE_COMPLETED = "FETCH_CLAIM_LIST_MINE_COMPLETED"; +export const ABANDON_CLAIM_STARTED = "ABANDON_CLAIM_STARTED"; +export const ABANDON_CLAIM_SUCCEEDED = "ABANDON_CLAIM_SUCCEEDED"; +export const FETCH_CHANNEL_LIST_MINE_STARTED = + "FETCH_CHANNEL_LIST_MINE_STARTED"; +export const FETCH_CHANNEL_LIST_MINE_COMPLETED = + "FETCH_CHANNEL_LIST_MINE_COMPLETED"; +export const CREATE_CHANNEL_STARTED = "CREATE_CHANNEL_STARTED"; +export const CREATE_CHANNEL_COMPLETED = "CREATE_CHANNEL_COMPLETED"; +export const PUBLISH_STARTED = "PUBLISH_STARTED"; +export const PUBLISH_COMPLETED = "PUBLISH_COMPLETED"; +export const PUBLISH_FAILED = "PUBLISH_FAILED"; + +// Files export const FILE_LIST_STARTED = "FILE_LIST_STARTED"; export const FILE_LIST_SUCCEEDED = "FILE_LIST_SUCCEEDED"; export const FETCH_FILE_INFO_STARTED = "FETCH_FILE_INFO_STARTED"; @@ -72,17 +88,6 @@ export const PLAY_VIDEO_STARTED = "PLAY_VIDEO_STARTED"; export const FETCH_AVAILABILITY_STARTED = "FETCH_AVAILABILITY_STARTED"; export const FETCH_AVAILABILITY_COMPLETED = "FETCH_AVAILABILITY_COMPLETED"; export const FILE_DELETE = "FILE_DELETE"; -export const ABANDON_CLAIM_STARTED = "ABANDON_CLAIM_STARTED"; -export const ABANDON_CLAIM_SUCCEEDED = "ABANDON_CLAIM_SUCCEEDED"; -export const FETCH_CHANNEL_LIST_MINE_STARTED = - "FETCH_CHANNEL_LIST_MINE_STARTED"; -export const FETCH_CHANNEL_LIST_MINE_COMPLETED = - "FETCH_CHANNEL_LIST_MINE_COMPLETED"; -export const CREATE_CHANNEL_STARTED = "CREATE_CHANNEL_STARTED"; -export const CREATE_CHANNEL_COMPLETED = "CREATE_CHANNEL_COMPLETED"; -export const PUBLISH_STARTED = "PUBLISH_STARTED"; -export const PUBLISH_COMPLETED = "PUBLISH_COMPLETED"; -export const PUBLISH_FAILED = "PUBLISH_FAILED"; // Search export const SEARCH_STARTED = "SEARCH_STARTED"; @@ -131,13 +136,6 @@ export const CLAIM_REWARD_FAILURE = "CLAIM_REWARD_FAILURE"; export const CLAIM_REWARD_CLEAR_ERROR = "CLAIM_REWARD_CLEAR_ERROR"; export const FETCH_REWARD_CONTENT_COMPLETED = "FETCH_REWARD_CONTENT_COMPLETED"; -// Supports -export const SUPPORT_TRANSACTION_STARTED = "SUPPORT_TRANSACTION_STARTED"; -export const SUPPORT_TRANSACTION_COMPLETED = "SUPPORT_TRANSACTION_COMPLETED"; -export const SUPPORT_TRANSACTION_FAILED = "SUPPORT_TRANSACTION_FAILED"; -export const HIDE_TIP_BOX = "HIDE_TIP_BOX"; -export const SHOW_TIP_BOX = "SHOW_TIP_BOX"; - //Language export const DOWNLOAD_LANGUAGE_SUCCEEDED = "DOWNLOAD_LANGUAGE_SUCCEEDED"; export const DOWNLOAD_LANGUAGE_FAILED = "DOWNLOAD_LANGUAGE_FAILED"; diff --git a/ui/js/modal/modalRemoveFile/index.js b/ui/js/modal/modalRemoveFile/index.js index 8c00f383e..39ae89ceb 100644 --- a/ui/js/modal/modalRemoveFile/index.js +++ b/ui/js/modal/modalRemoveFile/index.js @@ -2,16 +2,13 @@ import React from "react"; import { connect } from "react-redux"; import { doCloseModal } from "actions/app"; import { doDeleteFileAndGoBack } from "actions/file_info"; -import { - makeSelectMetadataForUri, - makeSelectClaimIsMine, -} from "selectors/claims"; +import { makeSelectTitleForUri, makeSelectClaimIsMine } from "selectors/claims"; import { makeSelectFileInfoForUri } from "selectors/file_info"; import ModalRemoveFile from "./view"; const select = (state, props) => ({ claimIsMine: makeSelectClaimIsMine(props.uri)(state), - metadata: makeSelectMetadataForUri(props.uri)(state), + title: makeSelectTitleForUri(props.uri)(state), fileInfo: makeSelectFileInfoForUri(props.uri)(state), }); diff --git a/ui/js/modal/modalRemoveFile/view.jsx b/ui/js/modal/modalRemoveFile/view.jsx index f646c5400..c18acb6f2 100644 --- a/ui/js/modal/modalRemoveFile/view.jsx +++ b/ui/js/modal/modalRemoveFile/view.jsx @@ -30,7 +30,7 @@ class ModalRemoveFile extends React.PureComponent { closeModal, deleteFile, fileInfo: { outpoint }, - metadata: { title }, + title, } = this.props; const { deleteChecked, abandonClaimChecked } = this.state; diff --git a/ui/js/page/file/view.jsx b/ui/js/page/file/view.jsx index 73d2ed405..35209ae18 100644 --- a/ui/js/page/file/view.jsx +++ b/ui/js/page/file/view.jsx @@ -1,45 +1,13 @@ import React from "react"; -import ReactMarkdown from "react-markdown"; import lbry from "lbry.js"; import lbryuri from "lbryuri.js"; import Video from "component/video"; -import TipLink from "component/tipLink"; import { Thumbnail } from "component/common"; import FilePrice from "component/filePrice"; -import FileActions from "component/fileActions"; -import Link from "component/link"; +import FileDetails from "component/fileDetails"; import UriIndicator from "component/uriIndicator"; import IconFeatured from "component/iconFeatured"; -import DateTime from "component/dateTime"; - -const FormatItem = props => { - const { - contentType, - claim: { height }, - metadata: { language, license }, - } = props; - - const mediaType = lbry.getMediaType(contentType); - - return ( - - - - - - - - - - - - - - - -
{__("Published on")}
{__("Content-Type")}{mediaType}
{__("Language")}{language}
{__("License")}{license}
- ); -}; +import WalletSendTip from "component/walletSendTip"; class FilePage extends React.PureComponent { componentDidMount() { @@ -82,24 +50,7 @@ class FilePage extends React.PureComponent { ); } - const { - txid, - nout, - channel_name: channelName, - has_signature: hasSignature, - signature_is_valid: signatureIsValid, - value, - } = claim; - - const outpoint = txid + ":" + nout; const title = metadata.title; - const channelClaimId = claim.value && claim.value.publisherSignature - ? claim.value.publisherSignature.certificateId - : null; - const channelUri = signatureIsValid && hasSignature && channelName - ? lbryuri.build({ channelName, claimId: channelClaimId }, false) - : null; - const uriIndicator = ; const isRewardContent = rewardedContentClaimIds.includes(claim.claim_id); const mediaType = lbry.getMediaType(contentType); const player = require("render-media"); @@ -109,7 +60,7 @@ class FilePage extends React.PureComponent { mediaType === "audio"; return ( -
+
{isPlayable ?
-
- {!fileInfo || fileInfo.written_bytes <= 0 - ? - - {isRewardContent && {" "}} - - : null} -

{title}

-
- {channelUri - ? - this.props.navigate("/show", { uri: channelUri })} - > - {uriIndicator} - - : uriIndicator} -
- -
- {!showTipBox && -
- + {(!tab || tab === "details") && +
+ {" "} {" "} +
+ {!fileInfo || fileInfo.written_bytes <= 0 + ? + + {isRewardContent && {" "}} + + : null} +

{title}

+
+ +
+
+
} + {tab === "tip" && + }
- {metadata && claim && !showTipBox - ?
- -
- : ""} - {showTipBox ? : ""} - {!showTipBox && -
- -
}
-
+ ); } } diff --git a/ui/js/reducers/claims.js b/ui/js/reducers/claims.js index ae80f1712..f18433cdc 100644 --- a/ui/js/reducers/claims.js +++ b/ui/js/reducers/claims.js @@ -2,9 +2,7 @@ import * as types from "constants/action_types"; const reducers = {}; -const defaultState = { - supportTransaction: {}, -}; +const defaultState = {}; reducers[types.RESOLVE_URI_COMPLETED] = function(state, action) { const { uri, certificate, claim } = action.data; @@ -192,49 +190,6 @@ reducers[types.CREATE_CHANNEL_COMPLETED] = function(state, action) { }); }; -reducers[types.HIDE_TIP_BOX] = function(state, action) { - return Object.assign({}, state, { - supportTransaction: buildSupportTransaction(), - }); -}; - -reducers[types.SHOW_TIP_BOX] = function(state, action) { - const newSupportTransaction = Object.assign({}, state.supportTransaction, { - tipBoxShown: true, - }); - - return Object.assign({}, state, { - supportTransaction: newSupportTransaction, - }); -}; - -reducers[types.SUPPORT_TRANSACTION_STARTED] = function(state, action) { - const newSupportTransaction = Object.assign({}, state.supportTransaction, { - sendingSupport: true, - }); - - return Object.assign({}, state, { - supportTransaction: newSupportTransaction, - }); -}; - -reducers[types.SUPPORT_TRANSACTION_COMPLETED] = function(state, action) { - return Object.assign({}, state, { - supportTransaction: buildSupportTransaction(), - }); -}; - -reducers[types.SUPPORT_TRANSACTION_FAILED] = function(state, action) { - const newSupportTransaction = Object.assign({}, state.supportTransaction, { - sendingSupport: false, - error: action.data.error, - }); - - return Object.assign({}, state, { - supportTransaction: newSupportTransaction, - }); -}; - export default function reducer(state = defaultState, action) { const handler = reducers[action.type]; if (handler) return handler(state, action); diff --git a/ui/js/reducers/wallet.js b/ui/js/reducers/wallet.js index e704222a6..7cc53b54a 100644 --- a/ui/js/reducers/wallet.js +++ b/ui/js/reducers/wallet.js @@ -15,6 +15,7 @@ const defaultState = { receiveAddress: address, gettingNewAddress: false, draftTransaction: buildDraftTransaction(), + sendingSupport: false, }; reducers[types.FETCH_TRANSACTIONS_STARTED] = function(state, action) { @@ -125,6 +126,25 @@ reducers[types.SEND_TRANSACTION_FAILED] = function(state, action) { }); }; +reducers[types.SUPPORT_TRANSACTION_STARTED] = function(state, action) { + return Object.assign({}, state, { + sendingSupport: true, + }); +}; + +reducers[types.SUPPORT_TRANSACTION_COMPLETED] = function(state, action) { + return Object.assign({}, state, { + sendingSupport: false, + }); +}; + +reducers[types.SUPPORT_TRANSACTION_FAILED] = function(state, action) { + return Object.assign({}, state, { + error: action.data.error, + sendingSupport: false, + }); +}; + reducers[types.FETCH_BLOCK_SUCCESS] = (state, action) => { const { block, block: { height } } = action.data, blocks = Object.assign({}, state.blocks); diff --git a/ui/js/selectors/claims.js b/ui/js/selectors/claims.js index 14ac231fc..61fd5fdc2 100644 --- a/ui/js/selectors/claims.js +++ b/ui/js/selectors/claims.js @@ -97,6 +97,13 @@ export const makeSelectMetadataForUri = uri => { }); }; +export const makeSelectTitleForUri = uri => { + return createSelector( + makeSelectMetadataForUri(uri), + metadata => metadata && metadata.title + ); +}; + export const makeSelectContentTypeForUri = uri => { return createSelector(makeSelectClaimForUri(uri), claim => { const source = @@ -174,8 +181,3 @@ export const selectMyChannelClaims = createSelector( return claims; } ); - -export const selectShowTipBox = createSelector( - _selectState, - state => state.supportTransaction.tipBoxShown -); diff --git a/ui/js/selectors/wallet.js b/ui/js/selectors/wallet.js index ab7e22e07..7469c2f48 100644 --- a/ui/js/selectors/wallet.js +++ b/ui/js/selectors/wallet.js @@ -61,6 +61,11 @@ export const selectIsFetchingTransactions = createSelector( state => state.fetchingTransactions ); +export const selectIsSendingSupport = createSelector( + _selectState, + state => state.sendingSupport +); + export const selectReceiveAddress = createSelector( _selectState, state => state.receiveAddress diff --git a/ui/scss/component/_card.scss b/ui/scss/component/_card.scss index e5dff4e73..0562b4040 100644 --- a/ui/scss/component/_card.scss +++ b/ui/scss/component/_card.scss @@ -7,6 +7,9 @@ border-radius: var(--card-radius); margin-bottom: var(--card-margin); overflow: auto; + + //below added to prevent scrollbar on long titles when show page loads, would prefer a cleaner CSS solution + overflow-x: hidden; } .card--obscured { @@ -62,6 +65,9 @@ .card__content { margin-top: var(--card-margin); margin-bottom: var(--card-margin); + table:not(:last-child) { + margin-bottom: var(--card-margin); + } } $font-size-subtext-multiple: 0.82; .card__subtext {