├── .editorconfig ├── .ember-cli ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── .npmignore ├── .template-lintrc.js ├── .travis.yml ├── .watchmanconfig ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── addon ├── .gitkeep ├── components │ ├── ember-notifier-notification │ │ ├── close │ │ │ ├── component.js │ │ │ └── template.hbs │ │ ├── component.js │ │ ├── content │ │ │ ├── component.js │ │ │ └── template.hbs │ │ ├── icon │ │ │ ├── component.js │ │ │ └── template.hbs │ │ └── template.hbs │ └── ember-notifier │ │ ├── component.js │ │ └── template.hbs ├── mixins │ └── swipe-support.js ├── services │ └── notifier.js └── utils │ └── default-value.js ├── app ├── .gitkeep ├── components │ ├── ember-notifier-notification │ │ ├── close │ │ │ └── component.js │ │ ├── component.js │ │ ├── content │ │ │ └── component.js │ │ └── icon │ │ │ └── component.js │ └── ember-notifier │ │ └── component.js ├── services │ └── notifier.js ├── styles │ └── ember-notifier.scss └── utils │ └── default-value.js ├── config ├── addon-docs.js ├── deploy.js ├── ember-try.js └── environment.js ├── ember-cli-build.js ├── index.js ├── package-lock.json ├── package.json ├── testem.js ├── tests ├── dummy │ ├── app │ │ ├── app.js │ │ ├── application │ │ │ ├── controller.js │ │ │ └── template.hbs │ │ ├── components │ │ │ ├── .gitkeep │ │ │ ├── addon-demo │ │ │ │ ├── component.js │ │ │ │ └── template.hbs │ │ │ ├── addon-dynamic-demo │ │ │ │ ├── component.js │ │ │ │ └── template.hbs │ │ │ ├── notification-icon │ │ │ │ ├── component.js │ │ │ │ └── template.hbs │ │ │ ├── tailwind-alert │ │ │ │ ├── component.js │ │ │ │ └── template.hbs │ │ │ └── task-message │ │ │ │ ├── component.js │ │ │ │ └── template.hbs │ │ ├── docs │ │ │ ├── animation │ │ │ │ ├── snippets │ │ │ │ │ └── animation-config-environment.js │ │ │ │ └── template.md │ │ │ ├── demo │ │ │ │ └── template.md │ │ │ ├── dynamic │ │ │ │ └── template.md │ │ │ ├── icons │ │ │ │ ├── snippets │ │ │ │ │ ├── fa-svg-application.hbs │ │ │ │ │ ├── fa-svg-component.hbs │ │ │ │ │ ├── fa-svg-component.js │ │ │ │ │ ├── fa-svg-config-environment.js │ │ │ │ │ └── fa-web-font-config-environment.js │ │ │ │ └── template.md │ │ │ ├── index │ │ │ │ └── template.md │ │ │ ├── options │ │ │ │ ├── snippets │ │ │ │ │ ├── global-options.js │ │ │ │ │ └── notification-options.js │ │ │ │ └── template.md │ │ │ ├── styles │ │ │ │ ├── snippets │ │ │ │ │ ├── bootstrap-application.hbs │ │ │ │ │ ├── bootstrap-config-environment.js │ │ │ │ │ ├── bulma-application.hbs │ │ │ │ │ ├── bulma-config-environment.js │ │ │ │ │ ├── spectre-application.hbs │ │ │ │ │ ├── spectre-config-environment.js │ │ │ │ │ ├── style-sass.scss │ │ │ │ │ ├── zurb-application.hbs │ │ │ │ │ └── zurb-config-environment.js │ │ │ │ └── template.md │ │ │ ├── template.hbs │ │ │ ├── touch │ │ │ │ ├── snippets │ │ │ │ │ └── touch-config-environment.js │ │ │ │ └── template.md │ │ │ └── usage │ │ │ │ └── template.md │ │ ├── helpers │ │ │ ├── .gitkeep │ │ │ └── capitalize.js │ │ ├── index.html │ │ ├── index │ │ │ ├── index-content │ │ │ │ └── template.md │ │ │ └── template.hbs │ │ ├── not-found │ │ │ ├── route.js │ │ │ └── template.hbs │ │ ├── resolver.js │ │ ├── router.js │ │ ├── services │ │ │ └── demo.js │ │ ├── styles │ │ │ └── app.scss │ │ └── templates │ │ │ └── .gitignore │ ├── config │ │ ├── environment.js │ │ ├── optional-features.json │ │ └── targets.js │ └── public │ │ ├── assets │ │ └── images │ │ │ ├── favicon.ico │ │ │ ├── favicon.png │ │ │ └── notification-demo.gif │ │ ├── crossdomain.xml │ │ └── robots.txt ├── helpers │ ├── .gitkeep │ └── trigger-swipe-event.js ├── index.html ├── integration │ ├── .gitkeep │ └── components │ │ ├── ember-notifier-notification │ │ ├── close │ │ │ └── component-test.js │ │ ├── component-test.js │ │ ├── content │ │ │ └── component-test.js │ │ └── icon │ │ │ └── component-test.js │ │ └── ember-notifier │ │ └── component-test.js ├── test-helper.js └── unit │ ├── .gitkeep │ ├── mixins │ └── swipe-support-test.js │ ├── services │ └── notifier-test.js │ └── utils │ └── default-value-test.js └── vendor └── .gitkeep /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.hbs] 17 | insert_final_newline = false 18 | 19 | [*.{diff,md}] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false 9 | } 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # unconventional js 2 | /blueprints/*/files/ 3 | /vendor/ 4 | tests/dummy/app/docs/**/snippets/** 5 | 6 | # compiled output 7 | /dist/ 8 | /tmp/ 9 | 10 | # dependencies 11 | /bower_components/ 12 | /node_modules/ 13 | 14 | # misc 15 | /coverage/ 16 | 17 | # ember-try 18 | /.node_modules.ember-try/ 19 | /bower.json.ember-try 20 | /package.json.ember-try 21 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | ecmaVersion: 2017, 5 | sourceType: 'module' 6 | }, 7 | plugins: [ 8 | 'ember' 9 | ], 10 | extends: [ 11 | 'eslint:recommended', 12 | 'plugin:ember/recommended' 13 | ], 14 | env: { 15 | browser: true 16 | }, 17 | rules: { 18 | }, 19 | overrides: [ 20 | // node files 21 | { 22 | files: [ 23 | '.eslintrc.js', 24 | '.template-lintrc.js', 25 | 'ember-cli-build.js', 26 | 'index.js', 27 | 'testem.js', 28 | 'blueprints/*/index.js', 29 | 'config/**/*.js', 30 | 'tests/dummy/config/**/*.js' 31 | ], 32 | excludedFiles: [ 33 | 'addon/**', 34 | 'addon-test-support/**', 35 | 'app/**', 36 | 'tests/dummy/app/**' 37 | ], 38 | parserOptions: { 39 | sourceType: 'script', 40 | ecmaVersion: 2015 41 | }, 42 | env: { 43 | browser: false, 44 | node: true 45 | }, 46 | plugins: ['node'], 47 | rules: Object.assign({}, require('eslint-plugin-node').configs.recommended.rules, { 48 | // add your custom rules and overrides for node files here 49 | }) 50 | } 51 | ] 52 | }; 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist/ 3 | /tmp/ 4 | 5 | # dependencies 6 | /bower_components/ 7 | /node_modules/ 8 | 9 | # misc 10 | /.sass-cache 11 | /connect.lock 12 | /coverage/ 13 | /libpeerconnection.log 14 | /npm-debug.log* 15 | /testem.log 16 | /yarn-error.log 17 | 18 | # ember-try 19 | /.node_modules.ember-try/ 20 | /bower.json.ember-try 21 | /package.json.ember-try 22 | 23 | # ember-cli-addon-docs 24 | /config/addon-docs.js 25 | 26 | # webstorm 27 | /.idea 28 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist/ 3 | /tmp/ 4 | 5 | # dependencies 6 | /bower_components/ 7 | 8 | # misc 9 | /.bowerrc 10 | /.editorconfig 11 | /.ember-cli 12 | /.eslintignore 13 | /.eslintrc.js 14 | /.gitignore 15 | /.watchmanconfig 16 | /.travis.yml 17 | /bower.json 18 | /config/ember-try.js 19 | /ember-cli-build.js 20 | /testem.js 21 | /tests/ 22 | /yarn.lock 23 | .gitkeep 24 | 25 | # ember-try 26 | /.node_modules.ember-try/ 27 | /bower.json.ember-try 28 | /package.json.ember-try 29 | 30 | # ember-cli-addon-docs 31 | /config/addon-docs.js 32 | 33 | # webstorm 34 | /.idea 35 | -------------------------------------------------------------------------------- /.template-lintrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | extends: 'recommended', 5 | rules: { 6 | 'attribute-indentation': { 7 | 'element-open-end': 'last-attribute', 8 | 'mustache-open-end': 'last-attribute', 9 | 'open-invocation-max-len': 120 10 | } 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | node_js: 4 | # we recommend testing addons with the same minimum supported node version as Ember CLI 5 | # so that your addon works for all apps 6 | - "6" 7 | 8 | sudo: false 9 | dist: trusty 10 | 11 | addons: 12 | chrome: stable 13 | 14 | cache: 15 | directories: 16 | - $HOME/.npm 17 | - $HOME/.cache/yarn 18 | 19 | env: 20 | global: 21 | # See https://git.io/vdao3 for details. 22 | - JOBS=1 23 | 24 | jobs: 25 | fail_fast: true 26 | allow_failures: 27 | - env: EMBER_TRY_SCENARIO=ember-canary 28 | 29 | include: 30 | # runs linting and tests with current locked deps 31 | 32 | - stage: "Tests" 33 | name: "Tests" 34 | script: 35 | - npm run lint:hbs 36 | - npm run lint:js 37 | - npm test 38 | 39 | # we recommend new addons test the current and previous LTS 40 | # as well as latest stable release (bonus points to beta/canary) 41 | - stage: "Additional Tests" 42 | env: EMBER_TRY_SCENARIO=ember-lts-2.16 43 | - env: EMBER_TRY_SCENARIO=ember-lts-2.18 44 | - env: EMBER_TRY_SCENARIO=ember-release 45 | - env: EMBER_TRY_SCENARIO=ember-beta 46 | - env: EMBER_TRY_SCENARIO=ember-canary 47 | - env: EMBER_TRY_SCENARIO=ember-default-with-jquery 48 | 49 | before_install: 50 | - npm config set spin false 51 | - npm install -g npm@4 52 | - npm --version 53 | 54 | script: 55 | - node_modules/.bin/ember try:one $EMBER_TRY_SCENARIO 56 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## [v0.1.3](https://github.com/scottwernervt/ember-notifier/releases/tag/v0.1.3) (2018-12-11) 4 | 5 | Bugs: 6 | 7 | - Leaflet defines an `{{icon}}` helper which gets called instead of rendering the `{{icon}}` property value in the icon component template. [\#21](https://github.com/scottwernervt/ember-notifier/issues/21#issuecomment-444194637) 8 | - Add extra styling to close button to make it independent of frameworks. [\#21](https://github.com/scottwernervt/ember-notifier/issues/21#issuecomment-444144615) 9 | 10 | | Old | New | 11 | | ------------------------------------- | -------------------------------------------- | 12 | | `$ember-notifier-close-width` | `$ember-notifier-close-button-width` | 13 | | | `$ember-notifier-close-button-height` | 14 | | `$ember-notifier-close-color` | `$ember-notifier-close-button-color` | 15 | | `$ember-notifier-close-opacity` | `$ember-notifier-close-button-opacity` | 16 | | `$ember-notifier-close-hover-opacity` | `$ember-notifier-close-button-hover-opacity` | 17 | 18 | Maintenance: 19 | 20 | - Update dependencies and dev dependencies. 21 | 22 | Docs: 23 | 24 | - Add custom theme to docs. 25 | 26 | ## [v0.1.2](https://github.com/scottwernervt/ember-notifier/releases/tag/v0.1.2) (2018-11-08) 27 | 28 | Maintenance: 29 | 30 | - Update dependencies and dev dependencies. 31 | 32 | ## [v0.1.1](https://github.com/scottwernervt/ember-notifier/releases/tag/v0.1.1) (2018-09-27) 33 | 34 | Features: 35 | 36 | - Swipe right to remove a notification. [\#4](https://github.com/scottwernervt/ember-notifier/issues/4) 37 | - Add CSS transitions when adding and removing a notification. [\#3](https://github.com/scottwernervt/ember-notifier/issues/3) 38 | 39 | Maintenance: 40 | 41 | - Update dependencies and dev dependencies. 42 | 43 | ## [v0.1.0](https://github.com/scottwernervt/ember-notifier/releases/tag/v0.1.0) (2018-09-27) 44 | 45 | Depreciated due to issue with deploying with `ember-cli-addon-docs`. 46 | 47 | ## [v0.0.1](https://github.com/scottwernervt/ember-notifier/releases/tag/v0.0.1) (2018-07-30) 48 | 49 | - First release. 50 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ember-notifier 2 | ============== 3 | 4 | [![Latest NPM release][npm-badge]][npm-badge-url] 5 | [![License][license-badge]][license-badge-url] 6 | [![TravisCI Build Status][travis-badge]][travis-badge-url] 7 | [![Ember Observer Score][ember-observer-badge]][ember-observer-badge-url] 8 | [![Code Climate][codeclimate-badge]][codeclimate-badge-url] 9 | [![Dependencies][dependencies-badge]][dependencies-badge-url] 10 | [![Dev Dependencies][devDependencies-badge]][devDependencies-badge-url] 11 | 12 | [npm-badge]: https://img.shields.io/npm/v/ember-notifier.svg 13 | [npm-badge-url]: https://www.npmjs.com/package/ember-notifier 14 | [travis-badge]: https://img.shields.io/travis/scottwernervt/ember-notifier/master.svg 15 | [travis-badge-url]: https://travis-ci.org/scottwernervt/ember-notifier 16 | [codeclimate-badge]: https://api.codeclimate.com/v1/badges/24b82ae0cd54584332e2/maintainability 17 | [codeclimate-badge-url]: https://codeclimate.com/github/scottwernervt/ember-notifier 18 | [ember-observer-badge]: http://emberobserver.com/badges/ember-notifier.svg 19 | [ember-observer-badge-url]: http://emberobserver.com/addons/ember-notifier 20 | [license-badge]: https://img.shields.io/npm/l/ember-notifier.svg 21 | [license-badge-url]: LICENSE.md 22 | [dependencies-badge]: https://david-dm.org/scottwernervt/ember-notifier.svg 23 | [dependencies-badge-url]: https://david-dm.org/scottwernervt/ember-notifier 24 | [devDependencies-badge]: https://david-dm.org/scottwernervt/ember-notifier/dev-status.svg?theme=shields.io 25 | [devDependencies-badge-url]: https://david-dm.org/scottwernervt/ember-notifier?type=dev 26 | 27 | Easy, beautiful notifications for your Ember project. 28 | 29 | 30 | Installation 31 | ------------------------------------------------------------------------------ 32 | 33 | ``` 34 | ember install ember-notifier 35 | ``` 36 | 37 | 38 | Usage 39 | ------------------------------------------------------------------------------ 40 | 41 | Add the `ember-notifier` component to your application template. This 42 | container displays notifications. 43 | 44 | ```hbs 45 | {{ember-notifier position="is-top-right"}} 46 | {{outlet}} 47 | ``` 48 | 49 | Inject the `notifier` service anywhere you want to launch a 50 | notification. 51 | 52 | ```js 53 | import Component from '@ember/component'; 54 | import { inject as service } from '@ember/service'; 55 | 56 | export default Component.extend({ 57 | notifier: service(), 58 | }); 59 | ``` 60 | 61 | Notifications can be added by calling styled functions. 62 | 63 | ```js 64 | this.get('notifier').primary('Primary notification'); 65 | this.get('notifier').info('Information notification'); 66 | this.get('notifier').success('Success notification'); 67 | this.get('notifier').warning('Warning notification'); 68 | this.get('notifier').danger('Danger notification'); 69 | this.get('notifier').secondary('Secondary notification'); 70 | ``` 71 | 72 | Custom notifications can be called using `add()`. 73 | 74 | ```js 75 | this.get('notifier').add('Custom notification', { type: 'custom-class' }); 76 | ``` 77 | 78 | All notifications can be cleared using `empty()`. 79 | 80 | ```js 81 | this.get('notifier').empty(); 82 | ``` 83 | 84 | Check out the [documentation](https://scottwernervt.github.io/ember-notifier) 85 | for more customization and options. 86 | 87 | Contributing 88 | ------------------------------------------------------------------------------ 89 | 90 | ### Issues 91 | 92 | Demonstrate bug using the provided [ember-twiddle](https://ember-twiddle.com/fc59431098da6a27cac671d0142a6440). 93 | 94 | ### Installation 95 | 96 | * `git clone https://github.com/scottwernervt/ember-notifier` 97 | * `cd ember-notifier` 98 | * `npm install` 99 | 100 | ### Linting 101 | 102 | * `npm run lint:hbs` 103 | * `npm run lint:js` 104 | * `npm run lint:js -- --fix` 105 | 106 | ### Running tests 107 | 108 | * `ember test` – Runs the test suite on the current Ember version 109 | * `ember test --server` – Runs the test suite in "watch mode" 110 | * `ember try:each` – Runs the test suite against multiple Ember versions 111 | 112 | ### Running the dummy application 113 | 114 | * `ember serve` 115 | * Visit the dummy application at [http://localhost:4200](http://localhost:4200). 116 | 117 | For more information on using ember-cli, visit [https://ember-cli.com/](https://ember-cli.com/). 118 | 119 | Favicon 120 | -------- 121 | 122 | Created at [favicon.io](https://favicon.io/?t=EN&ff=Aldrich&fs=72&fc=%23FFF&b=rounded&bc=%23A0A). 123 | 124 | License 125 | ------------------------------------------------------------------------------ 126 | 127 | This project is licensed under the [MIT License](LICENSE.md). 128 | -------------------------------------------------------------------------------- /addon/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scottwernervt/ember-notifier/cf231c52e1f8fab52293f350b88d894625a8ce54/addon/.gitkeep -------------------------------------------------------------------------------- /addon/components/ember-notifier-notification/close/component.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import layout from './template'; 3 | 4 | /** 5 | * The close button component. 6 | * 7 | * Inline usage: 8 | * ```hbs 9 | * {{ember-notifier-notification/close close=close}} 10 | * ``` 11 | * 12 | * Block param usage: 13 | * ```hbs 14 | * {{#ember-notifier-notification/close}} 15 | * 16 | * {{/ember-notifier-notification/close}} 17 | * ``` 18 | * 19 | * @class Close 20 | */ 21 | export default Component.extend({ 22 | layout, 23 | 24 | classNames: ['ember-notifier-close'], 25 | 26 | /** 27 | * Closure action to dismiss the notification. 28 | * 29 | * @argument close 30 | * @type ember/action 31 | */ 32 | close: null, 33 | }); 34 | -------------------------------------------------------------------------------- /addon/components/ember-notifier-notification/close/template.hbs: -------------------------------------------------------------------------------- 1 | {{#if hasBlock}} 2 | {{yield}} 3 | {{else}} 4 | 12 | {{/if}} -------------------------------------------------------------------------------- /addon/components/ember-notifier-notification/component.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import { readOnly } from '@ember/object/computed'; 3 | import { inject as service } from '@ember/service'; 4 | import SwipeSupportMixin from 'ember-notifier/mixins/swipe-support'; 5 | import defaultValue from 'ember-notifier/utils/default-value'; 6 | import layout from './template'; 7 | 8 | /** 9 | * The notification component which displays the icon, content, and close button. 10 | * 11 | * Inline usage: 12 | * ```hbs 13 | * {{ember-notifier-notification 14 | * notification=notification 15 | * close=(action "remove" notification)}} 16 | * ``` 17 | * 18 | * Custom notification components: 19 | * ```hbs 20 | * {{ember-notifier-notification 21 | * notification=notification 22 | * close=(action "remove" notification) 23 | * iconComponent='my-icon-component' 24 | * contentComponent='my-content-component' 25 | * closeComponent='my-close-component'}} 26 | * ``` 27 | * 28 | * If the mouse enters the notification and the notification is scheduled to be removed, it will be 29 | * paused and then restarted when the mouse leaves. If the user swipes right, the notification will 30 | * be closed. 31 | * 32 | * @class EmberNotifierNotification 33 | */ 34 | export default Component.extend(SwipeSupportMixin, { 35 | layout, 36 | 37 | notifier: service(), 38 | 39 | classNames: ['ember-notifier-notification-base'], 40 | classNameBindings: ['typeClass', 'animationStateClass'], 41 | attributeBindings: ['role'], 42 | role: 'alert', 43 | 44 | /** 45 | * The notification options object. 46 | * 47 | * @argument notification 48 | * @type !Object 49 | */ 50 | notification: undefined, 51 | 52 | /** 53 | * Closure action to remove the notification. 54 | * 55 | * @argument close 56 | * @type ember/action 57 | */ 58 | close: null, 59 | 60 | /** 61 | * The notification type class name. 62 | * 63 | * @argument typeClass 64 | * @type string 65 | * @readOnly 66 | */ 67 | typeClass: readOnly('notification.type'), 68 | 69 | /** 70 | * The notification animation state class name. 71 | * 72 | * @argument animationStateClass 73 | * @type string 74 | * @readOnly 75 | */ 76 | animationStateClass: readOnly('notification.animationState'), 77 | 78 | /** 79 | * The number of pixels a user must move before notification will close. 80 | * 81 | * @argument minSwipeDistance 82 | * @type number 83 | * @readOnly 84 | */ 85 | swipeThreshold: readOnly('notification.minSwipeDistance'), 86 | 87 | /** 88 | * The number of milliseconds a user must move before notification will close. 89 | * 90 | * @argument maxSwipeTime 91 | * @type number 92 | * @readOnly 93 | */ 94 | swipeTimeout: readOnly('notification.maxSwipeTime'), 95 | 96 | /** 97 | * The swipe direction, "left" or "right", to close a notification. 98 | * 99 | * @argument swipeDirection 100 | * @type string 101 | * @readOnly 102 | */ 103 | swipeDirection: readOnly('notification.swipeDirection'), 104 | 105 | /** 106 | * The icon component to render. 107 | * 108 | * Default is: `ember-notifier-notification/icon`. 109 | * 110 | * @argument iconComponent 111 | * @type string 112 | */ 113 | iconComponent: defaultValue('ember-notifier-notification/icon'), 114 | 115 | /** 116 | * The content component to render. 117 | * 118 | * Default is: `ember-notifier-notification/content`. 119 | * 120 | * @argument contentComponent 121 | * @type string 122 | */ 123 | contentComponent: defaultValue('ember-notifier-notification/content'), 124 | 125 | /** 126 | * The close component to render. 127 | * 128 | * Default is: `ember-notifier-notification/close`. 129 | * 130 | * @argument closeComponent 131 | * @type string 132 | */ 133 | closeComponent: defaultValue('ember-notifier-notification/close'), 134 | 135 | willDestroyElement() { 136 | this._super(...arguments); 137 | 138 | const notification = this.get('notification'); 139 | if (notification.get('timer')) { 140 | this.get('notifier').cancelRemoval(notification); 141 | } 142 | }, 143 | 144 | actions: { 145 | setOption(property, value) { 146 | this.get('notification').set(property, value); 147 | } 148 | }, 149 | 150 | mouseEnter(/* event */) { 151 | const notification = this.get('notification'); 152 | if (notification.get('duration') > 0) { 153 | this.get('notifier').cancelRemoval(notification); 154 | } 155 | }, 156 | 157 | mouseLeave(/* event */) { 158 | const notification = this.get('notification'); 159 | if (notification.get('duration') > 0) { 160 | this.get('notifier').scheduleRemoval(notification); 161 | } 162 | }, 163 | 164 | onSwipe(direction) { 165 | if (this.get('swipeDirection') === direction) { 166 | this.close(); 167 | } 168 | } 169 | }); 170 | -------------------------------------------------------------------------------- /addon/components/ember-notifier-notification/content/component.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import layout from './template'; 3 | 4 | /** 5 | * The content component which displays the title and message. 6 | * 7 | * Inline usage: 8 | * ```hbs 9 | * {{ember-notifier-notification/content 10 | * title=notification.title 11 | * message=notification.message}} 12 | * ``` 13 | * 14 | * Passing an a component name to `contentComponent` will rendered with the following 15 | * arguments: 16 | * ```hbs 17 | * {{component 18 | * contentComponent 19 | * title=title 20 | * message=message 21 | * setOption=setOption}} 22 | * ``` 23 | * 24 | * @class Content 25 | */ 26 | export default Component.extend({ 27 | layout, 28 | 29 | classNames: ['ember-notifier-content'], 30 | 31 | /** 32 | * Notification title/header. 33 | * 34 | * @argument title 35 | * @type [string] 36 | */ 37 | title: null, 38 | 39 | /** 40 | * Notification message. 41 | * 42 | * @argument message 43 | * @type [string] 44 | */ 45 | message: null, 46 | 47 | /** 48 | * Content component. 49 | * 50 | * @argument contentComponent 51 | * @type [Component] 52 | */ 53 | contentComponent: null, 54 | 55 | /** 56 | * Closure action to change a property on the notification object. 57 | * 58 | * @argument setOption 59 | * @type ember/action 60 | */ 61 | setOption: null, 62 | }); 63 | -------------------------------------------------------------------------------- /addon/components/ember-notifier-notification/content/template.hbs: -------------------------------------------------------------------------------- 1 | {{#if contentComponent}} 2 | {{component 3 | contentComponent 4 | title=title 5 | message=message 6 | setOption=setOption}} 7 | {{else}} 8 |
9 | {{this.title}} 10 |
11 | 14 | {{/if}} -------------------------------------------------------------------------------- /addon/components/ember-notifier-notification/icon/component.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import layout from './template'; 3 | 4 | /** 5 | * The icon component. 6 | * 7 | * Inline usage: 8 | * ```hbs 9 | * {{ember-notifier-notification/icon icon=notification.icon}} 10 | * ``` 11 | * 12 | * Block param usage: 13 | * ```hbs 14 | * {{#ember-notifier-notification/icon}} 15 | * {{fa-icon notification.icon}} 16 | * {{/ember-notifier-notification/icon}} 17 | * ``` 18 | * 19 | * @class Icon 20 | */ 21 | export default Component.extend({ 22 | layout, 23 | 24 | classNames: ['ember-notifier-icon'], 25 | 26 | /** 27 | * Icon class name or object name. 28 | * 29 | * @argument icon 30 | * @type string 31 | */ 32 | icon: null, 33 | }); 34 | -------------------------------------------------------------------------------- /addon/components/ember-notifier-notification/icon/template.hbs: -------------------------------------------------------------------------------- 1 | 2 | {{#if hasBlock}} 3 | {{yield}} 4 | {{else}} 5 | 6 | {{/if}} 7 | -------------------------------------------------------------------------------- /addon/components/ember-notifier-notification/template.hbs: -------------------------------------------------------------------------------- 1 | {{#if hasBlock}} 2 | {{yield}} 3 | {{else}} 4 | {{component 5 | iconComponent 6 | icon=notification.icon}} 7 | {{component 8 | contentComponent 9 | title=notification.title 10 | message=notification.message 11 | contentComponent=notification.contentComponent 12 | setOption=(action "setOption")}} 13 | {{component 14 | closeComponent 15 | close=close}} 16 | {{/if}} 17 | -------------------------------------------------------------------------------- /addon/components/ember-notifier/component.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import { readOnly } from '@ember/object/computed'; 3 | import { inject as service } from '@ember/service'; 4 | import layout from './template'; 5 | 6 | /** 7 | * The notification container which positions and displays active notifications. 8 | * 9 | * Inline usage: 10 | * ```hbs 11 | * {{ember-notifier position="is-top-right"}} 12 | * ``` 13 | * 14 | * Block param usage: 15 | * ```hbs 16 | * {{#ember-notifier notificationClass='alert' as |notification close|}} 17 | *{{notification.message}}
19 | * 20 | * {{/ember-notifier}} 21 | * ``` 22 | * 23 | * @class EmberNotifier 24 | * @yield {EmberObject} notification The notification object. 25 | * @yield {ember/action} close Closure action to dismiss the notification. 26 | */ 27 | export default Component.extend({ 28 | layout, 29 | 30 | notifier: service(), 31 | 32 | classNames: ['ember-notifier'], 33 | classNameBindings: ['position'], 34 | 35 | /** 36 | * The default class name for notifications. 37 | * 38 | * @argument notificationClass 39 | * @type string 40 | */ 41 | notificationClass: 'ember-notifier-notification', 42 | 43 | /** 44 | * The location class name of notifications on the screen. 45 | * 46 | * Supported positions: 47 | * * `is-top` 48 | * * `is-top-left` 49 | * * `is-top-right` 50 | * * `is-bottom` 51 | * * `is-bottom-left` 52 | * * `is-bottom-right` 53 | * 54 | * @argument position='is-top-right' 55 | * @type [string] 56 | */ 57 | position: null, 58 | 59 | /** 60 | * The default icon component. 61 | * 62 | * @argument iconComponent 63 | * @type [string] 64 | */ 65 | iconComponent: undefined, 66 | 67 | /** 68 | * The default content component. 69 | * 70 | * @argument contentComponent 71 | * @type [string] 72 | */ 73 | contentComponent: undefined, 74 | 75 | /** 76 | * The default close component. 77 | * 78 | * @argument closeComponent 79 | * @type [string] 80 | */ 81 | closeComponent: undefined, 82 | 83 | notifications: readOnly('notifier.notifications'), 84 | 85 | init() { 86 | this._super(...arguments); 87 | const config = this.get('notifier.config'); 88 | if (!this.get('position')) { 89 | this.set('position', config.position); 90 | } 91 | }, 92 | 93 | willDestroyElement() { 94 | this._super(...arguments); 95 | this.get('notifier').empty(); 96 | }, 97 | 98 | actions: { 99 | remove(message) { 100 | this.get('notifier').remove(message); 101 | }, 102 | }, 103 | }); 104 | -------------------------------------------------------------------------------- /addon/components/ember-notifier/template.hbs: -------------------------------------------------------------------------------- 1 | {{#each notifications as |notification|}} 2 | {{#if hasBlock}} 3 | {{#ember-notifier-notification 4 | class=(readonly notificationClass) 5 | notification=notification 6 | close=(action "remove" notification) 7 | iconComponent=(readonly iconComponent) 8 | contentComponent=(readonly contentComponent) 9 | closeComponent=(readonly closeComponent)}} 10 | {{yield notification (action "remove" notification)}} 11 | {{/ember-notifier-notification}} 12 | {{else}} 13 | {{ember-notifier-notification 14 | class=(readonly notificationClass) 15 | notification=notification 16 | close=(action "remove" notification) 17 | iconComponent=(readonly iconComponent) 18 | contentComponent=(readonly contentComponent) 19 | closeComponent=(readonly closeComponent)}} 20 | {{/if}} 21 | {{/each}} -------------------------------------------------------------------------------- /addon/mixins/swipe-support.js: -------------------------------------------------------------------------------- 1 | import { readOnly } from '@ember/object/computed'; 2 | import Mixin from '@ember/object/mixin'; 3 | import { isNone } from '@ember/utils'; 4 | 5 | let meta; 6 | 7 | // Source: https://github.com/offirgolan/ember-burger-menu/blob/master/addon/mixins/swipe-support.js 8 | export default Mixin.create({ 9 | minSwipeDistance: readOnly('notification.minSwipeDistance'), 10 | maxSwipeTime: readOnly('notification.maxSwipeTime'), 11 | 12 | onSwipe(/* direction, target */) { 13 | }, 14 | 15 | touchStart(event) { 16 | this._super(...arguments); 17 | 18 | const touch = event.touches[0]; 19 | 20 | meta = { 21 | target: event.target, 22 | start: { 23 | x: touch.pageX, 24 | y: touch.pageY, 25 | time: new Date().getTime(), 26 | } 27 | }; 28 | }, 29 | 30 | touchMove(event) { 31 | this._super(...arguments); 32 | 33 | const touch = event.touches[0]; 34 | 35 | meta.differences = { 36 | x: touch.pageX - meta.start.x, 37 | y: touch.pageY - meta.start.y 38 | }; 39 | 40 | // Compute swipe direction 41 | if (isNone(meta.isHorizontal)) { 42 | meta.isHorizontal = Math.abs(meta.differences.x) > Math.abs(meta.differences.y); 43 | } 44 | 45 | // A valid swipe event uses only one finger 46 | if (event.touches.length > 1) { 47 | meta.isInvalid = true; 48 | } 49 | }, 50 | 51 | touchEnd() { 52 | this._super(...arguments); 53 | 54 | const minSwipeDistance = this.get('minSwipeDistance'); 55 | const maxSwipeTime = this.get('maxSwipeTime'); 56 | const elapsedTime = new Date().getTime() - meta.start.time; 57 | 58 | if (meta.isHorizontal 59 | && !meta.isInvalid 60 | && Math.abs(meta.differences.x) >= minSwipeDistance 61 | && elapsedTime <= maxSwipeTime) { 62 | this.onSwipe(meta.differences.x > 0 ? 'right' : 'left', meta.target); 63 | } 64 | } 65 | }); 66 | -------------------------------------------------------------------------------- /addon/services/notifier.js: -------------------------------------------------------------------------------- 1 | import { getOwner } from '@ember/application'; 2 | import { A } from '@ember/array'; 3 | import EmberObject, { computed } from '@ember/object'; 4 | import { assign } from '@ember/polyfills'; 5 | import { cancel, later, run } from '@ember/runloop'; 6 | import Service from '@ember/service'; 7 | 8 | const defaultConfig = { 9 | position: 'is-top-right', 10 | duration: 4200, // ms 11 | primaryClass: 'is-primary', 12 | primaryIcon: 'fas fa-bell', 13 | infoClass: 'is-info', 14 | infoIcon: 'fas fa-info', 15 | successClass: 'is-success', 16 | successIcon: 'fas fa-check', 17 | warningClass: 'is-warning', 18 | warningIcon: 'fas fa-exclamation', 19 | dangerClass: 'is-danger', 20 | dangerIcon: 'fas fa-fire', 21 | secondaryClass: 'is-secondary', 22 | secondaryIcon: 'fas fa-comment', 23 | showAnimationClass: 'ember-notifier-notification-show', 24 | hideAnimationClass: 'ember-notifier-notification-hide', 25 | animationTimeout: 500, // ms 26 | minSwipeDistance: 150, // pixels 27 | maxSwipeTime: 300, // ms 28 | swipeDirection: 'right', // 'left' or 'right' 29 | }; 30 | 31 | /** 32 | * The notifier service is the public API that provides access to displaying, adding, or removing 33 | * notifications. 34 | * 35 | * Usage: 36 | * ```js 37 | * import Controller from '@ember/controller'; 38 | * import { inject as service } from '@ember/service'; 39 | * 40 | * export default Controller.extend({ 41 | * notifier: service(), 42 | * }); 43 | * ``` 44 | * 45 | * @class NotifierService 46 | * @public 47 | */ 48 | export default Service.extend({ 49 | /** 50 | * Notification array. 51 | * 52 | * @property notification 53 | * @type {ember/array} 54 | */ 55 | notifications: null, 56 | 57 | config: computed(function () { 58 | const config = getOwner(this).resolveRegistration('config:environment').emberNotifier || {}; 59 | return assign(defaultConfig, config); 60 | }), 61 | 62 | init() { 63 | this._super(...arguments); 64 | this.set('notifications', A()); 65 | }, 66 | 67 | /** 68 | * Adds a primary styled notification. 69 | * 70 | * @method primary 71 | * @param {string} message The notification message. 72 | * @param {Object} [options] Optional notification options. 73 | */ 74 | primary(message, options) { 75 | this.add(assign({ 76 | message, 77 | type: this.get('config.primaryClass'), 78 | icon: this.get('config.primaryIcon'), 79 | }, options)); 80 | }, 81 | 82 | /** 83 | * Adds an info styled notification. 84 | * 85 | * @method info 86 | * @param {string} message The notification message. 87 | * @param {Object} [options] Optional notification options. 88 | */ 89 | info(message, options) { 90 | this.add(assign({ 91 | message, 92 | type: this.get('config.infoClass'), 93 | icon: this.get('config.infoIcon'), 94 | }, options)); 95 | }, 96 | 97 | /** 98 | * Adds a success styled notification. 99 | * 100 | * @method success 101 | * @param {string} message The notification message. 102 | * @param {Object} [options] Optional notification options. 103 | */ 104 | success(message, options) { 105 | this.add(assign({ 106 | message, 107 | type: this.get('config.successClass'), 108 | icon: this.get('config.successIcon'), 109 | }, options)); 110 | }, 111 | 112 | /** 113 | * Adds a warning styled notification. 114 | * 115 | * @method warning 116 | * @param {string} message The notification message. 117 | * @param {Object} [options] Optional notification options. 118 | */ 119 | warning(message, options) { 120 | this.add(assign({ 121 | message, 122 | type: this.get('config.warningClass'), 123 | icon: this.get('config.warningIcon'), 124 | }, options)); 125 | }, 126 | 127 | /** 128 | * Adds a danger styled notification. 129 | * 130 | * @method danger 131 | * @param {string} message The notification message. 132 | * @param {Object} [options] Optional notification options. 133 | */ 134 | danger(message, options) { 135 | this.add(assign({ 136 | message, 137 | type: this.get('config.dangerClass'), 138 | icon: this.get('config.dangerIcon'), 139 | }, options)); 140 | }, 141 | 142 | /** 143 | * Adds a secondary styled notification. 144 | * 145 | * @method secondary 146 | * @param {string} message The notification message. 147 | * @param {Object} [options] Optional notification options. 148 | */ 149 | secondary(message, options) { 150 | this.add(assign({ 151 | message, 152 | type: this.get('config.secondaryClass'), 153 | icon: this.get('config.secondaryIcon'), 154 | }, options)); 155 | }, 156 | 157 | /** 158 | * Adds a custom notification. 159 | * 160 | * @method add 161 | * @param {Object} options Notification options. 162 | * @param {string} options.type Styled class name. 163 | * @param {number} options.duration Remove notification after "n" milliseconds. Disable scheduled 164 | * removal with a value of "0". 165 | * @param {string} [options.title] Optional title. 166 | * @param {string} [options.message] Optional message. 167 | * @param {string} [options.contentComponent] Optional content component name. 168 | * @param {string} [options.icon] Optional icon class name or object name. 169 | * @param {string} [options.showAnimationClass] Optional show animation class name. 170 | * @param {string} [options.hideAnimationClass] Optional hide animation class name. 171 | * @param {string} [options.animationTimeout] Optional number of milliseconds before a 172 | * notification is removed. 173 | * @param {number} [options.minSwipeDistance] Number of pixels a swipe right must travel. 174 | * @param {number} [options.maxSwipeTime] Number of milliseconds between touch start and end. 175 | * @param {string} [options.swipeDirection] The swipe direction which will close a notification. 176 | * @param {function} [options.onRemove] Optional callback function when notification is removed. 177 | */ 178 | add(options = {}) { 179 | if (!options.message && !options.contentComponent) { 180 | throw new Error('No message or contentComponent set.'); 181 | } 182 | 183 | const defaultOptions = EmberObject.create({ 184 | type: this.get('config.primaryClass'), 185 | duration: this.get('config.duration'), 186 | animationState: this.get('config.showAnimationClass'), 187 | animationTimeout: this.get('config.animationTimeout'), 188 | minSwipeDistance: this.get('config.minSwipeDistance'), 189 | maxSwipeTime: this.get('config.maxSwipeTime'), 190 | swipeDirection: this.get('config.swipeDirection'), 191 | timer: null, 192 | onRemove: () => void 0, 193 | }); 194 | 195 | const notification = assign(defaultOptions, options); 196 | this.get('notifications').insertAt(0, notification); 197 | 198 | if (notification.duration > 0) { 199 | this.scheduleRemoval(notification); 200 | } 201 | }, 202 | 203 | /** 204 | * Removes a notification. 205 | * 206 | * @method remove 207 | * @param {Object} notification The notification to remove. 208 | */ 209 | remove(notification) { 210 | this.cancelRemoval(notification); 211 | run(this, () => notification.set('animationState', this.get('config.hideAnimationClass'))); 212 | later(this, () => { 213 | notification.onRemove(); 214 | this.get('notifications').removeObject(notification); 215 | }, notification.get('animationTimeout')); 216 | }, 217 | 218 | /** 219 | * Removes all notifications. 220 | * 221 | * @method empty 222 | */ 223 | empty() { 224 | this.get('notifications').forEach(notification => this.remove(notification)); 225 | }, 226 | 227 | /** 228 | * Schedules removal of a notification based on a duration property. 229 | * 230 | * @method scheduleRemoval 231 | * @param {Object} notification The notification to schedule the removal on. 232 | */ 233 | scheduleRemoval(notification) { 234 | const timer = later(this, () => this.remove(notification), notification.get('duration')); 235 | notification.set('timer', timer); 236 | }, 237 | 238 | /** 239 | * Cancels a scheduled removal of a notification. 240 | * 241 | * @method cancelRemoval 242 | * @param {Object} notification The notification to cancel the timer on. 243 | */ 244 | cancelRemoval(notification) { 245 | cancel(notification.get('timer')); 246 | }, 247 | }); 248 | -------------------------------------------------------------------------------- /addon/utils/default-value.js: -------------------------------------------------------------------------------- 1 | import { computed } from '@ember/object'; 2 | 3 | /** 4 | * Fallback to a default value if the property is undefined. 5 | * 6 | * Source: 7 | * [github.com/cibernox/ember-power-select](https://github.com/cibernox/ember-power-select/blob/master/addon/utils/computed-fallback-if-undefined.js) 8 | * 9 | * @function defaultValue 10 | * @param {string} fallback Fallback value if property is undefined. 11 | * @return {string} The property value. 12 | */ 13 | export default function defaultValue(fallback) { 14 | return computed({ 15 | get() { 16 | return fallback; 17 | }, 18 | set(_, value) { 19 | return value === undefined ? fallback : value; 20 | } 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /app/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scottwernervt/ember-notifier/cf231c52e1f8fab52293f350b88d894625a8ce54/app/.gitkeep -------------------------------------------------------------------------------- /app/components/ember-notifier-notification/close/component.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-notifier/components/ember-notifier-notification/close/component'; -------------------------------------------------------------------------------- /app/components/ember-notifier-notification/component.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-notifier/components/ember-notifier-notification/component'; -------------------------------------------------------------------------------- /app/components/ember-notifier-notification/content/component.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-notifier/components/ember-notifier-notification/content/component'; -------------------------------------------------------------------------------- /app/components/ember-notifier-notification/icon/component.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-notifier/components/ember-notifier-notification/icon/component'; -------------------------------------------------------------------------------- /app/components/ember-notifier/component.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-notifier/components/ember-notifier/component'; -------------------------------------------------------------------------------- /app/services/notifier.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-notifier/services/notifier'; 2 | -------------------------------------------------------------------------------- /app/styles/ember-notifier.scss: -------------------------------------------------------------------------------- 1 | // Reference: https://github.com/finnp/dom-notifications 2 | $ember-notifier-z-index: 999999 !default; 3 | $ember-notifier-padding: 1rem !default; 4 | $ember-notifier-text-color: #ffffff !default; 5 | $ember-notifier-default-background-color: #ffffff !default; 6 | $ember-notifier-primary-background-color: #00d1b2 !default; 7 | $ember-notifier-info-background-color: #3ea2ff !default; 8 | $ember-notifier-success-background-color: #64ce83 !default; 9 | $ember-notifier-warning-background-color: #ff7f48 !default; 10 | $ember-notifier-danger-background-color: #e74c3c !default; 11 | $ember-notifier-secondary-background-color: #dbdbdb !default; 12 | $ember-notifier-width: 100% !default; 13 | $ember-notifier-max-width: 420px !default; 14 | $ember-notifier-max-height: 640px !default; 15 | $ember-notifier-border-radius: 4px !default; 16 | $ember-notifier-margin: 0.25rem 0 !default; 17 | 18 | $ember-notifier-icon-color: rgba(255, 255, 255, .74) !default; 19 | $ember-notifier-icon-width: 30px !default; 20 | $ember-notifier-icon-primary-background-color: darken($ember-notifier-primary-background-color, 8%) !default; 21 | $ember-notifier-icon-info-background-color: darken($ember-notifier-info-background-color, 8%) !default; 22 | $ember-notifier-icon-success-background-color: darken($ember-notifier-success-background-color, 8%) !default; 23 | $ember-notifier-icon-warning-background-color: darken($ember-notifier-warning-background-color, 8%) !default; 24 | $ember-notifier-icon-danger-background-color: darken($ember-notifier-danger-background-color, 8%) !default; 25 | $ember-notifier-icon-secondary-background-color: darken($ember-notifier-secondary-background-color, 8%) !default; 26 | 27 | $ember-notifier-content-padding: 5px 10px !default; 28 | $ember-notifier-content-margin: 0 30px !default; 29 | $ember-notifier-title-margin: 0 !default; 30 | $ember-notifier-message-margin: 0 !default; 31 | 32 | $ember-notifier-close-button-width: $ember-notifier-icon-width !default; 33 | $ember-notifier-close-button-height: $ember-notifier-icon-width !default; 34 | $ember-notifier-close-button-line-height: $ember-notifier-close-button-height !default; 35 | $ember-notifier-close-button-color: $ember-notifier-icon-color !default; 36 | $ember-notifier-close-button-opacity: 0.8 !default; 37 | $ember-notifier-close-button-hover-opacity: 1 !default; 38 | $ember-notifier-close-button-size: 1.5rem !default; 39 | 40 | .ember-notifier { 41 | position: fixed; 42 | z-index: $ember-notifier-z-index; 43 | display: flex; 44 | overflow: hidden; 45 | align-items: stretch; 46 | justify-content: flex-start; 47 | flex-direction: column; 48 | width: $ember-notifier-width; 49 | max-width: $ember-notifier-max-width; 50 | padding: $ember-notifier-padding; 51 | margin: 0 auto; 52 | pointer-events: none; 53 | 54 | // positions 55 | &.is-top { 56 | top: 0; 57 | left: 0; 58 | right: 0; 59 | } 60 | 61 | &.is-top-left { 62 | top: 0; 63 | left: 0; 64 | right: auto; 65 | } 66 | 67 | &.is-top-right { 68 | top: 0; 69 | left: auto; 70 | right: 0; 71 | } 72 | 73 | &.is-bottom { 74 | bottom: 0; 75 | left: 0; 76 | right: 0; 77 | flex-direction: column-reverse; 78 | } 79 | 80 | &.is-bottom-left { 81 | bottom: 0; 82 | left: 0; 83 | right: auto; 84 | flex-direction: column-reverse; 85 | } 86 | 87 | &.is-bottom-right { 88 | bottom: 0; 89 | left: auto; 90 | right: 0; 91 | flex-direction: column-reverse; 92 | } 93 | } 94 | 95 | .ember-notifier-notification-base { 96 | position: relative; 97 | overflow: hidden; 98 | margin: $ember-notifier-margin; 99 | pointer-events: auto; 100 | } 101 | 102 | .ember-notifier-notification { 103 | display: block; 104 | max-height: $ember-notifier-max-height; 105 | border-radius: $ember-notifier-border-radius; 106 | color: $ember-notifier-text-color; 107 | background-color: $ember-notifier-default-background-color; 108 | 109 | // colors 110 | &.is-primary { 111 | background-color: $ember-notifier-primary-background-color; 112 | 113 | .ember-notifier-icon { 114 | background-color: $ember-notifier-icon-primary-background-color; 115 | } 116 | } 117 | 118 | &.is-info { 119 | background-color: $ember-notifier-info-background-color; 120 | 121 | .ember-notifier-icon { 122 | background-color: $ember-notifier-icon-info-background-color; 123 | } 124 | } 125 | 126 | &.is-success { 127 | background-color: $ember-notifier-success-background-color; 128 | 129 | .ember-notifier-icon { 130 | background-color: $ember-notifier-icon-success-background-color; 131 | } 132 | } 133 | 134 | &.is-warning { 135 | background-color: $ember-notifier-warning-background-color; 136 | 137 | .ember-notifier-icon { 138 | background-color: $ember-notifier-icon-warning-background-color; 139 | } 140 | } 141 | 142 | &.is-danger { 143 | background-color: $ember-notifier-danger-background-color; 144 | 145 | .ember-notifier-icon { 146 | background-color: $ember-notifier-icon-danger-background-color; 147 | } 148 | } 149 | 150 | &.is-secondary { 151 | background-color: $ember-notifier-secondary-background-color; 152 | 153 | .ember-notifier-icon { 154 | background-color: $ember-notifier-icon-secondary-background-color; 155 | } 156 | } 157 | } 158 | 159 | .ember-notifier-icon { 160 | position: absolute; 161 | top: 0; 162 | left: 0; 163 | width: $ember-notifier-icon-width; 164 | height: 100%; 165 | color: $ember-notifier-icon-color; 166 | text-align: center; 167 | 168 | span { 169 | position: relative; 170 | top: 5px; 171 | } 172 | } 173 | 174 | .ember-notifier-content { 175 | padding: $ember-notifier-content-padding; 176 | margin: $ember-notifier-content-margin; 177 | -ms-word-wrap: break-word; 178 | word-wrap: break-word; 179 | } 180 | 181 | .ember-notifier-title { 182 | margin: $ember-notifier-title-margin; 183 | } 184 | 185 | .ember-notifier-message { 186 | margin: $ember-notifier-message-margin; 187 | } 188 | 189 | .ember-notifier-close { 190 | position: absolute; 191 | top: 0; 192 | right: 0; 193 | text-align: center; 194 | } 195 | 196 | .ember-notifier-close-button { 197 | position: relative; 198 | margin: 0; 199 | width: $ember-notifier-close-button-width; 200 | height: $ember-notifier-close-button-height; 201 | -moz-appearance: none; 202 | -webkit-appearance: none; 203 | appearance: none; 204 | padding: 0; 205 | border: none; 206 | background: transparent; 207 | color: $ember-notifier-close-button-color; 208 | opacity: $ember-notifier-close-button-opacity; 209 | font-size: $ember-notifier-close-button-size; 210 | line-height: $ember-notifier-close-button-line-height; 211 | text-align: center; 212 | cursor: pointer; 213 | 214 | &:hover, 215 | &:focus { 216 | opacity: $ember-notifier-close-button-hover-opacity; 217 | } 218 | } 219 | 220 | /* ---------------------------------------------- 221 | * Generated by Animista on 2018-9-21 14:33:11 222 | * w: http://animista.net, t: @cssanimista 223 | * ---------------------------------------------- */ 224 | .ember-notifier-notification-show { 225 | -webkit-animation: notification-show 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; 226 | animation: notification-show 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; 227 | } 228 | 229 | .ember-notifier-notification-hide { 230 | -webkit-animation: notification-hide 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; 231 | animation: notification-hide 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both; 232 | } 233 | 234 | @-webkit-keyframes notification-show { 235 | 0% { 236 | -webkit-transform: scale(0); 237 | transform: scale(0); 238 | opacity: 1; 239 | } 240 | 100% { 241 | -webkit-transform: scale(1); 242 | transform: scale(1); 243 | opacity: 1; 244 | } 245 | } 246 | 247 | @keyframes notification-show { 248 | 0% { 249 | -webkit-transform: scale(0); 250 | transform: scale(0); 251 | opacity: 1; 252 | } 253 | 100% { 254 | -webkit-transform: scale(1); 255 | transform: scale(1); 256 | opacity: 1; 257 | } 258 | } 259 | 260 | @-webkit-keyframes notification-hide { 261 | 0% { 262 | -webkit-transform: scale(1); 263 | transform: scale(1); 264 | opacity: 1; 265 | 266 | } 267 | 100% { 268 | -webkit-transform: scale(0); 269 | transform: scale(0); 270 | opacity: 1; 271 | } 272 | } 273 | 274 | @keyframes notification-hide { 275 | 0% { 276 | -webkit-transform: scale(1); 277 | transform: scale(1); 278 | opacity: 1; 279 | } 280 | 100% { 281 | -webkit-transform: scale(0); 282 | transform: scale(0); 283 | opacity: 1; 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /app/utils/default-value.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-notifier/utils/default-value'; 2 | -------------------------------------------------------------------------------- /config/addon-docs.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | const AddonDocsConfig = require('ember-cli-addon-docs/lib/config'); 5 | 6 | module.exports = class extends AddonDocsConfig { 7 | // See https://ember-learn.github.io/ember-cli-addon-docs/docs/deploying 8 | // for details on configuration you can override here. 9 | }; 10 | -------------------------------------------------------------------------------- /config/deploy.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 'use strict'; 3 | 4 | module.exports = function(deployTarget) { 5 | let ENV = { 6 | build: {} 7 | // include other plugin configuration that applies to all deploy targets here 8 | }; 9 | 10 | if (deployTarget === 'development') { 11 | ENV.build.environment = 'development'; 12 | // configure other plugins for development deploy target here 13 | } 14 | 15 | if (deployTarget === 'staging') { 16 | ENV.build.environment = 'production'; 17 | // configure other plugins for staging deploy target here 18 | } 19 | 20 | if (deployTarget === 'production') { 21 | ENV.build.environment = 'production'; 22 | // configure other plugins for production deploy target here 23 | } 24 | 25 | // Note: if you need to build some configuration asynchronously, you can return 26 | // a promise that resolves with the ENV object instead of returning the 27 | // ENV object synchronously. 28 | return ENV; 29 | }; 30 | -------------------------------------------------------------------------------- /config/ember-try.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const getChannelURL = require('ember-source-channel-url'); 4 | 5 | module.exports = function() { 6 | return Promise.all([ 7 | getChannelURL('release'), 8 | getChannelURL('beta'), 9 | getChannelURL('canary') 10 | ]).then((urls) => { 11 | return { 12 | // TODO: Toggle to false (https://github.com/ember-cli/ember-try/issues/207). 13 | useYarn: true, 14 | scenarios: [ 15 | { 16 | name: 'ember-lts-2.16', 17 | env: { 18 | EMBER_OPTIONAL_FEATURES: JSON.stringify({ 'jquery-integration': true }) 19 | }, 20 | npm: { 21 | devDependencies: { 22 | '@ember/jquery': '^0.5.1', 23 | 'ember-source': '~2.16.0' 24 | } 25 | } 26 | }, 27 | { 28 | name: 'ember-lts-2.18', 29 | env: { 30 | EMBER_OPTIONAL_FEATURES: JSON.stringify({ 'jquery-integration': true }) 31 | }, 32 | npm: { 33 | devDependencies: { 34 | '@ember/jquery': '^0.5.1', 35 | 'ember-source': '~2.18.0' 36 | } 37 | } 38 | }, 39 | { 40 | name: 'ember-release', 41 | npm: { 42 | devDependencies: { 43 | 'ember-source': urls[0] 44 | } 45 | } 46 | }, 47 | { 48 | name: 'ember-beta', 49 | npm: { 50 | devDependencies: { 51 | 'ember-source': urls[1] 52 | } 53 | } 54 | }, 55 | { 56 | name: 'ember-canary', 57 | npm: { 58 | devDependencies: { 59 | 'ember-source': urls[2] 60 | } 61 | } 62 | }, 63 | { 64 | name: 'ember-default', 65 | npm: { 66 | devDependencies: {} 67 | } 68 | }, 69 | { 70 | name: 'ember-default-with-jquery', 71 | env: { 72 | EMBER_OPTIONAL_FEATURES: JSON.stringify({ 73 | 'jquery-integration': true 74 | }) 75 | }, 76 | npm: { 77 | devDependencies: { 78 | '@ember/jquery': '^0.5.1' 79 | } 80 | } 81 | } 82 | ] 83 | }; 84 | }); 85 | }; 86 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(/* environment, appConfig */) { 4 | return { }; 5 | }; 6 | -------------------------------------------------------------------------------- /ember-cli-build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const EmberAddon = require('ember-cli/lib/broccoli/ember-addon'); 4 | const sass = require('sass'); 5 | 6 | module.exports = function(defaults) { 7 | let app = new EmberAddon(defaults, { 8 | sassOptions: { 9 | implementation: sass, 10 | }, 11 | // Workaround: Broccoli Builder ran into an error with `UglifyWriter` plugin. 12 | 'ember-cli-uglify': { 13 | uglify: { 14 | compress: false, 15 | } 16 | }, 17 | }); 18 | 19 | /* 20 | This build file specifies the options for the dummy test app of this 21 | addon, located in `/tests/dummy` 22 | This build file does *not* influence how the addon or the app using it 23 | behave. You most likely want to be modifying `./index.js` or app's build file 24 | */ 25 | 26 | return app.toTree(); 27 | }; 28 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | name: 'ember-notifier' 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-notifier", 3 | "version": "0.1.3", 4 | "description": "Easy, beautiful notifications for your Ember project.", 5 | "keywords": [ 6 | "ember-addon", 7 | "ember", 8 | "ember-cli", 9 | "notification", 10 | "notify", 11 | "flash", 12 | "callout", 13 | "growl", 14 | "toast" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/scottwernervt/ember-notifier.git" 19 | }, 20 | "license": "MIT", 21 | "author": { 22 | "name": "Scott Werner", 23 | "email": "scott.werner.vt@gmail.com", 24 | "url": "https://github.com/scottwernervt" 25 | }, 26 | "directories": { 27 | "doc": "doc", 28 | "test": "tests" 29 | }, 30 | "homepage": "https://scottwernervt.github.io/ember-notifier", 31 | "bugs": { 32 | "url": "https://github.com/scottwernervt/ember-notifier/issues", 33 | "email": "scott.werner.vt@gmail.com" 34 | }, 35 | "scripts": { 36 | "build": "ember build", 37 | "lint:hbs": "ember-template-lint .", 38 | "lint:js": "eslint .", 39 | "start": "ember serve", 40 | "test": "ember test", 41 | "test:all": "ember try:each", 42 | "test:reset": "ember try:reset", 43 | "test:server": "ember test --server" 44 | }, 45 | "dependencies": { 46 | "ember-cli-babel": "7.1.4", 47 | "ember-cli-htmlbars": "^3.0.1" 48 | }, 49 | "devDependencies": { 50 | "@ember/optional-features": "^0.7.0", 51 | "broccoli-asset-rev": "^3.0.0", 52 | "ember-ajax": "^4.0.1", 53 | "ember-cli": "~3.5.1", 54 | "ember-cli-addon-docs": "^0.6.1", 55 | "ember-cli-addon-docs-yuidoc": "^0.2.1", 56 | "ember-cli-dependency-checker": "^3.0.0", 57 | "ember-cli-deploy": "^1.0.2", 58 | "ember-cli-deploy-build": "^1.1.1", 59 | "ember-cli-deploy-git": "^1.3.3", 60 | "ember-cli-deploy-git-ci": "^1.0.1", 61 | "ember-cli-eslint": "^5.0.0", 62 | "ember-cli-htmlbars-inline-precompile": "^2.0.0", 63 | "ember-cli-inject-live-reload": "^2.0.1", 64 | "ember-cli-qunit": "^4.4.0", 65 | "ember-cli-sass": "^8.0.1", 66 | "ember-cli-sri": "^2.1.1", 67 | "ember-cli-template-lint": "^1.0.0-beta.2", 68 | "ember-cli-uglify": "^2.1.0", 69 | "ember-concurrency": "^0.8.25", 70 | "ember-disable-prototype-extensions": "^1.1.3", 71 | "ember-export-application-global": "^2.0.0", 72 | "ember-load-initializers": "^2.0.0", 73 | "ember-maybe-import-regenerator": "^0.1.6", 74 | "ember-resolver": "^5.0.1", 75 | "ember-source": "~3.6.0", 76 | "ember-source-channel-url": "^1.1.0", 77 | "ember-try": "^1.1.0", 78 | "eslint-plugin-ember": "^6.0.1", 79 | "eslint-plugin-node": "^8.0.0", 80 | "loader.js": "^4.7.0", 81 | "qunit-dom": "^0.8.3", 82 | "sass": "^1.15.2" 83 | }, 84 | "engines": { 85 | "node": "6.* || 8.* || >= 10.*" 86 | }, 87 | "ember-addon": { 88 | "configPath": "tests/dummy/config" 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /testem.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | test_page: 'tests/index.html?hidepassed', 3 | disable_watching: true, 4 | launch_in_ci: [ 5 | 'Chrome', 6 | ], 7 | launch_in_dev: [ 8 | 'Chrome' 9 | ], 10 | browser_args: { 11 | Chrome: { 12 | ci: [ 13 | // --no-sandbox is needed when running Chrome inside a container 14 | process.env.CI ? '--no-sandbox' : null, 15 | '--headless', 16 | '--disable-gpu', 17 | '--disable-dev-shm-usage', 18 | '--disable-software-rasterizer', 19 | '--mute-audio', 20 | '--remote-debugging-port=0', 21 | '--window-size=1440,900' 22 | ].filter(Boolean) 23 | } 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /tests/dummy/app/app.js: -------------------------------------------------------------------------------- 1 | import Application from '@ember/application'; 2 | import Resolver from './resolver'; 3 | import loadInitializers from 'ember-load-initializers'; 4 | import config from './config/environment'; 5 | 6 | const App = Application.extend({ 7 | modulePrefix: config.modulePrefix, 8 | podModulePrefix: config.podModulePrefix, 9 | Resolver 10 | }); 11 | 12 | loadInitializers(App, config.modulePrefix); 13 | 14 | export default App; 15 | -------------------------------------------------------------------------------- /tests/dummy/app/application/controller.js: -------------------------------------------------------------------------------- 1 | import Controller from '@ember/controller'; 2 | import { inject as service } from '@ember/service'; 3 | 4 | export default Controller.extend({ 5 | demo: service(), 6 | }); 7 | -------------------------------------------------------------------------------- /tests/dummy/app/application/template.hbs: -------------------------------------------------------------------------------- 1 | {{docs-header}} 2 | 3 | {{outlet}} 4 | 5 | {{docs-keyboard-shortcuts}} 6 | 7 | {{!--addon inline --}} 8 | {{ember-notifier position=demo.position}} 9 | 10 | {{!--addon block param --}} 11 | {{!--{{#ember-notifier notificationClass='alert' as |notification close|}}--}} 12 | {{!--{{notification.message}}
--}} 14 | {{!----}} 15 | {{!--{{/ember-notifier}}--}} 16 | 17 | {{!--bulma--}} 18 | {{!--{{#ember-notifier notificationClass='notification' as |notification close|}}--}} 19 | {{!----}} 20 | {{!--{{#if notification.contentComponent}}--}} 21 | {{!--{{component--}} 22 | {{!--notification.contentComponent--}} 23 | {{!--title=notification.title--}} 24 | {{!--message=notification.message}}--}} 25 | {{!--{{else}}--}} 26 | {{!--{{notification.message}}--}} 27 | {{!--{{/if}}--}} 28 | {{!--{{/ember-notifier}}--}} 29 | 30 | {{!--spectre--}} 31 | {{!--{{#ember-notifier notificationClass="toast" as |notification close|}}--}} 32 | {{!----}} 33 | {{!----}} 48 | {{!--{{#if notification.contentComponent}}--}} 49 | {{!--{{component--}} 50 | {{!--notification.contentComponent--}} 51 | {{!--title=notification.title--}} 52 | {{!--message=notification.message}}--}} 53 | {{!--{{else}}--}} 54 | {{!--{{notification.message}}--}} 55 | {{!--{{/if}}--}} 56 | {{!--
--}} 57 | {{!----}} 60 | {{!--{{/ember-notifier}}--}} 61 | 62 | {{!--bootstrap--}} 63 | {{!--{{#ember-notifier notificationClass="alert alert-dismissible" as |notification close|}}--}} 64 | {{!----}} 66 | {{!--{{#if notification.contentComponent}}--}} 67 | {{!--{{component--}} 68 | {{!--notification.contentComponent--}} 69 | {{!--title=notification.title--}} 70 | {{!--message=notification.message}}--}} 71 | {{!--{{else}}--}} 72 | {{!--{{notification.message}}--}} 73 | {{!--{{/if}}--}} 74 | {{!--
--}} 75 | {{!----}} 78 | {{!--{{/ember-notifier}}--}} 79 | -------------------------------------------------------------------------------- /tests/dummy/app/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scottwernervt/ember-notifier/cf231c52e1f8fab52293f350b88d894625a8ce54/tests/dummy/app/components/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/components/addon-demo/component.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import { alias } from '@ember/object/computed'; 3 | import { inject as service } from '@ember/service'; 4 | import { dasherize } from '@ember/string'; 5 | import layout from './template'; 6 | 7 | export default Component.extend({ 8 | layout, 9 | 10 | router: service(), 11 | notifier: service(), 12 | demo: service(), 13 | 14 | message: 'Testing notifications', 15 | contentComponent: null, 16 | types: null, 17 | positions: null, 18 | 19 | type: alias('demo.type'), 20 | position: alias('demo.position'), 21 | duration: alias('demo.duration'), 22 | 23 | init() { 24 | this._super(...arguments); 25 | this.set('types', ['primary', 'info', 'success', 'warning', 'danger', 'secondary']); 26 | this.set('positions', ['top', 'top left', 'top right', 'bottom', 'bottom left', 'bottom right']); 27 | }, 28 | 29 | actions: { 30 | show() { 31 | const type = this.get('type'); 32 | const message = this.get('message'); 33 | const duration = this.get('duration'); 34 | const contentComponent = this.get('contentComponent'); 35 | const title = `Notification ${type}`; // framework testing 36 | const options = { title, duration, contentComponent }; 37 | 38 | if (type === 'primary') { 39 | this.get('notifier').primary(message, options); 40 | } else if (type === 'info') { 41 | this.get('notifier').info(message, options); 42 | } else if (type === 'success') { 43 | this.get('notifier').success(message, options); 44 | } else if (type === 'warning') { 45 | this.get('notifier').warning(message, options); 46 | } else if (type === 'danger') { 47 | this.get('notifier').danger(message, options); 48 | } else if (type === 'secondary') { 49 | this.get('notifier').secondary(message, options); 50 | } 51 | }, 52 | 53 | unauthenticated() { 54 | const router = this.get('router'); 55 | this.get('notifier').warning( 56 | 'You must be logged in to access this resource ', { 57 | title: 'Unauthenticated', 58 | type: 'is-auth-error', 59 | icon: 'fas fa-user-astronaut', 60 | duration: 3200, 61 | onRemove() { 62 | router.transitionTo('docs.index'); 63 | }, 64 | } 65 | ); 66 | }, 67 | 68 | setPosition(position) { 69 | this.set('demo.position', dasherize(`is-${position}`)); 70 | }, 71 | 72 | clearAll() { 73 | this.get('notifier').empty(); 74 | }, 75 | } 76 | }); 77 | -------------------------------------------------------------------------------- /tests/dummy/app/components/addon-demo/template.hbs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/dummy/app/components/addon-dynamic-demo/component.js: -------------------------------------------------------------------------------- 1 | // BEGIN-SNIPPET addon-dynamic-demo.js 2 | import Component from '@ember/component'; 3 | import { inject as service } from '@ember/service'; 4 | import layout from './template'; 5 | 6 | export default Component.extend({ 7 | layout, 8 | 9 | notifier: service(), 10 | 11 | actions: { 12 | launchTask() { 13 | this.get('notifier').add({ 14 | type: 'is-info', 15 | contentComponent: 'task-message', 16 | duration: 0, 17 | }); 18 | }, 19 | } 20 | }); 21 | // END-SNIPPET 22 | -------------------------------------------------------------------------------- /tests/dummy/app/components/addon-dynamic-demo/template.hbs: -------------------------------------------------------------------------------- 1 | {{!--BEGIN-SNIPPET addon-dynamic-demo.hbs--}} 2 | 8 | {{!--END-SNIPPET--}} -------------------------------------------------------------------------------- /tests/dummy/app/components/notification-icon/component.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import layout from './template'; 3 | 4 | export default Component.extend({ 5 | layout, 6 | 7 | classNames: ['ember-notifier-icon'], 8 | }); 9 | -------------------------------------------------------------------------------- /tests/dummy/app/components/notification-icon/template.hbs: -------------------------------------------------------------------------------- 1 | 2 | {{fa-icon icon}} 3 | -------------------------------------------------------------------------------- /tests/dummy/app/components/tailwind-alert/component.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import layout from './template'; 3 | 4 | export default Component.extend({ 5 | layout, 6 | 7 | classNames: ['docs-border-l-4', 'docs-p-4'], 8 | classNameBindings: [ 9 | 'isInfo:docs-bg-purple-lightest', 10 | 'isInfo:docs-border-purple', 11 | 'isInfo:docs-text-purple-dark', 12 | 'isWarning:docs-bg-orange-lightest', 13 | 'isWarning:docs-border-orange', 14 | 'isWarning:docs-text-orange-dark', 15 | 'isDanger:docs-bg-red-lightest', 16 | 'isDanger:docs-border-red', 17 | 'isDanger:docs-text-red-dark', 18 | ], 19 | attributeBindings: ['role'], 20 | 21 | role: 'alert', 22 | }); 23 | -------------------------------------------------------------------------------- /tests/dummy/app/components/tailwind-alert/template.hbs: -------------------------------------------------------------------------------- 1 | {{yield}} -------------------------------------------------------------------------------- /tests/dummy/app/components/task-message/component.js: -------------------------------------------------------------------------------- 1 | // BEGIN-SNIPPET task-message.js 2 | import Component from '@ember/component'; 3 | import { on } from '@ember/object/evented'; 4 | import { task, timeout } from 'ember-concurrency'; 5 | import layout from './template'; 6 | 7 | export default Component.extend({ 8 | layout, 9 | 10 | didInsertElement() { 11 | this._super(...arguments); 12 | this.get('backgroundTask').perform(); 13 | }, 14 | 15 | didDestroyElement() { 16 | this.get('backgroundTask').cancelAll(); 17 | this._super(...arguments); 18 | }, 19 | 20 | backgroundTask: task(function* () { 21 | const ms = 2000 + 2000 * Math.random(); 22 | yield timeout(ms); 23 | 24 | if (parseInt(ms) % 2 === 0) { 25 | throw new Error('Background task failed.'); 26 | } 27 | return {}; 28 | }).evented(), 29 | 30 | // eslint-disable-next-line ember/no-on-calls-in-components 31 | backgroundTaskStarted: on('backgroundTask:started', function (/* taskInstance */) { 32 | this.setOption('icon', 'fas fa-spinner fa-pulse'); 33 | }), 34 | 35 | // eslint-disable-next-line ember/no-on-calls-in-components 36 | backgroundTaskSucceeded: on('backgroundTask:succeeded', function (/* taskInstance */) { 37 | this.setOption('icon', 'fas fa-check'); 38 | this.setOption('type', 'is-success'); 39 | }), 40 | 41 | // eslint-disable-next-line ember/no-on-calls-in-components 42 | backgroundTaskErrored: on('backgroundTask:errored', function (/* taskInstance, error */) { 43 | this.setOption('icon', 'fas fa-fire'); 44 | this.setOption('type', 'is-danger'); 45 | }), 46 | }); 47 | // END-SNIPPET 48 | -------------------------------------------------------------------------------- /tests/dummy/app/components/task-message/template.hbs: -------------------------------------------------------------------------------- 1 | {{!--BEGIN-SNIPPET task-message.hbs--}} 2 |3 | {{#if backgroundTask.isRunning}} 4 | Running background task... 5 | {{else}} 6 | {{#if backgroundTask.last.isSuccessful}} 7 | Task successful! 8 | {{else}} 9 | Task failed! 10 | {{/if}} 11 | {{/if}} 12 |
13 | {{!--END-SNIPPET--}} -------------------------------------------------------------------------------- /tests/dummy/app/docs/animation/snippets/animation-config-environment.js: -------------------------------------------------------------------------------- 1 | //! BEGIN-SNIPPET animation-config-environment.js 2 | let ENV = { 3 | emberNotifier: { 4 | showAnimationClass: 'my-animation-show-class', 5 | hideAnimationClass: 'my-animation-hide-class', 6 | animationTimeout: 150, // ms 7 | } 8 | } 9 | //! END-SNIPPET 10 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/animation/template.md: -------------------------------------------------------------------------------- 1 | # Animation 2 | 3 | CSS transitions are used to animate the launching and closing of a 4 | notification. Check out [animista](http://animista.net/) for various 5 | CSS transitions. 6 | 7 | ## Customize 8 | 9 | The following options are supported: 10 | 11 | * `showAnimationClass` -- The transition class applied when a 12 | notification is launched. Defaults to 13 | `ember-notifier-notification-show`. 14 | 15 | * `hideAnimationClass` -- The transition class applied when a 16 | notification is closed. Defaults to `ember-notifier-notification-hide`. 17 | 18 | * `animationTimeout` -- The number of milliseconds before a 19 | notification is closed. It should equal the CSS `animation-delay` 20 | property value. Defaults to `500`. 21 | 22 | Each option can be set using the global config or when launching a 23 | notification. 24 | 25 | {{docs-snippet name='animation-config-environment.js' title='config/environment.js'}} 26 | 27 | {{#docs-snippet name="animation-primary-function.js"}} 28 | this.get('notifier').primary('Primary notification', { 29 | showAnimationClass: 'my-animation-show-class', 30 | }); 31 | {{/docs-snippet}} 32 | 33 | ## Disable 34 | 35 | Set `showAnimationClass` and `hideAnimationClass` classes to `null` 36 | and `animationTimeout` to `0`. 37 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/demo/template.md: -------------------------------------------------------------------------------- 1 | # Demo 2 | 3 | {{addon-demo}} 4 | 5 | {{#tailwind-alert isInfo=true}} 6 |Notification Icons
7 | 8 |This demo is using [Font Awesome 5](https://fontawesome.com) for demonstration purposes.
9 | {{/tailwind-alert}} 10 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/dynamic/template.md: -------------------------------------------------------------------------------- 1 | # Dynamic 2 | 3 | The notification's content can be made dynamic by passing a component 4 | name to the `contentComponent` option. 5 | 6 | {{#docs-snippet name="message-component-option.js"}} 7 | this.get('notifier').info(null, { contentComponent: 'my-component' }); 8 | {{/docs-snippet}} 9 | 10 | For example: We are going to create a background task 11 | using [ember-concurrency](http://ember-concurrency.com/). Based on the 12 | task's result, the notification will be updated using the content 13 | component closure action `setOption`. If the task fails, it will be 14 | toggled to `is-danger` or if successful, `is-success`. 15 | 16 | Install `ember-concurrency`. 17 | 18 | {{#docs-snippet name="install-ember-concurrency"}} 19 | ember install ember-concurrency 20 | {{/docs-snippet}} 21 | 22 | Generate the dynamic content component. 23 | 24 | {{#docs-snippet name="ember-generate-notification-icon"}} 25 | ember g component task-message 26 | {{/docs-snippet}} 27 | 28 | {{#docs-demo as |demo|}} 29 | {{demo.snippet 'task-message.js' label='component.js'}} 30 | {{demo.snippet 'task-message.hbs' label='template.hbs'}} 31 | {{/docs-demo}} 32 | 33 | {{#docs-demo as |demo|}} 34 | {{#demo.example name='addon-dynamic-demo-component.hbs'}} 35 | {{addon-dynamic-demo}} 36 | {{/demo.example}} 37 | 38 | {{demo.snippet 'addon-dynamic-demo.js' label='component.js'}} 39 | {{demo.snippet 'addon-dynamic-demo.hbs' label='template.hbs'}} 40 | {{/docs-demo}} 41 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/icons/snippets/fa-svg-application.hbs: -------------------------------------------------------------------------------- 1 | {{! BEGIN-SNIPPET fa-svg-application.hbs }} 2 | {{ember-notifier iconComponent="notification-icon"}} 3 | {{outlet}} 4 | {{! END-SNIPPET }} -------------------------------------------------------------------------------- /tests/dummy/app/docs/icons/snippets/fa-svg-component.hbs: -------------------------------------------------------------------------------- 1 | {{! BEGIN-SNIPPET fa-svg-component.hbs }} 2 | {{fa-icon icon}} 3 | {{! END-SNIPPET }} -------------------------------------------------------------------------------- /tests/dummy/app/docs/icons/snippets/fa-svg-component.js: -------------------------------------------------------------------------------- 1 | //! BEGIN-SNIPPET fa-svg-component.js 2 | import Component from '@ember/component'; 3 | 4 | export default Component.extend({ 5 | classNames: ['ember-notifier-icon'], 6 | }); 7 | //! END-SNIPPET 8 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/icons/snippets/fa-svg-config-environment.js: -------------------------------------------------------------------------------- 1 | //! BEGIN-SNIPPET fa-svg-config-environment.js 2 | let ENV = { 3 | emberNotifier: { 4 | 'primaryIcon': 'bell', 5 | 'infoIcon': 'info', 6 | 'successIcon': 'check', 7 | 'warningIcon': 'exclamation', 8 | 'dangerIcon': 'fire', 9 | 'secondaryIcon': 'comment' 10 | }, 11 | fontawesome: { 12 | defaultPrefix: 'fas' 13 | } 14 | } 15 | //! END-SNIPPET 16 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/icons/snippets/fa-web-font-config-environment.js: -------------------------------------------------------------------------------- 1 | //! BEGIN-SNIPPET fa-web-font-config-environment.js 2 | let ENV = { 3 | emberNotifier: { 4 | 'primaryIcon': 'fas fa-comment', 5 | 'infoIcon': 'fas fa-info', 6 | 'successIcon': 'fas fa-check', 7 | 'warningIcon': 'fas fa-exclamation', 8 | 'dangerIcon': 'fas fa-fire', 9 | 'secondaryIcon': 'fas fa-bell', 10 | } 11 | } 12 | //! END-SNIPPET 13 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/icons/template.md: -------------------------------------------------------------------------------- 1 | # Icons 2 | 3 | Ember Notifier does not ship with an icon framework. If you are using a 4 | web font, you can take advantage of the global config icon class 5 | options. For SVG icons, it is recommended to create a custom icon 6 | component. 7 | 8 | ## Web Font 9 | 10 | {{#tailwind-alert isInfo=true}} 11 | Example using [Font Awesome 5 Web Fonts with CSS](https://fontawesome.com/get-started/web-fonts-with-css). 12 | {{/tailwind-alert}} 13 | 14 | Define each global config option icon class. 15 | 16 | {{docs-snippet name='fa-web-font-config-environment.js' title='config/environment.js'}} 17 | 18 | ## SVG 19 | 20 | {{#tailwind-alert isInfo=true}} 21 | Example using [ember-fontawesome](https://github.com/FortAwesome/ember-fontawesome). 22 | {{/tailwind-alert}} 23 | 24 | Create an icon component. 25 | 26 | {{#docs-snippet name="generate-notification-icon.sh"}} 27 | ember g component notification-icon 28 | {{/docs-snippet}} 29 | 30 | {{#docs-demo as |demo|}} 31 | {{demo.snippet 'fa-svg-component.js' label='component.js'}} 32 | {{demo.snippet 'fa-svg-component.hbs' label='template.hbs'}} 33 | {{/docs-demo}} 34 | 35 | Define icon names in the global options config. 36 | 37 | {{docs-snippet name='fa-svg-config-environment.js' title='config/environment.js'}} 38 | 39 | Set `notification-icon` for `iconComponent` argument. 40 | 41 | {{docs-snippet name='fa-svg-application.hbs' title='templates/application.hbs'}} 42 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/index/template.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | Install the package in your Ember project directory: 4 | 5 | {{#docs-snippet name="install.sh"}} 6 | ember install ember-notifier 7 | {{/docs-snippet}} 8 | 9 | This addon does not automatically include styling. You must import the 10 | addon style yourself. 11 | 12 | {{#docs-snippet name="app.css" title="styles/app.scss"}} 13 | @import "ember-notifier"; 14 | {{/docs-snippet}} 15 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/options/snippets/global-options.js: -------------------------------------------------------------------------------- 1 | //! BEGIN-SNIPPET global-options.js 2 | module.exports = function (environment) { 3 | let ENV = { 4 | emberNotifier: { 5 | position: 'is-top-right', 6 | duration: 4200, // ms 7 | primaryClass: 'is-primary', 8 | primaryIcon: 'fas fa-bell', 9 | infoClass: 'is-info', 10 | infoIcon: 'fas fa-info', 11 | successClass: 'is-success', 12 | successIcon: 'fas fa-check', 13 | warningClass: 'is-warning', 14 | warningIcon: 'fas fa-exclamation', 15 | dangerClass: 'is-danger', 16 | dangerIcon: 'fas fa-fire', 17 | secondaryClass: 'is-secondary', 18 | secondaryIcon: 'fas fa-comment', 19 | showAnimationClass: 'ember-notifier-notification-show', 20 | hideAnimationClass: 'ember-notifier-notification-hide', 21 | animationTimeout: 500, // ms 22 | swipeDirection: 'right', // 'left' or 'right' 23 | minSwipeDistance: 150, // px 24 | maxSwipeTime: 300, // ms 25 | }, 26 | }; 27 | 28 | return ENV; 29 | }; 30 | //! END-SNIPPET 31 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/options/snippets/notification-options.js: -------------------------------------------------------------------------------- 1 | //! BEGIN-SNIPPET notification-options.js 2 | import Component from '@ember/component'; 3 | import { inject as service } from '@ember/service'; 4 | 5 | export default Component.extend({ 6 | router: service(), 7 | notifier: service(), 8 | 9 | actions: { 10 | unauthenticated() { 11 | const router = this.get('router'); 12 | this.get('notifier').warning( 13 | 'You must be logged in to access this resource ', { 14 | title: 'Unauthenticated', 15 | type: 'is-auth-error', 16 | icon: 'fas fa-user-astronaut', 17 | duration: 3200, 18 | onRemove() { 19 | router.transitionTo('login'); 20 | }, 21 | } 22 | ); 23 | }, 24 | } 25 | }); 26 | //! END-SNIPPET 27 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/options/template.md: -------------------------------------------------------------------------------- 1 | # Options 2 | 3 | Notification options can be set globally and overridden when launching. 4 | 5 | ## Global 6 | 7 | In `config/environment.js`, the service defaults can be overridden using 8 | the `emberNotifier` object: 9 | 10 | {{docs-snippet name="global-options.js" title="config/environment.js"}} 11 | 12 | The notification container `position` can be set to: 13 | 14 | * `is-top` 15 | * `is-top-left` 16 | * `is-top-right` 17 | * `is-bottom` 18 | * `is-bottom-left` 19 | * `is-bottom-right` 20 | 21 | ## Notification 22 | 23 | The global config options can be overridden per notification. Extra 24 | options such as `onRemove()` callback function and `contentComponent` 25 | can be included. See {{#link-to "docs.api.item" "services/notifier" class="docs-md__a"}}ember-notifier.add(){{/link-to}} 26 | for all notification options. 27 | 28 | {{docs-snippet name="notification-options.js" title="component.js"}} 29 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/styles/snippets/bootstrap-application.hbs: -------------------------------------------------------------------------------- 1 | {{! BEGIN-SNIPPET bootstrap-application.hbs }} 2 | {{#ember-notifier 3 | notificationClass="alert alert-dismissible" 4 | as |notification close|}} 5 |9 | {{#if notification.contentComponent}} 10 | {{component 11 | notification.contentComponent 12 | title=notification.title 13 | message=notification.message 14 | setOption=(action "setOption")}} 15 | {{else}} 16 | {{notification.message}} 17 | {{/if}} 18 |
19 | 27 | {{/ember-notifier}} 28 | {{outlet}} 29 | {{! END-SNIPPET }} -------------------------------------------------------------------------------- /tests/dummy/app/docs/styles/snippets/bootstrap-config-environment.js: -------------------------------------------------------------------------------- 1 | //! BEGIN-SNIPPET bootstrap-config-environment.js 2 | let ENV = { 3 | emberNotifier: { 4 | 'primaryClass': 'alert-primary', 5 | 'infoClass': 'alert-info', 6 | 'successClass': 'alert-success', 7 | 'warningClass': 'alert-warning', 8 | 'dangerClass': 'alert-danger', 9 | 'secondaryClass': 'alert-secondary', 10 | } 11 | } 12 | //! END-SNIPPET 13 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/styles/snippets/bulma-application.hbs: -------------------------------------------------------------------------------- 1 | {{! BEGIN-SNIPPET bulma-application.hbs }} 2 | {{#ember-notifier 3 | notificationClass="notification" 4 | as |notification close|}} 5 | 6 | {{#if notification.contentComponent}} 7 | {{component 8 | notification.contentComponent 9 | title=notification.title 10 | message=notification.message 11 | setOption=(action "setOption")}} 12 | {{else}} 13 | {{notification.message}} 14 | {{/if}} 15 | {{/ember-notifier}} 16 | {{outlet}} 17 | {{! END-SNIPPET }} -------------------------------------------------------------------------------- /tests/dummy/app/docs/styles/snippets/bulma-config-environment.js: -------------------------------------------------------------------------------- 1 | //! BEGIN-SNIPPET bulma-config-environment.js 2 | let ENV = { 3 | emberNotifier: { 4 | 'secondaryClass': 'is-link', 5 | } 6 | } 7 | //! END-SNIPPET 8 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/styles/snippets/spectre-application.hbs: -------------------------------------------------------------------------------- 1 | {{! BEGIN-SNIPPET spectre-application.hbs }} 2 | {{#ember-notifier 3 | notificationClass="toast" 4 | as |notification close|}} 5 | 6 |9 | {{#if notification.contentComponent}} 10 | {{component 11 | notification.contentComponent 12 | title=notification.title 13 | message=notification.message 14 | setOption=(action "setOption")}} 15 | {{else}} 16 | {{notification.message}} 17 | {{/if}} 18 |
19 | 28 | {{/ember-notifier}} 29 | {{outlet}} 30 | {{! END-SNIPPET }} -------------------------------------------------------------------------------- /tests/dummy/app/docs/styles/snippets/zurb-config-environment.js: -------------------------------------------------------------------------------- 1 | //! BEGIN-SNIPPET zurb-config-environment.js 2 | let ENV = { 3 | emberNotifier: { 4 | 'primaryClass': 'primary', 5 | 'successClass': 'success', 6 | 'warningClass': 'warning', 7 | 'dangerClass': 'alert', 8 | 'secondaryClass': 'secondary', 9 | } 10 | } 11 | //! END-SNIPPET 12 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/styles/template.md: -------------------------------------------------------------------------------- 1 | # Styles 2 | 3 | This addon supports customizing the notification style through SASS or 4 | using `ember-notifier` as a block param to apply a framework's 5 | component class. 6 | 7 | ## SASS 8 | 9 | To customize the notification, set the addon variables before 10 | importing `ember-notifier.scss`. 11 | 12 | {{docs-snippet name='style-sass.scss' title='styles/app.scss' language='css'}} 13 | 14 | This approach is powerful enough to build entire themes on top of it. 15 | The entire list of available variables can be found in 16 | [ember-notifier.scss](https://github.com/scottwernervt/ember-notifier/blob/master/app/styles/ember-notifier.scss). 17 | 18 | ## Frameworks 19 | 20 | Applying a framework's theme is accomplished by mapping the addon's 21 | global config options to the framework's notification classes and using 22 | `ember-notifier` as a block param. 23 | 24 | ### Bulma 25 | 26 | {{#docs-demo as |demo|}} 27 | {{demo.snippet 'bulma-config-environment.js' label='environment.js'}} 28 | {{demo.snippet 'bulma-application.hbs' label='application.hbs'}} 29 | {{/docs-demo}} 30 | 31 | Documentation on [Bulma Notifications](https://bulma.io/documentation/elements/notification/). 32 | 33 | ### Spectre 34 | 35 | {{#docs-demo as |demo|}} 36 | {{demo.snippet 'spectre-config-environment.js' label='environment.js'}} 37 | {{demo.snippet 'spectre-application.hbs' label='application.hbs'}} 38 | {{/docs-demo}} 39 | 40 | Documentation on [Spectre Toasts](https://picturepan2.github.io/spectre/components.html#toasts). 41 | 42 | ### Bootstrap 43 | 44 | {{#docs-demo as |demo|}} 45 | {{demo.snippet 'bootstrap-config-environment.js' label='environment.js'}} 46 | {{demo.snippet 'bootstrap-application.hbs' label='application.hbs'}} 47 | {{/docs-demo}} 48 | 49 | Documentation on [Bootstrap Alerts](https://getbootstrap.com/docs/4.1/components/alerts/). 50 | 51 | ### Zurb Foundation 52 | 53 | {{#docs-demo as |demo|}} 54 | {{demo.snippet 'zurb-config-environment.js' label='environment.js'}} 55 | {{demo.snippet 'zurb-application.hbs' label='application.hbs'}} 56 | {{/docs-demo}} 57 | 58 | Documentation on [Zurb Foundation Callouts](https://foundation.zurb.com/sites/docs/callout.html). 59 | 60 | ### Other 61 | 62 | Do not see your framework? Make a request [here](https://github.com/scottwernervt/ember-notifier/issues). 63 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/template.hbs: -------------------------------------------------------------------------------- 1 | {{#docs-viewer as |viewer|}} 2 | {{#viewer.nav as |nav|}} 3 | {{nav.section "Getting started"}} 4 | {{nav.item "Installation" "docs.index"}} 5 | {{nav.item "Usage" "docs.usage"}} 6 | {{nav.item "Demo" "docs.demo"}} 7 | 8 | {{nav.section "Customization"}} 9 | {{nav.item "Styles" "docs.styles"}} 10 | {{nav.item "Icons" "docs.icons"}} 11 | {{nav.item "Animation" "docs.animation"}} 12 | {{nav.item "Touch" "docs.touch"}} 13 | {{nav.item "Dynamic" "docs.dynamic"}} 14 | {{nav.item "Options" "docs.options"}} 15 | {{/viewer.nav}} 16 | 17 | {{#viewer.main}} 18 | {{outlet}} 19 | {{/viewer.main}} 20 | {{/docs-viewer}} -------------------------------------------------------------------------------- /tests/dummy/app/docs/touch/snippets/touch-config-environment.js: -------------------------------------------------------------------------------- 1 | //! BEGIN-SNIPPET touch-config-environment.js 2 | let ENV = { 3 | emberNotifier: { 4 | swipeDirection: 'right', // 'left' or 'right' 5 | minSwipeDistance: 150, // px 6 | maxSwipeTime: 300, // ms 7 | } 8 | }; 9 | //! END-SNIPPET 10 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/touch/template.md: -------------------------------------------------------------------------------- 1 | # Touch 2 | 3 | A notification can be closed by swiping right on a touch device. 4 | 5 | ## Customize 6 | 7 | The following options are supported: 8 | 9 | * `swipeDirection` -- The horizontal direction the user must 10 | swipe. Can be `left`, `right`, or `null`. Defaults to `right`. 11 | 12 | * `minSwipeDistance` -- The minimum distance (px) the user must 13 | swipe. Defaults to `150`. 14 | 15 | * `maxSwipeTime` -- The maximum amount of time (ms) it must take the 16 | user to swipe. Defaults to `300`. 17 | 18 | Each option can be set using the global config or when launching a 19 | notification. 20 | 21 | {{docs-snippet name='touch-config-environment.js' title='config/environment.js'}} 22 | 23 | {{#docs-snippet name="touch-primary-function.js"}} 24 | this.get('notifier').primary('Primary notification', { 25 | contentComponent: 'my-large-dynamic-component', 26 | minSwipeDistance: '420', 27 | }); 28 | {{/docs-snippet}} 29 | 30 | ## Disable 31 | 32 | Set `swipeDirection` to `null` to disable closing a notification by a 33 | swipe event. 34 | -------------------------------------------------------------------------------- /tests/dummy/app/docs/usage/template.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | Add the `ember-notifier` component to your application template. This 4 | container displays notifications. 5 | 6 | {{#docs-snippet name="usage-template.hbs" title="templates/application.hbs"}} 7 | {{ember-notifier position="is-top-right"}} 8 | {{outlet}} 9 | {{/docs-snippet}} 10 | 11 | Inject the `notifier` service anywhere you want to launch a 12 | notification. 13 | 14 | {{#docs-snippet name="usage-service.js"}} 15 | import Component from '@ember/component'; 16 | import { inject as service } from '@ember/service'; 17 | 18 | export default Component.extend({ 19 | notifier: service(), 20 | }); 21 | {{/docs-snippet}} 22 | 23 | Notifications can be launched by calling styled functions. 24 | 25 | {{#docs-snippet name="usage-styled-functions.js"}} 26 | this.get('notifier').primary('Primary notification'); 27 | this.get('notifier').info('Information notification'); 28 | this.get('notifier').success('Success notification'); 29 | this.get('notifier').warning('Warning notification'); 30 | this.get('notifier').danger('Danger notification'); 31 | this.get('notifier').secondary('Secondary notification'); 32 | {{/docs-snippet}} 33 | 34 | Custom notifications can be launched using `add()`. 35 | 36 | {{#docs-snippet name="usage-add-function.js"}} 37 | this.get('notifier').add('Custom notification', { type: 'custom-class' }); 38 | {{/docs-snippet}} 39 | 40 | All notifications can be closed using `empty()`. 41 | 42 | {{#docs-snippet name="empty.js"}} 43 | this.get('notifier').empty(); 44 | {{/docs-snippet}} 45 | -------------------------------------------------------------------------------- /tests/dummy/app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scottwernervt/ember-notifier/cf231c52e1f8fab52293f350b88d894625a8ce54/tests/dummy/app/helpers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/helpers/capitalize.js: -------------------------------------------------------------------------------- 1 | import { helper } from '@ember/component/helper'; 2 | import { capitalize as _capitalize } from '@ember/string'; 3 | 4 | export function capitalize([value]) { 5 | return _capitalize(value); 6 | } 7 | 8 | export default helper(capitalize); 9 | -------------------------------------------------------------------------------- /tests/dummy/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |This page doesn't exist. {{#link-to "index" class="docs-md__a"}}Head home?{{/link-to}}
4 |{{notification.message}}
83 | 84 | {{/ember-notifier-notification}} 85 | `); 86 | 87 | assert 88 | .dom('.ember-notifier-notification-base') 89 | .exists(); 90 | assert 91 | .dom('.ember-notifier-notification-base') 92 | .hasClass('is-primary', 'Notification has correct type class'); 93 | assert 94 | .dom('h5') 95 | .exists(); 96 | assert 97 | .dom('h5') 98 | .hasText('title', 'Notification has a title'); 99 | assert 100 | .dom('p') 101 | .hasText('message', 'Notification has a message'); 102 | assert 103 | .dom('button') 104 | .exists(); 105 | assert 106 | .dom('button') 107 | .hasText('Close', 'Close button has text'); 108 | }); 109 | 110 | test('it renders with custom components', async function (assert) { 111 | assert.expect(11); 112 | 113 | let onClose = false; 114 | this.actions.onClose = () => (onClose = true); 115 | 116 | this.owner.register('component:icon-component', Component.extend({ 117 | layout: hbs` 118 |127 | {{title}} 128 |
129 | 132 |{{message}}
`, 33 | })); 34 | 35 | await render(hbs`{{ember-notifier-notification/content contentComponent="content-component" message=message title=title}}`); 36 | 37 | assert.dom('header').exists(); 38 | assert.dom('header').hasText(this.get('title')); 39 | assert.dom('p').exists(); 40 | assert.dom('p').hasText(this.get('message')); 41 | }); 42 | }); 43 | 44 | 45 | -------------------------------------------------------------------------------- /tests/integration/components/ember-notifier-notification/icon/component-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import { setupRenderingTest } from 'ember-qunit'; 3 | import { render } from '@ember/test-helpers'; 4 | import hbs from 'htmlbars-inline-precompile'; 5 | 6 | module('Integration | Component | ember-notifier-notification/icon', function(hooks) { 7 | setupRenderingTest(hooks); 8 | 9 | test('it renders', async function(assert) { 10 | assert.expect(4); 11 | 12 | await render(hbs`{{ember-notifier-notification/icon icon="fa-bell"}}`); 13 | 14 | assert.dom('.ember-notifier-icon').exists(); 15 | assert.dom('.fa-bell').exists(); 16 | 17 | await render(hbs` 18 | {{#ember-notifier-notification/icon}} 19 | 20 | {{/ember-notifier-notification/icon}} 21 | `); 22 | 23 | assert.dom('.ember-notifier-icon').exists(); 24 | assert.dom('.fa-bell').exists(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /tests/integration/components/ember-notifier/component-test.js: -------------------------------------------------------------------------------- 1 | import Component from '@ember/component'; 2 | import { click, render } from '@ember/test-helpers'; 3 | import { setupRenderingTest } from 'ember-qunit'; 4 | import hbs from 'htmlbars-inline-precompile'; 5 | import { module, test } from 'qunit'; 6 | 7 | function setupService(hooks) { 8 | hooks.afterEach(function (/* assert */) { 9 | this.owner.lookup('service:notifier').empty(); 10 | }); 11 | } 12 | 13 | module('Integration | Component | ember-notifier', function (hooks) { 14 | setupRenderingTest(hooks); 15 | setupService(hooks); 16 | 17 | test('it renders', async function (assert) { 18 | assert.expect(3); 19 | 20 | await render(hbs`{{ember-notifier}}`); 21 | 22 | assert.dom('.ember-notifier').exists(); 23 | assert.dom('.ember-notifier').hasClass('is-top'); 24 | 25 | await render(hbs`{{ember-notifier position="is-bottom"}}`); 26 | 27 | assert.dom('.ember-notifier').hasClass('is-bottom'); 28 | }); 29 | 30 | test('it renders a notification', async function (assert) { 31 | assert.expect(5); 32 | 33 | const service = this.owner.lookup('service:notifier'); 34 | service.add({ title: 'header', message: 'msg', duration: 0 }); 35 | 36 | await render(hbs`{{ember-notifier}}`); 37 | 38 | assert.dom('.ember-notifier-notification').exists(); 39 | assert.dom('.ember-notifier-notification-base').exists(); 40 | assert.dom('.ember-notifier-content').exists(); 41 | assert.dom('.ember-notifier-title').hasText('header'); 42 | assert.dom('.ember-notifier-message').hasText('msg'); 43 | }); 44 | 45 | test('it renders a notification with custom class', async function (assert) { 46 | assert.expect(2); 47 | 48 | const service = this.owner.lookup('service:notifier'); 49 | service.add({ title: 'header', message: 'msg', duration: 0 }); 50 | 51 | await render(hbs`{{ember-notifier notificationClass="alert"}}`); 52 | 53 | assert.dom('.alert').exists(); 54 | assert.dom('.ember-notifier-notification-base').exists(); 55 | }); 56 | 57 | test('a custom component can use the close closure action', async function (assert) { 58 | assert.expect(2); 59 | 60 | const service = this.owner.lookup('service:notifier'); 61 | service.add({ title: 'header', message: 'msg', duration: 0 }); 62 | 63 | await render(hbs` 64 | {{#ember-notifier as |notification close|}} 65 |{{notification.message}}
67 | 68 | {{/ember-notifier}} 69 | `); 70 | await click('button'); 71 | 72 | assert.dom('.ember-notifier-notification').exists({ count: 0 }); 73 | assert.equal(service.get('notifications.length'), 0, 'Notification was removed by button click.'); 74 | }); 75 | 76 | test('a custom component for icon, message, and close can be used', async function (assert) { 77 | assert.expect(7); 78 | 79 | this.owner.register('component:icon-component', Component.extend({ 80 | layout: hbs`