From 3b4258096c3c3dc160090436c9205e1ecf2e8e75 Mon Sep 17 00:00:00 2001 From: Dessalines Date: Wed, 22 Jan 2020 22:29:11 -0500 Subject: Adding a toaster to replace alerts. Fixes #457 --- ui/assets/css/toastify.css | 78 ++++++++++++++++++++++++++++ ui/package.json | 1 + ui/src/components/comment-form.tsx | 3 +- ui/src/components/communities.tsx | 4 +- ui/src/components/community-form.tsx | 15 ++---- ui/src/components/community.tsx | 3 +- ui/src/components/create-private-message.tsx | 3 +- ui/src/components/inbox.tsx | 12 ++--- ui/src/components/login.tsx | 16 ++---- ui/src/components/main.tsx | 3 +- ui/src/components/modlog.tsx | 15 ++---- ui/src/components/moment-time.tsx | 2 +- ui/src/components/navbar.tsx | 3 +- ui/src/components/password_change.tsx | 13 ++--- ui/src/components/post-form.tsx | 5 +- ui/src/components/post.tsx | 4 +- ui/src/components/private-message-form.tsx | 3 +- ui/src/components/private-message.tsx | 9 +++- ui/src/components/search.tsx | 3 +- ui/src/components/setup.tsx | 13 ++--- ui/src/components/user.tsx | 7 +-- ui/src/index.html | 1 + ui/src/services/WebSocketService.ts | 3 +- ui/src/translations/en.ts | 1 + ui/src/utils.ts | 9 ++++ ui/yarn.lock | 5 ++ 26 files changed, 153 insertions(+), 81 deletions(-) create mode 100644 ui/assets/css/toastify.css (limited to 'ui') diff --git a/ui/assets/css/toastify.css b/ui/assets/css/toastify.css new file mode 100644 index 00000000..8804e229 --- /dev/null +++ b/ui/assets/css/toastify.css @@ -0,0 +1,78 @@ +/*! + * Toastify js 1.6.2 + * https://github.com/apvarun/toastify-js + * @license MIT licensed + * + * Copyright (C) 2018 Varun A P + */ + +.toastify { + padding: 12px 20px; + color: #ffffff; + display: inline-block; + box-shadow: 0 3px 6px -1px rgba(0, 0, 0, 0.12), 0 10px 36px -4px rgba(77, 96, 232, 0.3); + background: -webkit-linear-gradient(315deg, #73a5ff, #5477f5); + background: linear-gradient(135deg, #73a5ff, #5477f5); + position: fixed; + opacity: 0; + transition: all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1); + border-radius: 2px; + cursor: pointer; + text-decoration: none; + max-width: calc(50% - 20px); + z-index: 2147483647; +} + +.toastify.on { + opacity: 1; +} + +.toast-close { + opacity: 0.4; + padding: 0 5px; +} + +.toastify-right { + right: 15px; +} + +.toastify-left { + left: 15px; +} + +.toastify-top { + top: -150px; +} + +.toastify-bottom { + bottom: -150px; +} + +.toastify-rounded { + border-radius: 25px; +} + +.toastify-avatar { + width: 1.5em; + height: 1.5em; + margin: 0 5px; + border-radius: 2px; +} + +.toastify-center { + margin-left: auto; + margin-right: auto; + left: 0; + right: 0; + max-width: fit-content; +} + +@media only screen and (max-width: 360px) { + .toastify-right, .toastify-left { + margin-left: auto; + margin-right: auto; + left: 0; + right: 0; + max-width: fit-content; + } +} diff --git a/ui/package.json b/ui/package.json index ea6343da..41f47088 100644 --- a/ui/package.json +++ b/ui/package.json @@ -36,6 +36,7 @@ "prettier": "^1.18.2", "rxjs": "^6.4.0", "terser": "^4.6.0", + "toastify-js": "^1.6.2", "tributejs": "^4.1.1", "twemoji": "^12.1.2", "ws": "^7.0.0" diff --git a/ui/src/components/comment-form.tsx b/ui/src/components/comment-form.tsx index f5816899..6fbdc5de 100644 --- a/ui/src/components/comment-form.tsx +++ b/ui/src/components/comment-form.tsx @@ -16,6 +16,7 @@ import { mdToHtml, randomStr, markdownHelpUrl, + toast, } from '../utils'; import { WebSocketService, UserService } from '../services'; import autosize from 'autosize'; @@ -293,7 +294,7 @@ export class CommentForm extends Component { .catch(error => { i.state.imageLoading = false; i.setState(i.state); - alert(error); + toast(error, 'danger'); }); } diff --git a/ui/src/components/communities.tsx b/ui/src/components/communities.tsx index 598a5dad..129051fb 100644 --- a/ui/src/components/communities.tsx +++ b/ui/src/components/communities.tsx @@ -12,7 +12,7 @@ import { SortType, } from '../interfaces'; import { WebSocketService } from '../services'; -import { msgOp } from '../utils'; +import { msgOp, toast } from '../utils'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -235,7 +235,7 @@ export class Communities extends Component { console.log(msg); let op: UserOperation = msgOp(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); return; } else if (op == UserOperation.ListCommunities) { let res: ListCommunitiesResponse = msg; diff --git a/ui/src/components/community-form.tsx b/ui/src/components/community-form.tsx index 2085da28..ec58b010 100644 --- a/ui/src/components/community-form.tsx +++ b/ui/src/components/community-form.tsx @@ -10,8 +10,8 @@ import { GetSiteResponse, } from '../interfaces'; import { WebSocketService } from '../services'; -import { msgOp, capitalizeFirstLetter } from '../utils'; -import * as autosize from 'autosize'; +import { msgOp, capitalizeFirstLetter, toast } from '../utils'; +import autosize from 'autosize'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -67,14 +67,7 @@ export class CommunityForm extends Component< } this.subscription = WebSocketService.Instance.subject - .pipe( - retryWhen(errors => - errors.pipe( - delay(3000), - take(10) - ) - ) - ) + .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) .subscribe( msg => this.parseMessage(msg), err => console.error(err), @@ -250,7 +243,7 @@ export class CommunityForm extends Component< let op: UserOperation = msgOp(msg); console.log(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); this.state.loading = false; this.setState(this.state); return; diff --git a/ui/src/components/community.tsx b/ui/src/components/community.tsx index 873b5a8a..dfd4d6b3 100644 --- a/ui/src/components/community.tsx +++ b/ui/src/components/community.tsx @@ -24,6 +24,7 @@ import { routeSortTypeToEnum, fetchLimit, postRefetchSeconds, + toast, } from '../utils'; import { T } from 'inferno-i18next'; import { i18n } from '../i18next'; @@ -257,7 +258,7 @@ export class Community extends Component { console.log(msg); let op: UserOperation = msgOp(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); this.context.router.history.push('/'); return; } else if (op == UserOperation.GetCommunity) { diff --git a/ui/src/components/create-private-message.tsx b/ui/src/components/create-private-message.tsx index f74d5e9f..7160bc52 100644 --- a/ui/src/components/create-private-message.tsx +++ b/ui/src/components/create-private-message.tsx @@ -2,6 +2,7 @@ import { Component } from 'inferno'; import { PrivateMessageForm } from './private-message-form'; import { WebSocketService } from '../services'; import { PrivateMessageFormParams } from '../interfaces'; +import { toast } from '../utils'; import { i18n } from '../i18next'; export class CreatePrivateMessage extends Component { @@ -44,7 +45,7 @@ export class CreatePrivateMessage extends Component { } handlePrivateMessageCreate() { - alert(i18n.t('message_sent')); + toast(i18n.t('message_sent')); // Navigate to the front this.props.history.push(`/`); diff --git a/ui/src/components/inbox.tsx b/ui/src/components/inbox.tsx index 6a426bcc..bf090179 100644 --- a/ui/src/components/inbox.tsx +++ b/ui/src/components/inbox.tsx @@ -18,7 +18,7 @@ import { PrivateMessageResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; -import { msgOp, fetchLimit, isCommentType } from '../utils'; +import { msgOp, fetchLimit, isCommentType, toast } from '../utils'; import { CommentNodes } from './comment-nodes'; import { PrivateMessage } from './private-message'; import { SortSelect } from './sort-select'; @@ -198,11 +198,7 @@ export class Inbox extends Component {
{combined.map(i => isCommentType(i) ? ( - + ) : ( ) @@ -328,7 +324,7 @@ export class Inbox extends Component { console.log(msg); let op: UserOperation = msgOp(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); return; } else if (op == UserOperation.GetReplies) { let res: GetRepliesResponse = msg; @@ -423,7 +419,7 @@ export class Inbox extends Component { this.setState(this.state); } else if (op == UserOperation.CreateComment) { // let res: CommentResponse = msg; - alert(i18n.t('reply_sent')); + toast(i18n.t('reply_sent')); // this.state.replies.unshift(res.comment); // TODO do this right // this.setState(this.state); } else if (op == UserOperation.SaveComment) { diff --git a/ui/src/components/login.tsx b/ui/src/components/login.tsx index 53b7a22f..0c8350aa 100644 --- a/ui/src/components/login.tsx +++ b/ui/src/components/login.tsx @@ -10,7 +10,7 @@ import { GetSiteResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; -import { msgOp, validEmail } from '../utils'; +import { msgOp, validEmail, toast } from '../utils'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -48,14 +48,7 @@ export class Login extends Component { this.state = this.emptyState; this.subscription = WebSocketService.Instance.subject - .pipe( - retryWhen(errors => - errors.pipe( - delay(3000), - take(10) - ) - ) - ) + .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) .subscribe( msg => this.parseMessage(msg), err => console.error(err), @@ -302,7 +295,7 @@ export class Login extends Component { parseMessage(msg: any) { let op: UserOperation = msgOp(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); this.state = this.emptyState; this.setState(this.state); return; @@ -312,6 +305,7 @@ export class Login extends Component { this.setState(this.state); let res: LoginResponse = msg; UserService.Instance.login(res); + toast(i18n.t('logged_in')); this.props.history.push('/'); } else if (op == UserOperation.Register) { this.state = this.emptyState; @@ -320,7 +314,7 @@ export class Login extends Component { UserService.Instance.login(res); this.props.history.push('/communities'); } else if (op == UserOperation.PasswordReset) { - alert(i18n.t('reset_password_mail_sent')); + toast(i18n.t('reset_password_mail_sent')); } else if (op == UserOperation.GetSite) { let res: GetSiteResponse = msg; this.state.enable_nsfw = res.site.enable_nsfw; diff --git a/ui/src/components/main.tsx b/ui/src/components/main.tsx index 5fdf23bb..b244ce66 100644 --- a/ui/src/components/main.tsx +++ b/ui/src/components/main.tsx @@ -33,6 +33,7 @@ import { postRefetchSeconds, pictshareAvatarThumbnail, showAvatars, + toast, } from '../utils'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -566,7 +567,7 @@ export class Main extends Component { console.log(msg); let op: UserOperation = msgOp(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); return; } else if (op == UserOperation.GetFollowedCommunities) { let res: GetFollowedCommunitiesResponse = msg; diff --git a/ui/src/components/modlog.tsx b/ui/src/components/modlog.tsx index 425710dd..6c35bce9 100644 --- a/ui/src/components/modlog.tsx +++ b/ui/src/components/modlog.tsx @@ -17,9 +17,9 @@ import { ModAdd, } from '../interfaces'; import { WebSocketService } from '../services'; -import { msgOp, addTypeInfo, fetchLimit } from '../utils'; +import { msgOp, addTypeInfo, fetchLimit, toast } from '../utils'; import { MomentTime } from './moment-time'; -import * as moment from 'moment'; +import moment from 'moment'; import { i18n } from '../i18next'; interface ModlogState { @@ -55,14 +55,7 @@ export class Modlog extends Component { ? Number(this.props.match.params.community_id) : undefined; this.subscription = WebSocketService.Instance.subject - .pipe( - retryWhen(errors => - errors.pipe( - delay(3000), - take(10) - ) - ) - ) + .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) .subscribe( msg => this.parseMessage(msg), err => console.error(err), @@ -433,7 +426,7 @@ export class Modlog extends Component { console.log(msg); let op: UserOperation = msgOp(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); return; } else if (op == UserOperation.GetModlog) { let res: GetModlogResponse = msg; diff --git a/ui/src/components/moment-time.tsx b/ui/src/components/moment-time.tsx index 6bb4d99c..fd2a7efa 100644 --- a/ui/src/components/moment-time.tsx +++ b/ui/src/components/moment-time.tsx @@ -1,5 +1,5 @@ import { Component } from 'inferno'; -import * as moment from 'moment'; +import moment from 'moment'; import { getMomentLanguage } from '../utils'; import { i18n } from '../i18next'; diff --git a/ui/src/components/navbar.tsx b/ui/src/components/navbar.tsx index 85a54987..81124f77 100644 --- a/ui/src/components/navbar.tsx +++ b/ui/src/components/navbar.tsx @@ -22,6 +22,7 @@ import { showAvatars, fetchLimit, isCommentType, + toast, } from '../utils'; import { version } from '../version'; import { i18n } from '../i18next'; @@ -318,7 +319,7 @@ export class Navbar extends Component { if (UserService.Instance.user) { document.addEventListener('DOMContentLoaded', function() { if (!Notification) { - alert(i18n.t('notifications_error')); + toast(i18n.t('notifications_error'), 'danger'); return; } diff --git a/ui/src/components/password_change.tsx b/ui/src/components/password_change.tsx index 3e542f7b..76b4fb01 100644 --- a/ui/src/components/password_change.tsx +++ b/ui/src/components/password_change.tsx @@ -7,7 +7,7 @@ import { PasswordChangeForm, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; -import { msgOp, capitalizeFirstLetter } from '../utils'; +import { msgOp, capitalizeFirstLetter, toast } from '../utils'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -34,14 +34,7 @@ export class PasswordChange extends Component { this.state = this.emptyState; this.subscription = WebSocketService.Instance.subject - .pipe( - retryWhen(errors => - errors.pipe( - delay(3000), - take(10) - ) - ) - ) + .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) .subscribe( msg => this.parseMessage(msg), err => console.error(err), @@ -143,7 +136,7 @@ export class PasswordChange extends Component { parseMessage(msg: any) { let op: UserOperation = msgOp(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); this.state.loading = false; this.setState(this.state); return; diff --git a/ui/src/components/post-form.tsx b/ui/src/components/post-form.tsx index fe633a01..97a44094 100644 --- a/ui/src/components/post-form.tsx +++ b/ui/src/components/post-form.tsx @@ -28,6 +28,7 @@ import { mdToHtml, debounce, isImage, + toast, } from '../utils'; import autosize from 'autosize'; import { i18n } from '../i18next'; @@ -453,14 +454,14 @@ export class PostForm extends Component { .catch(error => { i.state.imageLoading = false; i.setState(i.state); - alert(error); + toast(error, 'danger'); }); } parseMessage(msg: any) { let op: UserOperation = msgOp(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); this.state.loading = false; this.setState(this.state); return; diff --git a/ui/src/components/post.tsx b/ui/src/components/post.tsx index 2005cc17..308fce85 100644 --- a/ui/src/components/post.tsx +++ b/ui/src/components/post.tsx @@ -28,7 +28,7 @@ import { GetCommunityResponse, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; -import { msgOp, hotRank } from '../utils'; +import { msgOp, hotRank, toast } from '../utils'; import { PostListing } from './post-listing'; import { PostListings } from './post-listings'; import { Sidebar } from './sidebar'; @@ -345,7 +345,7 @@ export class Post extends Component { console.log(msg); let op: UserOperation = msgOp(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); return; } else if (op == UserOperation.GetPost) { let res: GetPostResponse = msg; diff --git a/ui/src/components/private-message-form.tsx b/ui/src/components/private-message-form.tsx index c628bf71..96bd807d 100644 --- a/ui/src/components/private-message-form.tsx +++ b/ui/src/components/private-message-form.tsx @@ -22,6 +22,7 @@ import { mdToHtml, showAvatars, pictshareAvatarThumbnail, + toast, } from '../utils'; import autosize from 'autosize'; import { i18n } from '../i18next'; @@ -268,7 +269,7 @@ export class PrivateMessageForm extends Component< parseMessage(msg: any) { let op: UserOperation = msgOp(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); this.state.loading = false; this.setState(this.state); return; diff --git a/ui/src/components/private-message.tsx b/ui/src/components/private-message.tsx index 524b1a9d..409dce4d 100644 --- a/ui/src/components/private-message.tsx +++ b/ui/src/components/private-message.tsx @@ -5,7 +5,12 @@ import { EditPrivateMessageForm, } from '../interfaces'; import { WebSocketService, UserService } from '../services'; -import { mdToHtml, pictshareAvatarThumbnail, showAvatars } from '../utils'; +import { + mdToHtml, + pictshareAvatarThumbnail, + showAvatars, + toast, +} from '../utils'; import { MomentTime } from './moment-time'; import { PrivateMessageForm } from './private-message-form'; import { i18n } from '../i18next'; @@ -244,6 +249,6 @@ export class PrivateMessage extends Component< handlePrivateMessageCreate() { this.state.showReply = false; this.setState(this.state); - alert(i18n.t('message_sent')); + toast(i18n.t('message_sent'), 'danger'); } } diff --git a/ui/src/components/search.tsx b/ui/src/components/search.tsx index 94bbbdb9..d2280cb2 100644 --- a/ui/src/components/search.tsx +++ b/ui/src/components/search.tsx @@ -23,6 +23,7 @@ import { routeSortTypeToEnum, pictshareAvatarThumbnail, showAvatars, + toast, } from '../utils'; import { PostListing } from './post-listing'; import { SortSelect } from './sort-select'; @@ -480,7 +481,7 @@ export class Search extends Component { console.log(msg); let op: UserOperation = msgOp(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); return; } else if (op == UserOperation.Search) { let res: SearchResponse = msg; diff --git a/ui/src/components/setup.tsx b/ui/src/components/setup.tsx index d421e46f..d06a9a58 100644 --- a/ui/src/components/setup.tsx +++ b/ui/src/components/setup.tsx @@ -3,7 +3,7 @@ import { Subscription } from 'rxjs'; import { retryWhen, delay, take } from 'rxjs/operators'; import { RegisterForm, LoginResponse, UserOperation } from '../interfaces'; import { WebSocketService, UserService } from '../services'; -import { msgOp } from '../utils'; +import { msgOp, toast } from '../utils'; import { SiteForm } from './site-form'; import { i18n } from '../i18next'; import { T } from 'inferno-i18next'; @@ -35,14 +35,7 @@ export class Setup extends Component { this.state = this.emptyState; this.subscription = WebSocketService.Instance.subject - .pipe( - retryWhen(errors => - errors.pipe( - delay(3000), - take(10) - ) - ) - ) + .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10)))) .subscribe( msg => this.parseMessage(msg), err => console.error(err), @@ -191,7 +184,7 @@ export class Setup extends Component { parseMessage(msg: any) { let op: UserOperation = msgOp(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); this.state.userLoading = false; this.setState(this.state); return; diff --git a/ui/src/components/user.tsx b/ui/src/components/user.tsx index 19bd5fb9..89bc4785 100644 --- a/ui/src/components/user.tsx +++ b/ui/src/components/user.tsx @@ -30,6 +30,7 @@ import { setTheme, languages, showAvatars, + toast, } from '../utils'; import { PostListing } from './post-listing'; import { SortSelect } from './sort-select'; @@ -975,7 +976,7 @@ export class User extends Component { .catch(error => { i.state.avatarLoading = false; i.setState(i.state); - alert(error); + toast(error, 'danger'); }); } @@ -1015,7 +1016,7 @@ export class User extends Component { console.log(msg); let op: UserOperation = msgOp(msg); if (msg.error) { - alert(i18n.t(msg.error)); + toast(i18n.t(msg.error), 'danger'); this.state.deleteAccountLoading = false; this.state.avatarLoading = false; this.state.userSettingsLoading = false; @@ -1069,7 +1070,7 @@ export class User extends Component { this.setState(this.state); } else if (op == UserOperation.CreateComment) { // let res: CommentResponse = msg; - alert(i18n.t('reply_sent')); + toast(i18n.t('reply_sent')); // this.state.comments.unshift(res.comment); // TODO do this right // this.setState(this.state); } else if (op == UserOperation.SaveComment) { diff --git a/ui/src/index.html b/ui/src/index.html index 933cdc68..122783d4 100644 --- a/ui/src/index.html +++ b/ui/src/index.html @@ -13,6 +13,7 @@ + diff --git a/ui/src/services/WebSocketService.ts b/ui/src/services/WebSocketService.ts index 146a9abf..e72a2871 100644 --- a/ui/src/services/WebSocketService.ts +++ b/ui/src/services/WebSocketService.ts @@ -41,6 +41,7 @@ import { Subject } from 'rxjs'; import { retryWhen, delay } from 'rxjs/operators'; import { UserService } from './'; import { i18n } from '../i18next'; +import { toast } from '../utils'; export class WebSocketService { private static _instance: WebSocketService; @@ -318,7 +319,7 @@ export class WebSocketService { private setAuth(obj: any, throwErr: boolean = true) { obj.auth = UserService.Instance.auth; if (obj.auth == null && throwErr) { - alert(i18n.t('not_logged_in')); + toast(i18n.t('not_logged_in'), 'danger'); throw 'Not logged in'; } } diff --git a/ui/src/translations/en.ts b/ui/src/translations/en.ts index ecd293b5..c932014f 100644 --- a/ui/src/translations/en.ts +++ b/ui/src/translations/en.ts @@ -191,6 +191,7 @@ export const en = { landing_0: "Lemmy is a <1>link aggregator / reddit alternative, intended to work in the <2>fediverse.<3>It's self-hostable, has live-updating comment threads, and is tiny (<4>~80kB). Federation into the ActivityPub network is on the roadmap. <5>This is a <6>very early beta version, and a lot of features are currently broken or missing. <7>Suggest new features or report bugs <8>here.<9>Made with <10>Rust, <11>Actix, <12>Inferno, <13>Typescript.", not_logged_in: 'Not logged in.', + logged_in: 'Logged in.', community_ban: 'You have been banned from this community.', site_ban: 'You have been banned from the site', couldnt_create_comment: "Couldn't create comment.", diff --git a/ui/src/utils.ts b/ui/src/utils.ts index dce746e2..a3aab09d 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -23,6 +23,7 @@ import markdownitEmoji from 'markdown-it-emoji/light'; import markdown_it_container from 'markdown-it-container'; import * as twemoji from 'twemoji'; import * as emojiShortName from 'emoji-short-name'; +import Toastify from 'toastify-js'; export const repoUrl = 'https://github.com/dessalines/lemmy'; export const markdownHelpUrl = 'https://commonmark.org/help/'; @@ -366,3 +367,11 @@ export function imageThumbnailer(url: string): string { export function isCommentType(item: Comment | PrivateMessage): item is Comment { return (item as Comment).community_id !== undefined; } + +export function toast(text: string, background: string = 'success') { + let backgroundColor = `var(--${background})`; + Toastify({ + text: text, + backgroundColor: backgroundColor, + }).showToast(); +} diff --git a/ui/yarn.lock b/ui/yarn.lock index 0c878707..b385b8b6 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -4622,6 +4622,11 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +toastify-js@^1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/toastify-js/-/toastify-js-1.6.2.tgz#38af35625797d3d3f51fa09851f0bda449271423" + integrity sha512-ECQzgjTjxaElfwp/8e8qoIYx7U5rU2G54e5aiPMv+UtmGOYEitrtNp/Kr8uMgntnQNrDZEQJNGjBtoNnEgR5EA== + toidentifier@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" -- cgit v1.2.3