1
0
mirror of https://github.com/ascribe/onion.git synced 2024-06-30 21:52:08 +02:00

Merge remote-tracking branch 'remotes/origin/AD-551-work-on-burn-down-list' into AD-419-decouple-piece-registration-from-

Conflicts:
	js/components/ascribe_detail/edition.js
This commit is contained in:
diminator 2015-07-09 14:59:16 +01:00
commit bf0a36f2a3
36 changed files with 664 additions and 198 deletions

View File

@ -4,12 +4,12 @@ import alt from '../alt';
import PieceListFetcher from '../fetchers/piece_list_fetcher'; import PieceListFetcher from '../fetchers/piece_list_fetcher';
class PieceListActions { class PieceListActions {
constructor() { constructor() {
this.generateActions( this.generateActions(
'updatePieceList', 'updatePieceList',
'updatePieceListRequestActions' 'updatePieceListRequestActions',
'addFirstEditionToPiece'
); );
} }
@ -32,6 +32,7 @@ class PieceListActions {
.catch((err) => reject(err)); .catch((err) => reject(err));
}); });
} }
fetchPieceRequestActions() { fetchPieceRequestActions() {
PieceListFetcher PieceListFetcher
.fetchRequestActions() .fetchRequestActions()
@ -40,6 +41,16 @@ class PieceListActions {
}); });
} }
fetchFirstEditionForPiece(pieceId) {
return new Promise((resolve, reject) => {
PieceListFetcher.fetchFirstEditionForPiece(pieceId)
.then((firstEdition) => {
this.actions.addFirstEditionToPiece({pieceId, firstEdition});
resolve();
})
.catch((err) => reject(err));
});
}
} }
export default alt.createActions(PieceListActions); export default alt.createActions(PieceListActions);

View File

@ -3,28 +3,36 @@
import React from 'react'; import React from 'react';
import Router from 'react-router'; import Router from 'react-router';
import PieceListStore from '../../stores/piece_list_store';
import PieceListActions from '../../actions/piece_list_actions';
import Glyphicon from 'react-bootstrap/lib/Glyphicon'; import Glyphicon from 'react-bootstrap/lib/Glyphicon';
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
import Tooltip from 'react-bootstrap/lib/Tooltip'; import Tooltip from 'react-bootstrap/lib/Tooltip';
import requests from '../../utils/requests'; import AccordionListItemEditionWidget from './accordion_list_item_edition_widget';
import { getLangText } from '../../utils/lang_utils'; import { getLangText } from '../../utils/lang_utils';
let AccordionListItem = React.createClass({ let AccordionListItem = React.createClass({
mixins: [Router.Navigation],
propTypes: { propTypes: {
className: React.PropTypes.string, className: React.PropTypes.string,
content: React.PropTypes.object, content: React.PropTypes.object,
children: React.PropTypes.object children: React.PropTypes.object
}, },
handleClick(event){
requests.get('piece_first_edition_id', {'piece_id': this.props.content.id})
.then((res) => this.transitionTo('edition', {editionId: res.bitcoin_id}));
console.log(event.target); mixins: [Router.Navigation],
componentDidMount() {
if(this.props.content.num_editions !== 0) {
PieceListActions.fetchFirstEditionForPiece(this.props.content.id);
}
}, },
onChange(state) {
this.setState(state);
},
getGlyphicon(){ getGlyphicon(){
if (this.props.content.requestAction){ if (this.props.content.requestAction){
return ( return (
@ -35,6 +43,7 @@ let AccordionListItem = React.createClass({
} }
return null; return null;
}, },
render() { render() {
return ( return (
<div className="row"> <div className="row">
@ -53,9 +62,12 @@ let AccordionListItem = React.createClass({
<h3>{getLangText('by %s', this.props.content.artist_name)}</h3> <h3>{getLangText('by %s', this.props.content.artist_name)}</h3>
<div> <div>
<span>{this.props.content.date_created.split('-')[0]}</span> <span>{this.props.content.date_created.split('-')[0]}</span>
<a href={this.props.content.license_type.url} target="_blank" className="pull-right"> <AccordionListItemEditionWidget
piece={this.props.content} />
{/* <a href={this.props.content.license_type.url} target="_blank" className="pull-right">
{getLangText('%s license', this.props.content.license_type.code)} {getLangText('%s license', this.props.content.license_type.code)}
</a> </a> */}
</div> </div>
</div> </div>
<span style={{'clear': 'both'}}></span> <span style={{'clear': 'both'}}></span>

View File

@ -0,0 +1,93 @@
'use strict';
import React from 'react';
import EditionListActions from '../../actions/edition_list_actions';
import EditionListStore from '../../stores/edition_list_store';
import { getLangText } from '../../utils/lang_utils';
import { mergeOptions } from '../../utils/general_utils';
let AccordionListItemEditionWidget = React.createClass({
propTypes: {
piece: React.PropTypes.object.isRequired
},
getInitialState() {
return EditionListStore.getState();
},
componentDidMount() {
EditionListStore.listen(this.onChange);
},
componentWillUnmount() {
EditionListStore.unlisten(this.onChange);
},
onChange(state) {
this.setState(state);
},
/**
* Calls the store to either show or hide the editionListTable
*/
toggleTable() {
let pieceId = this.props.piece.id;
let isEditionListOpen = this.state.isEditionListOpenForPieceId[pieceId] ? this.state.isEditionListOpenForPieceId[pieceId].show : false;
if(isEditionListOpen) {
EditionListActions.toggleEditionList(pieceId);
} else {
EditionListActions.toggleEditionList(pieceId);
EditionListActions.fetchEditionList(pieceId);
}
},
/**
* Depending on the state of isEditionListOpenForPieceId we either want to display
* a glyphicon arrow pointing upwards or downwards
*/
getGlyphicon() {
let pieceId = this.props.piece.id;
let isEditionListOpen = this.state.isEditionListOpenForPieceId[pieceId] ? this.state.isEditionListOpenForPieceId[pieceId].show : false;
if(isEditionListOpen) {
return (
<span className="glyphicon glyphicon-menu-up" aria-hidden="true" style={{top: 2}}></span>
);
} else {
return (
<span className="glyphicon glyphicon-menu-down" aria-hidden="true" style={{top: 2}}></span>
);
}
},
render() {
let piece = this.props.piece;
let numEditions = piece.num_editions;
if(numEditions === 1) {
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}
</span>
);
} else {
return (
<span
onClick={this.toggleTable}
className="ascribe-accordion-list-item-edition-widget pull-right">
{this.getGlyphicon()} {numEditions + ' ' + getLangText('Editions')}
</span>
);
}
}
});
export default AccordionListItemEditionWidget;

View File

@ -3,7 +3,7 @@
import React from 'react'; import React from 'react';
import Table from '../ascribe_table/table'; import Table from '../ascribe_table/table';
import TableItem from '../ascribe_table/table_item'; import TableItemSelectable from '../ascribe_table/table_item_selectable';
import { ColumnModel } from '../ascribe_table/models/table_models'; import { ColumnModel } from '../ascribe_table/models/table_models';
@ -16,7 +16,8 @@ let AccordionListItemTable = React.createClass({
show: React.PropTypes.bool, show: React.PropTypes.bool,
changeOrder: React.PropTypes.func, changeOrder: React.PropTypes.func,
orderBy: React.PropTypes.string, orderBy: React.PropTypes.string,
orderAsc: React.PropTypes.bool orderAsc: React.PropTypes.bool,
selectItem: React.PropTypes.func
}, },
render() { render() {
@ -32,9 +33,11 @@ let AccordionListItemTable = React.createClass({
orderAsc={this.props.orderAsc}> orderAsc={this.props.orderAsc}>
{this.props.itemList.map((item, i) => { {this.props.itemList.map((item, i) => {
return ( return (
<TableItem <TableItemSelectable
className="ascribe-table-item-selectable" className="ascribe-table-item-selectable"
key={i} /> key={i}
selectItem={this.props.selectItem}
parentId={this.props.parentId}/>
); );
})} })}
</Table> </Table>

View File

@ -69,16 +69,6 @@ let AccordionListItemTableEditions = React.createClass({
return selectedEditions; return selectedEditions;
}, },
toggleTable() {
let isEditionListOpen = this.state.isEditionListOpenForPieceId[this.props.parentId] ? this.state.isEditionListOpenForPieceId[this.props.parentId].show : false;
if(isEditionListOpen) {
EditionListActions.toggleEditionList(this.props.parentId);
} else {
EditionListActions.toggleEditionList(this.props.parentId);
EditionListActions.fetchEditionList(this.props.parentId);
}
},
loadFurtherEditions() { loadFurtherEditions() {
// trigger loading animation // trigger loading animation
this.setState({ this.setState({
@ -187,14 +177,14 @@ let AccordionListItemTableEditions = React.createClass({
) )
]; ];
let loadingSpinner = <span className="glyph-ascribe-spool-chunked ascribe-color spin"/> ; let loadingSpinner = <span className="glyph-ascribe-spool-chunked ascribe-color spin"/>;
return ( return (
<div className={this.props.className}> <div className={this.props.className}>
<AccordionListItemTableToggle {/* <AccordionListItemTableToggle
className="ascribe-accordion-list-table-toggle" className="ascribe-accordion-list-table-toggle"
onClick={this.toggleTable} onClick={this.toggleTable}
message={show && typeof editionsForPiece !== 'undefined' ? <span><span className="glyphicon glyphicon-menu-up" aria-hidden="true" style={{top: 2}}></span> {getLangText('Hide editions')}</span> : <span><span className="glyphicon glyphicon-menu-down" aria-hidden="true" style={{top: 2}}></span> {getLangText('Show editions')} {show && typeof editionsForPiece === 'undefined' ? loadingSpinner : null}</span>} /> message={show && typeof editionsForPiece !== 'undefined' ? <span><span className="glyphicon glyphicon-menu-up" aria-hidden="true" style={{top: 2}}></span> {getLangText('Hide editions')}</span> : <span><span className="glyphicon glyphicon-menu-down" aria-hidden="true" style={{top: 2}}></span> {getLangText('Show editions')} {show && typeof editionsForPiece === 'undefined' ? loadingSpinner : null}</span>} /> */}
<AccordionListItemTable <AccordionListItemTable
parentId={this.props.parentId} parentId={this.props.parentId}
itemList={editionsForPiece} itemList={editionsForPiece}
@ -202,7 +192,8 @@ let AccordionListItemTableEditions = React.createClass({
show={show} show={show}
orderBy={orderBy} orderBy={orderBy}
orderAsc={orderAsc} orderAsc={orderAsc}
changeOrder={this.changeEditionListOrder} /> changeOrder={this.changeEditionListOrder}
selectItem={this.selectItem}/>
<AccordionListItemTableToggle <AccordionListItemTableToggle
className="ascribe-accordion-list-table-toggle" className="ascribe-accordion-list-table-toggle"
onClick={this.loadFurtherEditions} onClick={this.loadFurtherEditions}

View File

@ -6,8 +6,6 @@ import CollapsibleMixin from 'react-bootstrap/lib/CollapsibleMixin';
import classNames from 'classnames'; import classNames from 'classnames';
import { getLangText } from '../../utils/lang_utils.js'
const CollapsibleParagraph = React.createClass({ const CollapsibleParagraph = React.createClass({
@ -43,13 +41,14 @@ const CollapsibleParagraph = React.createClass({
render() { render() {
let styles = this.getCollapsibleClassSet(); let styles = this.getCollapsibleClassSet();
let text = this.isExpanded() ? '[' + getLangText('hide') + ']' : '[' + getLangText('show') + ']'; let text = this.isExpanded() ? '-' : '+';
if(this.props.show) { if(this.props.show) {
return ( return (
<div className="ascribe-detail-header"> <div className="ascribe-detail-header">
<div className="ascribe-edition-collapsible-wrapper"> <div className="ascribe-edition-collapsible-wrapper">
<div onClick={this.handleToggle}> <div onClick={this.handleToggle}>
<span>{this.props.title}</span><span className="pull-right">{text}</span> <span>{text} {this.props.title}</span>
</div> </div>
<div ref='panel' className={classNames(styles) + ' ascribe-edition-collapible-content'}> <div ref='panel' className={classNames(styles) + ' ascribe-edition-collapible-content'}>
{this.props.children} {this.props.children}

View File

@ -39,6 +39,7 @@ import apiUrls from '../../constants/api_urls';
import AppConstants from '../../constants/application_constants'; import AppConstants from '../../constants/application_constants';
import { getCookie } from '../../utils/fetch_api_utils'; import { getCookie } from '../../utils/fetch_api_utils';
import { getLangText } from '../../utils/lang_utils';
let Link = Router.Link; let Link = Router.Link;
/** /**

View File

@ -17,10 +17,10 @@ let EditionContainer = React.createClass({
onChange(state) { onChange(state) {
this.setState(state); this.setState(state);
let isEncoding = state.edition.digital_work.isEncoding; let isEncoding = state.edition.digital_work ? state.edition.digital_work.isEncoding : null;
if (isEncoding !== undefined && isEncoding !== 100) { if (typeof isEncoding === 'number' && isEncoding !== 100 && !this.state.timerId) {
let timerId = window.setInterval(() => EditionActions.fetchOne(this.props.params.editionId), 10000); let timerId = window.setInterval(() => EditionActions.fetchOne(this.props.params.editionId), 10000);
this.setState({timerId: timerId}) this.setState({timerId: timerId});
} }
}, },

View File

@ -18,7 +18,8 @@ let Form = React.createClass({
children: React.PropTypes.oneOfType([ children: React.PropTypes.oneOfType([
React.PropTypes.object, React.PropTypes.object,
React.PropTypes.array React.PropTypes.array
]) ]),
className: React.PropTypes.string
}, },
getInitialState() { getInitialState() {
@ -141,10 +142,16 @@ let Form = React.createClass({
}); });
}, },
render() { render() {
let className = 'ascribe-form';
if(this.props.className) {
className += ' ' + this.props.className;
}
return ( return (
<form <form
role="form" role="form"
className="ascribe-form" className={className}
onSubmit={this.submit} onSubmit={this.submit}
autoComplete="on"> autoComplete="on">
{this.getErrors()} {this.getErrors()}

View File

@ -9,7 +9,7 @@ import ButtonSubmitOrClose from '../ascribe_buttons/button_submit_close';
import SignupModal from '../ascribe_modal/modal_signup'; import SignupModal from '../ascribe_modal/modal_signup';
import PasswordResetRequestModal from '../ascribe_modal/modal_password_request_reset'; import PasswordResetRequestModal from '../ascribe_modal/modal_password_request_reset';
import { getLangText } from '../../utils/lang_utils.js' import { getLangText } from '../../utils/lang_utils.js';
let LoginForm = React.createClass({ let LoginForm = React.createClass({
mixins: [FormMixin], mixins: [FormMixin],

View File

@ -0,0 +1,19 @@
'use strict';
import React from 'react';
let FormPropertyHeader = React.createClass({
propTypes: {
children: React.PropTypes.arrayOf(React.PropTypes.element)
},
render() {
return (
<div className="ascribe-form-header">
{this.props.children}
</div>
);
}
});
export default FormPropertyHeader;

View File

@ -0,0 +1,90 @@
'use strict';
import React from 'react';
import CollapsibleMixin from 'react-bootstrap/lib/CollapsibleMixin';
import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger';
import Tooltip from 'react-bootstrap/lib/Tooltip';
import classNames from 'classnames';
let PropertyCollapsile = React.createClass({
propTypes: {
children: React.PropTypes.arrayOf(React.PropTypes.element),
checkboxLabel: React.PropTypes.string,
tooltip: React.PropTypes.string
},
mixins: [CollapsibleMixin],
getInitialState() {
return {
show: false
};
},
getCollapsibleDOMNode(){
return React.findDOMNode(this.refs.panel);
},
getCollapsibleDimensionValue(){
return React.findDOMNode(this.refs.panel).scrollHeight;
},
handleFocus() {
this.refs.checkboxCollapsible.getDOMNode().checked = !this.refs.checkboxCollapsible.getDOMNode().checked;
this.setState({
show: this.refs.checkboxCollapsible.getDOMNode().checked
});
},
renderChildren() {
if(this.state.show) {
return (<div
className={classNames(this.getCollapsibleClassSet()) + ' ascribe-settings-property'}
ref="panel">
{this.props.children}
</div>);
} else {
return null;
}
},
render() {
let tooltip = <span/>;
if (this.props.tooltip){
tooltip = (
<Tooltip>
{this.props.tooltip}
</Tooltip>);
}
let style = this.state.show ? {} : {paddingBottom: 0};
return (
<div
className={'ascribe-settings-wrapper'}
style={style}>
<OverlayTrigger
delay={500}
placement="top"
overlay={tooltip}>
<div
className="ascribe-settings-property-collapsible-toggle"
onClick={this.handleFocus}
onFocus={this.handleFocus}>
<input
type="checkbox"
ref="checkboxCollapsible"/>
{/* PLEASE LEAVE THE SPACE BETWEEN LABEL and this.props.label */}
<span className="checkbox"> {this.props.checkboxLabel}</span>
</div>
</OverlayTrigger>
{this.renderChildren()}
</div>
);
}
});
export default PropertyCollapsile;

View File

@ -133,25 +133,6 @@ let Video = React.createClass({
} }
}); });
let EncodingStatus = React.createClass({
propTypes: {
encodingStatus: React.PropTypes.number.isRequired
},
render() {
return (
<video ref="video" className="video-js vjs-default-skin" poster={this.props.preview}
controls preload="none" width="auto" height="auto">
{this.props.extraData.map((data, i) =>
<source key={i} type={'video/' + data.type} src={data.url} />
)}
</video>
);
}
});
let resourceMap = { let resourceMap = {
'image': Image, 'image': Image,
'video': Video, 'video': Video,
@ -169,7 +150,7 @@ let MediaPlayer = React.createClass({
}, },
render() { render() {
if (this.props.encodingStatus !== undefined && this.props.encodingStatus !== 100) { if (this.props.mimetype === 'video' && this.props.encodingStatus !== undefined && this.props.encodingStatus !== 100) {
return ( return (
<div className="ascribe-detail-header ascribe-media-player"> <div className="ascribe-detail-header ascribe-media-player">
<p><em>Please be patient, the video is been encoded</em></p> <p><em>Please be patient, the video is been encoded</em></p>

View File

@ -12,12 +12,14 @@ let TableItem = React.createClass({
propTypes: { propTypes: {
columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(ColumnModel)), columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(ColumnModel)),
columnContent: React.PropTypes.object, columnContent: React.PropTypes.object,
className: React.PropTypes.string className: React.PropTypes.string,
onClick: React.PropTypes.func
}, },
render() { render() {
return ( return (
<TableItemWrapper <TableItemWrapper
onClick={this.props.onClick}
columnList={this.props.columnList} columnList={this.props.columnList}
columnContent={this.props.columnContent} columnContent={this.props.columnContent}
columnWidth={12} /> columnWidth={12} />

View File

@ -7,18 +7,13 @@ let TableItemCheckbox = React.createClass({
propTypes: { propTypes: {
editionId: React.PropTypes.number, editionId: React.PropTypes.number,
pieceId: React.PropTypes.number, pieceId: React.PropTypes.number,
selectItem: React.PropTypes.func,
selected: React.PropTypes.bool selected: React.PropTypes.bool
}, },
selectItem() {
this.props.selectItem(this.props.pieceId, this.props.editionId);
},
render() { render() {
return ( return (
<span> <span>
<input type="checkbox" onChange={this.selectItem} checked={this.props.selected}/> <input type="checkbox" checked={this.props.selected} readOnly/>
</span> </span>
); );
} }

View File

@ -19,7 +19,7 @@ let TableItemSelectable = React.createClass({
}, },
selectItem() { selectItem() {
this.props.selectItem(this.props.parentId, this.props.columnContent.edition_number); this.props.selectItem(this.props.parentId, this.props.columnContent.id);
}, },
render() { render() {

View File

@ -11,14 +11,15 @@ let TableItemWrapper = React.createClass({
propTypes: { propTypes: {
columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(ColumnModel)), columnList: React.PropTypes.arrayOf(React.PropTypes.instanceOf(ColumnModel)),
columnContent: React.PropTypes.object, columnContent: React.PropTypes.object,
columnWidth: React.PropTypes.number.isRequired columnWidth: React.PropTypes.number.isRequired,
onClick: React.PropTypes.func
}, },
mixins: [Router.Navigation], mixins: [Router.Navigation],
render() { render() {
return ( return (
<tr> <tr onClick={this.props.onClick}>
{this.props.columnList.map((column, i) => { {this.props.columnList.map((column, i) => {
let TypeElement = column.displayType; let TypeElement = column.displayType;

View File

@ -7,66 +7,116 @@ import GlobalNotificationStore from '../stores/global_notification_store';
import Row from 'react-bootstrap/lib/Row'; import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col'; import Col from 'react-bootstrap/lib/Col';
import { mergeOptions } from '../utils/general_utils';
let GlobalNotification = React.createClass({ let GlobalNotification = React.createClass({
getInitialState() {
return mergeOptions(
{
containerWidth: 0
},
this.extractFirstElem(GlobalNotificationStore.getState().notificationQue)
);
},
componentDidMount() { componentDidMount() {
GlobalNotificationStore.listen(this.onChange); GlobalNotificationStore.listen(this.onChange);
// init container width
this.handleContainerResize();
// we're using an event listener on window here,
// as it was not possible to listen to the resize events of a dom node
window.addEventListener('resize', this.handleContainerResize);
}, },
componentWillUnmount() { componentWillUnmount() {
GlobalNotificationStore.unlisten(this.onChange); GlobalNotificationStore.unlisten(this.onChange);
}, window.removeEventListener('resize', this.handleContainerResize);
getInititalState() {
return this.extractFirstElem(GlobalNotificationStore.getState().notificationQue);
}, },
extractFirstElem(l) { extractFirstElem(l) {
return l.length > 0 ? l[0] : null; if(l.length > 0) {
return {
show: true,
message: l[0]
};
} else {
return {
show: false,
message: ''
};
}
}, },
onChange(state) { onChange(state) {
let notification = this.extractFirstElem(state.notificationQue); let notification = this.extractFirstElem(state.notificationQue);
if(notification) { if(notification.show) {
this.setState(notification); this.setState(notification);
} else { } else {
this.replaceState(null); this.setState({
show: false
});
} }
}, },
handleContainerResize() {
this.setState({
containerWidth: this.refs.notificationWrapper.getDOMNode().offsetWidth
});
},
render() { render() {
let notificationClass = 'ascribe-global-notification '; let notificationClass = 'ascribe-global-notification';
let message = this.state && this.state.message ? this.state.message : null; let textClass;
if(message) { if(this.state.containerWidth > 768) {
let colors = { notificationClass = 'ascribe-global-notification-bubble';
warning: '#f0ad4e',
success: '#5cb85c',
info: 'rgba(2, 182, 163, 1)',
danger: '#d9534f'
};
let text = (<div style={{color: colors[this.state.type]}}>{message ? message : null}</div>); if(this.state.show) {
notificationClass += ' ascribe-global-notification-bubble-on';
} else {
notificationClass += ' ascribe-global-notification-bubble-off';
}
return ( } else {
notificationClass = 'ascribe-global-notification';
if(this.state.show) {
notificationClass += ' ascribe-global-notification-on';
} else {
notificationClass += ' ascribe-global-notification-off';
}
}
if(this.state.message) {
switch(this.state.message.type) {
case 'success':
textClass = 'ascribe-global-notification-success';
break;
case 'danger':
textClass = 'ascribe-global-notification-danger';
break;
default:
console.warn('Could not find a matching type in global_notification.js');
}
}
return (
<div ref="notificationWrapper">
<Row> <Row>
<Col> <Col>
<div className={notificationClass + 'ascribe-global-notification-on'}> <div className={notificationClass}>
{text} <div className={textClass}>{this.state.message.message}</div>
</div> </div>
</Col> </Col>
</Row> </Row>
); </div>
} else { );
return (
<Row>
<Col>
<div className={notificationClass + 'ascribe-global-notification-off'} />
</Col>
</Row>
);
}
} }
}); });

View File

@ -19,11 +19,12 @@ import MenuItem from 'react-bootstrap/lib/MenuItem';
import MenuItemLink from 'react-router-bootstrap/lib/MenuItemLink'; import MenuItemLink from 'react-router-bootstrap/lib/MenuItemLink';
import NavItemLink from 'react-router-bootstrap/lib/NavItemLink'; import NavItemLink from 'react-router-bootstrap/lib/NavItemLink';
import HeaderNotificationDebug from './header_notification_debug';
import { mergeOptions } from '../utils/general_utils'; import { mergeOptions } from '../utils/general_utils';
import { getLangText } from '../utils/lang_utils'; import { getLangText } from '../utils/lang_utils';
let Link = Router.Link;
let Header = React.createClass({ let Header = React.createClass({
mixins: [Router.Navigation], mixins: [Router.Navigation],
@ -43,11 +44,13 @@ let Header = React.createClass({
UserStore.unlisten(this.onChange); UserStore.unlisten(this.onChange);
WhitelabelStore.unlisten(this.onChange); WhitelabelStore.unlisten(this.onChange);
}, },
handleLogout(){ handleLogout(){
UserActions.logoutCurrentUser(); UserActions.logoutCurrentUser();
Alt.flush(); Alt.flush();
this.transitionTo('login'); this.transitionTo('login');
}, },
getLogo(){ getLogo(){
let logo = ( let logo = (
<span> <span>
@ -102,15 +105,14 @@ let Header = React.createClass({
<div> <div>
<Navbar <Navbar
brand={ brand={
<Link className="navbar-brand" to="pieces"> this.getLogo()
{this.getLogo()} }
</Link>}
toggleNavKey={0} toggleNavKey={0}
fixedTop={true}> fixedTop={true}>
<CollapsibleNav eventKey={0}> <CollapsibleNav eventKey={0}>
<Nav navbar left> <Nav navbar left />
</Nav>
<Nav navbar right> <Nav navbar right>
<HeaderNotificationDebug show={false}/>
{addNewWork} {addNewWork}
{collection} {collection}
{account} {account}

View File

@ -0,0 +1,51 @@
'use strict';
import React from 'react';
import GlobalNotificationModel from '../models/global_notification_model';
import GlobalNotificationActions from '../actions/global_notification_actions';
import MenuItem from 'react-bootstrap/lib/MenuItem';
/*
This components purpose is to be inserted into the page's navigation in order
debug the globalnotificationsaction easily
*/
let HeaderNotificationDebug = React.createClass({
propTypes: {
show: React.PropTypes.bool
},
getInitialState() {
return {
index: 0
};
},
triggerNotification() {
if(this.state.index === 1) {
this.setState({index: 0});
} else {
this.setState({index: this.state.index + 1});
}
let actions = ['success', 'danger'];
let notification = new GlobalNotificationModel('this is a test, please ignore', actions[this.state.index]);
GlobalNotificationActions.appendGlobalNotification(notification);
},
render() {
if(this.props.show) {
return (
<MenuItem onClick={this.triggerNotification}>Notification</MenuItem>
);
} else {
return null;
}
}
});
export default HeaderNotificationDebug;

View File

@ -5,39 +5,39 @@ import React from 'react';
import Button from 'react-bootstrap/lib/Button'; import Button from 'react-bootstrap/lib/Button';
import Modal from 'react-bootstrap/lib/Modal'; import Modal from 'react-bootstrap/lib/Modal';
import OverlayMixin from 'react-bootstrap/lib/OverlayMixin'; import OverlayMixin from 'react-bootstrap/lib/OverlayMixin';
import { getLangText } from '../utils/lang_utils.js' import { getLangText } from '../utils/lang_utils.js';
let LoginModalHandler = React.createClass({ let LoginModalHandler = React.createClass({
mixins: [OverlayMixin], mixins: [OverlayMixin],
getInitialState() { getInitialState() {
return { return {
isModalOpen: true isModalOpen: true
}; };
}, },
handleToggle() { handleToggle() {
this.setState({ this.setState({
isModalOpen: !this.state.isModalOpen isModalOpen: !this.state.isModalOpen
}); });
}, },
render() { render() {
if (!this.state.isModalOpen || !(this.props.query.login === '')) { if(!this.state.isModalOpen || !(this.props.query.login === '')) {
return <span/>; return <span/>;
}
return (
<Modal title='Modal heading' onRequestHide={this.handleToggle}>
<div className='modal-body'>
This modal is controlled by our custom trigger component.
</div>
<div className='modal-footer'>
<Button onClick={this.handleToggle}>{getLangText('Close')}</Button>
</div>
</Modal>
);
} }
return (
<Modal title='Modal heading' onRequestHide={this.handleToggle}>
<div className='modal-body'>
This modal is controlled by our custom trigger component.
</div>
<div className='modal-footer'>
<Button onClick={this.handleToggle}>{getLangText('Close')}</Button>
</div>
</Modal>
);
}
}); });
export default LoginModalHandler; export default LoginModalHandler;

View File

@ -47,6 +47,7 @@ let PieceList = React.createClass({
}, },
paginationGoToPage(page) { paginationGoToPage(page) {
document.body.scrollTop = document.documentElement.scrollTop = 0;
return () => PieceListActions.fetchPieceList(page, this.state.pageSize, return () => PieceListActions.fetchPieceList(page, this.state.pageSize,
this.state.search, this.state.orderBy, this.state.search, this.state.orderBy,
this.state.orderAsc); this.state.orderAsc);
@ -84,21 +85,14 @@ let PieceList = React.createClass({
pageSize={this.state.pageSize} pageSize={this.state.pageSize}
loadingElement={loadingElement}> loadingElement={loadingElement}>
{this.state.pieceList.map((piece, i) => { {this.state.pieceList.map((piece, i) => {
let editionsTableForPiece;
if(piece.num_editions !== 1) {
editionsTableForPiece = <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"
parentId={piece.id} />;
}
return ( return (
<AccordionListItem <AccordionListItem
className="col-xs-12 col-sm-10 col-md-8 col-lg-8 col-sm-offset-1 col-md-offset-2 col-lg-offset-2 ascribe-accordion-list-item" className="col-xs-12 col-sm-10 col-md-8 col-lg-8 col-sm-offset-1 col-md-offset-2 col-lg-offset-2 ascribe-accordion-list-item"
content={piece} content={piece}
key={i}> key={i}>
{editionsTableForPiece} <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"
parentId={piece.id} />
</AccordionListItem> </AccordionListItem>
); );
})} })}

View File

@ -23,6 +23,8 @@ import GlobalNotificationActions from '../actions/global_notification_actions';
import Form from './ascribe_forms/form'; import Form from './ascribe_forms/form';
import Property from './ascribe_forms/property'; import Property from './ascribe_forms/property';
import PropertyCollapsible from './ascribe_forms/property_collapsible';
import FormPropertyHeader from './ascribe_forms/form_property_header';
import LoginContainer from './login_container'; import LoginContainer from './login_container';
import SlidesContainer from './ascribe_slides_container/slides_container'; import SlidesContainer from './ascribe_slides_container/slides_container';
@ -172,8 +174,8 @@ let RegisterPiece = React.createClass( {
onFocus={this.changeSlide}> onFocus={this.changeSlide}>
<Row className="no-margin"> <Row className="no-margin">
<Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}> <Col xs={12} sm={10} md={8} smOffset={1} mdOffset={2}>
<h3 style={{'marginTop': 0, 'marginLeft': '1em'}}>{getLangText('Register your work')}</h3>
<Form <Form
className="ascribe-form-bordered"
ref='form' ref='form'
url={apiUrls.pieces_list} url={apiUrls.pieces_list}
getFormData={this.getFormData} getFormData={this.getFormData}
@ -189,6 +191,9 @@ let RegisterPiece = React.createClass( {
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" /> <img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
</button> </button>
}> }>
<FormPropertyHeader>
<h3>{getLangText('Register your work')}</h3>
</FormPropertyHeader>
<Property <Property
ignoreFocus={true}> ignoreFocus={true}>
<FileUploader <FileUploader
@ -222,8 +227,15 @@ let RegisterPiece = React.createClass( {
min={0} min={0}
required/> required/>
</Property> </Property>
<PropertyCollapsible
checkboxLabel={getLangText('Specify editions')}>
<span>{getLangText('Editions')}</span>
<input
type="number"
placeholder="(e.g. 32)"
min={0}/>
</PropertyCollapsible>
{this.getLicenses()} {this.getLicenses()}
<hr />
</Form> </Form>
</Col> </Col>
</Row> </Row>

View File

@ -131,6 +131,10 @@ let AccountSettings = React.createClass({
let BitcoinWalletSettings = React.createClass({ let BitcoinWalletSettings = React.createClass({
propTypes: {
defaultExpanded: React.PropTypes.bool
},
getInitialState() { getInitialState() {
return WalletSettingsStore.getState(); return WalletSettingsStore.getState();
}, },
@ -172,7 +176,7 @@ let BitcoinWalletSettings = React.createClass({
<CollapsibleParagraph <CollapsibleParagraph
title={getLangText('Crypto Wallet')} title={getLangText('Crypto Wallet')}
show={true} show={true}
defaultExpanded={true}> defaultExpanded={this.props.defaultExpanded}>
{content} {content}
</CollapsibleParagraph> </CollapsibleParagraph>
); );
@ -180,6 +184,9 @@ let BitcoinWalletSettings = React.createClass({
}); });
let LoanContractSettings = React.createClass({ let LoanContractSettings = React.createClass({
propTypes: {
defaultExpanded: React.PropTypes.bool
},
render() { render() {
@ -187,7 +194,7 @@ let LoanContractSettings = React.createClass({
<CollapsibleParagraph <CollapsibleParagraph
title="Loan Contract Settings" title="Loan Contract Settings"
show={true} show={true}
defaultExpanded={true}> defaultExpanded={this.props.defaultExpanded}>
<FileUploader /> <FileUploader />
</CollapsibleParagraph> </CollapsibleParagraph>
); );
@ -249,6 +256,10 @@ let FileUploader = React.createClass({
}); });
let APISettings = React.createClass({ let APISettings = React.createClass({
propTypes: {
defaultExpanded: React.PropTypes.bool
},
getInitialState() { getInitialState() {
return ApplicationStore.getState(); return ApplicationStore.getState();
}, },
@ -312,7 +323,7 @@ let APISettings = React.createClass({
<CollapsibleParagraph <CollapsibleParagraph
title={getLangText('API Integration')} title={getLangText('API Integration')}
show={true} show={true}
defaultExpanded={true}> defaultExpanded={this.props.defaultExpanded}>
<Form <Form
url={apiUrls.applications} url={apiUrls.applications}
handleSuccess={this.handleCreateSuccess}> handleSuccess={this.handleCreateSuccess}>

View File

@ -65,7 +65,7 @@ const languages = {
'Account': 'Account', 'Account': 'Account',
'Copyright license%s': 'Copyright license%s', 'Copyright license%s': 'Copyright license%s',
'Files to upload': 'Files to upload', 'Files to upload': 'Files to upload',
'Lock down title': 'Lock down title', 'Register your work': 'Register your work',
'Artist Name': 'Artist Name', 'Artist Name': 'Artist Name',
'The name of the creator': 'The name of the creator', 'The name of the creator': 'The name of the creator',
'Number of editions': 'Number of editions', 'Number of editions': 'Number of editions',
@ -85,8 +85,8 @@ const languages = {
'terms of service': 'terms of service', 'terms of service': 'terms of service',
'privacy': 'privacy', 'privacy': 'privacy',
'Search%s': 'Search%s', 'Search%s': 'Search%s',
'Hide all Editions' : 'Hide all Editions', 'Hide all Editions': 'Hide all Editions',
'Hide editions' : 'Hide editions', 'Hide editions': 'Hide editions',
'Show all Editions': 'Show all Editions', 'Show all Editions': 'Show all Editions',
'Show editions': 'Show editions', 'Show editions': 'Show editions',
'Edition': 'Edition', 'Edition': 'Edition',
@ -203,6 +203,9 @@ const languages = {
'NEW WORK': 'NEW WORK', 'NEW WORK': 'NEW WORK',
'Have someone else sell the artwork': 'Have someone else sell the artwork', 'Have someone else sell the artwork': 'Have someone else sell the artwork',
'Loan History': 'Loan History', 'Loan History': 'Loan History',
'Title': 'Title',
'Specify editions': 'Specify editions',
'Editions': 'Editions',
}, },
'de': { 'de': {
'ID': 'ID', 'ID': 'ID',
@ -268,7 +271,7 @@ const languages = {
'Account': 'Account', 'Account': 'Account',
'Copyright license%s': 'Copyright license%s', 'Copyright license%s': 'Copyright license%s',
'Files to upload': 'Files to upload', 'Files to upload': 'Files to upload',
'Lock down title': 'Lock down title', 'Register your work': 'Register your work',
'Artist Name': 'Artist Name', 'Artist Name': 'Artist Name',
'The name of the creator': 'The name of the creator', 'The name of the creator': 'The name of the creator',
'Number of editions': 'Number of editions', 'Number of editions': 'Number of editions',
@ -288,8 +291,8 @@ const languages = {
'terms of service': 'terms of service', 'terms of service': 'terms of service',
'privacy': 'privacy', 'privacy': 'privacy',
'Search%s': 'Search%s', 'Search%s': 'Search%s',
'Hide all Editions' : 'Hide all Editions', 'Hide all Editions': 'Hide all Editions',
'Hide editions' : 'Hide editions', 'Hide editions': 'Hide editions',
'Show all Editions': 'Show all Editions', 'Show all Editions': 'Show all Editions',
'Show editions': 'Show editions', 'Show editions': 'Show editions',
'Edition': 'Edition', 'Edition': 'Edition',
@ -406,6 +409,9 @@ const languages = {
'NEW WORK': 'NEW WORK', 'NEW WORK': 'NEW WORK',
'Have someone else sell the artwork': 'Have someone else sell the artwork', 'Have someone else sell the artwork': 'Have someone else sell the artwork',
'Loan History': 'Loan History', 'Loan History': 'Loan History',
'Title': 'Titel',
'Specify editions': 'Specify editions',
'Editions': 'Editions',
}, },
'fr': { 'fr': {
'ID': 'ID', 'ID': 'ID',
@ -471,7 +477,7 @@ const languages = {
'Account': 'Compte', 'Account': 'Compte',
'Copyright license%s': 'License de droit d\'auteur%s', 'Copyright license%s': 'License de droit d\'auteur%s',
'Files to upload': 'Fichiers à télécharger', 'Files to upload': 'Fichiers à télécharger',
'Lock down title': 'Verrouillez le titre', 'Register your work': 'Verrouillez le titre',
'Artist Name': 'Nom de l\'artiste', 'Artist Name': 'Nom de l\'artiste',
'The name of the creator': 'Le nom du créateur', 'The name of the creator': 'Le nom du créateur',
'Number of editions': 'Nombre d\'éditions', 'Number of editions': 'Nombre d\'éditions',
@ -489,10 +495,10 @@ const languages = {
'api': 'api', 'api': 'api',
'impressum': 'impressum', 'impressum': 'impressum',
'terms of service': 'conditions d\'utilisation', 'terms of service': 'conditions d\'utilisation',
'privacy': 'confidentialité', 'privacy': 'confidentialité',
'Search%s': 'Rechercher%s', 'Search%s': 'Rechercher%s',
'Hide all Editions' : 'Cacher toutes les Éditions', 'Hide all Editions': 'Cacher toutes les Éditions',
'Hide editions' : 'Cacher les éditions', 'Hide editions': 'Cacher les éditions',
'Show all Editions': 'Montrer toutes les Éditions', 'Show all Editions': 'Montrer toutes les Éditions',
'Show editions': 'Montrer les éditions', 'Show editions': 'Montrer les éditions',
'Edition': 'Édition', 'Edition': 'Édition',
@ -565,7 +571,7 @@ const languages = {
'Loan start date': 'Date du commencement du prêt', 'Loan start date': 'Date du commencement du prêt',
'Loan end date': 'Date de la fin de prêt', 'Loan end date': 'Date de la fin de prêt',
'LOAN': 'PRÊT', 'LOAN': 'PRÊT',
'I transfer ownership of': 'Je transfère la propriété de' , 'I transfer ownership of': 'Je transfère la propriété de',
'Transferee email': 'Courriel du cessionnaire', 'Transferee email': 'Courriel du cessionnaire',
'TRANSFER': 'TRANSFÉRER', 'TRANSFER': 'TRANSFÉRER',
'Forgot your password': 'Oubliez votre mot de passe', 'Forgot your password': 'Oubliez votre mot de passe',
@ -609,6 +615,9 @@ const languages = {
'NEW WORK': 'NOUVEL OEUVRE', 'NEW WORK': 'NOUVEL OEUVRE',
'Have someone else sell the artwork': 'Demandez à quelqu\'un de vendre l\'oeuvre', 'Have someone else sell the artwork': 'Demandez à quelqu\'un de vendre l\'oeuvre',
'Loan History': 'Historique de Prêts', 'Loan History': 'Historique de Prêts',
'Title': 'Title',
'Specify editions': 'Specify editions',
'Editions': 'Editions',
} }
}; };

View File

@ -16,6 +16,10 @@ let PieceListFetcher = {
fetchRequestActions() { fetchRequestActions() {
return requests.get('pieces_list_request_actions'); return requests.get('pieces_list_request_actions');
},
fetchFirstEditionForPiece(pieceId) {
return requests.get('piece_first_edition_id', {'piece_id': pieceId});
} }
}; };

View File

@ -27,26 +27,6 @@ class PieceListStore {
this.orderAsc = true; this.orderAsc = true;
this.bindActions(PieceListActions); this.bindActions(PieceListActions);
} }
/*onShowEditionList(pieceId) {
this.pieceList
.forEach((piece) => {
if(piece.id === pieceId) {
if(piece.show) {
piece.show = false;
} else {
piece.show = true;
}
}
});
}*/
/*onCloseAllEditionLists() {
this.pieceList
.forEach((piece) => {
piece.show = false;
});
}*/
onUpdatePieceList({ page, pageSize, search, pieceList, orderBy, orderAsc, pieceListCount }) { onUpdatePieceList({ page, pageSize, search, pieceList, orderBy, orderAsc, pieceListCount }) {
this.page = page; this.page = page;
@ -85,11 +65,25 @@ class PieceListStore {
this.pieceList = pieceList; this.pieceList = pieceList;
} }
onUpdatePieceListRequestActions(requestActions) { onUpdatePieceListRequestActions(requestActions) {
this.pieceList.forEach((piece) => { this.pieceList.forEach((piece) => {
piece.requestAction = requestActions.indexOf(piece.id) > -1; piece.requestAction = requestActions.indexOf(piece.id) > -1;
}); });
} }
onAddFirstEditionToPiece({pieceId, firstEdition}) {
let filteredPieceList = this.pieceList.filter((piece) => piece.id === pieceId);
if(filteredPieceList.length === 1) {
let piece = filteredPieceList[0];
piece.firstEdition = firstEdition.edition;
} else {
throw new Error('Could not find a matching piece in piece list since its either not there or piecelist contains duplicates.');
}
}
} }
export default alt.createStore(PieceListStore, 'PieceListStore'); export default alt.createStore(PieceListStore, 'PieceListStore');

View File

@ -70,11 +70,17 @@ export function formatText() {
function _doesObjectListHaveDuplicates(l) { function _doesObjectListHaveDuplicates(l) {
let mergedList = []; let mergedList = [];
l = l.map((obj) => Object.keys(obj)); l = l.map((obj) => {
if(!obj) {
throw new Error('The object you are trying to merge is null instead of an empty object');
}
return Object.keys(obj);
});
// Taken from: http://stackoverflow.com/a/10865042 // Taken from: http://stackoverflow.com/a/10865042
// How to flatten an array of arrays in javascript. // How to flatten an array of arrays in javascript.
// If two objects contain the same key, then these two keys // If two objects contain the same key, then these two keys
// will actually be represented in the merged array // will actually be represented in the merged array
mergedList = mergedList.concat.apply(mergedList, l); mergedList = mergedList.concat.apply(mergedList, l);
@ -102,6 +108,7 @@ export function mergeOptions(...l) {
for(let i = 1; i < l.length; i++) { for(let i = 1; i < l.length; i++) {
newObj = _mergeOptions(newObj, _mergeOptions(l[i - 1], l[i])); newObj = _mergeOptions(newObj, _mergeOptions(l[i - 1], l[i]));
} }
return newObj; return newObj;
} }

View File

@ -2,6 +2,7 @@
position: fixed; position: fixed;
background-color: #212121; background-color: #212121;
color: white;
width: 100%; width: 100%;
height:3.5em; height:3.5em;
left:0; left:0;
@ -18,12 +19,48 @@
bottom: 0; bottom: 0;
} }
.ascribe-global-notification > div { .ascribe-global-notification > div, .ascribe-global-notification-bubble > div {
display:table-cell; display:table-cell;
vertical-align: middle; vertical-align: middle;
color: $ascribe-color-full;
font-size: 1.25em; font-size: 1.25em;
font-family: 'Source Sans Pro'; font-family: 'Source Sans Pro';
text-align: right; text-align: right;
padding-right: 3em; padding-right: 3em;
}
.ascribe-global-notification-bubble > div {
padding: .75em 1.5em .75em 1.5em;
}
.ascribe-global-notification-bubble {
position: fixed;
bottom: 3em;
right: -50em;
display:table;
height: 3.5em;
background-color: #212121;
border-radius: 2px;
color: white;
transition: 1s right ease;
}
.ascribe-global-notification-bubble-off {
right: -50em;
}
.ascribe-global-notification-bubble-on {
right: 3.5em;
}
.ascribe-global-notification-danger {
background-color: #d9534f;
}
.ascribe-global-notification-success {
background-color: rgba(2, 182, 163, 1);
} }

View File

@ -82,7 +82,7 @@ $ascribe-accordion-list-font: 'Source Sans Pro';
thead:first-child { thead:first-child {
tr:first-child { tr:first-child {
border: none! important; border: none! important;
th{ th {
padding-left: 10px; padding-left: 10px;
border: none! important; border: none! important;
} }
@ -139,4 +139,12 @@ span.ascribe-accordion-list-table-toggle {
color: #666; color: #666;
font-size: 1.2em; font-size: 1.2em;
padding: 0.3em; padding: 0.3em;
}
.ascribe-accordion-list-item-edition-widget {
cursor: pointer;
&:hover {
color: $ascribe-color-full;
}
} }

View File

@ -11,13 +11,12 @@
.ascribe-edition-collapsible-wrapper > div:first-child { .ascribe-edition-collapsible-wrapper > div:first-child {
width: 100%; width: 100%;
cursor: pointer; cursor: pointer;
background-color: #EEE; background-color: #F5F5F5;
padding: 10px; padding: 10px;
border: 1px solid #CCC; margin-top: 20px;
} }
.ascribe-edition-collapsible-wrapper > div > span { .ascribe-edition-collapsible-wrapper > div > span {
font-size:1.3em; font-size: 1.2em;
margin-right: .5em; margin-right: .5em;
} }
.ascribe-edition-collapsible-wrapper > div > span:nth-child(2) { .ascribe-edition-collapsible-wrapper > div > span:nth-child(2) {
@ -26,8 +25,6 @@
.ascribe-edition-collapible-content { .ascribe-edition-collapible-content {
width:100%; width:100%;
margin-top: 1em;
} }
.coa-file-wrapper{ .coa-file-wrapper{
@ -44,4 +41,8 @@
vertical-align: middle; vertical-align: middle;
border: 1px solid #CCC; border: 1px solid #CCC;
background-color: #F8F8F8; background-color: #F8F8F8;
}
.ascribe-button-list {
margin-top: 1em;
} }

16
sass/ascribe_form.scss Normal file
View File

@ -0,0 +1,16 @@
.ascribe-form-bordered {
border: 1px solid #F5F5F5;
}
.ascribe-form-header {
padding-bottom: 0;
margin-bottom: 0;
background-color: white;
}
.ascribe-form-header > h3 {
padding: .75em 0 .75em 1em;
margin-top: 0;
margin-bottom: 0;
color: #616161;
}

View File

@ -4,7 +4,7 @@
text-align: center; text-align: center;
padding-bottom: 1em; padding-bottom: 1em;
background-color: rgba(0,0,0,0); background-color: white;
border-left: 3px solid rgba(0,0,0,0); border-left: 3px solid rgba(0,0,0,0);
@ -22,7 +22,7 @@
.is-focused { .is-focused {
background-color: rgba(2, 182, 163, 0.05); background-color: rgba(2, 182, 163, 0.05);
border-left: 3px solid rgba(2, 182, 163, 1)!important; border-left: 3px solid rgba(2, 182, 163, 1) !important;
} }
.is-error { .is-error {
@ -128,8 +128,67 @@
} }
} }
.ascribe-property-footer{ .ascribe-property-footer {
font-size: 0.8em; font-size: 0.8em;
margin-top: 10px; margin-top: 10px;
width: 100%; width: 100%;
}
.ascribe-settings-property-collapsible-toggle {
text-align: left;
display: inline-block;
width: 100%;
border-top: 1px solid rgba(0,0,0,.05);
padding: .5em 1.5em .5em 1.5em;
cursor:pointer;
/* Taken from: http://www.htmllion.com/css3-checkbox.html */
.checkbox {
display: inline-block;
cursor: pointer;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-weight: normal;
font-size: .9em;
color: rgba(0, 0, 0, .5);
vertical-align:middle;
span {
position: relative;
top: 1px;
left: 5px;
&:hover {
color: rgba(2, 182, 163, 1);
}
}
}
input[type=checkbox] {
display:none;
}
.checkbox:before {
content: "";
display: inline-block;
width: 17px;
height: 17px;
vertical-align:middle;
background-color: white;
color: #f3f3f3;
text-align: center;
border-radius: 1px;
border: 1px solid rgba(0, 0, 0, .5);
}
input[type=checkbox]:checked + .checkbox:before {
line-height: .8;
content: "\2713";
font-size: 20px;
color: rgba(2, 182, 163, 1);
}
} }

View File

@ -1,5 +1,6 @@
.ascribe-table { .ascribe-table {
margin-bottom:0; margin-bottom:0;
font-size: 1.1em;
} }
/*This is aligning the first checkbox in pieclist detail with all the other ones*/ /*This is aligning the first checkbox in pieclist detail with all the other ones*/
@ -8,6 +9,10 @@
} }
.table > thead > tr > th {
vertical-align: middle;
}
.ascribe-table-header-column > span { .ascribe-table-header-column > span {
display: table-cell; display: table-cell;
vertical-align: middle; vertical-align: middle;
@ -32,7 +37,7 @@
} }
.ascribe-table-item-column > span > input { .ascribe-table-item-column > span > input {
margin-top:16px; margin-top:18px;
} }
.ascribe-table-item-selected { .ascribe-table-item-selected {

View File

@ -4,7 +4,7 @@
vertical-align: middle; vertical-align: middle;
text-align: center; text-align: center;
height: auto; height: auto;
background-color: #FAFAFA; background-color: #FEFEFE;
overflow: auto; overflow: auto;
margin-top: 1em; margin-top: 1em;

View File

@ -26,6 +26,7 @@ $BASE_URL: '<%= BASE_URL %>';
@import 'offset_right'; @import 'offset_right';
@import 'ascribe_settings'; @import 'ascribe_settings';
@import 'ascribe_slides_container'; @import 'ascribe_slides_container';
@import 'ascribe_form';
body { body {
background-color: #FDFDFD; background-color: #FDFDFD;
@ -37,6 +38,10 @@ html {
overflow-y: scroll; overflow-y: scroll;
} }
hr {
margin-bottom: 15px;
}
.hidden { .hidden {
display: none; display: none;
} }
@ -187,10 +192,6 @@ html {
background-color: rgba(2, 182, 163, 0.5); background-color: rgba(2, 182, 163, 0.5);
} }
.ascribe-detail-header {
margin-top: 2em;
}
.ascribe-detail-title { .ascribe-detail-title {
font-size: 2em; font-size: 2em;
margin-bottom: -0.2em; margin-bottom: -0.2em;