deleting 1 file will show toast instead of dialog

Massimo Melina committed Feb 28, 2024 at 15:03 UTC f03ec647bae2f73852308d7fda84ab156d3c4071
6 files changed +32 -9
frontend/package.json
+1
@@ -12,6 +12,7 @@
12 "lodash": "^4.17.21",
13 "react": "^18.2.0",
14 "react-dom": "^18.2.0",
15 + "react-hot-toast": "^2.4.1",
16 "react-router-dom": "^6.1.1",
17 "talkr": "^3.3.9",
18 "tssrp6a": "^3.0.0",
frontend/src/App.ts
+9
@@ -10,6 +10,7 @@ import { I18Nprovider } from './i18n'
10 import { proxy, useSnapshot } from "valtio"
11 import { Spinner } from "./components"
12 import { getHFS, getPrefixUrl } from '@hfs/shared'
13 +import { Toaster } from 'react-hot-toast'
14
15 function App() {
16 useTheme()
@@ -22,6 +23,14 @@ function App() {
23 return h(I18Nprovider, {},
24 h(BrowserRouter, {},
25 h(NavigationExtractor, {},
26 + h(Toaster, {
27 + toastOptions: {
28 + style: {
29 + background: 'var(--faint-contrast)',
30 + color: 'var(--text-high-contrast)',
31 + },
32 + }
33 + }),
34 h(Dialogs, {},
35 h(Routes, {},
36 h(Route, { path:'*', element: h(BrowseFiles) })
frontend/src/dialog.ts
+8 -2
@@ -1,13 +1,14 @@
1 // This file is part of HFS - Copyright 2021-2023, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
2
3 import { createElement as h, ReactElement, ReactNode, useEffect, useRef, useState, KeyboardEvent,
4 - InputHTMLAttributes } from 'react'
4 + InputHTMLAttributes, isValidElement } from 'react'
5 import './dialog.css'
6 import { newDialog, closeDialog, DialogOptions, dialogsDefaults } from '@hfs/shared/dialogs'
7 import _ from 'lodash'
8 import { useInterval } from 'usehooks-ts'
9 import { t } from './i18n'
10 -import { err2msg, isCtrlKey, pendingPromise, Promisable } from './misc'
10 +import { err2msg, hIcon, isCtrlKey, pendingPromise, Promisable } from './misc'
11 +import hotToast from 'react-hot-toast'
12 export * from '@hfs/shared/dialogs'
13
14 _.merge(dialogsDefaults, { closableProps: { 'aria-label': t`Close` } })
@@ -167,3 +168,8 @@ export function confirmDialog(msg: ReactElement | string, options: ConfirmOption
168 )
169 }
170 }
171 +
172 +export function toast(msg: string | ReactElement, type: AlertType | 'success' | ReactElement='info') {
173 + console.debug("toast", msg)
174 + hotToast(msg, { position: 'top-right', icon: isValidElement(type) ? type : hIcon(type) })
175 +}
frontend/src/icons.ts
+2
@@ -43,6 +43,8 @@ const SYS_ICONS: Record<string, [string] | [string, string | false]> = { // fals
43 paste: ['📋'],
44 shuffle: ['🔀'],
45 repeat: ['🔁', 'reload'],
46 + success: ['👍', false],
47 + warning: ['⚠️', false],
48 }
49
50 document.fonts.ready.then(async ()=> {
frontend/src/index.scss
+7 -4
@@ -5,11 +5,12 @@
5
6 --bg: #fff;
7 --text: #555;
8 + --text-high-contrast: #111;
9 --ghost-contrast: #8882;
10 --ghost-contrast-alt: #eee;
10 - --faint-contrast: #8884;
11 - --mild-contrast: #8886;
12 - --good-contrast: #000a;
11 + --faint-contrast: #ddd;
12 + --mild-contrast: #aaa;
13 + --good-contrast: #444;
14 --button-bg: #6080aa;
15 --button-text: #eaeaea;
16 --focus-color: #468;
@@ -21,8 +22,10 @@
22 .theme-dark {
23 --bg: #000;
24 --text: #999;
25 + --text-high-contrast: #eee;
26 --ghost-contrast-alt: #181818;
25 - --good-contrast: #fffa;
27 + --faint-contrast: #2d2d2d;
28 + --good-contrast: #aaa;
29 --button-bg: #345;
30 --button-text: #999;
31 color-scheme: dark;
frontend/src/menu.ts
+5 -3
@@ -2,7 +2,7 @@
2
3 import { state, useSnapState } from './state'
4 import { createElement as h, Fragment, useEffect, useMemo, useState } from 'react'
5 -import { alertDialog, confirmDialog, ConfirmOptions, promptDialog } from './dialog'
5 +import { alertDialog, confirmDialog, ConfirmOptions, promptDialog, toast } from './dialog'
6 import { defaultPerms, err2msg, ErrorMsg, onlyTruthy, prefix, throw_, useStateMounted, VfsPerms, working } from './misc'
7 import { loginDialog } from './login'
8 import { showOptions } from './options'
@@ -195,9 +195,11 @@ export async function deleteFiles(uris: string[]) {
195 stop()
196 reloadList()
197 const e = errors.length
198 + const msg = t('delete_completed', {n: n-e}, "Deletion: {n} completed")
199 + if (n === 1 && !e)
200 + return toast(msg, 'success')
201 alertDialog(h(Fragment, {},
199 - t('delete_completed', {n: n-e}, "Deletion: {n} completed"),
200 - e > 0 && t('delete_failed', {n:e}, ", {n} failed"),
202 + msg, e > 0 && t('delete_failed', {n:e}, ", {n} failed"),
203 h('div', { style: { textAlign: 'left', marginTop: '1em', } },
204 ...errors.map(e => h(ErrorMsg, { err: t(err2msg(e.err)) + ': ' + e.uri }))
205 )