mirror of
https://github.com/ascribe/onion.git
synced 2024-12-23 01:39:36 +01:00
Merge remote-tracking branch 'origin/AD-419-decouple-piece-registration-from-' into AD-551-work-on-burn-down-list
This commit is contained in:
commit
0642185087
@ -68,22 +68,22 @@ let AccordionListItemEditionWidget = React.createClass({
|
||||
let numEditions = piece.num_editions;
|
||||
|
||||
if(numEditions === 1) {
|
||||
let firstEditionId = piece && piece.firstEdition ? ', ' + piece.firstEdition.bitcoin_id : '';
|
||||
//let firstEditionId = piece && piece.firstEdition ? ', ' + piece.firstEdition.bitcoin_id : '';
|
||||
let editionMapping = piece && piece.firstEdition ? piece.firstEdition.edition_number + '/' + piece.num_editions : '';
|
||||
|
||||
return (
|
||||
<span
|
||||
onClick={this.toggleTable}
|
||||
className="ascribe-accordion-list-item-edition-widget pull-right">
|
||||
{this.getGlyphicon()} {editionMapping + ' ' + getLangText('Edition') + firstEditionId}
|
||||
className="ascribe-accordion-list-item-edition-widget">
|
||||
{', ' + editionMapping + ' ' + getLangText('Edition')} {this.getGlyphicon()}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<span
|
||||
onClick={this.toggleTable}
|
||||
className="ascribe-accordion-list-item-edition-widget pull-right">
|
||||
{this.getGlyphicon()} {numEditions + ' ' + getLangText('Editions')}
|
||||
className="ascribe-accordion-list-item-edition-widget">
|
||||
{', ' + numEditions + ' ' + getLangText('Editions')} {this.getGlyphicon()}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
38
js/components/ascribe_collapsible/collapsible_button.js
Normal file
38
js/components/ascribe_collapsible/collapsible_button.js
Normal file
@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
let CollapsibleButton = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
panel: React.PropTypes.object,
|
||||
button: React.PropTypes.object,
|
||||
children: React.PropTypes.oneOfType([
|
||||
React.PropTypes.object,
|
||||
React.PropTypes.array
|
||||
])
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {expanded: false};
|
||||
},
|
||||
handleToggle(e){
|
||||
e.preventDefault();
|
||||
this.setState({expanded: !this.state.expanded});
|
||||
},
|
||||
render() {
|
||||
let isVisible = (this.state.expanded) ? '' : 'invisible';
|
||||
return (
|
||||
<span>
|
||||
<span onClick={this.handleToggle}>
|
||||
{this.props.button}
|
||||
</span>
|
||||
<div ref='panel' className={isVisible}>
|
||||
{this.props.panel}
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default CollapsibleButton;
|
55
js/components/ascribe_detail/detail_property.js
Normal file
55
js/components/ascribe_detail/detail_property.js
Normal file
@ -0,0 +1,55 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
let DetailProperty = React.createClass({
|
||||
propTypes: {
|
||||
label: React.PropTypes.string,
|
||||
value: React.PropTypes.oneOfType([
|
||||
React.PropTypes.string,
|
||||
React.PropTypes.element
|
||||
]),
|
||||
separator: React.PropTypes.string,
|
||||
labelClassName: React.PropTypes.string,
|
||||
valueClassName: React.PropTypes.string
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
separator: ':',
|
||||
labelClassName: 'col-xs-5 col-sm-4 col-md-3 col-lg-3',
|
||||
valueClassName: 'col-xs-7 col-sm-8 col-md-9 col-lg-9'
|
||||
};
|
||||
},
|
||||
|
||||
render() {
|
||||
let value = this.props.value;
|
||||
if (this.props.children){
|
||||
value = (
|
||||
<div className="row-same-height">
|
||||
<div className="col-xs-6 col-xs-height col-bottom no-padding">
|
||||
{ this.props.value }
|
||||
</div>
|
||||
<div className="col-xs-6 col-xs-height">
|
||||
{ this.props.children }
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
return (
|
||||
<div className="row ascribe-detail-property">
|
||||
<div className="row-same-height">
|
||||
<div className={this.props.labelClassName + ' col-xs-height col-bottom'}>
|
||||
<div>{ this.props.label + this.props.separator}</div>
|
||||
</div>
|
||||
<div className={this.props.valueClassName + ' col-xs-height col-bottom'}>
|
||||
{value}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
export default DetailProperty;
|
@ -8,35 +8,38 @@ import Col from 'react-bootstrap/lib/Col';
|
||||
import Button from 'react-bootstrap/lib/Button';
|
||||
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
||||
|
||||
import UserActions from '../actions/user_actions';
|
||||
import UserStore from '../stores/user_store';
|
||||
import CoaActions from '../actions/coa_actions';
|
||||
import CoaStore from '../stores/coa_store';
|
||||
import UserActions from '../../actions/user_actions';
|
||||
import UserStore from '../../stores/user_store';
|
||||
import CoaActions from '../../actions/coa_actions';
|
||||
import CoaStore from '../../stores/coa_store';
|
||||
|
||||
import MediaPlayer from './ascribe_media/media_player';
|
||||
import MediaContainer from './media_container';
|
||||
|
||||
import CollapsibleParagraph from './ascribe_collapsible/collapsible_paragraph';
|
||||
import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph';
|
||||
|
||||
import Form from './ascribe_forms/form';
|
||||
import Property from './ascribe_forms/property';
|
||||
import InputTextAreaToggable from './ascribe_forms/input_textarea_toggable';
|
||||
import Form from './../ascribe_forms/form';
|
||||
import Property from './../ascribe_forms/property';
|
||||
import EditionDetailProperty from './detail_property';
|
||||
import InputTextAreaToggable from './../ascribe_forms/input_textarea_toggable';
|
||||
|
||||
import PieceExtraDataForm from './ascribe_forms/form_piece_extradata';
|
||||
import RequestActionForm from './ascribe_forms/form_request_action';
|
||||
import EditionHeader from './header';
|
||||
import EditionFurtherDetails from './further_details';
|
||||
|
||||
import EditionActions from '../actions/edition_actions';
|
||||
import AclButtonList from './ascribe_buttons/acl_button_list';
|
||||
//import PieceExtraDataForm from './../ascribe_forms/form_piece_extradata';
|
||||
import RequestActionForm from './../ascribe_forms/form_request_action';
|
||||
import EditionActions from '../../actions/edition_actions';
|
||||
import AclButtonList from './../ascribe_buttons/acl_button_list';
|
||||
|
||||
import ReactS3FineUploader from './ascribe_uploader/react_s3_fine_uploader';
|
||||
//import ReactS3FineUploader from './../ascribe_uploader/react_s3_fine_uploader';
|
||||
|
||||
import GlobalNotificationModel from '../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../actions/global_notification_actions';
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
|
||||
import apiUrls from '../constants/api_urls';
|
||||
import AppConstants from '../constants/application_constants';
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
|
||||
import { getCookie } from '../utils/fetch_api_utils';
|
||||
import { getLangText } from '../utils/lang_utils';
|
||||
import { getCookie } from '../../utils/fetch_api_utils';
|
||||
import { getLangText } from '../../utils/lang_utils';
|
||||
|
||||
let Link = Router.Link;
|
||||
/**
|
||||
@ -69,14 +72,41 @@ let Edition = React.createClass({
|
||||
return (
|
||||
<Row>
|
||||
<Col md={6}>
|
||||
<MediaContainer edition={this.props.edition}/>
|
||||
<MediaContainer
|
||||
content={this.props.edition}/>
|
||||
</Col>
|
||||
<Col md={6} className="ascribe-edition-details">
|
||||
<EditionHeader edition={this.props.edition}/>
|
||||
<EditionHeader content={this.props.edition}/>
|
||||
<EditionSummary
|
||||
currentUser={this.state.currentUser}
|
||||
edition={this.props.edition} />
|
||||
|
||||
<CollapsibleParagraph
|
||||
title="Notes"
|
||||
show={(this.state.currentUser.username && true || false) ||
|
||||
(this.props.edition.acl.indexOf('edit') > -1 || this.props.edition.public_note)}>
|
||||
<EditionPersonalNote
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.loadEdition}
|
||||
edition={this.props.edition}/>
|
||||
<EditionPublicEditionNote
|
||||
handleSuccess={this.props.loadEdition}
|
||||
edition={this.props.edition}/>
|
||||
</CollapsibleParagraph>
|
||||
|
||||
<CollapsibleParagraph
|
||||
title={getLangText('Further Details')}
|
||||
show={this.props.edition.acl.indexOf('edit') > -1
|
||||
|| Object.keys(this.props.edition.extra_data).length > 0
|
||||
|| this.props.edition.other_data !== null}>
|
||||
<EditionFurtherDetails
|
||||
editable={this.props.edition.acl.indexOf('edit') > -1}
|
||||
pieceId={this.props.edition.parent}
|
||||
extraData={this.props.edition.extra_data}
|
||||
otherData={this.props.edition.other_data}
|
||||
handleSuccess={this.props.loadEdition}/>
|
||||
</CollapsibleParagraph>
|
||||
|
||||
<CollapsibleParagraph
|
||||
title={getLangText('Certificate of Authenticity')}
|
||||
show={this.props.edition.acl.indexOf('coa') > -1}>
|
||||
@ -110,138 +140,12 @@ let Edition = React.createClass({
|
||||
<SpoolDetails
|
||||
edition={this.props.edition} />
|
||||
</CollapsibleParagraph>
|
||||
|
||||
<CollapsibleParagraph
|
||||
title="Notes"
|
||||
show={(this.state.currentUser.username && true || false) ||
|
||||
(this.props.edition.acl.indexOf('edit') > -1 || this.props.edition.public_note)}>
|
||||
<EditionPersonalNote
|
||||
currentUser={this.state.currentUser}
|
||||
handleSuccess={this.props.loadEdition}
|
||||
edition={this.props.edition}/>
|
||||
<EditionPublicEditionNote
|
||||
handleSuccess={this.props.loadEdition}
|
||||
edition={this.props.edition}/>
|
||||
</CollapsibleParagraph>
|
||||
|
||||
<CollapsibleParagraph
|
||||
title={getLangText('Further Details')}
|
||||
show={this.props.edition.acl.indexOf('edit') > -1
|
||||
|| Object.keys(this.props.edition.extra_data).length > 0
|
||||
|| this.props.edition.other_data !== null}>
|
||||
<EditionFurtherDetails
|
||||
handleSuccess={this.props.loadEdition}
|
||||
edition={this.props.edition}/>
|
||||
</CollapsibleParagraph>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let MediaContainer = React.createClass({
|
||||
propTypes: {
|
||||
edition: React.PropTypes.object
|
||||
},
|
||||
|
||||
render() {
|
||||
let thumbnail = this.props.edition.thumbnail;
|
||||
let mimetype = this.props.edition.digital_work.mime;
|
||||
let embed = null;
|
||||
let extraData = null;
|
||||
let encodingStatus = this.props.edition.digital_work.isEncoding;
|
||||
|
||||
if (this.props.edition.digital_work.encoding_urls) {
|
||||
extraData = this.props.edition.digital_work.encoding_urls.map(e => { return { url: e.url, type: e.label }; });
|
||||
}
|
||||
|
||||
if (['video', 'audio'].indexOf(mimetype) > -1){
|
||||
embed = (
|
||||
<CollapsibleButton
|
||||
button={
|
||||
<Button bsSize="xsmall" className="ascribe-margin-1px">
|
||||
Embed
|
||||
</Button>
|
||||
}
|
||||
panel={
|
||||
<pre className="">
|
||||
{'<iframe width="560" height="315" src="http://embed.ascribe.io/edition/'
|
||||
+ this.props.edition.bitcoin_id + '" frameborder="0" allowfullscreen></iframe>'
|
||||
}
|
||||
</pre>
|
||||
}/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<MediaPlayer mimetype={mimetype}
|
||||
preview={thumbnail}
|
||||
url={this.props.edition.digital_work.url}
|
||||
extraData={extraData}
|
||||
encodingStatus={encodingStatus} />
|
||||
<p className="text-center">
|
||||
<Button bsSize="xsmall" className="ascribe-margin-1px" href={this.props.edition.digital_work.url} target="_blank">
|
||||
{getLangText('Download')} <Glyphicon glyph="cloud-download"/>
|
||||
</Button>
|
||||
{embed}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const CollapsibleButton = React.createClass({
|
||||
|
||||
propTypes: {
|
||||
button: React.PropTypes.object,
|
||||
children: React.PropTypes.oneOfType([
|
||||
React.PropTypes.object,
|
||||
React.PropTypes.array
|
||||
])
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {expanded: false};
|
||||
},
|
||||
handleToggle(e){
|
||||
e.preventDefault();
|
||||
this.setState({expanded: !this.state.expanded});
|
||||
},
|
||||
render() {
|
||||
let isVisible = (this.state.expanded) ? '' : 'invisible';
|
||||
return (
|
||||
<span>
|
||||
<span onClick={this.handleToggle}>
|
||||
{this.props.button}
|
||||
</span>
|
||||
<div ref='panel' className={isVisible}>
|
||||
{this.props.panel}
|
||||
</div>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let EditionHeader = React.createClass({
|
||||
propTypes: {
|
||||
edition: React.PropTypes.object
|
||||
},
|
||||
|
||||
render() {
|
||||
var titleHtml = <div className="ascribe-detail-title">{this.props.edition.title}</div>;
|
||||
return (
|
||||
<div className="ascribe-detail-header">
|
||||
<EditionDetailProperty label={getLangText('TITLE')} value={titleHtml} />
|
||||
<EditionDetailProperty label={getLangText('BY')} value={this.props.edition.artist_name} />
|
||||
<EditionDetailProperty label={getLangText('DATE')} value={ this.props.edition.date_created.slice(0, 4) } />
|
||||
<hr/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let EditionSummary = React.createClass({
|
||||
propTypes: {
|
||||
@ -259,28 +163,31 @@ let EditionSummary = React.createClass({
|
||||
let notification = new GlobalNotificationModel(response.notification, 'success');
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
},
|
||||
render() {
|
||||
getStatus(){
|
||||
let status = null;
|
||||
if (this.props.edition.status.length > 0){
|
||||
let statusStr = this.props.edition.status.join().replace(/_/, ' ');
|
||||
status = <EditionDetailProperty label={getLangText('STATUS')} value={ statusStr }/>;
|
||||
status = <EditionDetailProperty label="STATUS" value={ statusStr }/>;
|
||||
if (this.props.edition.pending_new_owner && this.props.edition.acl.indexOf('withdraw_transfer') > -1){
|
||||
status = (
|
||||
<Form
|
||||
url={apiUrls.ownership_transfers_withdraw}
|
||||
getFormData={this.getTransferWithdrawData}
|
||||
handleSuccess={this.showNotification}>
|
||||
<EditionDetailProperty label={getLangText('STATUS')} value={ statusStr }>
|
||||
<EditionDetailProperty label="STATUS" value={ statusStr }>
|
||||
<button
|
||||
type="submit"
|
||||
className="pull-right btn btn-default btn-sm">
|
||||
{getLangText('WITHDRAW')}
|
||||
WITHDRAW
|
||||
</button>
|
||||
</EditionDetailProperty>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
},
|
||||
getActions(){
|
||||
let actions = null;
|
||||
if (this.props.edition.request_action && this.props.edition.request_action.length > 0){
|
||||
actions = (
|
||||
@ -300,16 +207,18 @@ let EditionSummary = React.createClass({
|
||||
</Col>
|
||||
</Row>);
|
||||
}
|
||||
|
||||
return actions;
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<div className="ascribe-detail-header">
|
||||
<EditionDetailProperty label={getLangText('EDITION')}
|
||||
value={this.props.edition.edition_number + ' ' + getLangText('of') + ' ' + this.props.edition.num_editions} />
|
||||
<EditionDetailProperty label={getLangText('ID')} value={ this.props.edition.bitcoin_id } />
|
||||
<EditionDetailProperty label={getLangText('OWNER')} value={ this.props.edition.owner } />
|
||||
{status}
|
||||
{this.getStatus()}
|
||||
<br/>
|
||||
{actions}
|
||||
{this.getActions()}
|
||||
<hr/>
|
||||
</div>
|
||||
);
|
||||
@ -318,55 +227,6 @@ let EditionSummary = React.createClass({
|
||||
});
|
||||
|
||||
|
||||
let EditionDetailProperty = React.createClass({
|
||||
propTypes: {
|
||||
label: React.PropTypes.string,
|
||||
value: React.PropTypes.oneOfType([
|
||||
React.PropTypes.string,
|
||||
React.PropTypes.element
|
||||
]),
|
||||
separator: React.PropTypes.string,
|
||||
labelClassName: React.PropTypes.string,
|
||||
valueClassName: React.PropTypes.string,
|
||||
children: React.PropTypes.arrayOf(React.PropTypes.element)
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
return {
|
||||
separator: ':',
|
||||
labelClassName: 'col-xs-5 col-sm-4 col-md-3 col-lg-3',
|
||||
valueClassName: 'col-xs-7 col-sm-8 col-md-9 col-lg-9'
|
||||
};
|
||||
},
|
||||
|
||||
render() {
|
||||
let value = this.props.value;
|
||||
if (this.props.children){
|
||||
value = (
|
||||
<div className="row-same-height">
|
||||
<div className="col-xs-6 col-xs-height col-bottom no-padding">
|
||||
{ this.props.value }
|
||||
</div>
|
||||
<div className="col-xs-6 col-xs-height">
|
||||
{ this.props.children }
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
return (
|
||||
<div className="row ascribe-detail-property">
|
||||
<div className="row-same-height">
|
||||
<div className={this.props.labelClassName + ' col-xs-height col-bottom'}>
|
||||
<div>{ this.props.label + this.props.separator}</div>
|
||||
</div>
|
||||
<div className={this.props.valueClassName + ' col-xs-height col-bottom'}>
|
||||
{value}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let EditionDetailHistoryIterator = React.createClass({
|
||||
propTypes: {
|
||||
history: React.PropTypes.array
|
||||
@ -471,157 +331,6 @@ let EditionPublicEditionNote = React.createClass({
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let EditionFurtherDetails = React.createClass({
|
||||
propTypes: {
|
||||
edition: React.PropTypes.object,
|
||||
handleSuccess: React.PropTypes.func
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
loading: false
|
||||
};
|
||||
},
|
||||
|
||||
showNotification(){
|
||||
this.props.handleSuccess();
|
||||
let notification = new GlobalNotificationModel(getLangText('Details updated'), 'success');
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
},
|
||||
|
||||
submitKey(key){
|
||||
this.setState({
|
||||
otherDataKey: key
|
||||
});
|
||||
},
|
||||
|
||||
setIsUploadReady(isReady) {
|
||||
this.setState({
|
||||
isUploadReady: isReady
|
||||
});
|
||||
},
|
||||
|
||||
isReadyForFormSubmission(files) {
|
||||
files = files.filter((file) => file.status !== 'deleted' && file.status !== 'canceled');
|
||||
if(files.length > 0 && files[0].status === 'upload successful') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
let editable = this.props.edition.acl.indexOf('edit') > -1;
|
||||
|
||||
return (
|
||||
<Row>
|
||||
<Col md={12} className="ascribe-edition-personal-note">
|
||||
<PieceExtraDataForm
|
||||
name='artist_contact_info'
|
||||
title={getLangText('Artist Contact Info')}
|
||||
handleSuccess={this.showNotification}
|
||||
editable={editable}
|
||||
edition={this.props.edition} />
|
||||
<PieceExtraDataForm
|
||||
name='display_instructions'
|
||||
title={getLangText('Display Instructions')}
|
||||
handleSuccess={this.showNotification}
|
||||
editable={editable}
|
||||
edition={this.props.edition} />
|
||||
<PieceExtraDataForm
|
||||
name='technology_details'
|
||||
title={getLangText('Technology Details')}
|
||||
handleSuccess={this.showNotification}
|
||||
editable={editable}
|
||||
edition={this.props.edition} />
|
||||
<FileUploader
|
||||
submitKey={this.submitKey}
|
||||
setIsUploadReady={this.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.isReadyForFormSubmission}
|
||||
editable={editable}
|
||||
edition={this.props.edition}/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let FileUploader = React.createClass({
|
||||
propTypes: {
|
||||
edition: React.PropTypes.object,
|
||||
setIsUploadReady: React.PropTypes.func,
|
||||
submitKey: React.PropTypes.func,
|
||||
isReadyForFormSubmission: React.PropTypes.func,
|
||||
editable: React.PropTypes.bool
|
||||
},
|
||||
|
||||
render() {
|
||||
// Essentially there a three cases important to the fileuploader
|
||||
//
|
||||
// 1. there is no other_data => do not show the fileuploader at all
|
||||
// 2. there is other_data, but user has no edit rights => show fileuploader but without action buttons
|
||||
// 3. both other_data and editable are defined or true => show fileuploade with all action buttons
|
||||
if (!this.props.editable && !this.props.edition.other_data){
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Form>
|
||||
<Property
|
||||
label={getLangText('Additional files')}>
|
||||
<ReactS3FineUploader
|
||||
keyRoutine={{
|
||||
url: AppConstants.serverUrl + 's3/key/',
|
||||
fileClass: 'otherdata',
|
||||
bitcoinId: this.props.edition.bitcoin_id
|
||||
}}
|
||||
createBlobRoutine={{
|
||||
url: apiUrls.blob_otherdatas,
|
||||
bitcoinId: this.props.edition.bitcoin_id
|
||||
}}
|
||||
validation={{
|
||||
itemLimit: 100000,
|
||||
sizeLimit: '10000000'
|
||||
}}
|
||||
submitKey={this.props.submitKey}
|
||||
setIsUploadReady={this.props.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.props.isReadyForFormSubmission}
|
||||
session={{
|
||||
endpoint: AppConstants.serverUrl + 'api/blob/otherdatas/fineuploader_session/',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
},
|
||||
params: {
|
||||
'pk': this.props.edition.other_data ? this.props.edition.other_data.id : null
|
||||
},
|
||||
cors: {
|
||||
expected: true,
|
||||
sendCredentials: true
|
||||
}
|
||||
}}
|
||||
signature={{
|
||||
endpoint: AppConstants.serverUrl + 's3/signature/',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
}}
|
||||
deleteFile={{
|
||||
enabled: true,
|
||||
method: 'DELETE',
|
||||
endpoint: AppConstants.serverUrl + 's3/delete',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
}}
|
||||
areAssetsDownloadable={true}
|
||||
areAssetsEditable={this.props.editable}/>
|
||||
</Property>
|
||||
<hr />
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let CoaDetails = React.createClass({
|
||||
propTypes: {
|
||||
edition: React.PropTypes.object
|
@ -2,8 +2,8 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import EditionActions from '../actions/edition_actions';
|
||||
import EditionStore from '../stores/edition_store';
|
||||
import EditionActions from '../../actions/edition_actions';
|
||||
import EditionStore from '../../stores/edition_store';
|
||||
|
||||
import Edition from './edition';
|
||||
|
182
js/components/ascribe_detail/further_details.js
Normal file
182
js/components/ascribe_detail/further_details.js
Normal file
@ -0,0 +1,182 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import Row from 'react-bootstrap/lib/Row';
|
||||
import Col from 'react-bootstrap/lib/Col';
|
||||
|
||||
|
||||
import Form from './../ascribe_forms/form';
|
||||
import Property from './../ascribe_forms/property';
|
||||
|
||||
import PieceExtraDataForm from './../ascribe_forms/form_piece_extradata';
|
||||
|
||||
import ReactS3FineUploader from './../ascribe_uploader/react_s3_fine_uploader';
|
||||
|
||||
import GlobalNotificationModel from '../../models/global_notification_model';
|
||||
import GlobalNotificationActions from '../../actions/global_notification_actions';
|
||||
|
||||
import apiUrls from '../../constants/api_urls';
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
|
||||
import { getCookie } from '../../utils/fetch_api_utils';
|
||||
|
||||
let FurtherDetails = React.createClass({
|
||||
propTypes: {
|
||||
editable: React.PropTypes.bool,
|
||||
pieceId: React.PropTypes.int,
|
||||
extraData: React.PropTypes.object,
|
||||
otherData: React.PropTypes.object,
|
||||
handleSuccess: React.PropTypes.func
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
loading: false
|
||||
};
|
||||
},
|
||||
|
||||
showNotification(){
|
||||
this.props.handleSuccess();
|
||||
let notification = new GlobalNotificationModel('Details updated', 'success');
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
},
|
||||
|
||||
submitKey(key){
|
||||
this.setState({
|
||||
otherDataKey: key
|
||||
});
|
||||
},
|
||||
|
||||
setIsUploadReady(isReady) {
|
||||
this.setState({
|
||||
isUploadReady: isReady
|
||||
});
|
||||
},
|
||||
|
||||
isReadyForFormSubmission(files) {
|
||||
files = files.filter((file) => file.status !== 'deleted' && file.status !== 'canceled');
|
||||
if(files.length > 0 && files[0].status === 'upload successful') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
//return (<span />);
|
||||
return (
|
||||
<Row>
|
||||
<Col md={12} className="ascribe-edition-personal-note">
|
||||
<PieceExtraDataForm
|
||||
name='artist_contact_info'
|
||||
title='Artist Contact Info'
|
||||
handleSuccess={this.showNotification}
|
||||
editable={this.props.editable}
|
||||
pieceId={this.props.pieceId}
|
||||
extraData={this.props.extraData}
|
||||
/>
|
||||
<PieceExtraDataForm
|
||||
name='display_instructions'
|
||||
title='Display Instructions'
|
||||
handleSuccess={this.showNotification}
|
||||
editable={this.props.editable}
|
||||
pieceId={this.props.pieceId}
|
||||
extraData={this.props.extraData} />
|
||||
<PieceExtraDataForm
|
||||
name='technology_details'
|
||||
title='Technology Details'
|
||||
handleSuccess={this.showNotification}
|
||||
editable={this.props.editable}
|
||||
pieceId={this.props.pieceId}
|
||||
extraData={this.props.extraData} />
|
||||
<FileUploader
|
||||
submitKey={this.submitKey}
|
||||
setIsUploadReady={this.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.isReadyForFormSubmission}
|
||||
editable={this.props.editable}
|
||||
pieceId={this.props.pieceId}
|
||||
otherData={this.props.otherData}/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
let FileUploader = React.createClass({
|
||||
propTypes: {
|
||||
pieceId: React.PropTypes.int,
|
||||
otherData: React.PropTypes.object,
|
||||
setIsUploadReady: React.PropTypes.func,
|
||||
submitKey: React.PropTypes.func,
|
||||
isReadyForFormSubmission: React.PropTypes.func,
|
||||
editable: React.PropTypes.bool
|
||||
},
|
||||
|
||||
render() {
|
||||
// Essentially there a three cases important to the fileuploader
|
||||
//
|
||||
// 1. there is no other_data => do not show the fileuploader at all
|
||||
// 2. there is other_data, but user has no edit rights => show fileuploader but without action buttons
|
||||
// 3. both other_data and editable are defined or true => show fileuploade with all action buttons
|
||||
if (!this.props.editable && !this.props.otherData){
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Form>
|
||||
<Property
|
||||
label="Additional files">
|
||||
<ReactS3FineUploader
|
||||
keyRoutine={{
|
||||
url: AppConstants.serverUrl + 's3/key/',
|
||||
fileClass: 'otherdata',
|
||||
pieceId: this.props.pieceId
|
||||
}}
|
||||
createBlobRoutine={{
|
||||
url: apiUrls.blob_otherdatas,
|
||||
pieceId: this.props.pieceId
|
||||
}}
|
||||
validation={{
|
||||
itemLimit: 100000,
|
||||
sizeLimit: '10000000'
|
||||
}}
|
||||
submitKey={this.props.submitKey}
|
||||
setIsUploadReady={this.props.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.props.isReadyForFormSubmission}
|
||||
session={{
|
||||
endpoint: AppConstants.serverUrl + 'api/blob/otherdatas/fineuploader_session/',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
},
|
||||
params: {
|
||||
'pk': this.props.otherData ? this.props.otherData.id : null
|
||||
},
|
||||
cors: {
|
||||
expected: true,
|
||||
sendCredentials: true
|
||||
}
|
||||
}}
|
||||
signature={{
|
||||
endpoint: AppConstants.serverUrl + 's3/signature/',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
}}
|
||||
deleteFile={{
|
||||
enabled: true,
|
||||
method: 'DELETE',
|
||||
endpoint: AppConstants.serverUrl + 's3/delete',
|
||||
customHeaders: {
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
}
|
||||
}}
|
||||
areAssetsDownloadable={true}
|
||||
areAssetsEditable={this.props.editable}/>
|
||||
</Property>
|
||||
<hr />
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default FurtherDetails;
|
26
js/components/ascribe_detail/header.js
Normal file
26
js/components/ascribe_detail/header.js
Normal file
@ -0,0 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import EditionDetailProperty from './detail_property';
|
||||
|
||||
|
||||
let Header = React.createClass({
|
||||
propTypes: {
|
||||
content: React.PropTypes.object
|
||||
},
|
||||
|
||||
render() {
|
||||
var titleHtml = <div className="ascribe-detail-title">{this.props.content.title}</div>;
|
||||
return (
|
||||
<div className="ascribe-detail-header">
|
||||
<EditionDetailProperty label="TITLE" value={titleHtml} />
|
||||
<EditionDetailProperty label="BY" value={this.props.content.artist_name} />
|
||||
<EditionDetailProperty label="DATE" value={ this.props.content.date_created.slice(0, 4) } />
|
||||
<hr/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default Header;
|
62
js/components/ascribe_detail/media_container.js
Normal file
62
js/components/ascribe_detail/media_container.js
Normal file
@ -0,0 +1,62 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import Button from 'react-bootstrap/lib/Button';
|
||||
import Glyphicon from 'react-bootstrap/lib/Glyphicon';
|
||||
|
||||
import MediaPlayer from './../ascribe_media/media_player';
|
||||
|
||||
import CollapsibleButton from './../ascribe_collapsible/collapsible_button';
|
||||
|
||||
|
||||
let MediaContainer = React.createClass({
|
||||
propTypes: {
|
||||
content: React.PropTypes.object
|
||||
},
|
||||
|
||||
render() {
|
||||
let thumbnail = this.props.content.thumbnail;
|
||||
let mimetype = this.props.content.digital_work.mime;
|
||||
let embed = null;
|
||||
let extraData = null;
|
||||
|
||||
if (this.props.content.digital_work.encoding_urls) {
|
||||
extraData = this.props.content.digital_work.encoding_urls.map(e => { return { url: e.url, type: e.label }; });
|
||||
}
|
||||
|
||||
if (['video', 'audio'].indexOf(mimetype) > -1){
|
||||
embed = (
|
||||
<CollapsibleButton
|
||||
button={
|
||||
<Button bsSize="xsmall" className="ascribe-margin-1px">
|
||||
Embed
|
||||
</Button>
|
||||
}
|
||||
panel={
|
||||
<pre className="">
|
||||
{'<iframe width="560" height="315" src="http://embed.ascribe.io/content/'
|
||||
+ this.props.content.bitcoin_id + '" frameborder="0" allowfullscreen></iframe>'
|
||||
}
|
||||
</pre>
|
||||
}/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<MediaPlayer mimetype={mimetype}
|
||||
preview={thumbnail}
|
||||
url={this.props.content.digital_work.url}
|
||||
extraData={extraData} />
|
||||
<p className="text-center">
|
||||
<Button bsSize="xsmall" className="ascribe-margin-1px" href={this.props.content.digital_work.url} target="_blank">
|
||||
Download <Glyphicon glyph="cloud-download"/>
|
||||
</Button>
|
||||
{embed}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default MediaContainer;
|
74
js/components/ascribe_detail/piece.js
Normal file
74
js/components/ascribe_detail/piece.js
Normal file
@ -0,0 +1,74 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import Row from 'react-bootstrap/lib/Row';
|
||||
import Col from 'react-bootstrap/lib/Col';
|
||||
|
||||
import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph';
|
||||
|
||||
import FurtherDetails from './further_details';
|
||||
//import UserActions from '../../actions/user_actions';
|
||||
//import UserStore from '../../stores/user_store';
|
||||
|
||||
import MediaContainer from './media_container';
|
||||
|
||||
import Header from './header';
|
||||
|
||||
/**
|
||||
* This is the component that implements display-specific functionality
|
||||
*/
|
||||
let Piece = React.createClass({
|
||||
propTypes: {
|
||||
piece: React.PropTypes.object,
|
||||
loadPiece: React.PropTypes.func
|
||||
},
|
||||
|
||||
//getInitialState() {
|
||||
// return UserStore.getState();
|
||||
//},
|
||||
//
|
||||
//componentDidMount() {
|
||||
// UserStore.listen(this.onChange);
|
||||
// UserActions.fetchCurrentUser();
|
||||
//},
|
||||
//
|
||||
//componentWillUnmount() {
|
||||
// UserStore.unlisten(this.onChange);
|
||||
//},
|
||||
//
|
||||
//onChange(state) {
|
||||
// this.setState(state);
|
||||
//},
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<Row>
|
||||
<Col md={6}>
|
||||
<MediaContainer
|
||||
content={this.props.piece}/>
|
||||
</Col>
|
||||
<Col md={6} className="ascribe-edition-details">
|
||||
<Header
|
||||
content={this.props.piece}/>
|
||||
<CollapsibleParagraph
|
||||
title="Further Details"
|
||||
show={this.props.piece.acl.indexOf('edit') > -1
|
||||
|| Object.keys(this.props.piece.extra_data).length > 0
|
||||
|| this.props.piece.other_data !== null}>
|
||||
<FurtherDetails
|
||||
editable={this.props.piece.acl.indexOf('edit') > -1}
|
||||
pieceId={this.props.piece.id}
|
||||
extraData={this.props.piece.extra_data}
|
||||
otherData={this.props.piece.other_data}
|
||||
handleSuccess={this.props.loadPiece}/>
|
||||
</CollapsibleParagraph>
|
||||
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default Piece;
|
57
js/components/ascribe_detail/piece_container.js
Normal file
57
js/components/ascribe_detail/piece_container.js
Normal file
@ -0,0 +1,57 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import PieceActions from '../../actions/piece_actions';
|
||||
import PieceStore from '../../stores/piece_store';
|
||||
|
||||
import Piece from './piece';
|
||||
|
||||
/**
|
||||
* This is the component that implements resource/data specific functionality
|
||||
*/
|
||||
let PieceContainer = React.createClass({
|
||||
getInitialState() {
|
||||
return PieceStore.getState();
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
PieceStore.listen(this.onChange);
|
||||
PieceActions.fetchOne(this.props.params.pieceId);
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
// Every time we're leaving the piece detail page,
|
||||
// just reset the piece that is saved in the piece store
|
||||
// as it will otherwise display wrong/old data once the user loads
|
||||
// the piece detail a second time
|
||||
PieceActions.updatePiece({});
|
||||
|
||||
PieceStore.unlisten(this.onChange);
|
||||
},
|
||||
|
||||
|
||||
loadPiece() {
|
||||
PieceActions.fetchOne(this.props.params.pieceId);
|
||||
},
|
||||
|
||||
render() {
|
||||
if('title' in this.state.piece) {
|
||||
return (
|
||||
<Piece
|
||||
piece={this.state.piece}
|
||||
loadPiece={this.loadPiece}/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<p>Loading</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default PieceContainer;
|
@ -13,7 +13,8 @@ import InputTextAreaToggable from './input_textarea_toggable';
|
||||
|
||||
let PieceExtraDataForm = React.createClass({
|
||||
propTypes: {
|
||||
edition: React.PropTypes.object,
|
||||
pieceId: React.PropTypes.int,
|
||||
extraData: React.PropTypes.object,
|
||||
handleSuccess: React.PropTypes.func,
|
||||
name: React.PropTypes.string,
|
||||
title: React.PropTypes.string,
|
||||
@ -23,16 +24,16 @@ let PieceExtraDataForm = React.createClass({
|
||||
let extradata = {};
|
||||
extradata[this.props.name] = this.refs.form.refs[this.props.name].state.value;
|
||||
return {
|
||||
bitcoin_id: this.props.edition.bitcoin_id,
|
||||
extradata: extradata
|
||||
extradata: extradata,
|
||||
piece_id: this.props.pieceId
|
||||
};
|
||||
},
|
||||
render() {
|
||||
let defaultValue = this.props.edition.extra_data[this.props.name] || '';
|
||||
let defaultValue = this.props.extraData[this.props.name] || '';
|
||||
if (defaultValue.length === 0 && !this.props.editable){
|
||||
return null;
|
||||
}
|
||||
let url = requests.prepareUrl(apiUrls.piece_extradata, {piece_id: this.props.edition.bitcoin_id});
|
||||
let url = requests.prepareUrl(apiUrls.piece_extradata, {piece_id: this.props.pieceId});
|
||||
return (
|
||||
<Form
|
||||
ref='form'
|
||||
@ -44,15 +45,12 @@ let PieceExtraDataForm = React.createClass({
|
||||
label={this.props.title}
|
||||
editable={this.props.editable}>
|
||||
<InputTextAreaToggable
|
||||
rows={3}
|
||||
rows={1}
|
||||
editable={this.props.editable}
|
||||
defaultValue={defaultValue}
|
||||
placeholder={getLangText('Fill in%s', ' ') + this.props.title}
|
||||
required/>
|
||||
</Property>
|
||||
<Property hidden={true} name='bitcoin_id'>
|
||||
<input defaultValue={this.props.edition.bitcoin_id}/>
|
||||
</Property>
|
||||
<hr />
|
||||
</Form>
|
||||
);
|
||||
|
@ -24,11 +24,11 @@ var ReactS3FineUploader = React.createClass({
|
||||
keyRoutine: React.PropTypes.shape({
|
||||
url: React.PropTypes.string,
|
||||
fileClass: React.PropTypes.string,
|
||||
bitcoinId: React.PropTypes.string
|
||||
pieceId: React.PropTypes.string
|
||||
}),
|
||||
createBlobRoutine: React.PropTypes.shape({
|
||||
url: React.PropTypes.string,
|
||||
bitcoinId: React.PropTypes.string
|
||||
pieceId: React.PropTypes.string
|
||||
}),
|
||||
submitKey: React.PropTypes.func,
|
||||
autoUpload: React.PropTypes.bool,
|
||||
@ -207,7 +207,7 @@ var ReactS3FineUploader = React.createClass({
|
||||
body: JSON.stringify({
|
||||
'filename': filename,
|
||||
'file_class': this.props.keyRoutine.fileClass,
|
||||
'bitcoin_id': this.props.keyRoutine.bitcoinId
|
||||
'piece_id': this.props.keyRoutine.pieceId
|
||||
})
|
||||
})
|
||||
.then((res) => {
|
||||
@ -276,7 +276,7 @@ var ReactS3FineUploader = React.createClass({
|
||||
body: JSON.stringify({
|
||||
'filename': file.name,
|
||||
'key': file.key,
|
||||
'bitcoin_id': this.props.createBlobRoutine.bitcoinId
|
||||
'bitcoin_id': this.props.createBlobRoutine.pieceId
|
||||
})
|
||||
})
|
||||
.then((res) => {
|
||||
|
@ -91,7 +91,7 @@ let PieceList = React.createClass({
|
||||
content={piece}
|
||||
key={i}>
|
||||
<AccordionListItemTableEditions
|
||||
className="ascribe-accordion-list-item-table col-xs-12 col-sm-8 col-md-6 col-lg-6 col-sm-offset-2 col-md-offset-3 col-lg-offset-3"
|
||||
className="ascribe-accordion-list-item-table col-xs-12 col-sm-10 col-md-8 col-lg-8 col-sm-offset-1 col-md-offset-2 col-lg-offset-2"
|
||||
parentId={piece.id} />
|
||||
</AccordionListItem>
|
||||
);
|
||||
|
@ -87,9 +87,14 @@ let RegisterPiece = React.createClass( {
|
||||
|
||||
// once the user was able to register a piece successfully, we need to make sure to keep
|
||||
// the piece list up to date
|
||||
PieceListActions.fetchPieceList(this.state.page, this.state.pageSize, this.state.searchTerm, this.state.orderBy, this.state.orderAsc);
|
||||
PieceListActions.fetchPieceList(
|
||||
this.state.page,
|
||||
this.state.pageSize,
|
||||
this.state.searchTerm,
|
||||
this.state.orderBy,
|
||||
this.state.orderAsc);
|
||||
|
||||
this.transitionTo('edition', {editionId: response.edition.bitcoin_id});
|
||||
this.transitionTo('piece', {editionId: response.piece.id});
|
||||
},
|
||||
|
||||
getFormData(){
|
||||
|
@ -30,7 +30,7 @@ let apiUrls = {
|
||||
'ownership_unconsigns': AppConstants.apiEndpoint + 'ownership/unconsigns/',
|
||||
'ownership_unconsigns_deny': AppConstants.apiEndpoint + 'ownership/unconsigns/deny/',
|
||||
'ownership_unconsigns_request': AppConstants.apiEndpoint + 'ownership/unconsigns/request/',
|
||||
'piece': AppConstants.apiEndpoint + 'pieces/${piece_id}',
|
||||
'piece': AppConstants.apiEndpoint + 'pieces/${piece_id}/',
|
||||
'piece_extradata': AppConstants.apiEndpoint + 'pieces/${piece_id}/extradata/',
|
||||
'piece_first_edition_id': AppConstants.apiEndpoint + 'pieces/${piece_id}/edition_index/',
|
||||
'pieces_list': AppConstants.apiEndpoint + 'pieces/',
|
||||
|
@ -5,11 +5,10 @@ import requests from '../utils/requests';
|
||||
|
||||
let PieceFetcher = {
|
||||
/**
|
||||
* Fetch one user from the API.
|
||||
* If no arg is supplied, load the current user
|
||||
* Fetch a piece from the API.
|
||||
*/
|
||||
fetchOne() {
|
||||
return requests.get('piece');
|
||||
fetchOne(id) {
|
||||
return requests.get('piece', {'piece_id': id});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -5,7 +5,8 @@ import Router from 'react-router';
|
||||
|
||||
import AscribeApp from './components/ascribe_app';
|
||||
import PieceList from './components/piece_list';
|
||||
import EditionContainer from './components/edition_container';
|
||||
import PieceContainer from './components/ascribe_detail/piece_container';
|
||||
import EditionContainer from './components/ascribe_detail/edition_container';
|
||||
|
||||
import LoginContainer from './components/login_container';
|
||||
import SignupContainer from './components/signup_container';
|
||||
@ -26,6 +27,7 @@ let routes = (
|
||||
<Route name="signup" path="signup" handler={SignupContainer} />
|
||||
<Route name="login" path="login" handler={LoginContainer} />
|
||||
<Route name="pieces" path="collection" handler={PieceList} />
|
||||
<Route name="piece" path="pieces/:pieceId" handler={PieceContainer} />
|
||||
<Route name="edition" path="editions/:editionId" handler={EditionContainer} />
|
||||
<Route name="password_reset" path="password_reset" handler={PasswordResetContainer} />
|
||||
<Route name="register_piece" path="register_piece" handler={RegisterPiece} />
|
||||
|
@ -88,7 +88,7 @@ $ascribe-accordion-list-font: 'Source Sans Pro';
|
||||
}
|
||||
}
|
||||
border-left: 3px solid rgba(0,0,0,0);
|
||||
border-bottom: 1px solid rgba(0,0,0,.1);
|
||||
border-bottom: 1px solid rgba(0,0,0,.05);
|
||||
}
|
||||
tbody {
|
||||
tr {
|
||||
@ -98,7 +98,7 @@ $ascribe-accordion-list-font: 'Source Sans Pro';
|
||||
border-left: 3px solid rgba(2, 182, 163, 0.4);
|
||||
}
|
||||
border-left: 3px solid rgba(0,0,0,0);
|
||||
border-bottom: 1px solid rgba(0,0,0,.05);
|
||||
border-bottom: 1px solid rgba(0,0,0,.03);
|
||||
td {
|
||||
border: none! important;
|
||||
a {
|
||||
@ -143,6 +143,7 @@ span.ascribe-accordion-list-table-toggle {
|
||||
|
||||
.ascribe-accordion-list-item-edition-widget {
|
||||
cursor: pointer;
|
||||
//margin-left: 0.3em;
|
||||
|
||||
&:hover {
|
||||
color: $ascribe-color-full;
|
||||
|
Loading…
Reference in New Issue
Block a user