better code: split files
Massimo Melina committed
Oct 7, 2023 at 12:17 UTC
b5c54e0950a3524ff84b36efae2eb7887a702555
3 files changed
+77
-70
admin/src/CustomHtmlPage.ts
+5
-69
@@ -1,15 +1,15 @@
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 { ComponentProps, createElement as h, forwardRef, Fragment, useEffect, useMemo, useState } from 'react';
4
-import { Field, FieldProps, SelectField } from '@hfs/mui-grid-form'
3
+import { createElement as h, Fragment, useEffect, useMemo, useState } from 'react';
4
+import { Field, SelectField } from '@hfs/mui-grid-form'
5
import { apiCall, useApiEx } from './api'
6
-import { Alert, Box, TextField } from '@mui/material'
7
-import Editor from 'react-simple-code-editor'
8
-import { Dict, escapeHTML, focusableSelector, IconBtn, isCtrlKey, modifiedSx, reloadBtn, wikiLink } from './misc';
6
+import { Alert, Box } from '@mui/material'
7
+import { Dict, IconBtn, isCtrlKey, modifiedSx, reloadBtn, wikiLink } from './misc';
8
import { Save } from '@mui/icons-material'
9
import _ from 'lodash'
10
import { useDebounce } from 'usehooks-ts'
11
import md from './md'
12
+import { TextEditor } from './TextEditor';
13
14
export default function CustomHtmlPage() {
15
const { data, reload } = useApiEx<{ sections: Dict<string> }>('get_custom_html')
@@ -60,67 +60,3 @@ export default function CustomHtmlPage() {
60
return apiCall('set_custom_html', { sections: all }).then(() => setSaved(all))
61
}
62
}
63
-
64
-type OP = ComponentProps<typeof Editor>
65
-type Already = 'highlight' | 'padding' | 'tabSize' | 'insertSpaces' | 'ignoreTabKey'
66
-type TextEditorProps = Omit<OP, Already> & Partial<Pick<OP, Already>>
67
-const TextEditor = forwardRef(({ style, ...props }: TextEditorProps, ref) => h(Editor, {
68
- // Editor component doesn't seem to support ref, but I didn't cause any problem yet
69
- highlight: escapeHTML,
70
- padding: 10,
71
- tabSize: 4,
72
- insertSpaces: true,
73
- ignoreTabKey: false,
74
- style: {
75
- fontFamily: 'ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace',
76
- fontSize: '1em',
77
- flex: 1,
78
- background: '#8883',
79
- borderBottom: '1px solid #bbb',
80
- ...style,
81
- },
82
- ...props,
83
-}))
84
-
85
-export function TextEditorField({ onChange, value, onBlur, setApi, ...props }: FieldProps<string>) {
86
- const [state, setState] = useState(value || '')
87
- return h(TextField, {
88
- multiline: true,
89
- fullWidth: true,
90
- value: state,
91
- InputProps: { inputComponent: TextEditorAsInput },
92
- onChange(event) { setState(event.target.value) },
93
- onBlur(event) {
94
- onBlur?.(event)
95
- onChange(event.target.value, { was: value, event })
96
- },
97
- ...props,
98
- onKeyDown(ev) {
99
- if (isCtrlKey(ev) === 'Enter')
100
- return onChange(state, { was: value, event: ev })
101
- if (!ev.altKey || ev.key !== 'Tab') return
102
- ev.preventDefault()
103
- const focusable = document.querySelectorAll(focusableSelector)
104
- const i = _.indexOf(focusable, ev.target)
105
- const n = focusable.length
106
- const next = (i + (ev.shiftKey ? -1 : 1) + n) % n
107
- ;(focusable[next] as HTMLElement).focus()
108
- console.debug(focusable[next])
109
- },
110
- })
111
-}
112
-
113
-const TextEditorAsInput = forwardRef<HTMLInputElement, any>(({ onChange, ...rest }: any, ref) =>
114
- h(Box, { sx: { width: '100%', textarea: { outline: 0 } } },
115
- h(TextEditor, {
116
- ref,
117
- padding: 2,
118
- style: { background: 'initial', borderBottom: 'initial' },
119
- ...rest,
120
- onValueChange: value => onChange({ target: { value } }),
121
- onKeyDown(ev) {
122
- if (isCtrlKey(ev) === 'Enter')
123
- ev.preventDefault()
124
- },
125
- })
126
- ))
\ No newline at end of file
admin/src/OptionsPage.ts
+1
-1
@@ -15,7 +15,7 @@ import { proxyWarning } from './HomePage'
15
import _ from 'lodash';
16
import { proxy, subscribe, useSnapshot } from 'valtio'
17
import md from './md'
18
-import { TextEditorField } from './CustomHtmlPage'
18
+import { TextEditorField } from './TextEditor'
19
20
let loaded: Dict | undefined
21
let exposedReloadStatus: undefined | (() => void)
admin/src/TextEditor.ts
new
+71
@@ -0,0 +1,71 @@
1
+import { ComponentProps, createElement as h, forwardRef, useState } from 'react'
2
+import Editor from 'react-simple-code-editor'
3
+import { FieldProps } from '@hfs/mui-grid-form'
4
+import { Box, TextField, TextFieldProps } from '@mui/material'
5
+import { escapeHTML, focusableSelector, isCtrlKey } from './misc'
6
+import _ from 'lodash'
7
+
8
+type OP = ComponentProps<typeof Editor>
9
+type Already = 'highlight' | 'padding' | 'tabSize' | 'insertSpaces' | 'ignoreTabKey'
10
+type TextEditorProps = Omit<OP, Already> & Partial<Pick<OP, Already>>
11
+export const TextEditor = forwardRef(({ style, ...props }: TextEditorProps, ref) => h(Editor, {
12
+ // Editor component doesn't seem to support ref, but I didn't cause any problem yet
13
+ highlight: escapeHTML,
14
+ padding: 10,
15
+ tabSize: 4,
16
+ insertSpaces: true,
17
+ ignoreTabKey: false,
18
+ style: {
19
+ fontFamily: 'ui-monospace,SFMono-Regular,SF Mono,Consolas,Liberation Mono,Menlo,monospace',
20
+ fontSize: '1em',
21
+ flex: 1,
22
+ background: '#8883',
23
+ borderBottom: '1px solid #bbb',
24
+ ...style,
25
+ },
26
+ ...props,
27
+}))
28
+
29
+export function TextEditorField({ onChange, value, onBlur, setApi, ...props }: FieldProps<string> & Omit<TextFieldProps, 'onChange'>) {
30
+ const [state, setState] = useState(value || '')
31
+ return h(TextField, {
32
+ multiline: true,
33
+ fullWidth: true,
34
+ value: state,
35
+ InputProps: { inputComponent: TextEditorAsInput },
36
+ onChange(event) { setState(event.target.value) },
37
+ onBlur(event) {
38
+ onBlur?.(event)
39
+ onChange(event.target.value, { was: value, event })
40
+ },
41
+ ...props,
42
+ onKeyDown(ev) {
43
+ props.onKeyDown?.(ev)
44
+ if (isCtrlKey(ev) === 'Enter')
45
+ return onChange(state, { was: value, event: ev })
46
+ if (!ev.altKey || ev.key !== 'Tab') return
47
+ ev.preventDefault()
48
+ const focusable = document.querySelectorAll(focusableSelector)
49
+ const i = _.indexOf(focusable, ev.target)
50
+ const n = focusable.length
51
+ const next = (i + (ev.shiftKey ? -1 : 1) + n) % n
52
+ ;(focusable[next] as HTMLElement).focus()
53
+ console.debug(focusable[next])
54
+ },
55
+ })
56
+}
57
+
58
+const TextEditorAsInput = forwardRef<HTMLInputElement, any>(({ onChange, ...rest }: any, ref) =>
59
+ h(Box, { sx: { width: '100%', textarea: { outline: 0 } } },
60
+ h(TextEditor, {
61
+ ref,
62
+ padding: 2,
63
+ style: { background: 'initial', borderBottom: 'initial' },
64
+ ...rest,
65
+ onValueChange: value => onChange({ target: { value } }),
66
+ onKeyDown(ev) {
67
+ if (isCtrlKey(ev) === 'Enter')
68
+ ev.preventDefault()
69
+ },
70
+ })
71
+ ))
\ No newline at end of file