diff --git a/README.md b/README.md index ce2f437..8cb36de 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ module.exports = { { type: 'slack.channel', channel: 'general', + showPulse: true, columns: 1, rows: 1, x: 0, y: 0 }, @@ -112,6 +113,8 @@ key | required | description `title` | no | *Textual title to show. Example: '#mychannel'.* `channel` | no | *Name of the channel to follow. Defaults to all public channels where token has permissions to* `imageSize` | no | Scaling of image: initial, cover, contain. Default to `initial` +`showImages` | no | Show images or not. Defaults to `true` +`showPulse` | no | Show pulse visualisation on each message or not. Defaults to `false` `config` | no | Override default pulse config parameters or colors. See source code for details ### usage @@ -155,6 +158,10 @@ Distributed under the MIT license ## Changelog +### Release 0.6.0 + +- Add support to show pulse within channel widget + ### Release 0.5.0 - Adjust font size automatically: Based on given size and length of text diff --git a/package.json b/package.json index 187d948..1249822 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mozaik-ext-slack", - "version": "0.5.0", + "version": "0.6.0", "description": "Slack widgets to Mozaik dashboard", "main": "./components.js", "scripts": { diff --git a/src/components/Channel.jsx b/src/components/Channel.jsx index 6e13ff7..eff1964 100644 --- a/src/components/Channel.jsx +++ b/src/components/Channel.jsx @@ -5,6 +5,7 @@ import Mozaik from 'mozaik/browser'; import classNames from 'classnames'; import moment from 'moment'; import Since from './Since.jsx'; +import Impulse from './Impulse.jsx'; class Channel extends Component { constructor(props) { @@ -49,7 +50,6 @@ class Channel extends Component { } this.setState({ message: message }); - console.log('State changed', this.state); } getFontSize(width, height, textLength = 1) { @@ -99,6 +99,8 @@ class Channel extends Component { 'slack-channel__footer--image': message ? message.image : false }); + const pulse = this.props.showPulse ? : null; + return (
{content.title} @@ -108,6 +110,7 @@ class Channel extends Component {
{content.text}
+ {pulse}
@@ -124,12 +127,14 @@ Channel.propTypes = { title: React.PropTypes.string, channel: React.PropTypes.string, showImages: React.PropTypes.bool, + showPulse: React.PropTypes.bool, imageSize: React.PropTypes.oneOf(['initial', 'contain', 'cover']) }; Channel.defaultProps = { channel: null, showImages: true, + showPulse: false, imageSize: 'initial', }; diff --git a/src/components/Impulse.jsx b/src/components/Impulse.jsx new file mode 100644 index 0000000..3504b9d --- /dev/null +++ b/src/components/Impulse.jsx @@ -0,0 +1,120 @@ +import React, { Component } from 'react'; +import reactMixin from 'react-mixin'; +import { ListenerMixin } from 'reflux'; +import Mozaik from 'mozaik/browser'; +var d3 = require('d3'); +var ease = require('d3-ease'); +import _ from 'lodash'; + + +function pulse(opts) { + for (var i = 1; i < opts.count; ++i) { + d3.select(opts.element) + .append('circle') + .attr('cx', opts.position.x) + .attr('cy', opts.position.y) + .attr('r', 30) + .attr('stroke-width', opts.strokeWidth / (i)) + .attr('fill', 'transparent') + .attr('stroke', `rgba(${opts.color.r}, ${opts.color.g}, ${opts.color.b}, 255)`) + .transition() + .delay(Math.pow(i, 2.5) * opts.delay) + .duration(opts.duration) + .ease(ease.easeQuadIn) + .attr('stroke-width', 2) + .attr('stroke', `rgba(${opts.color.r}, ${opts.color.g}, ${opts.color.b}, 0)`) + .attr('r', opts.radius) + .remove(); + } +} + +function getRandom(min, max) { + return Math.floor(Math.random() * (max - min)) + min; +} + +class Impulse extends Component { + constructor(props) { + super(props); + this.mounted = false; + this.state = { + colorIndex: 0, + height: 400, + width: 400 + }; + this.config = _.defaultsDeep(this.props.config || {}, { + delay: 10, + count: 8, + duration: 4000, + strokeWidth: 20, + // Defaults to Slack colours + colors: [ + { r: 112, g: 204, b: 220 }, // blue + { r: 223, g: 168, b: 35 }, // orange + { r: 225, g: 22, b: 101 }, // red + { r: 61, g: 186, b: 145 } // green + ] + }); + } + + componentDidMount() { + this.mounted = true; + + // Get area size + const bodyElement = this._body.getDOMNode(); + this.setState({ + element: this._svg.getDOMNode(), + height: bodyElement.clientHeight, + width: bodyElement.clientWidth + }); + } + + componentWillUnmount() { + this.mounted = false; + } + + componentWillReceiveProps() { + // Increase / reset the color index on each update + const nextColorIndex = this.state.colorIndex < (this.config.colors.length - 1) ? this.state.colorIndex + 1 : 0; + this.setState({ colorIndex: nextColorIndex }); + } + + render() { + const title = this.props.title; + //const nextColorIndex = this.state.colorIndex < (this.config.colors.length - 1) ? this.state.colorIndex + 1 : 0; + + // NOTE: Modifying DOM with D3 is not ideal, consider + // using https://github.com/Olical/react-faux-dom later on + pulse(_.extend({ + height: this.state.height, + width: this.state.width, + radius: _.max([this.state.height, this.state.width]) + 100, + element: this.state.element, + color: this.config.colors[this.state.colorIndex || 0], + position: { + x: getRandom(0, this.state.width), + y: getRandom(0, this.state.height) + } + }, this.config)); + + return ( +
this._body = c}> + this._svg = c} height={this.state.height} width={this.state.width}> +
+ ); + } +} + +Impulse.propTypes = { + title: React.PropTypes.string, + channel: React.PropTypes.string, + config: React.PropTypes.object, + message: React.PropTypes.string +}; + +Impulse.defaultProps = { + title: 'Slack', + channel: null +}; + + +export default Impulse; diff --git a/src/components/Pulse.jsx b/src/components/Pulse.jsx index de35f02..2c3bbab 100644 --- a/src/components/Pulse.jsx +++ b/src/components/Pulse.jsx @@ -5,55 +5,16 @@ import Mozaik from 'mozaik/browser'; var d3 = require('d3'); var ease = require('d3-ease'); import _ from 'lodash'; +import Impulse from './Impulse.jsx'; -function pulse(opts) { - for (var i = 1; i < opts.count; ++i) { - d3.select(opts.element) - .append('circle') - .attr('cx', opts.position.x) - .attr('cy', opts.position.y) - .attr('r', 30) - .attr('stroke-width', opts.strokeWidth / (i)) - .attr('fill', 'transparent') - .attr('stroke', `rgba(${opts.color.r}, ${opts.color.g}, ${opts.color.b}, 255)`) - .transition() - .delay(Math.pow(i, 2.5) * opts.delay) - .duration(opts.duration) - .ease(ease.easeQuadIn) - .attr('stroke-width', 2) - .attr('stroke', `rgba(${opts.color.r}, ${opts.color.g}, ${opts.color.b}, 0)`) - .attr('r', opts.radius) - .remove(); - } -} - -function getRandom(min, max) { - return Math.floor(Math.random() * (max - min)) + min; -} - class Pulse extends Component { constructor(props) { super(props); this.mounted = false; this.state = { - colorIndex: 0, - height: 400, - width: 400 + message: null }; - this.config = _.defaultsDeep(this.props.config || {}, { - delay: 10, - count: 8, - duration: 4000, - strokeWidth: 20, - // Defaults to Slack colours - colors: [ - { r: 112, g: 204, b: 220 }, // blue - { r: 223, g: 168, b: 35 }, // orange - { r: 225, g: 22, b: 101 }, // red - { r: 61, g: 186, b: 145 } // green - ] - }); } getApiRequest() { @@ -67,46 +28,9 @@ class Pulse extends Component { } onApiData(data) { - const nextColorIndex = this.state.colorIndex < (this.config.colors.length - 1) ? this.state.colorIndex + 1 : 0; - const nextPositionIndex = this.state.positionIndex < (this.config.colors.length - 1) ? this.state.positionIndex + 1 : 0; - this.setState({ - colorIndex: nextColorIndex, - positionIndex: nextPositionIndex, + message: data }); - - if (!this.mounted) { - return; - } - - // Get area size - const bodyElement = this._body.getDOMNode(); - this.setState({ - height: bodyElement.clientHeight, - width: bodyElement.clientWidth - }); - - // NOTE: Modifying DOM with D3 is not ideal, consider - // using https://github.com/Olical/react-faux-dom later on - pulse(_.extend({ - height: this.state.height, - width: this.state.width, - radius: _.max([this.state.height, this.state.width]) + 100, - element: this._svg.getDOMNode(), - color: this.config.colors[this.state.colorIndex || 0], - position: { - x: getRandom(0, this.state.width), - y: getRandom(0, this.state.height) - } - }, this.config)); - } - - componentDidMount() { - this.mounted = true; - } - - componentWillUnmount() { - this.mounted = false; } render() { @@ -118,9 +42,7 @@ class Pulse extends Component { {title}
-
this._body = c}> - this._svg = c} height={this.state.height} width={this.state.width}> -
+
); } @@ -129,7 +51,6 @@ class Pulse extends Component { Pulse.propTypes = { title: React.PropTypes.string, channel: React.PropTypes.string, - config: React.PropTypes.object }; Pulse.defaultProps = { diff --git a/styl/_slack.styl b/styl/_slack.styl index 64bb9ce..4e71070 100644 --- a/styl/_slack.styl +++ b/styl/_slack.styl @@ -5,6 +5,7 @@ text-align: center font-size 2rem line-height 2.5rem + z-index 5000 .slack-channel__message--value color white @@ -65,3 +66,16 @@ overflow hidden height 100% width 100% + + +.slack-channel__impulse + z-index 0 + position absolute + top 0 + left 0 + +.slack__impulse--body + top 0 + overflow hidden + height 100% + width 100%