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
)