Skip to content

Instantly share code, notes, and snippets.

@brettburley
Forked from lennyburdette/components.custom-toast.js
Last active September 13, 2016 02:07
Show Gist options
  • Select an option

  • Save brettburley/c6e0c3d43a296bdb7188d668e3c1b078 to your computer and use it in GitHub Desktop.

Select an option

Save brettburley/c6e0c3d43a296bdb7188d668e3c1b078 to your computer and use it in GitHub Desktop.
Toast Service animation
import Ember from 'ember';
export default Ember.Component.extend({
classNames: ['toast-message__custom'],
progress: 0,
didInsertElement() {
this._super(...arguments);
Ember.run.later(this, this.update, this.get('toast.hideAfter') / 10);
},
update() {
this.set('progress', this.get('progress') + 0.1);
Ember.run.later(this, this.update, this.get('toast.hideAfter') / 10);
},
progressStyle: Ember.computed('progress', function() {
return Ember.String.htmlSafe(`width: ${this.get('progress') * 100}%`);
})
});
import Ember from 'ember';
export default Ember.Component.extend({
toasts: Ember.inject.service(),
classNames: ['toast-manager'],
messages: Ember.computed.alias('toasts.orderedMessages')
});
import Ember from 'ember';
export default Ember.Component.extend({
toasts: Ember.inject.service(),
classNames: ['toast-message'],
classNameBindings: [
'type',
'isActive:toast-message--is-active'
],
isActive: false,
attributeBindings: ['style'],
type: Ember.computed('toast.type', function() {
return `toast-message--${this.get('toast.type')}`;
}),
style: Ember.computed('toast.index', 'toast.swipeDelay', 'height', 'isActive', function() {
const swipeDelay = this.get('toast.swipeDelay');
const maxHeight = this.get('isActive') ? `max-height: ${this.get('height')}px` : '';
if (!Ember.isBlank(swipeDelay)) {
return Ember.String.htmlSafe(`transition: all 400ms ease-out ${swipeDelay}ms;transform: translateX(-600px); opacity: 0; ${maxHeight}`);
}
return Ember.String.htmlSafe(maxHeight);
}),
_cancelTimers() {
const { hideTimer, removeTimer } = this.getProperties('hideTimer', 'removeTimer');
Ember.run.cancel(hideTimer);
Ember.run.cancel(removeTimer);
},
click() {
if (this.get('toast.action')) {
const shouldDismiss = this.get('toast.action')(this.get('toast'));
if (!shouldDismiss) {
return;
}
}
this._cancelTimers();
this.set('isActive', false);
Ember.run.later(() => {
this.get('toasts').remove(this.get('toast'));
}, 100);
},
didInsertElement() {
this._super(...arguments);
Ember.run.next(() => {
this.set('height', this.$()[0].scrollHeight);
this.set('isActive', true);
});
if (this.get('toast.persistent')) {
return;
}
const hideTimer = Ember.run.later(() => {
this.set('isActive', false);
}, this.get('toast.hideAfter'));
const removeTimer = Ember.run.later(() => {
this.get('toasts').remove(this.get('toast'));
}, this.get('toast.removeAfter'));
this.setProperties({
hideTimer,
removeTimer
});
},
willRemoveElement() {
this._super(...arguments);
this._cancelTimers();
}
});
import Ember from 'ember';
let messageCount = 0;
export default Ember.Controller.extend({
toasts: Ember.inject.service(),
actions: {
simple() {
this.get('toasts').info(`Info message`);
},
success() {
this.get('toasts').success(`Success message that!`);
},
warning() {
this.get('toasts').warning(`Warning message ¯\_(ツ)_/¯`);
},
error() {
this.get('toasts').error(`Error message 😭`);
},
callout() {
this.get('toasts').callout(`A general callout`);
},
custom() {
this.get('toasts').show('', {
componentName: 'custom-toast'
});
},
lotsOfText() {
this.get('toasts').info(`Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`);
},
long() {
this.get('toasts').show(`Longer timeout`, { timeout: 10000 });
},
action() {
this.get('toasts').show(`Custom Action (Click me)`, {
action() {
alert('Custom Action!');
return true;
}
});
},
persistent() {
this.get('toasts').info('Must dismiss with click', { persistent: true });
},
clear() {
this.get('toasts').clearMessages();
}
}
});
import Ember from 'ember';
const DEFAULT_TIMEOUT = 5000;
const DELAY = 100;
let id = 0;
export default Ember.Service.extend({
init() {
this.set('messages', []);
},
orderedMessages: Ember.computed('messages.[]', function() {
return this.get('messages').sortBy('id').reverse().map((m, i) => {
m.set('index', i);
return m;
});
}),
clearMessages() {
const length = this.get('orderedMessages.length');
this.get('orderedMessages').map((m, i) => {
m.set('swipeDelay', (length - i) * 25);
});
Ember.run.later(() => this.set('messages', []), 100 + length * 50);
},
show(message, options = {}) {
const timeout = options.timeout || DEFAULT_TIMEOUT;
const toast = Ember.Object.create({
id: id++,
message,
hideAfter: timeout - DELAY,
removeAfter: timeout,
componentName: options.componentName,
type: options.type || 'info',
action: options.action,
persistent: options.persistent
});
this.get('messages').pushObject(toast);
},
info(message, options = {}) {
this.show(message, options);
},
callout(message, options = {}) {
options.type = 'callout';
this.show(message, options);
},
success(message, options = {}) {
options.type = 'success';
this.show(message, options);
},
warning(message, options = {}) {
options.type = 'warning';
this.show(message, options);
},
error(message, options = {}) {
options.type = 'error';
this.show(message, options);
},
remove(toast) {
this.get('messages').removeObject(toast);
}
});
* {
box-sizing: border-box;
}
[data-ember-action] {
cursor: pointer;
}
ul li:hover {
text-decoration: underline;
}
body {
margin: 12px 16px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12pt;
}
.toast-manager {
position: fixed;
bottom: 36px;
left: 36px;
display: flex;
flex-direction: column-reverse;
margin: -6px;
}
.toast-message {
z-index: 1000;
transition: all 100ms linear;
opacity: 0;
max-height: 0;
margin: 6px 0;
}
.toast-message__body {
width: 320px;
transition: all 100ms linear;
border-radius: 5px;
display: flex;
align-items: center;
padding: 19px 24px;
background: #fff;
cursor: pointer;
}
.toast-message__text {
}
.toast-message--is-active {
opacity: 1;
}
.toast-message--info .toast-message__body {
background: #85898c;
color: white;
}
.toast-message--success .toast-message__body {
background: #4ab300;
color: white;
}
.toast-message--warning .toast-message__body {
background: #f4a800;
color: white;
}
.toast-message--callout .toast-message__body {
background: #2996cc;
color: white;
}
.toast-message--error .toast-message__body {
background: #e52817;
color: white;
}
.toast-message__custom {
flex: 1 1 0;
}
<h1>Toast Service Demo</h1>
<ul>
<li {{action (action 'simple')}}>Simple Message</li>
<li {{action (action 'success')}}>Success Message</li>
<li {{action (action 'warning')}}>Warning Message</li>
<li {{action (action 'error')}}>Error Message</li>
<li {{action (action 'callout')}}>Callout Message</li>
<li {{action (action 'lotsOfText')}}>Lots of Text</li>
<li {{action (action 'long')}}>Long Lived Message</li>
<li {{action (action 'custom')}}>Custom Body</li>
<li {{action (action 'action')}}>Custom Action</li>
<li {{action (action 'persistent')}}>Persistent</li>
</ul>
<button {{action (action 'clear')}}>Clear All</button>
{{toast-manager}}
<strong>Custom Toast</strong>
<div style="height: 5px; width: 100%; position: relative; background: white">
<div style="transition: all 500ms linear; position: absolute; height: 100%; background-color: red; {{progressStyle}}"></div>
</div>
{{#each messages key="id" as |toast|}}
{{toast-message toast=toast}}
{{/each}}
<div class="toast-message__body">
{{#if toast.componentName}}
{{component toast.componentName toast=toast}}
{{else}}
<div class="toast-message__text">{{toast.message}}</div>
{{/if}}
</div>
{
"version": "0.10.4",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "2.7.0",
"ember-data": "2.7.0",
"ember-template-compiler": "2.7.0"
},
"addons": {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment