Notifications

by evgkch

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.9/react-with-addons.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.9/react-dom.js"></script>
<div id="app"></div>

SCSS

$green-color: rgb(29, 182, 119);

body {
  font-family: Arial;
  background-color: #2F2F30;
}

.container {
  clear: both;
  width: 100%;
  padding-top: 20px;
  transition: all 300ms ease-out;
}

.nt-container {
  transition: all 300ms ease-out;
  position: absolute;
  perspective: 150px;
  perspective-origin: bottom center;

  .nt-box {
    position: relative;
    matgin-top: 0;
    top: 0;
    transition: all 100ms ease-out;

    .nt-close-button {
      position: absolute;
      cursor: pointer;
      user-select: none;
      z-index: 9999;
      transition: all 100ms ease-out;

      &:hover {
        transform: scale(1.5);
      }
      &:active {
        transform: scale(1);
      }
    }
  }
  
  .nt-theme-white {
    background-color: white;
      .nt-close-button {
        color: #363436;
      }
  }
  
  .nt-theme-grey {
    background-color: #dbdbe3;
    .nt-close-button {
      color: white;
    }
  }
  
  .nt-theme-green {
    background-color: $green-color;
    .nt-close-button {
      color: #363436;
    }
  }
  
  .nt-animate-slide-left {
    transform: translateX(-150%);
    opacity: 0;
  }
  .nt-animate-slide-right {
    transform: translateX(150%);
    opacity: 0;
  }
  .nt-animate-slide-top {
    transform: translateY(-150%);
    opacity: 0;
  }
  .nt-animate-slide-bottom {
    transform: translateY(150%);
    opacity: 0;
  }
  .nt-animate-scale {
    transform: scale(0);
  }
  .nt-animate-hidden {
    opacity: 0;
  }
  .nt-animate-3d {
    transform: rotateX(90deg);
    transform-style: preserve-3d;
  }
}

.nt-body-content {
  margin-top: 15px;
}

.nt-body-incident, .nt-body-task {
  display: flex;
  flex-direction: column;
  color: #232224;
}

.nt-body-incident-dscr {
  display: flex;
  align-items: center;
  margin-bottom: 5px;
  
  .nt-body-incident-dscr-icon {
    width: 30px;
    height: 30px;
    margin-right: 5px;
    background-color: whitesmoke;
    border-radius: 100%;
  }
}

Babel + JSX

// Local store
class Store {
	constructor(name, initialState = {}) {
  	this.name = name;
    this.subscribers = [];
  	this.state = initialState;
  }
  subscribe(subscriber) {
  	this.subscribers.push(subscriber);
  }
  unsubscribe(subscriber) {
  	this.subscribers = this.subscribers.filter(item => item !== subscriber);
  }
  update(state) {
  	this.state = { ...this.state, ...state };
    console.log(this.state);
    this.subscribers.map(component => component.setState(this.state));
  }
}

// Subscribe component to store with controller
const connect = (component, controller, store) =>
	class Container extends React.Component {
    constructor() {
      super();
      if (store) store.subscribe(this);
      this.ctrl = controller(
        (state) => store
          ? store.update(state)
          : this.setState(state),
        () => this.state
      );
    }
    componentDidMount() {
    	if (store) this.setState(store.state);
    }
    componentWillUnmount() {
    	if (store) store.unsubscribe(this);
    }
    render() {
      return React.createElement(component, {...this.state, ...this.props, ctrl: this.ctrl })
    }
  }

// For changes without React
const Model = (controller, store) =>
	controller(
  	store.update.bind(store),
    () => store.state
  );
  
const createMessage = (message, type = 'default') => ({
	id: Math.random(),
  type: type,
  message: `<div>${message}</div>`,
})

const data = Array.from({ length: 5 }, (v, k) => createMessage('message', 'default'))

class NotificationsBox extends React.Component {
	constructor(props) {
  	super(props);
    this.CLOSE_BUTTON = '✖';
  }
	animate(flag) {
		const { effect = 'hidden' } = this.props;
		return flag
			? `nt-animate-${effect}`
      : '';
	}
	render() {
  	const {
      body,
      notifications = [],
      theme = 'white',
      style = {},
      onOpen = () => {},
      ctrl,
    } = this.props;
    const {
    	padding = '10px',
      margin = '5px',
      width = '300px',
      minHeight =...