From 9d590c994fd788022e747eaeed16ee69720f3b6a Mon Sep 17 00:00:00 2001 From: maxim Date: Fri, 21 Feb 2025 21:21:26 +0300 Subject: [PATCH] upgrade `create` & `edit` for `/article` route using `react-simplemde-editor` --- package.json | 4 +- pnpm-lock.yaml | 72 ++++++++++++++++++++++++++++++++++++ src/globals.css | 35 ++++++++++++++++++ src/pages/article/create.tsx | 31 +++++++++------- src/pages/article/edit.tsx | 35 ++++++++++-------- 5 files changed, 148 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index 5b9e402..68cd839 100644 --- a/package.json +++ b/package.json @@ -19,12 +19,14 @@ "@refinedev/react-router": "^1.0.0", "@refinedev/simple-rest": "^5.0.1", "axios": "^1.7.9", + "easymde": "^2.19.0", "i18next": "^24.2.2", "react": "^18.0.0", "react-dom": "^18.0.0", "react-hook-form": "^7.30.0", "react-i18next": "^15.4.1", - "react-router": "^7.0.2" + "react-router": "^7.0.2", + "react-simplemde-editor": "^5.2.0" }, "devDependencies": { "@types/node": "^18.16.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 47ce003..e830601 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -53,6 +53,9 @@ importers: axios: specifier: ^1.7.9 version: 1.7.9 + easymde: + specifier: ^2.19.0 + version: 2.19.0 i18next: specifier: ^24.2.2 version: 24.2.2(typescript@5.7.3) @@ -71,6 +74,9 @@ importers: react-router: specifier: ^7.0.2 version: 7.1.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-simplemde-editor: + specifier: ^5.2.0 + version: 5.2.0(easymde@2.19.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) devDependencies: '@types/node': specifier: ^18.16.2 @@ -936,9 +942,15 @@ packages: '@types/babel__traverse@7.20.6': resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + '@types/codemirror@5.60.15': + resolution: {integrity: sha512-dTOvwEQ+ouKJ/rE9LT1Ue2hmP6H1mZv5+CCnNWu2qtiOe2LQa9lCprEY20HxiDmV/Bxh+dXjywmy5aKvoGjULA==} + '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/hast@2.3.10': resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==} @@ -948,6 +960,9 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/marked@4.3.2': + resolution: {integrity: sha512-a79Yc3TOk6dGdituy8hmTTJXjOkZ7zsFYV10L337ttq/rec8lRMDBpV7fL3uLx6TgbFCa5DU/h8FmIBQPSbU0w==} + '@types/mdast@3.0.15': resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==} @@ -976,6 +991,9 @@ packages: '@types/semver@7.5.8': resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} + '@types/tern@0.23.9': + resolution: {integrity: sha512-ypzHFE/wBzh+BlH6rrBgS5I/Z7RD21pGhZ2rltb/+ZrVM1awdZwjx7hE5XfuYgHWk9uvV5HLZN3SloevCAp3Bw==} + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} @@ -1279,6 +1297,12 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} + codemirror-spell-checker@1.1.2: + resolution: {integrity: sha512-2Tl6n0v+GJRsC9K3MLCdLaMOmvWL0uukajNJseorZJsslaxZyZMgENocPU8R0DyoTAiKsyqiemSOZo7kjGV0LQ==} + + codemirror@5.65.18: + resolution: {integrity: sha512-Gaz4gHnkbHMGgahNt3CA5HBk5lLQBqmD/pBgeB4kQU6OedZmqMBjlRF0LSrp2tJ4wlLNPm2FfaUd1pDy0mdlpA==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -1439,6 +1463,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + easymde@2.19.0: + resolution: {integrity: sha512-4F1aNImqse+9xIjLh9ttfpOVenecjFPxUmKbl1tGp72Z+OyIqLZPE/SgNyy88c/xU0mOy0WC3+tfbZDQ5PDWhg==} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -2605,6 +2632,13 @@ packages: react-dom: optional: true + react-simplemde-editor@5.2.0: + resolution: {integrity: sha512-GkTg1MlQHVK2Rks++7sjuQr/GVS/xm6y+HchZ4GPBWrhcgLieh4CjK04GTKbsfYorSRYKa0n37rtNSJmOzEDkQ==} + peerDependencies: + easymde: '>= 2.0.0 < 3.0.0' + react: '>=16.8.2' + react-dom: '>=16.8.2' + react-transition-group@4.4.5: resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} peerDependencies: @@ -2970,6 +3004,9 @@ packages: engines: {node: '>=14.17'} hasBin: true + typo-js@1.2.5: + resolution: {integrity: sha512-F45vFWdGX8xahIk/sOp79z2NJs8ETMYsmMChm9D5Hlx3+9j7VnCyQyvij5MOCrNY3NNe8noSyokRjQRfq+Bc7A==} + uglify-js@3.19.3: resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} engines: {node: '>=0.8.0'} @@ -4149,8 +4186,14 @@ snapshots: dependencies: '@babel/types': 7.26.5 + '@types/codemirror@5.60.15': + dependencies: + '@types/tern': 0.23.9 + '@types/cookie@0.6.0': {} + '@types/estree@1.0.6': {} + '@types/hast@2.3.10': dependencies: '@types/unist': 2.0.11 @@ -4161,6 +4204,8 @@ snapshots: '@types/json-schema@7.0.15': {} + '@types/marked@4.3.2': {} + '@types/mdast@3.0.15': dependencies: '@types/unist': 2.0.11 @@ -4188,6 +4233,10 @@ snapshots: '@types/semver@7.5.8': {} + '@types/tern@0.23.9': + dependencies: + '@types/estree': 1.0.6 + '@types/unist@2.0.11': {} '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.3))(eslint@8.57.1)(typescript@5.7.3)': @@ -4522,6 +4571,12 @@ snapshots: clsx@2.1.1: {} + codemirror-spell-checker@1.1.2: + dependencies: + typo-js: 1.2.5 + + codemirror@5.65.18: {} + color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -4664,6 +4719,14 @@ snapshots: eastasianwidth@0.2.0: {} + easymde@2.19.0: + dependencies: + '@types/codemirror': 5.60.15 + '@types/marked': 4.3.2 + codemirror: 5.65.18 + codemirror-spell-checker: 1.1.2 + marked: 4.3.0 + ee-first@1.1.1: {} electron-to-chromium@1.5.83: {} @@ -5932,6 +5995,13 @@ snapshots: optionalDependencies: react-dom: 18.3.1(react@18.3.1) + react-simplemde-editor@5.2.0(easymde@2.19.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@types/codemirror': 5.60.15 + easymde: 2.19.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-transition-group@4.4.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: '@babel/runtime': 7.26.0 @@ -6290,6 +6360,8 @@ snapshots: typescript@5.7.3: {} + typo-js@1.2.5: {} + uglify-js@3.19.3: optional: true diff --git a/src/globals.css b/src/globals.css index f598f80..b6de5a7 100644 --- a/src/globals.css +++ b/src/globals.css @@ -1,3 +1,38 @@ .refine-list-button { display: none !important; } + +.my-markdown-editor .editor-statusbar { + display: none !important; +} + +.my-markdown-editor .CodeMirror { + background-color: transparent !important; + color: white !important; +} + +.my-markdown-editor .CodeMirror-gutters { + background-color: transparent !important; + border-right: 1px solid #444; + color: white !important; +} + +.my-markdown-editor .CodeMirror-cursor { + border-left: 1px solid white !important; +} + +.my-markdown-editor .editor-toolbar i { + color: white !important; +} + +.my-markdown-editor .editor-toolbar button:hover i { + color: #000 !important; +} + +.my-markdown-editor .editor-toolbar button.active i { + color: #000 !important; +} + +.my-markdown-editor .editor-toolbar .separator { + color: transparent !important; +} diff --git a/src/pages/article/create.tsx b/src/pages/article/create.tsx index 2afca28..e2bb0d2 100644 --- a/src/pages/article/create.tsx +++ b/src/pages/article/create.tsx @@ -1,12 +1,20 @@ import {Box, TextField} from '@mui/material' import {Create} from '@refinedev/mui' import {useForm} from '@refinedev/react-hook-form' +import {Controller} from 'react-hook-form' +import React from 'react' + +import SimpleMDE from 'react-simplemde-editor' +import 'easymde/dist/easymde.min.css' + +const MemoizedSimpleMDE = React.memo(SimpleMDE) export const ArticleCreate = () => { const { saveButtonProps, refineCore: {formLoading}, register, + control, formState: {errors}, } = useForm({ refineCoreProps: { @@ -14,6 +22,14 @@ export const ArticleCreate = () => { }, }) + const simpleMDEOptions = React.useMemo( + () => ({ + placeholder: 'Введите контент в формате Markdown...', + spellChecker: false, + }), + [], + ) + return ( @@ -30,19 +46,8 @@ export const ArticleCreate = () => { label={'Заголовок'} name="heading" /> - + + } /> ) diff --git a/src/pages/article/edit.tsx b/src/pages/article/edit.tsx index 7ca0d05..b91d2e6 100644 --- a/src/pages/article/edit.tsx +++ b/src/pages/article/edit.tsx @@ -1,13 +1,29 @@ import {Box, TextField} from '@mui/material' import {Edit} from '@refinedev/mui' import {useForm} from '@refinedev/react-hook-form' +import {Controller} from 'react-hook-form' +import React from 'react' + +import SimpleMDE from 'react-simplemde-editor' +import 'easymde/dist/easymde.min.css' + +const MemoizedSimpleMDE = React.memo(SimpleMDE) export const ArticleEdit = () => { const { saveButtonProps, register, + control, formState: {errors}, - } = useForm({}) + } = useForm() + + const simpleMDEOptions = React.useMemo( + () => ({ + placeholder: 'Введите контент в формате Markdown...', + spellChecker: false, + }), + [], + ) return ( @@ -22,22 +38,11 @@ export const ArticleEdit = () => { fullWidth InputLabelProps={{shrink: true}} type="text" - label={'Заголовок'} + label="Заголовок" name="heading" /> - + + } /> )