sight edit update

This commit is contained in:
2025-04-25 05:23:07 +03:00
parent 463c593a0e
commit 9927c0afd6
22 changed files with 3011 additions and 1742 deletions

View File

@ -1,72 +1,196 @@
import {Box, TextField, Typography, Paper} from '@mui/material'
import {Create} from '@refinedev/mui'
import {useForm} from '@refinedev/react-hook-form'
import {Controller} from 'react-hook-form'
import React, {useState, useEffect} from 'react'
import ReactMarkdown from 'react-markdown'
import { Box, TextField, Typography, Paper } from "@mui/material";
import { Create } from "@refinedev/mui";
import { useForm } from "@refinedev/react-hook-form";
import { Controller } from "react-hook-form";
import React, { useState, useEffect } from "react";
import ReactMarkdown from "react-markdown";
import Cookies from "js-cookie";
import { MarkdownEditor } from "../../components/MarkdownEditor";
import "easymde/dist/easymde.min.css";
import {MarkdownEditor} from '../../components/MarkdownEditor'
import 'easymde/dist/easymde.min.css'
const MemoizedSimpleMDE = React.memo(MarkdownEditor)
const MemoizedSimpleMDE = React.memo(MarkdownEditor);
export const ArticleCreate = () => {
const [language, setLanguage] = useState(Cookies.get("lang")!);
const [articleData, setArticleData] = useState<{
ru: { heading: string; body: string };
en: { heading: string; body: string };
zh: { heading: string; body: string };
}>({
ru: { heading: "", body: "" },
en: { heading: "", body: "" },
zh: { heading: "", body: "" },
});
const {
saveButtonProps,
refineCore: {formLoading},
refineCore: { formLoading },
register,
control,
watch,
formState: {errors},
formState: { errors },
setValue,
} = useForm({
refineCoreProps: {
resource: 'article/',
resource: "article/",
meta: {
headers: {
"Accept-Language": language,
},
},
},
})
});
const [preview, setPreview] = useState('')
const [headingPreview, setHeadingPreview] = useState('')
useEffect(() => {
const lang = Cookies.get("lang")!;
Cookies.set("lang", language);
return () => {
Cookies.set("lang", lang);
};
}, [language]);
useEffect(() => {
setValue(
"heading",
articleData[language as keyof typeof articleData]?.heading || ""
);
setValue(
"body",
articleData[language as keyof typeof articleData]?.body || ""
);
setPreview(articleData[language as keyof typeof articleData]?.body || "");
setHeadingPreview(
articleData[language as keyof typeof articleData]?.heading || ""
);
}, [language, articleData, setValue]);
const handleLanguageChange = (lang: string) => {
setArticleData((prevData) => ({
...prevData,
[language]: {
heading: watch("heading") || "",
body: watch("body") || "",
},
}));
setLanguage(lang);
Cookies.set("lang", lang);
};
const [preview, setPreview] = useState("");
const [headingPreview, setHeadingPreview] = useState("");
// Следим за изменениями в полях body и heading
const bodyContent = watch('body')
const headingContent = watch('heading')
const bodyContent = watch("body");
const headingContent = watch("heading");
useEffect(() => {
setPreview(bodyContent || '')
}, [bodyContent])
setPreview(bodyContent || "");
}, [bodyContent]);
useEffect(() => {
setHeadingPreview(headingContent || '')
}, [headingContent])
setHeadingPreview(headingContent || "");
}, [headingContent]);
const simpleMDEOptions = React.useMemo(
() => ({
placeholder: 'Введите контент в формате Markdown...',
placeholder: "Введите контент в формате Markdown...",
spellChecker: false,
}),
[],
)
[]
);
return (
<Create isLoading={formLoading} saveButtonProps={saveButtonProps}>
<Box sx={{display: 'flex', gap: 2}}>
<Box sx={{ display: "flex", flex: 1, gap: 2 }}>
{/* Форма создания */}
<Box component="form" sx={{flex: 1, display: 'flex', flexDirection: 'column'}} autoComplete="off">
<TextField
{...register('heading', {
required: 'Это поле является обязательным',
})}
error={!!(errors as any)?.heading}
helperText={(errors as any)?.heading?.message}
margin="normal"
fullWidth
InputLabelProps={{shrink: true}}
type="text"
label="Заголовок *"
name="heading"
/>
<Box sx={{ display: "flex", flex: 1, flexDirection: "column", gap: 2 }}>
<Box
sx={{
flex: 1,
display: "flex",
gap: 2,
}}
>
<Box
sx={{
cursor: "pointer",
flex: 1,
display: "flex",
justifyContent: "center",
bgcolor: language === "ru" ? "primary.main" : "transparent",
color: language === "ru" ? "white" : "inherit",
p: 1,
borderRadius: 1,
}}
onClick={() => handleLanguageChange("ru")}
>
RU
</Box>
<Box
sx={{
cursor: "pointer",
flex: 1,
display: "flex",
justifyContent: "center",
bgcolor: language === "en" ? "primary.main" : "transparent",
color: language === "en" ? "white" : "inherit",
p: 1,
borderRadius: 1,
}}
onClick={() => handleLanguageChange("en")}
>
EN
</Box>
<Box
sx={{
cursor: "pointer",
flex: 1,
display: "flex",
justifyContent: "center",
bgcolor: language === "zh" ? "primary.main" : "transparent",
color: language === "zh" ? "white" : "inherit",
p: 1,
borderRadius: 1,
}}
onClick={() => handleLanguageChange("zh")}
>
ZH
</Box>
</Box>
<Box
component="form"
sx={{ flex: 1, display: "flex", flexDirection: "column" }}
autoComplete="off"
>
<TextField
{...register("heading", {
required: "Это поле является обязательным",
})}
error={!!(errors as any)?.heading}
helperText={(errors as any)?.heading?.message}
margin="normal"
fullWidth
InputLabelProps={{ shrink: true }}
type="text"
label="Заголовок *"
name="heading"
/>
<Controller control={control} name="body" rules={{required: 'Это поле является обязательным'}} defaultValue="" render={({field: {onChange, value}}) => <MemoizedSimpleMDE value={value} onChange={onChange} options={simpleMDEOptions} className="my-markdown-editor" />} />
<Controller
control={control}
name="body"
rules={{ required: "Это поле является обязательным" }}
defaultValue=""
render={({ field: { onChange, value } }) => (
<MemoizedSimpleMDE
value={value}
onChange={onChange}
options={simpleMDEOptions}
className="my-markdown-editor"
/>
)}
/>
</Box>
</Box>
{/* Блок предпросмотра */}
@ -74,14 +198,15 @@ export const ArticleCreate = () => {
sx={{
flex: 1,
p: 2,
maxHeight: 'calc(100vh - 200px)',
overflowY: 'auto',
position: 'sticky',
maxHeight: "calc(100vh - 200px)",
overflowY: "auto",
position: "sticky",
top: 16,
borderRadius: 2,
border: '1px solid',
borderColor: 'primary.main',
bgcolor: (theme) => (theme.palette.mode === 'dark' ? 'background.paper' : '#fff'),
border: "1px solid",
borderColor: "primary.main",
bgcolor: (theme) =>
theme.palette.mode === "dark" ? "background.paper" : "#fff",
}}
>
<Typography variant="h6" gutterBottom color="primary">
@ -93,7 +218,8 @@ export const ArticleCreate = () => {
variant="h4"
gutterBottom
sx={{
color: (theme) => (theme.palette.mode === 'dark' ? 'grey.300' : 'grey.800'),
color: (theme) =>
theme.palette.mode === "dark" ? "grey.300" : "grey.800",
mb: 3,
}}
>
@ -103,39 +229,41 @@ export const ArticleCreate = () => {
{/* Markdown контент */}
<Box
sx={{
'& img': {
maxWidth: '100%',
height: 'auto',
"& img": {
maxWidth: "100%",
height: "auto",
borderRadius: 1,
},
'& h1, & h2, & h3, & h4, & h5, & h6': {
color: 'primary.main',
"& h1, & h2, & h3, & h4, & h5, & h6": {
color: "primary.main",
mt: 2,
mb: 1,
},
'& p': {
"& p": {
mb: 2,
color: (theme) => (theme.palette.mode === 'dark' ? 'grey.300' : 'grey.800'),
color: (theme) =>
theme.palette.mode === "dark" ? "grey.300" : "grey.800",
},
'& a': {
color: 'primary.main',
textDecoration: 'none',
'&:hover': {
textDecoration: 'underline',
"& a": {
color: "primary.main",
textDecoration: "none",
"&:hover": {
textDecoration: "underline",
},
},
'& blockquote': {
borderLeft: '4px solid',
borderColor: 'primary.main',
"& blockquote": {
borderLeft: "4px solid",
borderColor: "primary.main",
pl: 2,
my: 2,
color: 'text.secondary',
color: "text.secondary",
},
'& code': {
bgcolor: (theme) => (theme.palette.mode === 'dark' ? 'grey.900' : 'grey.100'),
"& code": {
bgcolor: (theme) =>
theme.palette.mode === "dark" ? "grey.900" : "grey.100",
p: 0.5,
borderRadius: 0.5,
color: 'primary.main',
color: "primary.main",
},
}}
>
@ -144,5 +272,5 @@ export const ArticleCreate = () => {
</Paper>
</Box>
</Create>
)
}
);
};