hfs 0.26.8 → 0.27.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -2
- package/admin/assets/index-509bb1d6.js +415 -0
- package/admin/assets/index-60a380a7.css +1 -0
- package/admin/assets/sha512-738f0943.js +8 -0
- package/admin/index.html +3 -1
- package/admin/{public/logo.svg → logo.svg} +0 -0
- package/frontend/assets/index-6e178dfd.css +1 -0
- package/frontend/assets/index-aea7654e.js +85 -0
- package/frontend/assets/sha512-bf915587.js +8 -0
- package/frontend/{public/fontello.css → fontello.css} +0 -0
- package/frontend/{public/fontello.woff2 → fontello.woff2} +0 -0
- package/frontend/index.html +4 -2
- package/package.json +2 -6
- package/plugins/vhosting/plugin.js +23 -20
- package/src/QuickZipStream.js +285 -0
- package/src/ThrottledStream.js +93 -0
- package/src/adminApis.js +169 -0
- package/src/api.accounts.js +59 -0
- package/src/api.auth.js +128 -0
- package/src/api.file_list.js +110 -0
- package/src/api.helpers.js +32 -0
- package/src/api.monitor.js +104 -0
- package/src/api.plugins.js +128 -0
- package/src/api.vfs.js +167 -0
- package/src/apiMiddleware.js +123 -0
- package/src/block.js +34 -0
- package/src/commands.js +125 -0
- package/src/config.js +168 -0
- package/src/connections.js +57 -0
- package/src/const.js +94 -0
- package/src/crypt.js +21 -0
- package/src/debounceAsync.js +49 -0
- package/src/events.js +9 -0
- package/src/frontEndApis.js +38 -0
- package/src/github.js +104 -0
- package/src/index.js +57 -0
- package/src/listen.js +235 -0
- package/src/log.js +137 -0
- package/src/middlewares.js +195 -0
- package/src/misc.js +160 -0
- package/src/pbkdf2.js +74 -0
- package/src/perm.js +183 -0
- package/src/plugins.js +343 -0
- package/src/serveFile.js +105 -0
- package/src/serveGuiFiles.js +113 -0
- package/src/sse.js +30 -0
- package/src/throttler.js +91 -0
- package/src/update.js +70 -0
- package/src/util-files.js +163 -0
- package/src/util-generators.js +31 -0
- package/src/util-http.js +32 -0
- package/src/vfs.js +232 -0
- package/src/watchLoad.js +73 -0
- package/src/zip.js +73 -0
- package/admin/.DS_Store +0 -0
- package/admin/.eslintrc +0 -8
- package/admin/.gitignore +0 -23
- package/admin/package.json +0 -67
- package/admin/src/AccountForm.ts +0 -92
- package/admin/src/AccountsPage.ts +0 -143
- package/admin/src/App.ts +0 -83
- package/admin/src/ArrayField.ts +0 -84
- package/admin/src/ConfigPage.ts +0 -279
- package/admin/src/FileField.ts +0 -52
- package/admin/src/FileForm.ts +0 -148
- package/admin/src/FilePicker.ts +0 -166
- package/admin/src/HomePage.ts +0 -96
- package/admin/src/InstalledPlugins.ts +0 -158
- package/admin/src/LoginRequired.ts +0 -75
- package/admin/src/LogoutPage.ts +0 -27
- package/admin/src/LogsPage.ts +0 -75
- package/admin/src/MainMenu.ts +0 -74
- package/admin/src/MenuButton.ts +0 -38
- package/admin/src/MonitorPage.ts +0 -200
- package/admin/src/OnlinePlugins.ts +0 -101
- package/admin/src/PermField.ts +0 -80
- package/admin/src/PluginsPage.ts +0 -27
- package/admin/src/VfsMenuBar.ts +0 -58
- package/admin/src/VfsPage.ts +0 -124
- package/admin/src/VfsTree.ts +0 -95
- package/admin/src/addFiles.ts +0 -59
- package/admin/src/api.ts +0 -246
- package/admin/src/dialog.ts +0 -203
- package/admin/src/index.css +0 -21
- package/admin/src/index.ts +0 -10
- package/admin/src/md.ts +0 -31
- package/admin/src/misc.ts +0 -141
- package/admin/src/react-app-env.d.ts +0 -1
- package/admin/src/reportWebVitals.ts +0 -15
- package/admin/src/setupTests.ts +0 -5
- package/admin/src/state.ts +0 -40
- package/admin/src/theme.ts +0 -37
- package/admin/tsconfig.json +0 -26
- package/admin/vite.config.ts +0 -32
- package/frontend/.DS_Store +0 -0
- package/frontend/.eslintrc +0 -8
- package/frontend/.gitignore +0 -23
- package/frontend/package.json +0 -51
- package/frontend/src/App.ts +0 -25
- package/frontend/src/Breadcrumbs.ts +0 -43
- package/frontend/src/BrowseFiles.ts +0 -141
- package/frontend/src/Head.ts +0 -45
- package/frontend/src/UserPanel.ts +0 -52
- package/frontend/src/api.ts +0 -78
- package/frontend/src/components.ts +0 -54
- package/frontend/src/dialog.css +0 -76
- package/frontend/src/dialog.ts +0 -105
- package/frontend/src/icons.ts +0 -46
- package/frontend/src/index.scss +0 -307
- package/frontend/src/index.ts +0 -10
- package/frontend/src/login.ts +0 -50
- package/frontend/src/menu.ts +0 -188
- package/frontend/src/misc.ts +0 -54
- package/frontend/src/options.ts +0 -52
- package/frontend/src/react-app-env.d.ts +0 -1
- package/frontend/src/reportWebVitals.ts +0 -15
- package/frontend/src/setupTests.ts +0 -5
- package/frontend/src/state.ts +0 -82
- package/frontend/src/useAuthorized.ts +0 -17
- package/frontend/src/useFetchList.ts +0 -144
- package/frontend/src/useTheme.ts +0 -23
- package/frontend/tsconfig.json +0 -26
- package/frontend/vite.config.ts +0 -21
- package/src/QuickZipStream.ts +0 -279
- package/src/ThrottledStream.ts +0 -98
- package/src/adminApis.ts +0 -161
- package/src/api.accounts.ts +0 -78
- package/src/api.auth.ts +0 -131
- package/src/api.file_list.ts +0 -102
- package/src/api.helpers.ts +0 -30
- package/src/api.monitor.ts +0 -106
- package/src/api.plugins.ts +0 -139
- package/src/api.vfs.ts +0 -182
- package/src/apiMiddleware.ts +0 -124
- package/src/block.ts +0 -35
- package/src/commands.ts +0 -122
- package/src/config.ts +0 -166
- package/src/connections.ts +0 -60
- package/src/const.ts +0 -57
- package/src/crypt.ts +0 -16
- package/src/debounceAsync.ts +0 -51
- package/src/events.ts +0 -6
- package/src/frontEndApis.ts +0 -17
- package/src/github.ts +0 -102
- package/src/index.ts +0 -53
- package/src/listen.ts +0 -220
- package/src/log.ts +0 -128
- package/src/middlewares.ts +0 -176
- package/src/misc.ts +0 -149
- package/src/pbkdf2.ts +0 -83
- package/src/perm.ts +0 -194
- package/src/plugins.ts +0 -342
- package/src/serveFile.ts +0 -104
- package/src/serveGuiFiles.ts +0 -95
- package/src/sse.ts +0 -29
- package/src/throttler.ts +0 -106
- package/src/update.ts +0 -67
- package/src/util-files.ts +0 -137
- package/src/util-generators.ts +0 -29
- package/src/util-http.ts +0 -29
- package/src/vfs.ts +0 -258
- package/src/watchLoad.ts +0 -75
- package/src/zip.ts +0 -69
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
|
|
2
|
-
|
|
3
|
-
import { useSnapState } from './state'
|
|
4
|
-
import { createElement as h } from 'react'
|
|
5
|
-
import { alertDialog, closeDialog, newDialog, promptDialog } from './dialog'
|
|
6
|
-
import { createVerifierAndSalt, SRPParameters, SRPRoutines } from 'tssrp6a'
|
|
7
|
-
import { apiCall } from './api'
|
|
8
|
-
import { logout } from './login'
|
|
9
|
-
import { MenuButton } from './menu'
|
|
10
|
-
|
|
11
|
-
export default function showUserPanel() {
|
|
12
|
-
newDialog({ Content })
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
function Content() {
|
|
16
|
-
const snap = useSnapState()
|
|
17
|
-
return h('div', { id: 'user-panel' },
|
|
18
|
-
h('div', {}, "User: " + snap.username),
|
|
19
|
-
h(MenuButton, {
|
|
20
|
-
icon: 'password',
|
|
21
|
-
label: "Change password",
|
|
22
|
-
async onClick() {
|
|
23
|
-
const pwd = await promptDialog("Enter new password", { type: 'password' })
|
|
24
|
-
if (!pwd) return
|
|
25
|
-
const check = await promptDialog("RE-enter new password", { type: 'password' })
|
|
26
|
-
if (!check) return
|
|
27
|
-
if (check !== pwd)
|
|
28
|
-
return alertDialog("The second password you entered did not match the first. Procedure aborted.", 'warning')
|
|
29
|
-
const srp6aNimbusRoutines = new SRPRoutines(new SRPParameters())
|
|
30
|
-
const res = await createVerifierAndSalt(srp6aNimbusRoutines, snap.username, pwd)
|
|
31
|
-
try {
|
|
32
|
-
await apiCall('change_srp', { salt: String(res.s), verifier: String(res.v) }).catch(e => {
|
|
33
|
-
if (e.code !== 406) // 406 = server was configured to support clear text authentication
|
|
34
|
-
throw e
|
|
35
|
-
return apiCall('change_password', { newPassword: pwd }) // unencrypted version
|
|
36
|
-
})
|
|
37
|
-
return alertDialog("Password changed")
|
|
38
|
-
}
|
|
39
|
-
catch(e) {
|
|
40
|
-
return alertDialog(e as Error)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}),
|
|
44
|
-
h(MenuButton, {
|
|
45
|
-
icon: 'logout',
|
|
46
|
-
label: "Logout",
|
|
47
|
-
onClick() {
|
|
48
|
-
logout().then(closeDialog, alertDialog)
|
|
49
|
-
}
|
|
50
|
-
})
|
|
51
|
-
)
|
|
52
|
-
}
|
package/frontend/src/api.ts
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
// This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
|
|
2
|
-
|
|
3
|
-
import { useEffect, useState } from 'react';
|
|
4
|
-
import { Dict, Falsy, getCookie, working } from './misc'
|
|
5
|
-
|
|
6
|
-
const PREFIX = '/~/api/'
|
|
7
|
-
|
|
8
|
-
interface ApiCallOptions { noModal?:true }
|
|
9
|
-
export function apiCall(cmd: string, params?: Dict, options: ApiCallOptions={}) : Promise<any> {
|
|
10
|
-
const stop = options.noModal ? undefined : working()
|
|
11
|
-
const csrf = getCsrf()
|
|
12
|
-
if (csrf)
|
|
13
|
-
params = { csrf, ...params }
|
|
14
|
-
return fetch(PREFIX+cmd, {
|
|
15
|
-
method: 'POST',
|
|
16
|
-
headers: { 'content-type': 'application/json' },
|
|
17
|
-
body: params && JSON.stringify(params),
|
|
18
|
-
}).then(res => {
|
|
19
|
-
stop?.()
|
|
20
|
-
if (res.ok)
|
|
21
|
-
return res.json()
|
|
22
|
-
const msg = `Failed API ${cmd}: ${res.statusText}`
|
|
23
|
-
console.warn(msg + (params ? ' ' + JSON.stringify(params) : ''))
|
|
24
|
-
throw new ApiError(res.status, msg)
|
|
25
|
-
}, err => {
|
|
26
|
-
stop?.()
|
|
27
|
-
if (err?.message?.includes('fetch'))
|
|
28
|
-
throw Error("Network error")
|
|
29
|
-
throw err
|
|
30
|
-
})
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export class ApiError extends Error {
|
|
34
|
-
constructor(readonly code:number, message: string) {
|
|
35
|
-
super(message);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export function useApi(cmd: string | Falsy, params?: object) : any {
|
|
40
|
-
const [x, setX] = useState()
|
|
41
|
-
useEffect(()=>{
|
|
42
|
-
setX(undefined)
|
|
43
|
-
if (cmd)
|
|
44
|
-
apiCall(cmd, params).then(setX, setX)
|
|
45
|
-
}, [cmd, JSON.stringify(params)]) //eslint-disable-line
|
|
46
|
-
return x
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
type EventHandler = (type:string, data?:any) => void
|
|
50
|
-
|
|
51
|
-
export function apiEvents(cmd: string, params: Dict, cb:EventHandler) {
|
|
52
|
-
const csrf = getCsrf()
|
|
53
|
-
const processed: Record<string,string> = { csrf: csrf && JSON.stringify(csrf) }
|
|
54
|
-
for (const k in params) {
|
|
55
|
-
const v = params[k]
|
|
56
|
-
if (v === undefined) continue
|
|
57
|
-
processed[k] = JSON.stringify(v)
|
|
58
|
-
}
|
|
59
|
-
const source = new EventSource(PREFIX + cmd + '?' + new URLSearchParams(processed))
|
|
60
|
-
source.onopen = () => cb('connected')
|
|
61
|
-
source.onerror = err => cb('error', err)
|
|
62
|
-
source.onmessage = ({ data }) => {
|
|
63
|
-
if (!data) {
|
|
64
|
-
cb('closed')
|
|
65
|
-
return source.close()
|
|
66
|
-
}
|
|
67
|
-
try { data = JSON.parse(data) }
|
|
68
|
-
catch {
|
|
69
|
-
return cb('string', data)
|
|
70
|
-
}
|
|
71
|
-
cb('msg', data)
|
|
72
|
-
}
|
|
73
|
-
return source
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function getCsrf() {
|
|
77
|
-
return getCookie('csrf')
|
|
78
|
-
}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
// This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
|
|
2
|
-
|
|
3
|
-
import { hIcon } from './misc'
|
|
4
|
-
import { createElement as h, HTMLAttributes, ReactNode, useMemo } from 'react'
|
|
5
|
-
|
|
6
|
-
export function Spinner() {
|
|
7
|
-
return hIcon('spinner', { className:'spinner' })
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export function Flex({ gap='1em', vert=false, children=null }) {
|
|
11
|
-
return h('div', {
|
|
12
|
-
style: {
|
|
13
|
-
display: 'flex',
|
|
14
|
-
gap,
|
|
15
|
-
flexDirection: vert ? 'column' : undefined,
|
|
16
|
-
}
|
|
17
|
-
}, children)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function FlexV(props:any) {
|
|
21
|
-
return h(Flex, { vert:true, ...props })
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
interface CheckboxProps { children?:ReactNode, value:any, onChange?:(v:boolean)=>void }
|
|
25
|
-
export function Checkbox({ onChange, value, children, ...props }:CheckboxProps) {
|
|
26
|
-
return h('label', {},
|
|
27
|
-
h('input',{
|
|
28
|
-
type:'checkbox',
|
|
29
|
-
onChange: ev => onChange?.(Boolean(ev.target.checked)),
|
|
30
|
-
checked: Boolean(value),
|
|
31
|
-
value: 1,
|
|
32
|
-
...props
|
|
33
|
-
}),
|
|
34
|
-
children
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
type Options = { label:string, value:string }[]
|
|
39
|
-
interface SelectProps { value:any, onChange?:(v:string)=>void, options:Options }
|
|
40
|
-
export function Select({ onChange, value, options, ...props }:SelectProps) {
|
|
41
|
-
return h('select', {
|
|
42
|
-
onChange: ev => // @ts-ignore
|
|
43
|
-
onChange?.(ev.target.value),
|
|
44
|
-
value,
|
|
45
|
-
...props,
|
|
46
|
-
}, options.map(({ value, label }) => h('option', { key:value, value }, label)))
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function Html({ code, ...rest }:{ code:string } & HTMLAttributes<any>) {
|
|
50
|
-
const o = useMemo(() => ({ __html: code }), [code])
|
|
51
|
-
if (!code)
|
|
52
|
-
return null
|
|
53
|
-
return h('span', { ...rest, dangerouslySetInnerHTML: o })
|
|
54
|
-
}
|
package/frontend/src/dialog.css
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
.dialog-backdrop {
|
|
2
|
-
position: fixed;
|
|
3
|
-
top: 0;
|
|
4
|
-
bottom: 0;
|
|
5
|
-
left: 0;
|
|
6
|
-
right: 0;
|
|
7
|
-
background: #888a;
|
|
8
|
-
display: flex;
|
|
9
|
-
justify-content: center;
|
|
10
|
-
align-items: center;
|
|
11
|
-
z-index: 1000;
|
|
12
|
-
}
|
|
13
|
-
.dialog {
|
|
14
|
-
background: #fff; /*fallback*/
|
|
15
|
-
background: var(--bg);
|
|
16
|
-
padding: max(0.5em, 1vw);
|
|
17
|
-
border-radius: 1em;
|
|
18
|
-
position: relative;
|
|
19
|
-
margin: 0 3vw;
|
|
20
|
-
overflow: hidden;
|
|
21
|
-
max-height: calc(100vh - 2em)
|
|
22
|
-
}
|
|
23
|
-
.dialog-icon {
|
|
24
|
-
color: #fff;
|
|
25
|
-
background-color: var(--color);
|
|
26
|
-
position: absolute;
|
|
27
|
-
top: 0;
|
|
28
|
-
width: 1.8em;
|
|
29
|
-
height: 1.7em;
|
|
30
|
-
text-align: center;
|
|
31
|
-
border-radius: .8em 0;
|
|
32
|
-
}
|
|
33
|
-
.dialog-closer {
|
|
34
|
-
border-radius: 0 0.8em;
|
|
35
|
-
right: 0;
|
|
36
|
-
padding: 0;
|
|
37
|
-
background-color: #c99;
|
|
38
|
-
}
|
|
39
|
-
.dialog-icon ~ .dialog-content {
|
|
40
|
-
margin-top: 1.3em;
|
|
41
|
-
}
|
|
42
|
-
.dialog-type {
|
|
43
|
-
left: 0;
|
|
44
|
-
top: 0;
|
|
45
|
-
overflow: hidden;
|
|
46
|
-
line-height: 1.7em;
|
|
47
|
-
}
|
|
48
|
-
.dialog-content {
|
|
49
|
-
overflow: auto;
|
|
50
|
-
max-height: calc(100vh - 4em);
|
|
51
|
-
}
|
|
52
|
-
.dialog-content p {
|
|
53
|
-
white-space: pre-wrap;
|
|
54
|
-
margin: .5em 0;
|
|
55
|
-
}
|
|
56
|
-
.dialog-confirm .dialog-content button {
|
|
57
|
-
margin-top: 1em;
|
|
58
|
-
}
|
|
59
|
-
.dialog-alert-info {
|
|
60
|
-
--color: #282
|
|
61
|
-
}
|
|
62
|
-
.dialog-alert-warning {
|
|
63
|
-
--color: #c91
|
|
64
|
-
}
|
|
65
|
-
.dialog-alert-error {
|
|
66
|
-
--color: #822;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
@media (max-width: 50em) {
|
|
70
|
-
.dialog-closer {
|
|
71
|
-
font-size: 120%
|
|
72
|
-
}
|
|
73
|
-
.dialog-icon ~ .dialog-content {
|
|
74
|
-
margin-top: 2em;
|
|
75
|
-
}
|
|
76
|
-
}
|
package/frontend/src/dialog.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
// This file is part of HFS - Copyright 2021-2022, 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 } from 'react'
|
|
4
|
-
import './dialog.css'
|
|
5
|
-
import { newDialog, closeDialog } from '@hfs/shared/lib/dialogs'
|
|
6
|
-
export * from '@hfs/shared/lib/dialogs'
|
|
7
|
-
|
|
8
|
-
interface PromptOptions { def?:string, type?:string }
|
|
9
|
-
export async function promptDialog(msg: string, { def, type }:PromptOptions={}) : Promise<string | null> {
|
|
10
|
-
return new Promise(resolve => newDialog({
|
|
11
|
-
className: 'dialog-prompt',
|
|
12
|
-
icon: '?',
|
|
13
|
-
onClose: resolve,
|
|
14
|
-
Content
|
|
15
|
-
}) )
|
|
16
|
-
|
|
17
|
-
function Content() {
|
|
18
|
-
const ref = useRef<HTMLInputElement>()
|
|
19
|
-
useEffect(()=>{
|
|
20
|
-
const e = ref.current
|
|
21
|
-
if (!e) return
|
|
22
|
-
const inp = e as HTMLInputElement
|
|
23
|
-
setTimeout(()=> inp.focus(),100)
|
|
24
|
-
if (def)
|
|
25
|
-
inp.value = def
|
|
26
|
-
},[])
|
|
27
|
-
return h('div', {},
|
|
28
|
-
h('p', {}, msg),
|
|
29
|
-
h('input', {
|
|
30
|
-
ref,
|
|
31
|
-
type,
|
|
32
|
-
autoFocus: true,
|
|
33
|
-
onKeyDown(ev: KeyboardEvent) {
|
|
34
|
-
const { key } = ev
|
|
35
|
-
if (key === 'Escape')
|
|
36
|
-
return closeDialog(null)
|
|
37
|
-
if (key === 'Enter')
|
|
38
|
-
return go()
|
|
39
|
-
}
|
|
40
|
-
}),
|
|
41
|
-
h('div', { style: { textAlign: 'right', marginTop: '.8em' } },
|
|
42
|
-
h('button', { onClick: go }, "Continue")),
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
function go() {
|
|
46
|
-
closeDialog(ref.current?.value)
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
type AlertType = 'error' | 'warning' | 'info'
|
|
52
|
-
|
|
53
|
-
export async function alertDialog(msg: ReactElement | string | Error, type:AlertType='info') {
|
|
54
|
-
if (msg instanceof Error) {
|
|
55
|
-
msg = String(msg)
|
|
56
|
-
type = 'error'
|
|
57
|
-
}
|
|
58
|
-
return new Promise(resolve => newDialog({
|
|
59
|
-
className: 'dialog-alert-'+type,
|
|
60
|
-
icon: '!',
|
|
61
|
-
onClose: resolve,
|
|
62
|
-
Content
|
|
63
|
-
}))
|
|
64
|
-
|
|
65
|
-
function Content(){
|
|
66
|
-
if (typeof msg === 'string' || msg instanceof Error)
|
|
67
|
-
msg = h('p', {}, String(msg))
|
|
68
|
-
return msg
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export interface ConfirmOptions { href?: string, afterButtons?: ReactNode }
|
|
73
|
-
export async function confirmDialog(msg: ReactElement | string, { href, afterButtons }: ConfirmOptions={}) : Promise<boolean> {
|
|
74
|
-
if (typeof msg === 'string')
|
|
75
|
-
msg = h('p', {}, msg)
|
|
76
|
-
return new Promise(resolve => newDialog({
|
|
77
|
-
className: 'dialog-confirm',
|
|
78
|
-
icon: '?',
|
|
79
|
-
onClose: resolve,
|
|
80
|
-
Content
|
|
81
|
-
}) )
|
|
82
|
-
|
|
83
|
-
function Content() {
|
|
84
|
-
return h('div', {},
|
|
85
|
-
msg,
|
|
86
|
-
h('div', {
|
|
87
|
-
style: {
|
|
88
|
-
display: 'flex',
|
|
89
|
-
justifyContent: 'flex-end',
|
|
90
|
-
gap: '1em'
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
h('a', {
|
|
94
|
-
href,
|
|
95
|
-
onClick() { closeDialog(true) },
|
|
96
|
-
}, h('button', {}, "Confirm")),
|
|
97
|
-
h('button', {
|
|
98
|
-
onClick() { closeDialog(false) },
|
|
99
|
-
}, "Don't"),
|
|
100
|
-
afterButtons,
|
|
101
|
-
)
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
package/frontend/src/icons.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
// This file is part of HFS - Copyright 2021-2022, Massimo Melina <a@rejetto.com> - License https://www.gnu.org/licenses/gpl-3.0.txt
|
|
2
|
-
|
|
3
|
-
import { state, useSnapState } from './state'
|
|
4
|
-
import { createElement as h, memo } from 'react'
|
|
5
|
-
|
|
6
|
-
const SYS_ICONS = {
|
|
7
|
-
login: 'user:👤',
|
|
8
|
-
user: 'user:👤',
|
|
9
|
-
filter: ':✂',
|
|
10
|
-
search: ':🔍',
|
|
11
|
-
search_off: 'cancel:❌',
|
|
12
|
-
stop: ':⏹️',
|
|
13
|
-
settings: 'cog:⚙',
|
|
14
|
-
archive: 'file-archive:📦',
|
|
15
|
-
logout: ':🚪',
|
|
16
|
-
home: ':🏠',
|
|
17
|
-
parent: 'level-up mirror:⬆',
|
|
18
|
-
folder: ':📂',
|
|
19
|
-
file: 'doc:📄',
|
|
20
|
-
spinner: 'spin6 spinner:🎲',
|
|
21
|
-
password: 'key:🗝️',
|
|
22
|
-
download: ':📥',
|
|
23
|
-
invert: 'retweet:🙃',
|
|
24
|
-
admin: 'crown:👑',
|
|
25
|
-
check: ':✔️',
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
document.fonts.ready.then(async ()=> {
|
|
29
|
-
const fontTester = '9px "fontello"'
|
|
30
|
-
await document.fonts.load(fontTester) // force font to be loaded even if we didn't display anything with it yet
|
|
31
|
-
if (document.fonts.check(fontTester))
|
|
32
|
-
state.iconsClass = ' ' // with fontello we don't need an additional class (unlike google material icons), but the empty space will cause reload
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
export const Icon = memo(({ name, alt, className='', ...props }: { name:string, className?:string, alt?:string, style?:any }) => {
|
|
36
|
-
// @ts-ignore
|
|
37
|
-
const [clazz,emoji] = (SYS_ICONS[name] || name).split(':')
|
|
38
|
-
const { iconsClass } = useSnapState()
|
|
39
|
-
className += ' icon ' + (iconsClass ? 'fa-'+(clazz||name) : 'emoji')
|
|
40
|
-
return h('span',{
|
|
41
|
-
...props,
|
|
42
|
-
'aria-label': alt,
|
|
43
|
-
role: 'img',
|
|
44
|
-
className,
|
|
45
|
-
}, iconsClass ? null : (emoji||'#'))
|
|
46
|
-
})
|