I am using Angular 9 and ngx-toastr
I have the task of using toastr to create a set of toasts which look quite different from the default toast styles. Each in the set are basically the same, except for border colour, fontawesome icon and message (which I can just pass in).
Here is one of the toast mockups: enter image description here
Toastr has it's own toastr.css style sheet which I added to angular.json. Without it, toasts won't even open. I have my own toast-messages.scss file that contains all the css to realize my mockup. I will include it. It's also added to angular.json
"styles": [
"node_modules/@fortawesome/fontawesome-free/css/fontawesome.css",
"node_modules/@fortawesome/fontawesome-free/css/solid.css",
"src/styles.scss",
"node_modules/ngx-toastr/toastr.css",
"src/app/styles/toast-messages.scss"
],
What I find is that unless every line in my toast-messages.scss file needs an !important in it for it to override what's in the toastr.css and you know that's horrible.
my question What are my options to create this style of toast without using all these !important tags in my css. Am I referencing the css/scss files in the wrong spot? Should I create a custom toast and if so, is there a good resource for that? I am only 2 months into Angular.
toast-messages.scss I know my formatting is horrible, this has been trial and error
.toast-container .ngx-toastr {
position: relative;
width: 888px;
height: 79px;
margin-left: auto;
margin-right: auto;
top: 60px;
padding-right: 0px;
padding-top: 0px;
padding-bottom: 0px;
border-radius: 5px;
background-position: 15px center;
background-repeat: no-repeat;
background-size: 24px;
box-shadow: 0 0 12px #999999;
color: #FFFFFF;
}
.toast-container .ngx-toastr:hover {
box-shadow: 0 0 12px #000000 ;
opacity: 1;
cursor: pointer ;
}
.toast-container {
pointer-events: none;
position: fixed;
z-index: 9999;
}
.toast-container * {
box-sizing: border-box;
}
.toast-message {
position: relative;
word-wrap: break-word;
background-color: #FFFFFF;
top: 2px;
width: 886px;
height: 75px;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
}
.message-boxy {
top: 2px;
width: 886px;
height: 75px;
}
.message-symbol {
background-color: #800017;
width: 79px;
height: 75px;
text-align: center;
position: relative;
float: left;
left: 0px;
}
.message-symbol i {
width: 28px;
height: 28px;
transform: translateY(0.7em);
}
.toast-text-container {
position: relative;
width:886px;
border-style:solid;
border-color: #FFAE15;
border-width:2px;
left: 0px;
height: 75px;
background-color: transparent;
z-index: 10;
}
.message-text {
line-height: 75px;
border-style:solid;
left: 79px;
height: 75px;
border-color: #157EF9;
border-width:2px;
width: 500px;
letter-spacing: 0px;
text-align: left;
text-indent: 10px;
font-weight: bold;
font-size: 18px;
color: #555555;
z-index: 10;
}
.btncontainer {
background-color: pink;
position: relative;
float:right;
padding: 0 20px;
z-index: 20;
}
.reloadpage {
color: #157EF9;
font-weight: bold;
opacity: 1;
z-index: 20;
}
.reloadpage:hover {
opacity: 0.8;
}
.toast-close-button {
border: none;
top: 27px;
right: 10px;
float: right;
background-color: #FFFFFF;
width: 25px !important;
height: 25px !important;
opacity: 1;
z-index: 10;
}
/*Additional properties for button version
iOS requires the button element instead of an anchor tag.
If you want the anchor version, it requires `href="#"`.*/
button.toast-close-button {
cursor: pointer;
border: none;
background-color: #FFFFFF;
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' width='512' height='512'%3E%3Cpath fill='rgb(255,255,255)' d='M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z'/%3E%3C/svg%3E");
width: 25px !important;
height: 25px !important;
opacity: 1;
z-index: 10;
}
.toast-close-button:hover,
.toast-close-button:focus {
text-decoration: none;
cursor: pointer;
opacity: 1;
}
/* https://github.com/FortAwesome/Font-Awesome-Pro/blob/master/advanced-options/raw-svg/regular/info-circle.svg */
.toast-info {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' width='512' height='512'%3E%3Cpath fill='rgb(255,255,255)' d='M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z'/%3E%3C/svg%3E");
width: 28.74px;
height: 28.74px;
padding: 25px;
}
/* https://github.com/FortAwesome/Font-Awesome-Pro/blob/master/advanced-options/raw-svg/regular/times-circle.svg */
.toast-error {
background-image: none;
}
/* https://github.com/FortAwesome/Font-Awesome-Pro/blob/master/advanced-options/raw-svg/regular/check.svg */
.toast-success {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' width='512' height='512'%3E%3Cpath fill='rgb(255,255,255)' d='M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z'/%3E%3C/svg%3E");
width: 28.74px;
height: 70px;
justify-self: center !important;
}
/* https://github.com/FortAwesome/Font-Awesome-Pro/blob/master/advanced-options/raw-svg/regular/exclamation-triangle.svg */
.toast-warning {
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' width='512' height='512'%3E%3Cpath fill='rgb(255,255,255)' d='M173.898 439.404l-166.4-166.4c-9.997-9.997-9.997-26.206 0-36.204l36.203-36.204c9.997-9.998 26.207-9.998 36.204 0L192 312.69 432.095 72.596c9.997-9.997 26.207-9.997 36.204 0l36.203 36.204c9.997 9.997 9.997 26.206 0 36.204l-294.4 294.401c-9.998 9.997-26.207 9.997-36.204-.001z'/%3E%3C/svg%3E");
width: 28.74px;
height: 28.74px;
}
.toast-container.toast-top-full-width .ngx-toastr,
.toast-container.toast-bottom-full-width .ngx-toastr {
width: 96%;
margin-left: auto;
margin-right: auto;
}
.ngx-toastr {
background-color: #030303;
pointer-events: auto;
}
.toast-success {
background-color: #4C6A13;
}
.toast-error {
background-color: #800017;
}
.toast-info {
background-color: #555555;
}
.toast-warning {
background-color: #FFAE15;
}
.toast-progress {
position: absolute;
left: 0;
bottom: 0;
height: 4px;
background-color: #000000;
opacity: 0.4;
}
You can create your custom toast as mentioned in the documentation
You can follow this code:
import {
animate,
keyframes,
state,
style,
transition,
trigger
} from '@angular/animations';
import { Component } from '@angular/core';
import { Toast, ToastrService, ToastPackage } from '../lib/public_api';
@Component({
selector: '[pink-toast-component]',
styles: [`
:host {
background-color: #FF69B4;
position: relative;
overflow: hidden;
margin: 0 0 6px;
padding: 10px 10px 10px 10px;
width: 300px;
border-radius: 3px 3px 3px 3px;
color: #FFFFFF;
pointer-events: all;
cursor: pointer;
}
.btn-pink {
-webkit-backface-visibility: hidden;
-webkit-transform: translateZ(0);
}
`],
template: `
<div class="row" [style.display]="state.value === 'inactive' ? 'none' : ''">
<div class="col-9">
<div *ngIf="title" [class]="options.titleClass" [attr.aria-label]="title">
{{ title }}
</div>
<div *ngIf="message && options.enableHtml" role="alert" aria-live="polite"
[class]="options.messageClass" [innerHTML]="message">
</div>
<div *ngIf="message && !options.enableHtml" role="alert" aria-live="polite"
[class]="options.messageClass" [attr.aria-label]="message">
{{ message }}
</div>
</div>
<div class="col-3 text-right">
<a *ngIf="!options.closeButton" class="btn btn-pink btn-sm" (click)="action($event)">
{{ undoString }}
</a>
<a *ngIf="options.closeButton" (click)="remove()" class="btn btn-pink btn-sm">
close
</a>
</div>
</div>
<div *ngIf="options.progressBar">
<div class="toast-progress" [style.width]="width + '%'"></div>
</div>
`,
animations: [
trigger('flyInOut', [
state('inactive', style({
opacity: 0,
})),
transition('inactive => active', animate('400ms ease-out', keyframes([
style({
transform: 'translate3d(100%, 0, 0) skewX(-30deg)',
opacity: 0,
}),
style({
transform: 'skewX(20deg)',
opacity: 1,
}),
style({
transform: 'skewX(-5deg)',
opacity: 1,
}),
style({
transform: 'none',
opacity: 1,
}),
]))),
transition('active => removed', animate('400ms ease-out', keyframes([
style({
opacity: 1,
}),
style({
transform: 'translate3d(100%, 0, 0) skewX(30deg)',
opacity: 0,
}),
]))),
]),
],
preserveWhitespaces: false,
})
export class PinkToast extends Toast {
// used for demo purposes
undoString = 'undo';
// constructor is only necessary when not using AoT
constructor(
protected toastrService: ToastrService,
public toastPackage: ToastPackage,
) {
super(toastrService, toastPackage);
}
action(event: Event) {
event.stopPropagation();
this.undoString = 'undid';
this.toastPackage.triggerAction();
return false;
}
}