├── .gitignore
├── .travis.yml
├── bundle-css.js
├── example
├── example.js
└── index.html
├── index.js
├── main.js
├── notifications.css
├── package.json
├── readme.md
└── style.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | example/bundle.js
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | notifications:
4 | email: false
5 | node_js:
6 | - '9'
7 | after_success:
8 | - npx semantic-release
9 |
--------------------------------------------------------------------------------
/bundle-css.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs')
2 |
3 | var css = fs.readFileSync('./notifications.css', 'utf-8').replace(/\n+/g, '')
4 | var style = `// Generated by bundle-css.js
5 | module.exports = '${css}'
6 | `
7 | fs.writeFileSync('style.js', style)
8 |
--------------------------------------------------------------------------------
/example/example.js:
--------------------------------------------------------------------------------
1 | var notifications = require('../')()
2 | var button = document.querySelector('button')
3 | var message = document.querySelector('#message')
4 | var repo = document.querySelector('#repo')
5 |
6 | document.body.appendChild(notifications.render([]))
7 |
8 | button.onclick = function () {
9 | var type = document.querySelector('input:checked').value
10 | notifications.repo = repo.value
11 | notifications.add({ message: message.value, type: type })
12 | }
13 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | notifications
6 |
7 |
44 |
45 | dom-notifications example
46 | GitHub repository
47 | Message
48 |
49 | Type
50 |
51 |
52 |
53 |
54 |
55 |
56 | Options
57 | Repo
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var Notifications = require('./main')
2 | var style = require('./style')
3 | var insertCss = require('insert-css')
4 |
5 | module.exports = function (opts) {
6 | insertCss(style)
7 | return new Notifications(opts)
8 | }
9 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | var Nanocomponent = require('nanocomponent')
2 | var html = require('nanohtml')
3 |
4 | class Notifications extends Nanocomponent {
5 | constructor (opts) {
6 | opts = opts || {}
7 | super()
8 |
9 | this.repo = opts.repo
10 | this.icons = Object.assign({
11 | error: 'octicon octicon-flame',
12 | warning: 'octicon octicon-alert',
13 | info: 'octicon octicon-info',
14 | success: 'octicon octicon-check',
15 | close: 'octicon octicon-x'
16 | }, opts.icons)
17 |
18 | this.getMessageBody = this.getMessageBody.bind(this)
19 | this.notifications = []
20 | this.renderedLength = -1
21 | }
22 |
23 | add (notification) {
24 | this.notifications.push(notification)
25 | this.rerender()
26 | }
27 |
28 | info (text) {
29 | this.add({ type: 'info', message: text })
30 | }
31 |
32 | error (text) {
33 | this.add({ type: 'error', message: text })
34 | }
35 |
36 | warning (text) {
37 | this.add({ type: 'warning', message: text })
38 | }
39 |
40 | success (text) {
41 | this.add({ type: 'success', message: text })
42 | }
43 |
44 | getMessageBody (notification) {
45 | if (notification.element) {
46 | notification.element.className = 'notification-message'
47 | return notification.element
48 | }
49 | if (this.repo && notification.type === 'error') {
50 | return html`
51 | `
55 | } else {
56 | return html`${notification.message}
`
57 | }
58 | }
59 |
60 | createElement (notifications) {
61 | if (notifications) this.notifications = notifications
62 | this.renderedLength = notifications.length
63 | return html`${
64 | notifications
65 | .map((notification) => {
66 | var classNames = [
67 | 'notification',
68 | notification.closed ? 'notification-hidden' : 'notification-show',
69 | 'notification-' + (notification.type || 'info')
70 | ]
71 | return html`
72 |
73 |
74 |
75 |
76 |
77 |
78 | ${this.getMessageBody(notification)}
79 |
{ notification.closed = true; this.rerender() }} class="notification-close" title="Dismiss this notification">
80 |
81 |
82 |
`
83 | })
84 | }
85 |
`
86 | }
87 |
88 | update (notifications) {
89 | return notifications !== this.notifications || notifications.length !== this.renderedLength
90 | }
91 | }
92 |
93 | module.exports = Notifications
94 |
--------------------------------------------------------------------------------
/notifications.css:
--------------------------------------------------------------------------------
1 | .notification-container {
2 | top: 10px;
3 | right: 0;
4 | bottom: auto;
5 | left: 0;
6 | position: fixed;
7 | z-index: 1060;
8 | width: 80%;
9 | max-width: 400px;
10 | margin: auto;
11 | }
12 |
13 | .notification-error {
14 | background-color: #e74c3c;
15 | }
16 |
17 | .notification-warning {
18 | background-color: #ff7f48;
19 | }
20 |
21 | .notification-info {
22 | background-color: #3ea2ff;
23 | }
24 |
25 | .notification-success {
26 | background-color: #64ce83;
27 | }
28 |
29 | .notification-error .notification-icon {
30 | background-color: #ba2c1d;
31 | }
32 |
33 | .notification-warning .notification-icon {
34 | background-color: #f44e06;
35 | }
36 |
37 | .notification-info .notification-icon {
38 | background-color: #067cea;
39 | }
40 |
41 | .notification-success .notification-icon {
42 | background-color: #3da95c;
43 | }
44 |
45 | .notification-hidden {
46 | animation: notification-hide 250ms cubic-bezier(.33859,-.42,1,-.22),notification-shrink 250ms 250ms cubic-bezier(.5,0,0,1);
47 | -webkit-animation: notification-hide 250ms cubic-bezier(.33859,-.42,1,-.22),notification-shrink 250ms 250ms cubic-bezier(.5,0,0,1);
48 | animation-fill-mode: forwards;
49 | -webkit-animation-fill-mode: forwards;
50 | }
51 |
52 | .notification-show {
53 | animation: notification-show 180ms cubic-bezier(.175,.885,.32,1.27499);
54 | -webkit-animation: notification-show 180ms cubic-bezier(.175,.885,.32,1.27499);
55 | }
56 |
57 | .notification {
58 | font: 14px Helvetica,sans-serif;
59 | position: relative;
60 | border-radius: 4px;
61 | margin-bottom: 2px;
62 | max-height: 800px;
63 | color: #fff;
64 | overflow: hidden;
65 | }
66 |
67 | .notification-icon {
68 | position: absolute;
69 | left: 0;
70 | top: 0;
71 | height: 100%;
72 | width: 30px;
73 | color: rgba(255,255,255,.74);
74 | text-align: center;
75 | }
76 |
77 | .notification-icon span {
78 | position: relative;
79 | top: 5px;
80 | }
81 |
82 | .notification-message {
83 | word-break: break-word;
84 | padding: 10px 30px 10px 40px;
85 | }
86 |
87 | .notification-close {
88 | position: absolute;
89 | top: 10px;
90 | right: 10px;
91 | opacity: .3;
92 | cursor: pointer;
93 | }
94 |
95 | .notification-countdown {
96 | position: absolute;
97 | bottom: 0;
98 | width: 0;
99 | height: 4px;
100 | animation: notification-countdown linear 1;
101 | -webkit-animation: notification-countdown linear 1;
102 | }
103 |
104 | .notification-btn {
105 | position: relative;
106 | color: #fff;
107 | background-color: #ba2c1d;
108 | display: inline-block;
109 | padding: 6px 8px 7px;
110 | margin-top: 5px;
111 | margin-bottom: 0;
112 | margin-right: 10px;
113 | font-size: 12px;
114 | font-weight: 400;
115 | line-height: 1;
116 | text-align: center;
117 | white-space: nowrap;
118 | vertical-align: top;
119 | cursor: pointer;
120 | border-radius: 3px;
121 | text-decoration: none;
122 | border: 0px;
123 | }
124 |
125 | @keyframes notification-show {
126 | 0% {
127 | opacity: 0;
128 | transform: perspective(450px) translate(0, -30px) rotateX(90deg);
129 | }
130 |
131 | 100% {
132 | opacity: 1;
133 | transform: perspective(450px) translate(0, 0) rotateX(0deg);
134 | }
135 | }
136 |
137 | @-webkit-keyframes notification-show {
138 | 0% {
139 | opacity: 0;
140 | -webkit-transform: perspective(450px) translate(0, -30px) rotateX(90deg);
141 | }
142 |
143 | 100% {
144 | opacity: 1;
145 | -webkit-transform: perspective(450px) translate(0, 0) rotateX(0deg);
146 | }
147 | }
148 |
149 | @keyframes notification-shrink {
150 | 0% {
151 | opacity: 0;
152 | transform: scale(.8);
153 | }
154 |
155 | 100% {
156 | opacity: 0;
157 | max-height: 0;
158 | margin-bottom: 0;
159 | transform: scale(.8);
160 | }
161 | }
162 |
163 | @-webkit-keyframes notification-shrink {
164 | 0% {
165 | opacity: 0;
166 | -webkit-transform: scale(.8);
167 | }
168 |
169 | 100% {
170 | opacity: 0;
171 | max-height: 0;
172 | margin-bottom: 0;
173 | -webkit-transform: scale(.8);
174 | }
175 | }
176 |
177 | @keyframes notification-hide {
178 | 0% {
179 | opacity: 1;
180 | transform: scale(1);
181 | }
182 |
183 | 100% {
184 | opacity: 0;
185 | transform: scale(.8);
186 | }
187 | }
188 |
189 | @-webkit-keyframes notification-hide {
190 | 0% {
191 | opacity: 1;
192 | -webkit-transform: scale(1);
193 | }
194 |
195 | 100% {
196 | opacity: 0;
197 | -webkit-transform: scale(.8);
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "dom-notifications",
3 | "description": "atom-inspired notifications",
4 | "main": "index.js",
5 | "style": "notifications.css",
6 | "scripts": {
7 | "test": "standard",
8 | "deploy": "browserify example/example.js -o example/bundle.js && gh-pages -d example",
9 | "semantic-release": "semantic-release pre && npm publish && semantic-release post"
10 | },
11 | "author": "Finn Pauls",
12 | "license": "ISC",
13 | "dependencies": {
14 | "insert-css": "2.0.0",
15 | "nanocomponent": "^6.5.2",
16 | "nanohtml": "^1.2.4"
17 | },
18 | "devDependencies": {
19 | "browserify": "^16.2.2",
20 | "cz-conventional-changelog": "^2.1.0",
21 | "gh-pages": "^1.2.0",
22 | "standard": "^12.0.1"
23 | },
24 | "directories": {
25 | "example": "example"
26 | },
27 | "repository": {
28 | "type": "git",
29 | "url": "https://github.com/finnp/dom-notifications.git"
30 | },
31 | "keywords": [
32 | "nanohtml",
33 | "yo-yo",
34 | "bel",
35 | "choo",
36 | "atom",
37 | "notifications"
38 | ],
39 | "bugs": {
40 | "url": "https://github.com/finnp/dom-notifications/issues"
41 | },
42 | "homepage": "https://github.com/finnp/dom-notifications#readme",
43 | "config": {
44 | "commitizen": {
45 | "path": "./node_modules/cz-conventional-changelog"
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # dom-notifications
2 | [](https://github.com/semantic-release/semantic-release)
3 | [](https://greenkeeper.io/)
4 | [](https://github.com/choojs/nanocomponent)
5 |
6 | 
7 |
8 | Have a look at the [example page](http://www.finnpauls.de/dom-notifications/).
9 |
10 | ## usage
11 |
12 | Install with `npm install dom-notifications --save` and use something like
13 | [browserify](http://browserify.org/) to create a bundle for the browser.
14 |
15 | ```js
16 | var domNotifications = require('dom-notifications')
17 | var notifications = domNotifications(options)
18 |
19 | document.body.appendChild(notifications.render())
20 |
21 | notifications.add({message: 'You are now logged in'}) // defaults to `info`
22 | notifications.add({message: 'This is a warning', type: 'warning'})
23 | notifications.error('Oh noes: File not found')
24 | ```
25 |
26 | By default this uses [octicons](https://octicons.github.com/) icon classes
27 | that are not included automatically. Here's a CDN link that serves octicons that
28 | you can include in your HTML:
29 | ```html
30 |