diff --git a/app/components/App.jsx b/app/components/App.jsx index b6670505..bc41149a 100644 --- a/app/components/App.jsx +++ b/app/components/App.jsx @@ -49,33 +49,43 @@ export default class App extends Component { }); this.props.controller.on(Events.DECRYPTION_FAILED, (state) => { - const message = [ - 'We were unable to decrypt the document. Either the secret has not', - 'been supplied or it is invalid.', - 'We have redirected you to a new document.' - ].join(' '); + const message = { + content: [ + 'We were unable to decrypt the document. Either the secret has not', + 'been supplied or it is invalid.', + 'We have redirected you to a new document.' + ].join(' '), + type: 'error' + } this.loadAndRedirect(state.document, '/', message); }); this.props.controller.on(Events.DOCUMENT_NOT_FOUND, (state) => { - const message = [ - 'We could not find the document you were trying to load, so we have', - 'redirected you to a new document.' - ].join(' '); + const message = { + content: [ + 'We could not find the document you were trying to load, so we have', + 'redirected you to a new document.' + ].join(' '), + type: 'error' + }; this.loadAndRedirect(state.document, '/', message); }); this.props.controller.on(Events.CONFLICT, (state) => { - const message = [ - Snap!, - ' The document you were working on has been updated by a third,', - ' and you are now working on a fork. You can still find the original', - ' (and updated) document: ', - here, - '.' - ]; + const message = { + content: ( + + Snap!  + The document you were working on has been updated by a third, + and you are now working on a fork. You can still find the original + (and updated) document:  + here. + + ), + type: 'warning' + }; this.loadAndRedirect( state.fork.document, @@ -87,10 +97,13 @@ export default class App extends Component { this.props.controller.on(Events.UPDATE_WITHOUT_CONFLICT, (state) => { this.setState({ document: state.document, - message: [ - 'We have updated the document you are viewing to its latest revision.', - 'Happy reading/working!' - ].join(' ') + message: { + content: [ + 'We have updated the document you are viewing to its latest revision.', + 'Happy reading/working!' + ].join(' '), + type: 'info' + } }); }); @@ -124,7 +137,7 @@ export default class App extends Component { return (
- + -

{this.props.message}

+
+

{this.props.message.content}

); } @@ -15,3 +17,7 @@ export default class MessageBox extends Component { return null; } } + +MessageBox.propTypes = { + message: object.isRequired +} diff --git a/app/components/__tests__/MessageBox-test.js b/app/components/__tests__/MessageBox-test.js index 50b53227..de7766e5 100644 --- a/app/components/__tests__/MessageBox-test.js +++ b/app/components/__tests__/MessageBox-test.js @@ -17,9 +17,23 @@ describe('', () => { }); it('renders a message', () => { - const wrapper = shallow(); + const message = { + content: 'hello.' + }; + const wrapper = shallow(); expect(wrapper.find('.message-box')).to.have.length(1); expect(wrapper.text()).to.equal('hello.'); }); + +it('renders a typed message', () => { + const message = { + content: 'hello.', + type: 'info' + }; + const wrapper = shallow(); + + expect(wrapper.find('.message-box.info')).to.have.length(1); + expect(wrapper.text()).to.equal('hello.'); + }); }); diff --git a/app/scss/_settings.scss b/app/scss/_settings.scss index edbce433..05cbcb74 100644 --- a/app/scss/_settings.scss +++ b/app/scss/_settings.scss @@ -17,7 +17,7 @@ $foundation-palette: ( secondary: $mercury, success: #3adb76, warning: #ffae00, - alert: #ec5840, + alert: #ec5840 ); // Global @@ -27,6 +27,7 @@ $global-radius: 5px; $common-font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; $body-font-family: 'LatoLatinLight', $common-font-family; $header-font-family: 'LatoLatin', $common-font-family; +$callout-font-family: $header-font-family; // Typography $code-font-family: Consolas, 'Liberation Mono', Courier, monospace; @@ -37,6 +38,9 @@ $print-transparent-backgrounds: false; // Callout $callout-radius: 0; $callout-margin: 0; +$callout-background-fade: 20%; +$callout-font-color: $alabaster; +$callout-border: 0 none none; /* -- Monod settings -- */ $footer-font-family: 'LatoLatin', $common-font-family; diff --git a/app/scss/components/_message_box.scss b/app/scss/components/_message_box.scss index 71392ddf..42286c44 100644 --- a/app/scss/components/_message_box.scss +++ b/app/scss/components/_message_box.scss @@ -1,9 +1,51 @@ +/* + * MessageBox component + */ +$message-box-height: 65px; + .message-box { - @include callout-base; - background-color: lighten($warning-color, 40%); + @include callout; + position: fixed; + width: 100%; + z-index: 10000; + font-size: 1.2rem; + font-family: $callout-font-family; + min-height: $message-box-height; + + // We support up to 10 simultaneous notifications + @for $i from 1 through 10 { + &:nth-child(#{$i}) { + margin-top: #{($i - 2) * $message-box-height}; + } + } + + &.warning { + @include callout-style($warning-color); + color: darken($warning-color, 15%); + border-bottom: 3px solid $warning-color; + } + + &.error { + @include callout-style($alert-color); + border-bottom: 3px solid $alert-color; + } + + &.success { + @include callout-style($success-color); + border-bottom: 3px solid $success-color; + } + + &.info { + @include callout-style(lighten($primary-color, 5%)); + border-bottom: 3px solid $primary-color; + } + + a { + color: inherit; + text-decoration: underline; - p { - margin-bottom: 0 !important; - margin-right: 1rem; - } + &:hover { + background-color: rgba(#fff, 0.2); + } + } }