Skip to content
This repository was archived by the owner on Feb 3, 2023. It is now read-only.

Commit 776a6d2

Browse files
committed
Use SVG icons
1 parent f827ea3 commit 776a6d2

File tree

7 files changed

+663
-174
lines changed

7 files changed

+663
-174
lines changed

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
"prepare": "jlpm run clean && jlpm run build"
3333
},
3434
"dependencies": {
35+
"@fortawesome/fontawesome-svg-core": "^1.2.30",
36+
"@fortawesome/free-solid-svg-icons": "^5.14.0",
37+
"@fortawesome/react-fontawesome": "^0.1.11",
38+
"@jupyterlab/ui-components": "^2.0.0",
3539
"react-toastify": "^6.0.5"
3640
},
3741
"peerDependencies": {

src/ToastJupyterLab.tsx

Lines changed: 109 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
import * as React from "react";
2+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
3+
import {
4+
faSpinner,
5+
faBell,
6+
faCheck,
7+
faExclamationTriangle,
8+
faExclamationCircle
9+
} from "@fortawesome/free-solid-svg-icons";
10+
import { closeIcon } from "@jupyterlab/ui-components";
211
import {
312
ToastContent,
413
ToastOptions,
@@ -90,12 +99,15 @@ export namespace INotification {
9099
function createContent(
91100
message: React.ReactNode,
92101
closeHandler: () => void,
93-
buttons?: IButton[]
102+
buttons?: IButton[],
103+
icon?: JSX.Element
94104
): React.ReactNode {
95-
if (buttons && buttons.length > 0) {
96-
return (
97-
<div>
98-
{message}
105+
const hasButtons = buttons && buttons.length > 0;
106+
return (
107+
<>
108+
{icon ? icon : null}
109+
{message}
110+
{hasButtons && (
99111
<div className="jp-toast-buttonBar">
100112
<div className="jp-toast-spacer" />
101113
{buttons.map((button, idx) => {
@@ -108,26 +120,31 @@ export namespace INotification {
108120
);
109121
})}
110122
</div>
111-
</div>
112-
);
113-
} else {
114-
return <div>{message}</div>;
115-
}
123+
)}
124+
</>
125+
);
116126
}
117127

118128
async function createToast(
119129
message: React.ReactNode,
120130
buttons?: IButton[],
121-
options?: ToastOptions
131+
options?: ToastOptions,
132+
icon?: JSX.Element
122133
): Promise<React.ReactText> {
123134
let _resolve: (value: React.ReactText) => void;
124135
const toast = await Private.toast();
125136
const promise = new Promise<React.ReactText>(resolve => {
126137
_resolve = resolve;
127138
});
139+
const theOptions = { ...options };
128140
const toastId: React.ReactText = toast(
129141
({ closeToast }: { closeToast: () => void }) =>
130-
createContent(message, closeToast, buttons),
142+
createContent(
143+
message,
144+
closeToast,
145+
buttons,
146+
icon || Private.type2Icon.get(theOptions.type)
147+
),
131148
{
132149
...options,
133150
onOpen: () => _resolve(toastId)
@@ -186,9 +203,11 @@ export namespace INotification {
186203
message: React.ReactNode,
187204
options?: IOptions
188205
): Promise<React.ReactText> => {
189-
const buttons = options && options.buttons;
206+
const theOptions = { ...options };
207+
const buttons = theOptions.buttons;
190208
const autoClose =
191-
options.autoClose || (buttons && buttons.length > 0 ? false : undefined);
209+
theOptions.autoClose ||
210+
(buttons && buttons.length > 0 ? false : undefined);
192211
return createToast(message, buttons, {
193212
type: "info",
194213
className: "jp-toast-info",
@@ -208,9 +227,11 @@ export namespace INotification {
208227
message: React.ReactNode,
209228
options?: IOptions
210229
): Promise<React.ReactText> => {
211-
const buttons = options && options.buttons;
230+
const theOptions = { ...options };
231+
const buttons = theOptions.buttons;
212232
const autoClose =
213-
options.autoClose || (buttons && buttons.length > 0 ? false : undefined);
233+
theOptions.autoClose ||
234+
(buttons && buttons.length > 0 ? false : undefined);
214235
return createToast(message, buttons, {
215236
type: "success",
216237
className: "jp-toast-success",
@@ -230,11 +251,21 @@ export namespace INotification {
230251
message: React.ReactNode,
231252
options?: IOptions
232253
): Promise<React.ReactText> => {
233-
return createToast(message, options && options.buttons, {
234-
type: "default",
235-
className: "jp-toast-inprogress",
236-
autoClose: (options && options.autoClose) || false
237-
});
254+
return createToast(
255+
message,
256+
options && options.buttons,
257+
{
258+
type: "default",
259+
className: "jp-toast-inprogress",
260+
autoClose: (options && options.autoClose) || false
261+
},
262+
<FontAwesomeIcon
263+
icon={faSpinner}
264+
pull="left"
265+
spin
266+
style={{ color: "var(--jp-inverse-layout-color3)" }}
267+
/>
268+
);
238269
};
239270

240271
/** Options needed to update an existing toast */
@@ -280,7 +311,12 @@ export namespace INotification {
280311
};
281312
toast.update(args.toastId, {
282313
...options,
283-
render: createContent(args.message, closeToast, args.buttons)
314+
render: createContent(
315+
args.message,
316+
closeToast,
317+
args.buttons,
318+
Private.type2Icon.get(options.type)
319+
)
284320
});
285321
} else {
286322
// Needs to recreate a closed toast
@@ -405,6 +441,42 @@ interface IToast {
405441
}
406442

407443
namespace Private {
444+
export const type2Icon = new Map<TypeOptions, JSX.Element>([
445+
["default", null],
446+
[
447+
"error",
448+
<FontAwesomeIcon
449+
icon={faExclamationCircle}
450+
pull="left"
451+
style={{ color: "var(--jp-error-color1)" }}
452+
/>
453+
],
454+
[
455+
"warning",
456+
<FontAwesomeIcon
457+
icon={faExclamationTriangle}
458+
pull="left"
459+
style={{ color: "var(--jp-warn-color1)" }}
460+
/>
461+
],
462+
[
463+
"info",
464+
<FontAwesomeIcon
465+
icon={faBell}
466+
pull="left"
467+
style={{ color: "var(--jp-info-color1)" }}
468+
/>
469+
],
470+
[
471+
"success",
472+
<FontAwesomeIcon
473+
icon={faCheck}
474+
pull="left"
475+
style={{ color: "var(--jp-success-color1)" }}
476+
/>
477+
]
478+
]);
479+
408480
let toastify: {
409481
toast: IToast;
410482
Slide: (
@@ -418,6 +490,19 @@ namespace Private {
418490
) => JSX.Element;
419491
} = null;
420492

493+
const CloseButton: React.FunctionComponent<{ closeToast: () => void }> = ({
494+
closeToast
495+
}) => (
496+
<i onClick={closeToast}>
497+
<closeIcon.react
498+
className="jp-icon-hover"
499+
elementPosition="center"
500+
height="16px"
501+
width="16px"
502+
/>
503+
</i>
504+
);
505+
421506
export async function toast(): Promise<IToast> {
422507
if (toastify === null) {
423508
toastify = await import("react-toastify");
@@ -431,7 +516,8 @@ namespace Private {
431516
pauseOnHover: true,
432517
position: "bottom-right",
433518
className: "jp-toastContainer",
434-
transition: toastify.Slide
519+
transition: toastify.Slide,
520+
closeButton: CloseButton
435521
});
436522
}
437523

style/index.css

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -13,107 +13,26 @@
1313
cursor: default;
1414
}
1515

16-
.Toastify__close-button {
17-
color: transparent;
18-
background-size: 16px;
19-
height: 16px;
20-
width: 16px;
21-
background-image: var(--jp-icon-close);
22-
background-position: center;
23-
background-repeat: no-repeat;
24-
}
25-
26-
.Toastify__close-button:hover {
27-
background-image: var(--jp-icon-close-circle);
28-
}
29-
3016
.Toastify__toast--error {
3117
border-top: 5px solid var(--jp-error-color1);
3218
}
3319

34-
.Toastify__toast--error::before {
35-
content: "\F06A";
36-
font-family: FontAwesome;
37-
display: inline-block;
38-
flex: 0 0 auto;
39-
padding-top: 3px;
40-
padding-right: 5px;
41-
color: var(--jp-error-color1);
42-
}
43-
4420
.Toastify__toast--warning {
4521
border-top: 5px solid var(--jp-warn-color1);
4622
}
4723

48-
.Toastify__toast--warning::before {
49-
content: "\F071";
50-
font-family: FontAwesome;
51-
display: inline-block;
52-
flex: 0 0 auto;
53-
padding-top: 3px;
54-
padding-right: 5px;
55-
color: var(--jp-warn-color1);
56-
}
57-
5824
.Toastify__toast--info {
5925
border-top: 5px solid var(--jp-info-color1);
6026
}
6127

62-
.Toastify__toast--info::before {
63-
content: "\F0F3";
64-
font-family: FontAwesome;
65-
display: inline-block;
66-
flex: 0 0 auto;
67-
padding-top: 3px;
68-
padding-right: 5px;
69-
color: var(--jp-info-color1);
70-
}
71-
7228
.Toastify__toast--success {
7329
border-top: 5px solid var(--jp-success-color1);
7430
}
7531

76-
.Toastify__toast--success::before {
77-
content: "\F00C";
78-
font-family: FontAwesome;
79-
display: inline-block;
80-
flex: 0 0 auto;
81-
padding-top: 3px;
82-
padding-right: 5px;
83-
color: var(--jp-success-color1);
84-
}
85-
86-
@keyframes fa-spin {
87-
0% {
88-
-webkit-transform: rotate(0deg);
89-
transform: rotate(0deg);
90-
}
91-
100% {
92-
-webkit-transform: rotate(359deg);
93-
transform: rotate(359deg);
94-
}
95-
}
96-
9732
.Toastify__toast--default.jp-toast-inprogress {
9833
border-top: 5px solid var(--jp-layout-color1);
9934
}
10035

101-
.Toastify__toast--default.jp-toast-inprogress::before {
102-
content: "\F110";
103-
font-family: FontAwesome;
104-
width: 1.28571429em;
105-
height: 1.28571429em;
106-
text-align: center;
107-
box-sizing: border-box;
108-
display: inline-block;
109-
flex: 0 0 auto;
110-
padding: 2px 0px;
111-
margin-right: 2px;
112-
113-
-webkit-animation: fa-spin 1s infinite steps(8);
114-
animation: fa-spin 1s infinite steps(8);
115-
}
116-
11736
.jp-toast-buttonBar {
11837
display: flex;
11938
flex-direction: row;

test-jlab-toastify/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
},
3333
"dependencies": {
3434
"@jupyterlab/application": "^2.0.0",
35-
"jupyterlab_toastify": "file:/home/fcollonval/jupyterlab_toastify"
35+
"jupyterlab_toastify": "file:/home/fcollonval/jupyterlab_toastify/test-jlab-toastify/.."
3636
},
3737
"devDependencies": {
3838
"@types/react": "^16.9.0",

0 commit comments

Comments
 (0)