@samitouri / QOSami-HFS / commits / b5c54e09

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