diff --git a/ui/dev-dist/sw.js b/ui/dev-dist/sw.js index cbb992b0..89b1520a 100644 --- a/ui/dev-dist/sw.js +++ b/ui/dev-dist/sw.js @@ -82,7 +82,7 @@ define(['./workbox-54d0af47'], (function (workbox) { 'use strict'; "revision": "3ca0b8505b4bec776b69afdba2768812" }, { "url": "index.html", - "revision": "0.6nc9e67jtoo" + "revision": "0.u5bbu0futh" }], {}); workbox.cleanupOutdatedCaches(); workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), { diff --git a/ui/package-lock.json b/ui/package-lock.json index fbe6ea70..7eac2ad1 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1538,7 +1538,9 @@ } }, "node_modules/@devexpress/utils": { - "version": "1.4.3", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/@devexpress/utils/-/utils-1.4.4.tgz", + "integrity": "sha512-0DahzzG7m3bP/mHZI+Xc2xWezq2tvqJh+Rggx+TWVYC1nFpo1QiwoJbwWJrNk+DWMWf3Cs55EYeP5iNlEnJSHg==", "license": "SEE LICENSE IN README.md", "dependencies": { "tslib": "2.3.1" @@ -1546,10 +1548,14 @@ }, "node_modules/@devexpress/utils/node_modules/tslib": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", "license": "0BSD" }, "node_modules/@devextreme/runtime": { "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@devextreme/runtime/-/runtime-3.0.13.tgz", + "integrity": "sha512-//24I6vo5a+XG/Ul3+vOGqU4M22IWyldpECxLY8iyGJWA5fiNaYzAedrMV2Ixo5oRj8DawiHTZKy5iKKF9ks5g==", "license": "SEE LICENSE IN LICENSE", "dependencies": { "inferno": "^7.4.6", @@ -4852,6 +4858,8 @@ }, "node_modules/devexpress-diagram": { "version": "2.2.13", + "resolved": "https://registry.npmjs.org/devexpress-diagram/-/devexpress-diagram-2.2.13.tgz", + "integrity": "sha512-OfAcfcFWJYlU/1kMtqrSSQUY3GQWKPHqU27A9e+TzFEhxI8XDyIPOCOnslRxnzYkfhB/RZ7hbGv9U0aHmtVbRg==", "license": "SEE LICENSE IN README.md", "dependencies": { "@devexpress/utils": "^1.4.3", @@ -4860,6 +4868,8 @@ }, "node_modules/devexpress-gantt": { "version": "4.1.56", + "resolved": "https://registry.npmjs.org/devexpress-gantt/-/devexpress-gantt-4.1.56.tgz", + "integrity": "sha512-jnnvDYDDzjqr8pnWYsAM96mug6yXEQ1H26QLLBRbwLC72ckb1yv0Rk6DUae9ZwewIFNzIKHt1klQMF/KD9Mb8A==", "license": "SEE LICENSE IN README.md", "dependencies": { "@devexpress/utils": "^1.4.3", @@ -4868,10 +4878,14 @@ }, "node_modules/devexpress-gantt/node_modules/tslib": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", "license": "0BSD" }, "node_modules/devextreme": { - "version": "23.2.11", + "version": "23.2.13", + "resolved": "https://registry.npmjs.org/devextreme/-/devextreme-23.2.13.tgz", + "integrity": "sha512-uye7B0A1sQYZ/7+dkjPbxm7mA0PkfYopBMO6xa1fUBuxV0B9CUAqk/7xPJykReir1hDrF/HyOcBCaAA3In3a6w==", "license": "SEE LICENSE IN README.md", "dependencies": { "@babel/runtime": "^7.12.1", @@ -4893,6 +4907,8 @@ }, "node_modules/devextreme-quill": { "version": "1.6.4", + "resolved": "https://registry.npmjs.org/devextreme-quill/-/devextreme-quill-1.6.4.tgz", + "integrity": "sha512-qs8lt+nn/2vQX1PrImQmCj2B1c8ydD5Hrjn42wWeqa4sVFd/9e2UM+PL979EtKqX0k1M4ncMe25cSbgYz5nNdA==", "license": "BSD-3-Clause", "dependencies": { "core-js": "^3.34.0", @@ -4905,13 +4921,15 @@ } }, "node_modules/devextreme-react": { - "version": "23.2.11", + "version": "23.2.13", + "resolved": "https://registry.npmjs.org/devextreme-react/-/devextreme-react-23.2.13.tgz", + "integrity": "sha512-xPbjPLer7Ph3EYEIW+kjje1KnqUreENLKAHaGWLFDbd5KQK5h9ryf1FbESu1qjd6Br+vdKIPcjJXsM3bvz2XLQ==", "license": "MIT", "dependencies": { "prop-types": "^15.8.1" }, "peerDependencies": { - "devextreme": "~23.2.11", + "devextreme": "~23.2.13", "react": "^16.2.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.2.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } @@ -5016,6 +5034,8 @@ }, "node_modules/domino": { "version": "2.1.6", + "resolved": "https://registry.npmjs.org/domino/-/domino-2.1.6.tgz", + "integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ==", "license": "BSD-2-Clause" }, "node_modules/dompurify": { @@ -5302,6 +5322,8 @@ }, "node_modules/es6-object-assign": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw==", "license": "MIT" }, "node_modules/esbuild": { @@ -6799,6 +6821,8 @@ }, "node_modules/inferno": { "version": "7.4.11", + "resolved": "https://registry.npmjs.org/inferno/-/inferno-7.4.11.tgz", + "integrity": "sha512-N+cs33ESWI8fdToCd98yMRYl7jkLnCkJskxov3FKKlaKOvk3PRlAttbhmUaYdWXlRvt2WeXi+J4MbzNj3V6G0w==", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -6809,6 +6833,8 @@ }, "node_modules/inferno-create-element": { "version": "7.4.11", + "resolved": "https://registry.npmjs.org/inferno-create-element/-/inferno-create-element-7.4.11.tgz", + "integrity": "sha512-kE6XIx2hPAd5qpDli2iGjNXgubvuyxdLvoiW71WnSzIIxA+Uxa/s8lY8m03VyHHVypFV3n329ZY5dFvKc7UQMg==", "license": "MIT", "dependencies": { "inferno": "7.4.11" @@ -6816,6 +6842,8 @@ }, "node_modules/inferno-hydrate": { "version": "7.4.11", + "resolved": "https://registry.npmjs.org/inferno-hydrate/-/inferno-hydrate-7.4.11.tgz", + "integrity": "sha512-hF9Ke4GHAkj8GQrMXBZPfsUqhq6WjkoDCAfXhPBuF1Wiceqyy8KerOOXEnuocHky77fuEXq0AzVnQcC064Bkfw==", "license": "MIT", "dependencies": { "inferno": "7.4.11" @@ -6823,10 +6851,14 @@ }, "node_modules/inferno-shared": { "version": "7.4.11", + "resolved": "https://registry.npmjs.org/inferno-shared/-/inferno-shared-7.4.11.tgz", + "integrity": "sha512-pN725bDSTxkQmRS3e/3H02/xAqgHl+xgddCMjPm8M0etRdRcVCisi3NGPhzSbDDmiftrxhY31exs7+dwsngcDA==", "license": "MIT" }, "node_modules/inferno-vnode-flags": { "version": "7.4.11", + "resolved": "https://registry.npmjs.org/inferno-vnode-flags/-/inferno-vnode-flags-7.4.11.tgz", + "integrity": "sha512-L7lslEQCq3IfwgT/b9zhuMf8fv6KXCNXXHZevk/WYxnqJsOWGDcKpJn0zkzXfvmj0otbB149iLUQVBq3oe2sfA==", "license": "MIT" }, "node_modules/inflight": { @@ -7479,6 +7511,8 @@ }, "node_modules/lodash.clonedeep": { "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", "license": "MIT" }, "node_modules/lodash.debounce": { @@ -7928,6 +7962,8 @@ }, "node_modules/opencollective-postinstall": { "version": "2.0.3", + "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", + "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", "license": "MIT", "bin": { "opencollective-postinstall": "index.js" @@ -8024,6 +8060,8 @@ }, "node_modules/parchment": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-2.0.1.tgz", + "integrity": "sha512-VBKrlEoZCBD+iwoeag0QTtY1Cti+Ma4nLpVYcc/uus/wHhMsPOi5InH3RL1s4aekahPZpabcS2ToKyGf7RMH/g==", "license": "BSD-3-Clause" }, "node_modules/parent-module": { @@ -9217,6 +9255,8 @@ }, "node_modules/quill-delta": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", + "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==", "license": "MIT", "dependencies": { "fast-diff": "^1.3.0", @@ -10613,7 +10653,9 @@ "dev": true }, "node_modules/rrule": { - "version": "2.7.2", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/rrule/-/rrule-2.8.1.tgz", + "integrity": "sha512-hM3dHSBMeaJ0Ktp7W38BJZ7O1zOgaFEsn41PDk+yHoEtfLV+PoJt9E9xAlZiWgf/iqEqionN0ebHFZIDAp+iGw==", "license": "BSD-3-Clause", "dependencies": { "tslib": "^2.4.0" @@ -10752,6 +10794,8 @@ }, "node_modules/showdown": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz", + "integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==", "license": "MIT", "dependencies": { "commander": "^9.0.0" @@ -10766,6 +10810,8 @@ }, "node_modules/showdown/node_modules/commander": { "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", "license": "MIT", "engines": { "node": "^12.20.0 || >=14" @@ -11589,6 +11635,8 @@ }, "node_modules/turndown": { "version": "7.1.3", + "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.1.3.tgz", + "integrity": "sha512-Z3/iJ6IWh8VBiACWQJaA5ulPQE5E1QwvBHj00uGzdQxdRnd8fh1DPqNOJqzQDu6DkOstORrtXzf/9adB+vMtEA==", "license": "MIT", "dependencies": { "domino": "^2.1.6" diff --git a/ui/package.json b/ui/package.json index 200e56da..a81fe435 100644 --- a/ui/package.json +++ b/ui/package.json @@ -58,7 +58,6 @@ "react-highlight-words": "^0.20.0", "react-icons": "^5.4.0", "react-modal": "^3.16.3", - "react-quill": "^2.0.0", "react-router-dom": "^6.14.1", "react-select": "^5.9.0", "redux-state-sync": "^3.1.4", diff --git a/ui/src/assets/styles/vendors/index.css b/ui/src/assets/styles/vendors/index.css index 627c8a6e..c75986c9 100644 --- a/ui/src/assets/styles/vendors/index.css +++ b/ui/src/assets/styles/vendors/index.css @@ -1,2 +1 @@ -@import "./_react-quill.css"; -@import "./_full-calendar.css"; +@import './_full-calendar.css'; diff --git a/ui/src/proxy/html-editor/data.ts b/ui/src/proxy/html-editor/data.ts new file mode 100644 index 00000000..1139700c --- /dev/null +++ b/ui/src/proxy/html-editor/data.ts @@ -0,0 +1,27 @@ +export const sizeValues = ['8pt', '10pt', '12pt', '14pt', '18pt', '24pt', '36pt'] +export const fontValues = [ + 'Arial', + 'Courier New', + 'Georgia', + 'Impact', + 'Lucida Console', + 'Tahoma', + 'Times New Roman', + 'Verdana', +] +export const headerValues = [false, 1, 2, 3, 4, 5] +export const fontSizeOptions = { + inputAttr: { + 'aria-label': 'Font size', + }, +} +export const fontFamilyOptions = { + inputAttr: { + 'aria-label': 'Font family', + }, +} +export const headerOptions = { + inputAttr: { + 'aria-label': 'Font family', + }, +} diff --git a/ui/src/views/forum/admin/PostManagement.tsx b/ui/src/views/forum/admin/PostManagement.tsx index 02e4394f..94fffa52 100644 --- a/ui/src/views/forum/admin/PostManagement.tsx +++ b/ui/src/views/forum/admin/PostManagement.tsx @@ -1,14 +1,21 @@ import React, { useState } from 'react' import { Plus, Edit2, Trash2, CheckCircle, Circle, Heart, Loader2 } from 'lucide-react' import { ForumPost, ForumTopic } from '@/proxy/forum/forum' -import ReactQuill from 'react-quill' -import 'react-quill/dist/quill.snow.css' +import { HtmlEditor, ImageUpload, Item, MediaResizing, Toolbar } from 'devextreme-react/html-editor' import { useStoreState } from '@/store/store' import { useLocalization } from '@/utils/hooks/useLocalization' import { Formik, Form, Field, FieldProps } from 'formik' import * as Yup from 'yup' import { FormContainer, FormItem, Button } from '@/components/ui' import { ConfirmDialog } from '@/components/shared' +import { + fontFamilyOptions, + fontSizeOptions, + fontValues, + headerOptions, + headerValues, + sizeValues, +} from '@/proxy/html-editor/data' interface PostManagementProps { posts: ForumPost[] @@ -232,13 +239,68 @@ export function PostManagement({ > {({ field }: FieldProps) => ( - setFieldValue('content', val)} - style={{ height: '400px', marginBottom: '50px' }} + onValueChanged={(e) => setFieldValue('content', e.value)} + height={400} placeholder="Write your message..." - /> + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )} diff --git a/ui/src/views/forum/forum/CreatePostModal.tsx b/ui/src/views/forum/forum/CreatePostModal.tsx index a842b14d..c92ea8f9 100644 --- a/ui/src/views/forum/forum/CreatePostModal.tsx +++ b/ui/src/views/forum/forum/CreatePostModal.tsx @@ -2,11 +2,18 @@ import React from 'react' import { X } from 'lucide-react' import { Formik, Form, Field, FieldProps } from 'formik' import * as Yup from 'yup' -import ReactQuill from 'react-quill' -import 'react-quill/dist/quill.snow.css' +import { HtmlEditor, ImageUpload, Item, MediaResizing, Toolbar } from 'devextreme-react/html-editor' import { useStoreState } from '@/store/store' import { useLocalization } from '@/utils/hooks/useLocalization' import { Button, FormContainer, FormItem } from '@/components/ui' +import { + fontFamilyOptions, + fontSizeOptions, + fontValues, + headerOptions, + headerValues, + sizeValues, +} from '@/proxy/html-editor/data' interface CreatePostModalProps { onClose: () => void @@ -78,17 +85,68 @@ export function CreatePostModal({ onClose, onSubmit, parentPostId }: CreatePostM > {({ field }: FieldProps) => ( - setFieldValue('content', val)} - style={{ height: '300px', marginBottom: '50px' }} + onValueChanged={(e) => setFieldValue('content', e.value)} + height={300} placeholder={ parentPostId ? translate('::App.Forum.PostManagement.MessageEdit') : translate('::App.Forum.PostManagement.MessageNew') } - /> + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + )}