Skip to content

Commit

Permalink
NFT UI
Browse files Browse the repository at this point in the history
  • Loading branch information
1aerostorm committed Oct 22, 2023
1 parent cc3352d commit a8c89ad
Show file tree
Hide file tree
Showing 46 changed files with 4,025 additions and 68 deletions.
27 changes: 25 additions & 2 deletions app/ResolveRoute.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
export const routeRegex = {
UserProfile1: /^\/(@[\w\.\d-]+)\/?$/,
UserProfile2: /^\/(@[\w\.\d-]+)\/(transfers|assets|create-asset|invites|curation-rewards|author-rewards|donates-from|donates-to|filled-orders|permissions|created|password|witness|settings)\/??(?:&?[^=&]*=[^=&]*)*$/,
UserProfile2: /^\/(@[\w\.\d-]+)\/(transfers|assets|create-asset|invites|curation-rewards|author-rewards|donates-from|donates-to|nft-history|nft-tokens|nft-collections|filled-orders|permissions|created|password|witness|settings)\/??(?:&?[^=&]*=[^=&]*)*$/,
UserProfile3: /^\/(@[\w\.\d-]+)\/[\w\.\d-]+/,
UserNFTEndPoints: /^\/(@[\w\.\d-]+)\/nft-tokens\/([\w\d.-]+)\/?$/,
UserAssetEndPoints: /^\/(@[\w\.\d-]+)\/assets\/([\w\d.-]+)\/(update|transfer)$/,
UserEndPoints: /^(transfers|assets|create-asset|invites|curation-rewards|author-rewards|donates-from|donates-to|filled-orders|permissions|created|password|witness|settings)$/,
UserEndPoints: /^(transfers|assets|create-asset|invites|curation-rewards|author-rewards|donates-from|donates-to|nft-history|nft-tokens|nft-collections|filled-orders|permissions|created|password|witness|settings)$/,
WorkerSort: /^\/workers\/([\w\d\-]+)\/?($|\?)/,
WorkerSearchByAuthor: /^\/workers\/([\w\d\-]+)\/(\@[\w\d.-]+)\/?($|\?)/,
WorkerRequest: /^\/workers\/([\w\d\-]+)\/(\@[\w\d.-]+)\/([\w\d-]+)\/?($|\?)/,
MarketPair: /^\/market\/([\w\d\.]+)\/([\w\d.]+)\/?($|\?)/,
ConvertPair: /^\/convert\/([\w\d\.]+)\/([\w\d.]+)\/?($|\?)/,
NFTCollection: /^\/nft-collections\/([\w\d\.]+)\/?($|\?)/,
NFTToken: /^\/nft-tokens\/([\w\d\.]+)\/?($|\?)/,
NFTMarket: /^\/nft\/([\w\d\.]+)\/?($|\?)/,
UserJson: /^\/(@[\w\.\d-]+)(\.json)$/,
UserNameJson: /^.*(?=(\.json))/
};
Expand Down Expand Up @@ -72,6 +76,10 @@ export default function resolveRoute(path)
if (match) {
return {page: 'Workers', params: match.slice(1)};
}
match = path.match(routeRegex.UserNFTEndPoints)
if (match) {
return {page: 'UserProfile', params: [match[1], 'nft-tokens', match[2]]}
}
match = path.match(routeRegex.UserAssetEndPoints);
if (match) {
return {page: 'UserProfile', params: [match[1], 'assets', match[2], match[3]]};
Expand All @@ -89,5 +97,20 @@ export default function resolveRoute(path)
if (match) {
return {page: 'ConvertAssetsPage', params: match.slice(1)}
}
match = path.match(routeRegex.NFTCollection)
if (match) {
return {page: 'NFTCollectionPage', params: match.slice(1)}
}
match = path.match(routeRegex.NFTToken)
if (match) {
return {page: 'NFTTokenPage', params: match.slice(1)}
}
if (path === '/nft') {
return {page: 'NFTMarketPage'}
}
match = path.match(routeRegex.NFTMarket)
if (match) {
return {page: 'NFTMarketPage', params: match.slice(1)}
}
return {page: 'NotFound'};
}
6 changes: 6 additions & 0 deletions app/RootRoute.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@ export default {
cb(null, [require('@pages/UserProfile')]);
} else if (route.page === 'ConvertAssetsPage') {
cb(null, [require('@pages/ConvertAssetsPage')]);
} else if (route.page === 'NFTCollectionPage') {
cb(null, [require('@pages/nft/NFTCollectionPage')]);
} else if (route.page === 'NFTTokenPage') {
cb(null, [require('@pages/nft/NFTTokenPage')]);
} else if (route.page === 'NFTMarketPage') {
cb(null, [require('@pages/nft/NFTMarketPage')]);
} else if (route.page === 'Market') {
cb(null, [require('@pages/MarketLoader')]);
} else if (route.page === 'Rating') {
Expand Down
Binary file added app/assets/images/nft.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions app/components/all.scss
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
@import "./elements/market/MarketPair";
@import "./elements/market/OrderForm";
@import "./elements/market/TickerPriceStat";
@import "./elements/nft/NFTSmallIcon";
@import "./elements/nft/NFTMarketCollections";
@import "./elements/nft/NFTTokenItem";
@import "./elements/workers/WorkerRequestVoting";

// dialogs
Expand Down Expand Up @@ -67,6 +70,12 @@
@import "./modules/Powerdown.scss";
@import "./modules/QuickBuy.scss";
@import "./modules/Modals";
@import "./modules/nft/NFTCollections";
@import "./modules/nft/CreateNFTCollection";
@import "./modules/nft/IssueNFTToken";
@import "./modules/nft/NFTTokens";
@import "./modules/nft/NFTTokenSell";
@import "./modules/nft/NFTTokenTransfer";

// pages
@import "./pages/Exchanges";
Expand All @@ -76,3 +85,6 @@
@import "./pages/Rating";
@import "./pages/UserProfile";
@import "./pages/Witnesses";
@import "./pages/nft/NFTCollectionPage";
@import "./pages/nft/NFTMarketPage";
@import "./pages/nft/NFTTokenPage";
104 changes: 99 additions & 5 deletions app/components/cards/TransferHistoryRow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,38 @@ class TransferHistoryRow extends React.Component {
/* all transfers involve up to 2 accounts, context and 1 other. */
let description_start = "";
let link = null, linkTitle = null, linkExternal = false
let description_middle = ''
let link2 = null, linkTitle2 = null, linkExternal2 = false
let description_middle2 = ''
let link3 = null, linkTitle3 = null, linkExternal3 = false
let code_key = "";
let description_end = "";
let link4 = null, linkTitle4 = null, linkExternal4 = false
let target_hint = "";
let data_memo = data.memo;

const getToken = (token_id) => {
const { nft_tokens } = this.props
let tokenLink
let tokenTitle
const token = nft_tokens && nft_tokens.toJS()[data.token_id]
if (token) {
try {
const meta = JSON.parse(token.json_metadata)
tokenTitle = meta.title
} catch (err) {
console.error(err)
}
}
if (!tokenTitle) {
tokenTitle = '#' + data.token_id
}
tokenLink = <Link to={'/nft-tokens/' + data.token_id} target='_blank' rel='noopener noreferrer'>
{tokenTitle}
</Link>
return { tokenTitle, tokenLink }
}

if (/^transfer$|^transfer_to_savings$|^transfer_from_savings$/.test(type)) {
const fromWhere =
type === 'transfer_to_savings' ? tt('transferhistoryrow_jsx.to_savings') :
Expand Down Expand Up @@ -312,10 +339,73 @@ class TransferHistoryRow extends React.Component {
} else {
code_key = JSON.stringify({type, ...data}, null, 2);
}
} else if (type === 'nft_token') {
link = data.creator
description_middle = tt('transferhistoryrow_jsx.nft_issued') + tt('transferhistoryrow_jsx.nft_token') + ' '
const { tokenTitle, tokenLink } = getToken(data.token_id)
link2 = tokenLink
if (!link2) {
description_middle += tokenTitle
}
linkExternal2 = true
if (data.creator !== data.to) {
description_middle2 += tt('transferhistoryrow_jsx.nft_issued_for')
link3 = data.to
}
description_end = ', ' + tt('transferhistoryrow_jsx.nft_issued_cost') + Asset(data.issue_cost).floatString
} else if (type === 'nft_transfer') {
if (this.props.context === data.from) {
if (data.to === 'null') {
description_end += tt('transferhistoryrow_jsx.burnt') + ' '
description_end += tt('transferhistoryrow_jsx.nft_token')
} else {
description_start += tt('transferhistoryrow_jsx.you_gifted0') + ' '
link = data.to
description_end += tt('transferhistoryrow_jsx.you_gifted') + ': '
description_end += tt('transferhistoryrow_jsx.nft_token')
}
} else {
link = data.from
description_end += ' ' + tt('transferhistoryrow_jsx.gifted') + ' '
description_end += tt('transferhistoryrow_jsx.nft_token')
}
const { tokenTitle, tokenLink } = getToken(data.token_id)
link4 = tokenLink
linkExternal4 = true
description_end += ' ' + (!link4 ? tokenTitle : '')
} else if (type === 'nft_sell') {
link = data.seller
description_middle = tt('transferhistoryrow_jsx.nft_sell')
description_middle += tt('transferhistoryrow_jsx.nft_token') + ' '
const { tokenTitle, tokenLink } = getToken(data.token_id)
link2 = tokenLink
if (!link2) {
description_middle += tokenTitle
}
linkExternal2 = true
description_middle2 += tt('transferhistoryrow_jsx.for')
description_middle2 += Asset(data.price).floatString
} else if (type === 'nft_token_sold') {
link = data.seller
description_middle = tt('transferhistoryrow_jsx.sold')
link2 = data.buyer
description_middle2 = ' ' + tt('transferhistoryrow_jsx.nft_token') + ' '
const { tokenTitle, tokenLink } = getToken(data.token_id)
link3 = tokenLink
if (!link3) {
description_middle2 += tokenTitle
}
linkExternal3 = true
description_end = tt('transferhistoryrow_jsx.for')
description_end += Asset(data.price).floatString
} else {
code_key = JSON.stringify({type, ...data}, null, 2);
}

else {
code_key = JSON.stringify({type, ...data}, null, 2);
const wrapLink = (href, title, isExternal) => {
return (isExternal ?
<a href={href} target='_blank' rel='noreferrer noopener'>{title || href}</a> :
<Link to={`/@${href}`}>{title || href}</Link>)
}

return(
Expand All @@ -328,10 +418,13 @@ class TransferHistoryRow extends React.Component {
<td className="TransferHistoryRow__text" style={{maxWidth: "35rem"}}>
{description_start}
{code_key && <span style={{fontSize: "85%"}}>{code_key}</span>}
{link && (linkExternal ?
<a href={link} target='_blank' rel='noreferrer noopener'>{linkTitle || link}</a> :
<Link to={`/@${link}`}>{linkTitle || link}</Link>)}
{link && wrapLink(link, linkTitle, linkExternal)}
{description_middle}
{link2 && wrapLink(link2, linkTitle2, linkExternal2)}
{description_middle2}
{link3 && wrapLink(link3, linkTitle3, linkExternal3)}
{description_end}
{link4 && wrapLink(link4, linkTitle4, linkExternal4)}
{target_hint && <span style={{fontSize: "85%", padding: "5px"}}>[{target_hint}]</span>}
</td>
<td className="show-for-medium" style={{maxWidth: "25rem", wordWrap: "break-word", fontSize: "85%"}}>
Expand All @@ -358,6 +451,7 @@ export default connect(
username,
curation_reward,
author_reward,
nft_tokens: state.global.get('nft_token_map')
}
},
)(TransferHistoryRow)
4 changes: 2 additions & 2 deletions app/components/elements/DropdownMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@ export default class DropdownMenu extends React.Component {
}

render() {
const {el, items, selected, children, className, title, href, noArrow} = this.props;
const {el, items, selected, children, className, title, href, onClick, noArrow} = this.props;
const hasDropdown = items.length > 0

let entry = children || <span key='label'>
{this.getSelectedLabel(items, selected)}
{hasDropdown && !noArrow && <Icon name="dropdown-arrow" />}
</span>

if(hasDropdown) entry = <a key="entry" href={href || '#'} onClick={this.toggle}>{entry}</a>
if(hasDropdown) entry = <a key="entry" href={href || '#'} onClick={onClick ? (e) => { onClick(e); this.toggle(e) } : this.toggle}>{entry}</a>

const menu = <VerticalMenu key="menu" title={title} items={items} hideValue={selected} className="VerticalMenu" />;
const cls = 'DropdownMenu' + (this.state.shown ? ' show' : '') + (className ? ` ${className}` : '')
Expand Down
4 changes: 2 additions & 2 deletions app/components/elements/Expandable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ class Expandable extends Component {
};

render() {
const { title, } = this.props;
const { title, ...rest } = this.props;
const { opened, } = this.state;
return (<div className={'Expandable' + (opened ? ' opened' : '')}>
return (<div className={'Expandable' + (opened ? ' opened' : '')} {...rest}>
<div className='Expander' onClick={this.onToggleExpander}>
<Icon name={opened ? 'chevron-up-circle' : 'chevron-down-circle'} size='2x' />
<h5 style={{ paddingLeft: '0.5rem', }}>{title}</h5>
Expand Down
17 changes: 15 additions & 2 deletions app/components/elements/Memo.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { connect, } from 'react-redux';
import tt from 'counterpart';
import { memo, } from 'golos-lib-js';
import { Link, } from 'react-router';
import links from 'app/utils/Links';

import links from 'app/utils/Links'
import shouldComponentUpdate from 'app/utils/shouldComponentUpdate'
import { validate_account_name, } from 'app/utils/ChainValidation'
import user from 'app/redux/User';
import user from 'app/redux/User'
import { blogsUrl } from 'app/utils/blogsUtils'

class Memo extends React.Component {
static propTypes = {
Expand Down Expand Up @@ -36,6 +38,17 @@ class Memo extends React.Component {
const sections = []
let idx = 0
if (!text || (typeof text.split !== 'function')) return
const isNftPost = text.startsWith('Post: ')
const isNftComment = !isNftPost && text.startsWith('Comment: ')
if (isNftPost || isNftComment) {
sections.push((isNftPost ? tt('g.for_the_post') : tt('g.for_the_comment')) + ': ')
const link = text.split(' ')[1]
let linkText = link
const truncateText = isNftPost ? 50 : 40
if (linkText.length > truncateText) linkText = linkText.substr(0, truncateText) + '...'
sections.push(<a key={idx++} href={blogsUrl(link)} target='_blank' rel='nofollow noreferrer'>{linkText}&nbsp;</a>)
return sections
}
for (let section of text.split(' ')) {
if (section.trim().length === 0) continue
const matchUserName = section.match(/(^|\s)(@[a-z][-\.a-z\d]+[a-z\d])/i)
Expand Down
50 changes: 50 additions & 0 deletions app/components/elements/forms/AmountAssetField.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react'
import { Field, } from 'formik'
import { Asset, AssetEditor, } from 'golos-lib-js/lib/utils'

class AmountAssetField extends React.Component {
static defaultProps = {
amountField: 'amount',
}

onChange = (e) => {
const { amountField, values, setFieldValue, assets } = this.props
const value = e.target.value
const asset = assets[value]
if (asset) {
const { supply } = asset
const oldValue = values[amountField].asset
setFieldValue(amountField, AssetEditor(oldValue.amount,
supply.precision, supply.symbol))

if (!values.author) { // if not edit mode
if (asset.allow_override_transfer || value === 'GBG') {
if (values.tip_cost)
setFieldValue('tip_cost', false)
setFieldValue('disable_tip', true)
} else {
setFieldValue('disable_tip', false)
}
}
}
}

render() {
const { name, assets, values, amountField } = this.props

const options = []
for (const [ sym, asset ] of Object.entries(assets)) {
options.push(<option value={sym}>{sym}</option>)
}

const { asset } = values[amountField]

return (<Field name={name} as='select' value={asset.symbol} onChange={this.onChange}
style={{ minWidth: '5rem', height: 'inherit', backgroundColor: 'transparent', border: 'none' }}
autoComplete='off' autoCorrect='off' spellCheck='false'>
{options}
</Field>)
}
}

export default AmountAssetField
21 changes: 14 additions & 7 deletions app/components/elements/forms/AmountField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,33 @@ import { Field, ErrorMessage, } from 'formik'
import { AssetEditor } from 'golos-lib-js/lib/utils'

class AmountField extends React.Component {
static defaultProps = {
name: 'amount',
}

_renderInput = ({ field, form }) => {
const { value, ...rest } = field
// TODO: is it right to pass all props to input
const { placeholder, name, ...rest } = this.props
const { value, } = field
const { values, setFieldValue } = form
return <input type='text' value={value.amountStr}
return <input type='text' value={value.amountStr} placeholder={placeholder}
{...rest} onChange={(e) => this.onChange(e, values, setFieldValue)}
/>
}

onChange = (e, values, setFieldValue) => {
const newAmount = values.amount.withChange(e.target.value)
const { name } = this.props
const newAmount = values[name].withChange(e.target.value)
if (newAmount.hasChange && newAmount.asset.amount >= 0) {
setFieldValue('amount', newAmount)
setFieldValue(name, newAmount)
}
}

render() {
const { placeholder, } = this.props
return (<Field name='amount' type='text'
const { placeholder, name, ...rest } = this.props
return (<Field name={name} type='text'
placeholder={placeholder}
autoComplete='off' autoCorrect='off' spellCheck='false'>
autoComplete='off' autoCorrect='off' spellCheck='false' {...rest}>
{this._renderInput}
</Field>)
}
Expand Down
Loading

0 comments on commit a8c89ad

Please sign in to comment.