diff --git a/templates/devtest/toast-and-message.tmpl b/templates/devtest/toast-and-message.tmpl index 85385082b7..7c6d347784 100644 --- a/templates/devtest/toast-and-message.tmpl +++ b/templates/devtest/toast-and-message.tmpl @@ -4,6 +4,7 @@

Toast

+ diff --git a/web_src/css/modules/toast.css b/web_src/css/modules/toast.css index 33c1f7547c..ffef40779e 100644 --- a/web_src/css/modules/toast.css +++ b/web_src/css/modules/toast.css @@ -1,5 +1,7 @@ .toastify { - color: var(--color-white); + color: var(--color-text); + background: var(--color-menu); + border: 1px solid var(--color-secondary); position: fixed; opacity: 0; transition: all .2s ease; @@ -16,6 +18,11 @@ opacity: 1; } +.toast-success .toast-icon { color: var(--color-success-text); } +.toast-info .toast-icon { color: var(--color-info-text); } +.toast-warning .toast-icon { color: var(--color-warning-text); } +.toast-error .toast-icon { color: var(--color-error-text); } + .toast-body { flex: 1; padding: 5px 0; diff --git a/web_src/js/modules/devtest.ts b/web_src/js/modules/devtest.ts index 01359e0fb5..8efe7e9959 100644 --- a/web_src/js/modules/devtest.ts +++ b/web_src/js/modules/devtest.ts @@ -1,21 +1,19 @@ -import {showInfoToast, showWarningToast, showErrorToast} from './toast.ts'; -import type {Toast} from './toast.ts'; +import {showSuccessToast, showInfoToast, showWarningToast, showErrorToast} from './toast.ts'; import {registerGlobalInitFunc} from './observer.ts'; import {showFomanticModal} from './fomantic/modal.ts'; import {createElementFromHTML} from '../utils/dom.ts'; import {html} from '../utils/html.ts'; import {showGlobalErrorMessage} from './errors.ts'; import {AnsiLineRenderer} from '../render/ansi.ts'; - -type LevelMap = Record Toast | null>; +import type {Intent} from '../types.ts'; function initDevtestPage() { const toastButtons = document.querySelectorAll('.toast-test-button'); if (toastButtons.length) { - const levelMap: LevelMap = {info: showInfoToast, warning: showWarningToast, error: showErrorToast}; + const levelMap = {success: showSuccessToast, info: showInfoToast, warning: showWarningToast, error: showErrorToast}; for (const el of toastButtons) { el.addEventListener('click', () => { - const level = el.getAttribute('data-toast-level')!; + const level = el.getAttribute('data-toast-level') as Intent; const message = el.getAttribute('data-toast-message')!; levelMap[level](message); }); diff --git a/web_src/js/modules/toast.test.ts b/web_src/js/modules/toast.test.ts index b29e9a32bd..2c16f0cae3 100644 --- a/web_src/js/modules/toast.test.ts +++ b/web_src/js/modules/toast.test.ts @@ -1,16 +1,21 @@ -import {showInfoToast, showErrorToast, showWarningToast} from './toast.ts'; +import {showSuccessToast, showInfoToast, showErrorToast, showWarningToast} from './toast.ts'; + +test('showSuccessToast', async () => { + showSuccessToast('success', {duration: -1}); + expect(document.querySelector('.toastify')).toBeTruthy(); +}); test('showInfoToast', async () => { - showInfoToast('success 😀', {duration: -1}); + showInfoToast('info', {duration: -1}); expect(document.querySelector('.toastify')).toBeTruthy(); }); test('showWarningToast', async () => { - showWarningToast('warning 😐', {duration: -1}); + showWarningToast('warning', {duration: -1}); expect(document.querySelector('.toastify')).toBeTruthy(); }); test('showErrorToast', async () => { - showErrorToast('error 🙁', {duration: -1}); + showErrorToast('error', {duration: -1}); expect(document.querySelector('.toastify')).toBeTruthy(); }); diff --git a/web_src/js/modules/toast.ts b/web_src/js/modules/toast.ts index a6cfef6848..0f6a054593 100644 --- a/web_src/js/modules/toast.ts +++ b/web_src/js/modules/toast.ts @@ -12,25 +12,25 @@ export type Toast = ReturnType; type ToastLevels = { [intent in Intent]: { icon: SvgName, - background: string, duration: number, } }; const levels: ToastLevels = { - info: { + success: { icon: 'octicon-check', - background: 'var(--color-green)', duration: 2500, }, + info: { + icon: 'octicon-info', + duration: 5000, + }, warning: { icon: 'gitea-exclamation', - background: 'var(--color-orange)', duration: -1, // requires dismissal to hide }, error: { icon: 'gitea-exclamation', - background: 'var(--color-red)', duration: -1, // requires dismissal to hide }, }; @@ -43,7 +43,7 @@ type ToastOpts = { type ToastifyElement = HTMLElement & {_giteaToastifyInstance?: Toast}; /** See https://github.com/apvarun/toastify-js#api for options */ -function showToast(message: string, level: Intent, {gravity, position, duration, useHtmlBody, preventDuplicates = true, ...other}: ToastOpts = {}): Toast | null { +function showToast(message: string, level: Intent = 'info', {gravity, position, duration, useHtmlBody, preventDuplicates = true, ...other}: ToastOpts = {}): Toast | null { const parent = document.querySelector('.ui.dimmer.active') ?? document.body; const duplicateKey = preventDuplicates ? (typeof preventDuplicates === 'string' ? preventDuplicates : `${level}-${message}`) : ''; @@ -59,7 +59,7 @@ function showToast(message: string, level: Intent, {gravity, position, duration, } } - const {icon, background, duration: levelDuration} = levels[level ?? 'info']; + const {icon, duration: levelDuration} = levels[level]; const bodyHtml = useHtmlBody ? message : htmlEscape(message); const toast = Toastify({ selector: parent, @@ -69,10 +69,10 @@ function showToast(message: string, level: Intent, {gravity, position, duration, `, escapeMarkup: false, + className: `toast-${level}`, gravity: gravity ?? 'top', position: position ?? 'center', duration: duration ?? levelDuration, - style: {background}, ...other, }); @@ -84,6 +84,10 @@ function showToast(message: string, level: Intent, {gravity, position, duration, return toast; } +export function showSuccessToast(message: string, opts?: ToastOpts): Toast | null { + return showToast(message, 'success', opts); +} + export function showInfoToast(message: string, opts?: ToastOpts): Toast | null { return showToast(message, 'info', opts); } diff --git a/web_src/js/svg.ts b/web_src/js/svg.ts index a24b542e0d..bd8b96691b 100644 --- a/web_src/js/svg.ts +++ b/web_src/js/svg.ts @@ -50,6 +50,7 @@ import octiconHistory from '../../public/assets/img/svg/octicon-history.svg'; import octiconHorizontalRule from '../../public/assets/img/svg/octicon-horizontal-rule.svg'; import octiconHome from '../../public/assets/img/svg/octicon-home.svg'; import octiconImage from '../../public/assets/img/svg/octicon-image.svg'; +import octiconInfo from '../../public/assets/img/svg/octicon-info.svg'; import octiconIssueClosed from '../../public/assets/img/svg/octicon-issue-closed.svg'; import octiconIssueOpened from '../../public/assets/img/svg/octicon-issue-opened.svg'; import octiconItalic from '../../public/assets/img/svg/octicon-italic.svg'; @@ -139,6 +140,7 @@ const svgs = { 'octicon-horizontal-rule': octiconHorizontalRule, 'octicon-home': octiconHome, 'octicon-image': octiconImage, + 'octicon-info': octiconInfo, 'octicon-issue-closed': octiconIssueClosed, 'octicon-issue-opened': octiconIssueOpened, 'octicon-italic': octiconItalic, diff --git a/web_src/js/types.ts b/web_src/js/types.ts index 8c2ad5f7b2..a3168ca69d 100644 --- a/web_src/js/types.ts +++ b/web_src/js/types.ts @@ -1,7 +1,7 @@ export type TimeoutId = ReturnType; export type IntervalId = ReturnType; -export type Intent = 'error' | 'warning' | 'info'; +export type Intent = 'error' | 'warning' | 'info' | 'success'; export type Mention = { key: string,