#53 added qr-creator and button in admin interface (#424)
Co-authored-by: amueller <amueller@scopeset.de>
arminus committed
Dec 31, 2023 at 19:08 UTC
b0fabfcbed46c54a27f6120e7d2912bf4d4b8870
2 files changed
+49
-3
admin/src/FileForm.ts
+48
-3
@@ -2,7 +2,7 @@
2
3
import { state, useSnapState } from './state'
4
import { createElement as h, forwardRef, ReactElement, ReactNode, useEffect, useMemo, useState } from 'react'
5
-import { Alert, Box, Collapse, FormHelperText, Link, MenuItem, MenuList } from '@mui/material'
5
+import { Alert, Box, Collapse, FormHelperText, Link, MenuItem, MenuList, Dialog, DialogTitle, DialogContent, Button } from '@mui/material'
6
import { BoolField, DisplayField, Field, FieldProps, Form, MultiSelectField, SelectField, StringField
7
} from '@hfs/mui-grid-form'
8
import { apiCall, UseApi, useApiEx } from './api'
@@ -15,8 +15,9 @@ import _ from 'lodash'
15
import FileField from './FileField'
16
import { alertDialog, toast, useDialogBarColors } from './dialog'
17
import yaml from 'yaml'
18
-import { Check, ContentCopy, ContentCut, ContentPaste, Delete, Edit, Save } from '@mui/icons-material'
18
+import { Check, ContentCopy, ContentCut, ContentPaste, Delete, Edit, QrCode2, Save } from '@mui/icons-material'
19
import { moveVfs } from './VfsTree'
20
+import QrCreator from 'qr-creator';
21
22
interface Account { username: string }
23
@@ -279,6 +280,32 @@ function LinkField({ value, statusApi }: LinkFieldProps) {
280
value &&= value.indexOf(root) === 1 ? value.slice(root.length) : undefined
281
const link = prefix(data?.baseUrl || '', value)
282
const RenderLink = useMemo(() => forwardRef((props: any, ref) => h(Link, { ref, ...props, href: link, style: { height: 'auto' }, target: 'frontend' }, link)), [link])
283
+
284
+
285
+ const [isQrDialogOpen, setQrDialogOpen] = useState(false);
286
+
287
+ const showQrDialog = () => {
288
+ setQrDialogOpen(true);
289
+ };
290
+
291
+ const closeDialog = () => {
292
+ setQrDialogOpen(false);
293
+ };
294
+
295
+ const generateQRCode = async (canvas: HTMLCanvasElement, text: string) => {
296
+ try {
297
+ QrCreator.render({
298
+ text: text,
299
+ radius: 0.0, // 0.0 to 0.5
300
+ ecLevel: 'H', // L, M, Q, H
301
+ fill: '#536DFE', // foreground color
302
+ background: null, // color or null for transparent
303
+ size: 300 // in pixels
304
+ }, canvas);
305
+ } catch (error) {
306
+ console.error('Error generating QR code:', error);
307
+ }
308
+ };
309
return h(Box, { display: 'flex' },
310
!urls ? 'error' : // check data is ok
311
h(DisplayField, {
@@ -293,10 +320,28 @@ function LinkField({ value, statusApi }: LinkFieldProps) {
320
disabled: !link,
321
onClick: () => navigator.clipboard.writeText(link)
322
}),
323
+ h(IconBtn, {
324
+ icon: QrCode2,
325
+ title: "QR Code",
326
+ onClick: showQrDialog
327
+ }),
328
h(IconBtn, { icon: Edit, title: "Change", onClick() { changeBaseUrl().then(reload) } }),
329
)
330
}),
299
- )
331
+ h(Dialog, { open: isQrDialogOpen, onClose: closeDialog },
332
+ h(DialogTitle, null, "QR Code"),
333
+ h(DialogContent, { style: { maxWidth: '350px', margin: '0 auto' } },
334
+ h('canvas', {
335
+ id: 'qrcode-canvas',
336
+ ref: (canvas: HTMLCanvasElement) => canvas && generateQRCode(canvas, link),
337
+ style: { width: '100%' },
338
+ }),
339
+ ),
340
+ h(Box, { display: 'flex', justifyContent: 'center', marginBottom: 2 },
341
+ h(Button, { onClick: closeDialog }, "Close")
342
+ )
343
+ )
344
+ );
345
}
346
347
export async function changeBaseUrl() {
package.json
+1
@@ -82,6 +82,7 @@
82
"minimist": "^1.2.6",
83
"nat-upnp-ts": "^2.0.1",
84
"open": "^8.4.0",
85
+ "qr-creator": "^1.0.0",
86
"picomatch": "^3.0.1",
87
"tssrp6a": "^3.0.0",
88
"unzip-stream": "^0.3.1",