last changes
This commit is contained in:
parent
177653d84a
commit
042b53e6a4
13089
package-lock.json
generated
Normal file
13089
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -21,8 +21,7 @@ import routerBindings, {
|
||||
import { ColorModeContextProvider } from "./contexts/color-mode";
|
||||
import { Header } from "./components/header";
|
||||
import { Login } from "./pages/login";
|
||||
import { authProvider } from "./authProvider";
|
||||
import { i18nProvider } from "./i18nProvider";
|
||||
import { authProvider, i18nProvider } from "@providers";
|
||||
|
||||
import {
|
||||
CountryList,
|
||||
|
@ -12,7 +12,7 @@ import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
||||
import { axiosInstance } from "../providers/data";
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
import { MarkdownEditor } from "./MarkdownEditor";
|
||||
import React, { useState, useCallback } from "react";
|
||||
import React, { useState, useCallback, useEffect } from "react";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import {
|
||||
ALLOWED_IMAGE_TYPES,
|
||||
@ -20,6 +20,8 @@ import {
|
||||
} from "../components/media/MediaFormUtils";
|
||||
import { LinkedItems } from "./LinkedItems";
|
||||
import { mediaFields, MediaItem } from "../pages/article/types";
|
||||
import { LanguageSelector } from "@ui";
|
||||
import { EVERY_LANGUAGE, Languages, languageStore } from "@stores";
|
||||
|
||||
const MemoizedSimpleMDE = React.memo(MarkdownEditor);
|
||||
|
||||
@ -47,12 +49,15 @@ export const CreateSightArticle = ({
|
||||
}: Props) => {
|
||||
const theme = useTheme();
|
||||
const [mediaFiles, setMediaFiles] = useState<MediaFile[]>([]);
|
||||
const { language, setLanguageAction } = languageStore;
|
||||
|
||||
const {
|
||||
register: registerItem,
|
||||
watch,
|
||||
control: controlItem,
|
||||
handleSubmit: handleSubmitItem,
|
||||
reset: resetItem,
|
||||
setValue,
|
||||
formState: { errors: itemErrors },
|
||||
} = useForm({
|
||||
defaultValues: {
|
||||
@ -61,6 +66,45 @@ export const CreateSightArticle = ({
|
||||
},
|
||||
});
|
||||
|
||||
const [articleData, setArticleData] = useState({
|
||||
heading: EVERY_LANGUAGE(""),
|
||||
body: EVERY_LANGUAGE("")
|
||||
});
|
||||
|
||||
function updateTranslations() {
|
||||
const newArticleData = {
|
||||
...articleData,
|
||||
heading: {
|
||||
...articleData.heading,
|
||||
[language]: watch("heading") ?? "",
|
||||
},
|
||||
body: {
|
||||
...articleData.body,
|
||||
[language]: watch("body") ?? "",
|
||||
}
|
||||
}
|
||||
setArticleData(newArticleData);
|
||||
return newArticleData;
|
||||
}
|
||||
|
||||
// const handleFormSubmit = handleSubmit((values: FieldValues) => {
|
||||
// const newTranslations = updateTranslations();
|
||||
// console.log(newTranslations);
|
||||
// return onFinish({
|
||||
// translations: newTranslations
|
||||
// });
|
||||
// });
|
||||
|
||||
useEffect(() => {
|
||||
setValue("heading", articleData.heading[language] ?? "");
|
||||
setValue("body", articleData.body[language] ?? "");
|
||||
}, [language, articleData, setValue]);
|
||||
|
||||
const handleLanguageChange = (lang: Languages) => {
|
||||
updateTranslations();
|
||||
setLanguageAction(lang);
|
||||
};
|
||||
|
||||
const simpleMDEOptions = React.useMemo(
|
||||
() => ({
|
||||
placeholder: "Введите контент в формате Markdown...",
|
||||
@ -109,7 +153,10 @@ export const CreateSightArticle = ({
|
||||
// Создаем статью
|
||||
const response = await axiosInstance.post(
|
||||
`${import.meta.env.VITE_KRBL_API}/${childResource}`,
|
||||
data
|
||||
{
|
||||
...data,
|
||||
translations: updateTranslations()
|
||||
}
|
||||
);
|
||||
const itemId = response.data.id;
|
||||
|
||||
@ -119,7 +166,7 @@ export const CreateSightArticle = ({
|
||||
import.meta.env.VITE_KRBL_API
|
||||
}/${parentResource}/${parentId}/${childResource}`
|
||||
);
|
||||
const existingItems = existingItemsResponse.data || [];
|
||||
const existingItems = existingItemsResponse.data ?? [];
|
||||
const nextPageNum = existingItems.length + 1;
|
||||
|
||||
if (!left) {
|
||||
@ -189,6 +236,7 @@ export const CreateSightArticle = ({
|
||||
</AccordionSummary>
|
||||
<AccordionDetails sx={{ background: theme.palette.background.paper }}>
|
||||
<Box component="form" onSubmit={handleSubmitItem(handleCreate)}>
|
||||
<LanguageSelector action={handleLanguageChange} />
|
||||
<TextField
|
||||
{...registerItem("heading", {
|
||||
required: "Это поле является обязательным",
|
||||
|
@ -1,14 +1,12 @@
|
||||
import { Box } from "@mui/material";
|
||||
import { languageStore } from "../../store/LanguageStore";
|
||||
import { Languages, languageStore } from "../../store/LanguageStore";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
export const LanguageSwitch = observer(({ action }: any) => {
|
||||
const { language, setLanguageAction } = languageStore;
|
||||
|
||||
const handleLanguageChange = (lang: string) => {
|
||||
if (action) {
|
||||
action();
|
||||
}
|
||||
const handleLanguageChange = (lang: Languages) => {
|
||||
action?.();
|
||||
setLanguageAction(lang);
|
||||
};
|
||||
|
||||
|
@ -287,114 +287,116 @@ export const LinkedItems = <T extends { id: number; [key: string]: any }>({
|
||||
|
||||
<AccordionDetails sx={{ background: theme.palette.background.paper }}>
|
||||
<Stack gap={2}>
|
||||
<DragDropContext onDragEnd={onDragEnd}>
|
||||
<TableContainer component={Paper}>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{type === "edit" && dragAllowed && (
|
||||
<TableCell width="40px"></TableCell>
|
||||
)}
|
||||
<TableCell key="id">№</TableCell>
|
||||
{fields.map((field) => (
|
||||
<TableCell key={String(field.data)}>
|
||||
{field.label}
|
||||
</TableCell>
|
||||
))}
|
||||
|
||||
{type === "edit" && (
|
||||
<TableCell width="120px">Действие</TableCell>
|
||||
)}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
|
||||
<Droppable
|
||||
droppableId="droppable"
|
||||
isDropDisabled={type !== "edit" || !dragAllowed}
|
||||
>
|
||||
{(provided) => (
|
||||
<TableBody
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
>
|
||||
{linkedItems.map((item, index) => (
|
||||
<Draggable
|
||||
key={item.id}
|
||||
draggableId={"q" + String(item.id)}
|
||||
index={index}
|
||||
isDragDisabled={type !== "edit" || !dragAllowed}
|
||||
>
|
||||
{(provided) => (
|
||||
<TableRow
|
||||
sx={{
|
||||
cursor:
|
||||
childResource === "article"
|
||||
? "pointer"
|
||||
: "default",
|
||||
}}
|
||||
onClick={() => {
|
||||
if (childResource === "article") {
|
||||
setArticleModalOpenAction(true);
|
||||
setArticleIdAction(item.id);
|
||||
}
|
||||
if (childResource === "station") {
|
||||
setStationModalOpenAction(true);
|
||||
setStationIdAction(item.id);
|
||||
setRouteIdAction(Number(parentId));
|
||||
}
|
||||
}}
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
hover
|
||||
>
|
||||
{type === "edit" && dragAllowed && (
|
||||
<TableCell {...provided.dragHandleProps}>
|
||||
<IconButton size="small">
|
||||
<DragIndicatorIcon />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
)}
|
||||
<TableCell key={String(item.id)}>
|
||||
{index + 1}
|
||||
</TableCell>
|
||||
{fields.map((field, index) => (
|
||||
<TableCell
|
||||
key={String(field.data) + String(index)}
|
||||
>
|
||||
{field.render
|
||||
? field.render(item[field.data])
|
||||
: item[field.data]}
|
||||
</TableCell>
|
||||
))}
|
||||
|
||||
{type === "edit" && (
|
||||
<TableCell>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="error"
|
||||
size="small"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
deleteItem(item.id);
|
||||
}}
|
||||
>
|
||||
Отвязать
|
||||
</Button>
|
||||
</TableCell>
|
||||
)}
|
||||
</TableRow>
|
||||
)}
|
||||
</Draggable>
|
||||
{linkedItems?.length > 0 && (
|
||||
<DragDropContext onDragEnd={onDragEnd}>
|
||||
<TableContainer component={Paper}>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
{type === "edit" && dragAllowed && (
|
||||
<TableCell width="40px"></TableCell>
|
||||
)}
|
||||
<TableCell key="id">№</TableCell>
|
||||
{fields.map((field) => (
|
||||
<TableCell key={String(field.data)}>
|
||||
{field.label}
|
||||
</TableCell>
|
||||
))}
|
||||
|
||||
{provided.placeholder}
|
||||
</TableBody>
|
||||
)}
|
||||
</Droppable>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</DragDropContext>
|
||||
{type === "edit" && (
|
||||
<TableCell width="120px">Действие</TableCell>
|
||||
)}
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
|
||||
<Droppable
|
||||
droppableId="droppable"
|
||||
isDropDisabled={type !== "edit" || !dragAllowed}
|
||||
>
|
||||
{(provided) => (
|
||||
<TableBody
|
||||
ref={provided.innerRef}
|
||||
{...provided.droppableProps}
|
||||
>
|
||||
{linkedItems.map((item, index) => (
|
||||
<Draggable
|
||||
key={item.id}
|
||||
draggableId={"q" + String(item.id)}
|
||||
index={index}
|
||||
isDragDisabled={type !== "edit" || !dragAllowed}
|
||||
>
|
||||
{(provided) => (
|
||||
<TableRow
|
||||
sx={{
|
||||
cursor:
|
||||
childResource === "article"
|
||||
? "pointer"
|
||||
: "default",
|
||||
}}
|
||||
onClick={() => {
|
||||
if (childResource === "article") {
|
||||
setArticleModalOpenAction(true);
|
||||
setArticleIdAction(item.id);
|
||||
}
|
||||
if (childResource === "station") {
|
||||
setStationModalOpenAction(true);
|
||||
setStationIdAction(item.id);
|
||||
setRouteIdAction(Number(parentId));
|
||||
}
|
||||
}}
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
hover
|
||||
>
|
||||
{type === "edit" && dragAllowed && (
|
||||
<TableCell {...provided.dragHandleProps}>
|
||||
<IconButton size="small">
|
||||
<DragIndicatorIcon />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
)}
|
||||
<TableCell key={String(item.id)}>
|
||||
{index + 1}
|
||||
</TableCell>
|
||||
{fields.map((field, index) => (
|
||||
<TableCell
|
||||
key={String(field.data) + String(index)}
|
||||
>
|
||||
{field.render
|
||||
? field.render(item[field.data])
|
||||
: item[field.data]}
|
||||
</TableCell>
|
||||
))}
|
||||
|
||||
{type === "edit" && (
|
||||
<TableCell>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="error"
|
||||
size="small"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
deleteItem(item.id);
|
||||
}}
|
||||
>
|
||||
Отвязать
|
||||
</Button>
|
||||
</TableCell>
|
||||
)}
|
||||
</TableRow>
|
||||
)}
|
||||
</Draggable>
|
||||
))}
|
||||
|
||||
{provided.placeholder}
|
||||
</TableBody>
|
||||
)}
|
||||
</Droppable>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</DragDropContext>
|
||||
)}
|
||||
|
||||
{linkedItems.length === 0 && !isLoading && (
|
||||
<Typography color="textSecondary" textAlign="center" py={2}>
|
||||
@ -448,7 +450,7 @@ export const LinkedItems = <T extends { id: number; [key: string]: any }>({
|
||||
)}
|
||||
/>
|
||||
|
||||
{childResource === "article" && (
|
||||
{/* {childResource === "article" && (
|
||||
<FormControl fullWidth>
|
||||
<TextField
|
||||
type="number"
|
||||
@ -464,7 +466,7 @@ export const LinkedItems = <T extends { id: number; [key: string]: any }>({
|
||||
InputLabelProps={{ shrink: true }}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
)} */}
|
||||
|
||||
{childResource === "media" && (
|
||||
<FormControl fullWidth>
|
||||
|
@ -4,20 +4,17 @@ import { observer } from "mobx-react-lite";
|
||||
import { useForm } from "@refinedev/react-hook-form";
|
||||
import { Controller } from "react-hook-form";
|
||||
import "easymde/dist/easymde.min.css";
|
||||
import { memo, useMemo, useEffect, useCallback } from "react";
|
||||
import { memo, useMemo, useEffect, useCallback, useState } from "react";
|
||||
import { MarkdownEditor } from "../../MarkdownEditor";
|
||||
import { Edit } from "@refinedev/mui";
|
||||
import { languageStore } from "../../../store/LanguageStore";
|
||||
import { LanguageSwitch } from "../../LanguageSwitch/index";
|
||||
import { useNavigate } from "react-router";
|
||||
import { useState } from "react";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import {
|
||||
ALLOWED_IMAGE_TYPES,
|
||||
ALLOWED_VIDEO_TYPES,
|
||||
} from "../../media/MediaFormUtils";
|
||||
import { axiosInstance } from "../../../providers/data";
|
||||
import { TOKEN_KEY } from "../../../authProvider";
|
||||
import { TOKEN_KEY, axiosInstance } from "@providers";
|
||||
import { LinkedItems } from "../../../components/LinkedItems";
|
||||
import { mediaFields, MediaItem } from "../../../pages/article/types";
|
||||
|
||||
|
71
src/components/ui/LanguageSelector.tsx
Normal file
71
src/components/ui/LanguageSelector.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import { Box } from "@mui/material";
|
||||
import { Languages, languageStore } from "@stores";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
|
||||
export const LanguageSelector = observer(({
|
||||
action
|
||||
}: {action?: (lang: Languages) => void}) => {
|
||||
const { language, setLanguageAction } = languageStore;
|
||||
|
||||
function handleLanguageChange(language: Languages) {
|
||||
if(action) action(language);
|
||||
else setLanguageAction(language);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
gap: 2,
|
||||
height: "min-content"
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
cursor: "pointer",
|
||||
flex: 1,
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
bgcolor: language === "ru" ? "primary.main" : "transparent",
|
||||
color: language === "ru" ? "white" : "inherit",
|
||||
borderRadius: 1,
|
||||
p: 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",
|
||||
borderRadius: 1,
|
||||
p: 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",
|
||||
borderRadius: 1,
|
||||
p: 1,
|
||||
}}
|
||||
onClick={() => handleLanguageChange("zh")}
|
||||
>
|
||||
ZH
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
});
|
97
src/components/ui/MediaView.tsx
Normal file
97
src/components/ui/MediaView.tsx
Normal file
@ -0,0 +1,97 @@
|
||||
import { Box } from "@mui/material";
|
||||
import { TOKEN_KEY } from "@providers";
|
||||
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer";
|
||||
import { ModelViewer } from "./ModelViewer";
|
||||
|
||||
export interface MediaData {
|
||||
filename?: string;
|
||||
id: string | number;
|
||||
media_name?: string;
|
||||
media_type: number;
|
||||
}
|
||||
|
||||
export function MediaView({media} : Readonly<{media?: MediaData}>) {
|
||||
const token = localStorage.getItem(TOKEN_KEY);
|
||||
return (
|
||||
<Box
|
||||
sx={{maxHeight: "50vh", height: "100%", width: "100%", display: "flex", justifyContent: "center"}}
|
||||
>
|
||||
{media?.media_type === 1 && (
|
||||
<img
|
||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
media?.id
|
||||
}/download?token=${token}`}
|
||||
alt={media?.filename}
|
||||
style={{
|
||||
maxWidth: "100%",
|
||||
height: "100%",
|
||||
objectFit: "contain",
|
||||
borderRadius: 8,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{media?.media_type === 2 && (
|
||||
<video
|
||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
media?.id
|
||||
}/download?token=${token}`}
|
||||
style={{
|
||||
|
||||
objectFit: "contain",
|
||||
borderRadius: 30,
|
||||
}}
|
||||
controls
|
||||
autoPlay
|
||||
muted
|
||||
/>
|
||||
)}
|
||||
{media?.media_type === 3 && (
|
||||
<img
|
||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
media?.id
|
||||
}/download?token=${token}`}
|
||||
alt={media?.filename}
|
||||
style={{
|
||||
maxWidth: "100%",
|
||||
height: "100%",
|
||||
objectFit: "contain",
|
||||
borderRadius: 8,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{media?.media_type === 4 && (
|
||||
<img
|
||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
media?.id
|
||||
}/download?token=${token}`}
|
||||
alt={media?.filename}
|
||||
style={{
|
||||
maxWidth: "100%",
|
||||
height: "100%",
|
||||
objectFit: "contain",
|
||||
borderRadius: 8,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{media?.media_type === 5 && (
|
||||
<ReactPhotoSphereViewer
|
||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
media?.id
|
||||
}/download?token=${token}`}
|
||||
width={"100%"}
|
||||
height={"100%"}
|
||||
/>
|
||||
)}
|
||||
|
||||
{media?.media_type === 6 && (
|
||||
<ModelViewer
|
||||
fileUrl={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
media?.id
|
||||
}/download?token=${token}`}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
}
|
@ -6,7 +6,7 @@ type ModelViewerProps = {
|
||||
height?: string;
|
||||
};
|
||||
|
||||
export const ModelViewer = ({ fileUrl, height = "80vh" }: ModelViewerProps) => {
|
||||
export const ModelViewer = ({ fileUrl, height = "100%" }: ModelViewerProps) => {
|
||||
const { scene } = useGLTF(fileUrl);
|
||||
|
||||
return (
|
5
src/components/ui/index.ts
Normal file
5
src/components/ui/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export * from './Icons';
|
||||
export * from './LanguageSelector';
|
||||
export * from './SidebarTitle';
|
||||
export * from './MediaView';
|
||||
export * from './ModelViewer';
|
@ -10,4 +10,4 @@ export const MEDIA_TYPES = [
|
||||
export const VEHICLE_TYPES = [
|
||||
{ label: "Трамвай", value: 1 },
|
||||
{ label: "Троллейбус", value: 2 },
|
||||
];
|
||||
];
|
1
src/lib/index.ts
Normal file
1
src/lib/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { MEDIA_TYPES, VEHICLE_TYPES } from './constants'
|
@ -1,94 +1,92 @@
|
||||
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 { Controller, FieldValues } 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 { LanguageSelector } from "@ui";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { EVERY_LANGUAGE, Languages, languageStore, META_LANGUAGE } from "@stores";
|
||||
import { axiosInstance } from "@/providers/data";
|
||||
|
||||
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: "" },
|
||||
export const ArticleCreate = observer(() => {
|
||||
const { language, setLanguageAction } = languageStore;
|
||||
const [articleData, setArticleData] = useState({
|
||||
heading: EVERY_LANGUAGE(""),
|
||||
body: EVERY_LANGUAGE("")
|
||||
});
|
||||
|
||||
const {
|
||||
saveButtonProps,
|
||||
refineCore: { formLoading },
|
||||
refineCore: { formLoading, onFinish },
|
||||
register,
|
||||
control,
|
||||
watch,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
handleSubmit,
|
||||
} = useForm({
|
||||
refineCoreProps: {
|
||||
resource: "article/",
|
||||
meta: {
|
||||
headers: {
|
||||
"Accept-Language": language,
|
||||
},
|
||||
},
|
||||
resource: "article",
|
||||
...META_LANGUAGE(language)
|
||||
},
|
||||
warnWhenUnsavedChanges: false
|
||||
});
|
||||
|
||||
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");
|
||||
|
||||
function updateTranslations() {
|
||||
const newArticleData = {
|
||||
...articleData,
|
||||
heading: {
|
||||
...articleData.heading,
|
||||
[language]: watch("heading") ?? "",
|
||||
},
|
||||
body: {
|
||||
...articleData.body,
|
||||
[language]: watch("body") ?? "",
|
||||
}
|
||||
}
|
||||
setArticleData(newArticleData);
|
||||
return newArticleData;
|
||||
}
|
||||
|
||||
const handleFormSubmit = handleSubmit((values: FieldValues) => {
|
||||
const newTranslations = updateTranslations();
|
||||
console.log(newTranslations);
|
||||
return onFinish({
|
||||
translations: newTranslations
|
||||
});
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setPreview(bodyContent || "");
|
||||
setValue("heading", articleData.heading[language] ?? "");
|
||||
setValue("body", articleData.body[language] ?? "");
|
||||
setPreview(articleData.body[language] ?? "");
|
||||
setHeadingPreview(articleData.heading[language] ?? "");
|
||||
}, [language, articleData, setValue]);
|
||||
|
||||
const handleLanguageChange = (lang: Languages) => {
|
||||
updateTranslations();
|
||||
setLanguageAction(lang);
|
||||
};
|
||||
|
||||
const [preview, setPreview] = useState("");
|
||||
const [headingPreview, setHeadingPreview] = useState("");
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
setPreview(bodyContent ?? "");
|
||||
}, [bodyContent]);
|
||||
|
||||
useEffect(() => {
|
||||
setHeadingPreview(headingContent || "");
|
||||
setHeadingPreview(headingContent ?? "");
|
||||
}, [headingContent]);
|
||||
|
||||
const simpleMDEOptions = React.useMemo(
|
||||
@ -100,63 +98,14 @@ export const ArticleCreate = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<Create isLoading={formLoading} saveButtonProps={saveButtonProps}>
|
||||
<Create isLoading={formLoading} saveButtonProps={{
|
||||
//...saveButtonProps,
|
||||
onClick: handleFormSubmit
|
||||
}}>
|
||||
<Box sx={{ display: "flex", flex: 1, gap: 2 }}>
|
||||
{/* Форма создания */}
|
||||
<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>
|
||||
<LanguageSelector action={handleLanguageChange} />
|
||||
<Box
|
||||
component="form"
|
||||
sx={{ flex: 1, display: "flex", flexDirection: "column" }}
|
||||
@ -273,4 +222,4 @@ export const ArticleCreate = () => {
|
||||
</Box>
|
||||
</Create>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Box, TextField, Typography, Paper } from "@mui/material";
|
||||
import { Edit } from "@refinedev/mui";
|
||||
import { useForm } from "@refinedev/react-hook-form";
|
||||
import { Controller } from "react-hook-form";
|
||||
import { Controller, FieldValues } from "react-hook-form";
|
||||
import { useParams } from "react-router";
|
||||
import React, { useState, useEffect, useMemo } from "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
@ -10,23 +10,19 @@ import { useList } from "@refinedev/core";
|
||||
import { MarkdownEditor } from "../../components/MarkdownEditor";
|
||||
import { LinkedItems } from "../../components/LinkedItems";
|
||||
import { MediaItem, mediaFields } from "./types";
|
||||
import { TOKEN_KEY } from "../../authProvider";
|
||||
import { TOKEN_KEY } from "@providers";
|
||||
import "easymde/dist/easymde.min.css";
|
||||
import { languageStore } from "../../store/LanguageStore";
|
||||
import { EVERY_LANGUAGE, Languages, languageStore, META_LANGUAGE } from "@stores";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { LanguageSelector, MediaView } from "@ui";
|
||||
const MemoizedSimpleMDE = React.memo(MarkdownEditor);
|
||||
|
||||
export const ArticleEdit = observer(() => {
|
||||
const { language, setLanguageAction } = languageStore;
|
||||
|
||||
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 [articleData, setArticleData] = useState({
|
||||
heading: EVERY_LANGUAGE(""),
|
||||
body: EVERY_LANGUAGE("")
|
||||
});
|
||||
const { id: articleId } = useParams<{ id: string }>();
|
||||
const [preview, setPreview] = useState("");
|
||||
@ -41,6 +37,7 @@ export const ArticleEdit = observer(() => {
|
||||
|
||||
const {
|
||||
saveButtonProps,
|
||||
refineCore: { onFinish },
|
||||
register,
|
||||
control,
|
||||
handleSubmit,
|
||||
@ -48,54 +45,54 @@ export const ArticleEdit = observer(() => {
|
||||
formState: { errors },
|
||||
setValue,
|
||||
} = useForm<{ heading: string; body: string }>({
|
||||
refineCoreProps: {
|
||||
meta: {
|
||||
headers: {
|
||||
"Accept-Language": language,
|
||||
},
|
||||
},
|
||||
},
|
||||
refineCoreProps: META_LANGUAGE(language)
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (articleData[language as keyof typeof articleData]?.heading) {
|
||||
setValue(
|
||||
"heading",
|
||||
articleData[language as keyof typeof articleData]?.heading
|
||||
);
|
||||
setHeadingPreview(
|
||||
articleData[language as keyof typeof articleData]?.heading || ""
|
||||
);
|
||||
}
|
||||
if (articleData[language as keyof typeof articleData]?.body) {
|
||||
setValue(
|
||||
"body",
|
||||
articleData[language as keyof typeof articleData]?.body || ""
|
||||
);
|
||||
setPreview(articleData[language as keyof typeof articleData]?.body || "");
|
||||
}
|
||||
}, [language, articleData, setValue]);
|
||||
|
||||
const handleLanguageChange = (lang: string) => {
|
||||
setArticleData((prevData) => ({
|
||||
...prevData,
|
||||
[language]: {
|
||||
heading: watch("heading") ?? "",
|
||||
body: watch("body") ?? "",
|
||||
},
|
||||
}));
|
||||
setLanguageAction(lang);
|
||||
};
|
||||
|
||||
const bodyContent = watch("body");
|
||||
const headingContent = watch("heading");
|
||||
|
||||
useEffect(() => {
|
||||
setPreview(bodyContent || "");
|
||||
setValue("heading", articleData.heading[language] ?? "");
|
||||
setHeadingPreview(articleData.heading[language] ?? "");
|
||||
setValue("body", articleData.body[language] ?? "");
|
||||
setPreview(articleData.body[language] ?? "");
|
||||
}, [language, articleData, setValue]);
|
||||
|
||||
function updateTranslations() {
|
||||
const newArticleData = {
|
||||
...articleData,
|
||||
heading: {
|
||||
...articleData.heading,
|
||||
[language]: watch("heading") ?? "",
|
||||
},
|
||||
body: {
|
||||
...articleData.body,
|
||||
[language]: watch("body") ?? "",
|
||||
}
|
||||
}
|
||||
setArticleData(newArticleData);
|
||||
return newArticleData;
|
||||
}
|
||||
|
||||
const handleLanguageChange = (lang: Languages) => {
|
||||
updateTranslations();
|
||||
setLanguageAction(lang);
|
||||
};
|
||||
|
||||
const handleFormSubmit = handleSubmit((values: FieldValues) => {
|
||||
const newTranslations = updateTranslations();
|
||||
console.log(newTranslations);
|
||||
return onFinish({
|
||||
translations: newTranslations
|
||||
});
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setPreview(bodyContent ?? "");
|
||||
}, [bodyContent]);
|
||||
|
||||
useEffect(() => {
|
||||
setHeadingPreview(headingContent || "");
|
||||
setHeadingPreview(headingContent ?? "");
|
||||
}, [headingContent]);
|
||||
|
||||
const { data: mediaData } = useList<MediaItem>({
|
||||
@ -109,64 +106,17 @@ export const ArticleEdit = observer(() => {
|
||||
}, [setLanguageAction]);
|
||||
|
||||
return (
|
||||
<Edit saveButtonProps={saveButtonProps}>
|
||||
<Edit saveButtonProps={{
|
||||
...saveButtonProps,
|
||||
onClick: handleFormSubmit
|
||||
}}
|
||||
>
|
||||
<Box sx={{ display: "flex", gap: 2 }}>
|
||||
{/* Форма редактирования */}
|
||||
{/* Форма создания */}
|
||||
<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>
|
||||
|
||||
<LanguageSelector action={handleLanguageChange} />
|
||||
<Box
|
||||
component="form"
|
||||
sx={{ flex: 1, display: "flex", flexDirection: "column" }}
|
||||
@ -317,7 +267,8 @@ export const ArticleEdit = observer(() => {
|
||||
borderColor: "primary.main",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
<MediaView media={media} />
|
||||
{/* <img
|
||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
media.id
|
||||
}/download?token=${localStorage.getItem(TOKEN_KEY)}`}
|
||||
@ -327,7 +278,7 @@ export const ArticleEdit = observer(() => {
|
||||
height: "100%",
|
||||
objectFit: "cover",
|
||||
}}
|
||||
/>
|
||||
/> */}
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
|
@ -8,21 +8,18 @@ import {
|
||||
useDataGrid,
|
||||
} from "@refinedev/mui";
|
||||
import React, { useEffect } from "react";
|
||||
import { useDelete } from "@refinedev/core";
|
||||
|
||||
import { localeText } from "../../locales/ru/localeText";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { languageStore } from "../../store/LanguageStore";
|
||||
import { languageStore, META_LANGUAGE } from "@stores";
|
||||
|
||||
export const ArticleList = observer(() => {
|
||||
const { language } = languageStore;
|
||||
|
||||
const { dataGridProps } = useDataGrid({
|
||||
resource: "article/",
|
||||
meta: {
|
||||
headers: {
|
||||
"Accept-Language": language,
|
||||
},
|
||||
},
|
||||
resource: "article",
|
||||
...META_LANGUAGE(language)
|
||||
});
|
||||
|
||||
const columns = React.useMemo<GridColDef[]>(
|
||||
@ -70,7 +67,10 @@ export const ArticleList = observer(() => {
|
||||
<>
|
||||
<EditButton hideText recordItemId={row.id} />
|
||||
<ShowButton hideText recordItemId={row.id} />
|
||||
<DeleteButton hideText recordItemId={row.id} />
|
||||
<DeleteButton
|
||||
hideText
|
||||
recordItemId={row.id}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
},
|
||||
|
@ -4,7 +4,7 @@ export type MediaItem = {
|
||||
id: number
|
||||
filename: string
|
||||
media_name: string
|
||||
media_type: string
|
||||
media_type: number
|
||||
media_order?: number
|
||||
}
|
||||
|
||||
|
@ -1,15 +1,22 @@
|
||||
import { Autocomplete, Box, TextField } from "@mui/material";
|
||||
import { Edit, useAutocomplete } from "@refinedev/mui";
|
||||
import { useForm } from "@refinedev/react-hook-form";
|
||||
import { languageStore, META_LANGUAGE } from "@stores";
|
||||
import { LanguageSelector, MediaData, MediaView } from "@ui";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { Controller } from "react-hook-form";
|
||||
|
||||
export const CarrierEdit = () => {
|
||||
export const CarrierEdit = observer(() => {
|
||||
const { language } = languageStore;
|
||||
const {
|
||||
saveButtonProps,
|
||||
register,
|
||||
control,
|
||||
watch,
|
||||
formState: { errors },
|
||||
} = useForm();
|
||||
} = useForm({
|
||||
refineCoreProps: META_LANGUAGE(language)
|
||||
});
|
||||
|
||||
const { autocompleteProps: cityAutocompleteProps } = useAutocomplete({
|
||||
resource: "city",
|
||||
@ -20,6 +27,7 @@ export const CarrierEdit = () => {
|
||||
value,
|
||||
},
|
||||
],
|
||||
...META_LANGUAGE("ru")
|
||||
});
|
||||
|
||||
const { autocompleteProps: mediaAutocompleteProps } = useAutocomplete({
|
||||
@ -31,6 +39,7 @@ export const CarrierEdit = () => {
|
||||
value,
|
||||
},
|
||||
],
|
||||
...META_LANGUAGE(language)
|
||||
});
|
||||
|
||||
return (
|
||||
@ -40,6 +49,7 @@ export const CarrierEdit = () => {
|
||||
sx={{ display: "flex", flexDirection: "column" }}
|
||||
autoComplete="off"
|
||||
>
|
||||
<LanguageSelector />
|
||||
<Controller
|
||||
control={control}
|
||||
name="city_id"
|
||||
@ -110,70 +120,77 @@ export const CarrierEdit = () => {
|
||||
name="short_name"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("main_color", {
|
||||
// required: 'Это поле является обязательным',
|
||||
})}
|
||||
error={!!(errors as any)?.main_color}
|
||||
helperText={(errors as any)?.main_color?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="color"
|
||||
label={"Основной цвет"}
|
||||
name="main_color"
|
||||
sx={{
|
||||
"& input": {
|
||||
height: "50px",
|
||||
paddingBlock: "14px",
|
||||
paddingInline: "14px",
|
||||
cursor: "pointer",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Box component="form"
|
||||
sx={{ display: "flex" }}
|
||||
autoComplete="off"
|
||||
>
|
||||
<TextField
|
||||
{...register("main_color", {
|
||||
// required: 'Это поле является обязательным',
|
||||
})}
|
||||
error={!!(errors as any)?.main_color}
|
||||
helperText={(errors as any)?.main_color?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="color"
|
||||
label={"Основной цвет"}
|
||||
name="main_color"
|
||||
sx={{
|
||||
"& input": {
|
||||
height: "50px",
|
||||
paddingBlock: "14px",
|
||||
paddingInline: "14px",
|
||||
cursor: "pointer",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("left_color", {
|
||||
// required: 'Это поле является обязательным',
|
||||
})}
|
||||
error={!!(errors as any)?.left_color}
|
||||
helperText={(errors as any)?.left_color?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="color"
|
||||
label={"Цвет левого виджета"}
|
||||
name="left_color"
|
||||
sx={{
|
||||
"& input": {
|
||||
height: "50px",
|
||||
paddingBlock: "14px",
|
||||
paddingInline: "14px",
|
||||
cursor: "pointer",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<TextField
|
||||
{...register("right_color", {
|
||||
// required: 'Это поле является обязательным',
|
||||
})}
|
||||
error={!!(errors as any)?.right_color}
|
||||
helperText={(errors as any)?.right_color?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="color"
|
||||
label={"Цвет правого виджета"}
|
||||
name="right_color"
|
||||
sx={{
|
||||
"& input": {
|
||||
height: "50px",
|
||||
paddingBlock: "14px",
|
||||
paddingInline: "14px",
|
||||
cursor: "pointer",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<TextField
|
||||
{...register("left_color", {
|
||||
// required: 'Это поле является обязательным',
|
||||
})}
|
||||
error={!!(errors as any)?.left_color}
|
||||
helperText={(errors as any)?.left_color?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="color"
|
||||
label={"Цвет левого виджета"}
|
||||
name="left_color"
|
||||
sx={{
|
||||
marginLeft: "16px",
|
||||
marginRight: "16px",
|
||||
"& input": {
|
||||
height: "50px",
|
||||
paddingBlock: "14px",
|
||||
paddingInline: "14px",
|
||||
cursor: "pointer",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<TextField
|
||||
{...register("right_color", {
|
||||
// required: 'Это поле является обязательным',
|
||||
})}
|
||||
error={!!(errors as any)?.right_color}
|
||||
helperText={(errors as any)?.right_color?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="color"
|
||||
label={"Цвет правого виджета"}
|
||||
name="right_color"
|
||||
sx={{
|
||||
"& input": {
|
||||
height: "50px",
|
||||
paddingBlock: "14px",
|
||||
paddingInline: "14px",
|
||||
cursor: "pointer",
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<TextField
|
||||
{...register("slogan", {
|
||||
@ -231,7 +248,10 @@ export const CarrierEdit = () => {
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Box height={150} sx={{display: "flex", justifyContent: "start"}}>
|
||||
<MediaView media={{id: watch("logo"), media_type: 1}} />
|
||||
</Box>
|
||||
</Box>
|
||||
</Edit>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { Box, Stack, Typography } from "@mui/material";
|
||||
import { useShow } from "@refinedev/core";
|
||||
import { Show, TextFieldComponent as TextField } from "@refinedev/mui";
|
||||
import { TOKEN_KEY } from "../../authProvider";
|
||||
import { TOKEN_KEY } from "@providers";
|
||||
import { MediaView } from "@ui";
|
||||
|
||||
export type FieldType = {
|
||||
label: string;
|
||||
@ -81,13 +82,9 @@ export const CarrierShow = () => {
|
||||
label: "Логотип",
|
||||
data: "logo",
|
||||
render: (value: number) => (
|
||||
<img
|
||||
src={`${
|
||||
import.meta.env.VITE_KRBL_MEDIA
|
||||
}${value}/download?token=${localStorage.getItem(TOKEN_KEY)}`}
|
||||
alt={String(value)}
|
||||
style={{ maxWidth: "10%", objectFit: "contain", borderRadius: 8 }}
|
||||
/>
|
||||
<Box height={150} sx={{display: "flex", justifyContent: "start"}}>
|
||||
<MediaView media={{id: value, media_type: 1}} />
|
||||
</Box>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
@ -1,18 +1,26 @@
|
||||
import {Autocomplete, Box, TextField} from '@mui/material'
|
||||
import {Edit, useAutocomplete} from '@refinedev/mui'
|
||||
import {useForm} from '@refinedev/react-hook-form'
|
||||
import { EVERY_LANGUAGE, Languages, languageStore, META_LANGUAGE } from '@stores'
|
||||
import { LanguageSelector } from '@ui'
|
||||
import { observer } from 'mobx-react-lite'
|
||||
import { useEffect, useState } from 'react'
|
||||
import {Controller} from 'react-hook-form'
|
||||
|
||||
export const CityEdit = () => {
|
||||
export const CityEdit = observer(() => {
|
||||
const { language } = languageStore;
|
||||
const {
|
||||
saveButtonProps,
|
||||
register,
|
||||
control,
|
||||
formState: {errors},
|
||||
} = useForm({})
|
||||
} = useForm({
|
||||
refineCoreProps: META_LANGUAGE(language)
|
||||
})
|
||||
|
||||
const {autocompleteProps: countryAutocompleteProps} = useAutocomplete({
|
||||
resource: 'country',
|
||||
...META_LANGUAGE(language)
|
||||
})
|
||||
|
||||
const {autocompleteProps: mediaAutocompleteProps} = useAutocomplete({
|
||||
@ -24,11 +32,14 @@ export const CityEdit = () => {
|
||||
value,
|
||||
},
|
||||
],
|
||||
})
|
||||
...META_LANGUAGE(language)
|
||||
});
|
||||
|
||||
return (
|
||||
<Edit saveButtonProps={saveButtonProps}>
|
||||
<Box component="form" sx={{display: 'flex', flexDirection: 'column'}} autoComplete="off">
|
||||
<LanguageSelector/>
|
||||
|
||||
<Controller
|
||||
control={control}
|
||||
name="country_code"
|
||||
@ -94,4 +105,4 @@ export const CityEdit = () => {
|
||||
</Box>
|
||||
</Edit>
|
||||
)
|
||||
}
|
||||
})
|
@ -1,7 +1,7 @@
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
import { useShow } from "@refinedev/core";
|
||||
import { Show, TextFieldComponent as TextField } from "@refinedev/mui";
|
||||
import { TOKEN_KEY } from "../../authProvider";
|
||||
import { TOKEN_KEY } from "@providers";
|
||||
|
||||
export const CityShow = () => {
|
||||
const { query } = useShow({});
|
||||
|
@ -1,13 +1,19 @@
|
||||
import { Box, TextField } from "@mui/material";
|
||||
import { Edit } from "@refinedev/mui";
|
||||
import { useForm } from "@refinedev/react-hook-form";
|
||||
import { languageStore, META_LANGUAGE } from "@stores";
|
||||
import { LanguageSelector } from "@ui";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
export const CountryEdit = () => {
|
||||
export const CountryEdit = observer(() => {
|
||||
const { language } = languageStore;
|
||||
const {
|
||||
saveButtonProps,
|
||||
register,
|
||||
formState: { errors },
|
||||
} = useForm({});
|
||||
} = useForm({
|
||||
refineCoreProps: META_LANGUAGE(language)
|
||||
});
|
||||
|
||||
return (
|
||||
<Edit saveButtonProps={saveButtonProps}>
|
||||
@ -16,6 +22,7 @@ export const CountryEdit = () => {
|
||||
sx={{ display: "flex", flexDirection: "column" }}
|
||||
autoComplete="off"
|
||||
>
|
||||
<LanguageSelector />
|
||||
<TextField
|
||||
{...register("code", {
|
||||
required: "Это поле является обязательным",
|
||||
@ -27,6 +34,7 @@ export const CountryEdit = () => {
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="text"
|
||||
label={"Код *"}
|
||||
disabled
|
||||
name="code"
|
||||
/>
|
||||
<TextField
|
||||
@ -45,4 +53,4 @@ export const CountryEdit = () => {
|
||||
</Box>
|
||||
</Edit>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -20,7 +20,7 @@ import {
|
||||
useMediaFileUpload,
|
||||
} from "../../components/media/MediaFormUtils";
|
||||
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer";
|
||||
import { ModelViewer } from "./ModelViewer/index";
|
||||
import { ModelViewer } from "@ui";
|
||||
|
||||
type MediaFormValues = {
|
||||
media_name: string;
|
||||
|
@ -11,8 +11,8 @@ import { useEffect } from "react";
|
||||
import { useShow } from "@refinedev/core";
|
||||
import { Controller } from "react-hook-form";
|
||||
|
||||
import { TOKEN_KEY } from "../../authProvider";
|
||||
import { MEDIA_TYPES } from "../../lib/constants";
|
||||
import { TOKEN_KEY } from "@providers";
|
||||
import { MEDIA_TYPES } from "@lib";
|
||||
import {
|
||||
ALLOWED_IMAGE_TYPES,
|
||||
ALLOWED_VIDEO_TYPES,
|
||||
@ -22,6 +22,9 @@ import {
|
||||
ALLOWED_3D_MODEL_TYPES,
|
||||
useMediaFileUpload,
|
||||
} from "../../components/media/MediaFormUtils";
|
||||
import { languageStore, META_LANGUAGE } from "@stores";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { LanguageSelector, MediaData, MediaView } from "@ui";
|
||||
|
||||
type MediaFormValues = {
|
||||
media_name: string;
|
||||
@ -29,7 +32,8 @@ type MediaFormValues = {
|
||||
file?: File;
|
||||
};
|
||||
|
||||
export const MediaEdit = () => {
|
||||
export const MediaEdit = observer(() => {
|
||||
const { language } = languageStore;
|
||||
const {
|
||||
saveButtonProps,
|
||||
refineCore: { onFinish },
|
||||
@ -47,6 +51,7 @@ export const MediaEdit = () => {
|
||||
media_type: "",
|
||||
file: undefined,
|
||||
},
|
||||
refineCoreProps: META_LANGUAGE(language)
|
||||
});
|
||||
|
||||
const { query } = useShow();
|
||||
@ -100,6 +105,7 @@ export const MediaEdit = () => {
|
||||
sx={{ display: "flex", flexDirection: "column" }}
|
||||
autoComplete="off"
|
||||
>
|
||||
<LanguageSelector />
|
||||
<Controller
|
||||
control={control}
|
||||
name="media_type"
|
||||
@ -177,7 +183,7 @@ export const MediaEdit = () => {
|
||||
hidden
|
||||
onChange={handleFileChange}
|
||||
accept={
|
||||
selectedMediaType === 1
|
||||
selectedMediaType === 1
|
||||
? ALLOWED_IMAGE_TYPES.join(",")
|
||||
: selectedMediaType === 2
|
||||
? ALLOWED_VIDEO_TYPES.join(",")
|
||||
@ -207,7 +213,9 @@ export const MediaEdit = () => {
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{previewUrl && selectedMediaType === 1 && (
|
||||
|
||||
<MediaView media={record as MediaData} />
|
||||
{/* {previewUrl && selectedMediaType === 1 && (
|
||||
<Box mt={2} display="flex" justifyContent="center">
|
||||
<img
|
||||
src={previewUrl}
|
||||
@ -215,9 +223,9 @@ export const MediaEdit = () => {
|
||||
style={{ maxWidth: "200px", borderRadius: 8 }}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
)} */}
|
||||
</Box>
|
||||
</Box>
|
||||
</Edit>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -3,11 +3,16 @@ import {CustomDataGrid} from '../../components/CustomDataGrid'
|
||||
import {DeleteButton, EditButton, List, ShowButton, useDataGrid} from '@refinedev/mui'
|
||||
import React from 'react'
|
||||
import {MEDIA_TYPES} from '../../lib/constants'
|
||||
import { observer } from "mobx-react-lite"
|
||||
|
||||
import {localeText} from '../../locales/ru/localeText'
|
||||
import { languageStore, META_LANGUAGE } from '@stores'
|
||||
|
||||
export const MediaList = () => {
|
||||
const {dataGridProps} = useDataGrid({})
|
||||
export const MediaList = observer(() => {
|
||||
const { language } = languageStore;
|
||||
const {dataGridProps} = useDataGrid({
|
||||
...META_LANGUAGE(language)
|
||||
})
|
||||
|
||||
const columns = React.useMemo<GridColDef[]>(
|
||||
() => [
|
||||
@ -77,7 +82,7 @@ export const MediaList = () => {
|
||||
|
||||
return (
|
||||
<List>
|
||||
<CustomDataGrid {...dataGridProps} columns={columns} localeText={localeText} getRowId={(row: any) => row.id} />
|
||||
<CustomDataGrid {...dataGridProps} columns={columns} localeText={localeText} getRowId={(row: any) => row.id} languageEnabled/>
|
||||
</List>
|
||||
)
|
||||
}
|
||||
});
|
||||
|
@ -1,11 +1,9 @@
|
||||
import { Stack, Typography, Box, Button } from "@mui/material";
|
||||
import { useShow } from "@refinedev/core";
|
||||
import { Show, TextFieldComponent as TextField } from "@refinedev/mui";
|
||||
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer";
|
||||
import sky from "./12414.jpg";
|
||||
import { MEDIA_TYPES } from "../../lib/constants";
|
||||
import { TOKEN_KEY } from "../../authProvider";
|
||||
import { ModelViewer } from "./ModelViewer/index";
|
||||
import { MEDIA_TYPES } from "@lib";
|
||||
import { TOKEN_KEY } from "@providers";
|
||||
import { MediaData, MediaView } from "@ui";
|
||||
|
||||
export const MediaShow = () => {
|
||||
const { query } = useShow({});
|
||||
@ -29,83 +27,7 @@ export const MediaShow = () => {
|
||||
return (
|
||||
<Show isLoading={isLoading}>
|
||||
<Stack gap={4}>
|
||||
{record && record.media_type === 1 && (
|
||||
<img
|
||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
record?.id
|
||||
}/download?token=${token}`}
|
||||
alt={record?.filename}
|
||||
style={{
|
||||
maxWidth: "100%",
|
||||
height: "40vh",
|
||||
objectFit: "contain",
|
||||
borderRadius: 8,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{record && record.media_type === 2 && (
|
||||
<video
|
||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
record?.id
|
||||
}/download?token=${token}`}
|
||||
style={{
|
||||
maxWidth: "50%",
|
||||
|
||||
objectFit: "contain",
|
||||
borderRadius: 30,
|
||||
}}
|
||||
controls
|
||||
autoPlay
|
||||
muted
|
||||
/>
|
||||
)}
|
||||
{record && record.media_type === 3 && (
|
||||
<img
|
||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
record?.id
|
||||
}/download?token=${token}`}
|
||||
alt={record?.filename}
|
||||
style={{
|
||||
maxWidth: "100%",
|
||||
height: "40vh",
|
||||
objectFit: "contain",
|
||||
borderRadius: 8,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{record && record.media_type === 4 && (
|
||||
<img
|
||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
record?.id
|
||||
}/download?token=${token}`}
|
||||
alt={record?.filename}
|
||||
style={{
|
||||
maxWidth: "100%",
|
||||
height: "40vh",
|
||||
objectFit: "contain",
|
||||
borderRadius: 8,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{record && record.media_type === 5 && (
|
||||
<ReactPhotoSphereViewer
|
||||
src={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
record?.id
|
||||
}/download?token=${token}`}
|
||||
width={"100%"}
|
||||
height={"80vh"}
|
||||
/>
|
||||
)}
|
||||
|
||||
{record && record.media_type === 6 && (
|
||||
<ModelViewer
|
||||
fileUrl={`${import.meta.env.VITE_KRBL_MEDIA}${
|
||||
record?.id
|
||||
}/download?token=${token}`}
|
||||
/>
|
||||
)}
|
||||
<MediaView media={record as MediaData} />
|
||||
{fields.map(({ label, data, render }) => (
|
||||
<Stack key={data} gap={1}>
|
||||
<Typography variant="body1" fontWeight="bold">
|
||||
|
@ -5,11 +5,12 @@ import {
|
||||
FormControlLabel,
|
||||
Checkbox,
|
||||
Typography,
|
||||
Button,
|
||||
} from "@mui/material";
|
||||
import { Edit, useAutocomplete } from "@refinedev/mui";
|
||||
import { useForm } from "@refinedev/react-hook-form";
|
||||
import { Controller } from "react-hook-form";
|
||||
import { useParams } from "react-router";
|
||||
import { useNavigate, useParams } from "react-router";
|
||||
import { LinkedItems } from "../../components/LinkedItems";
|
||||
import {
|
||||
StationItem,
|
||||
@ -29,6 +30,7 @@ export const RouteEdit = () => {
|
||||
setValue,
|
||||
watch,
|
||||
} = useForm({});
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { id: routeId } = useParams<{ id: string }>();
|
||||
|
||||
@ -53,38 +55,213 @@ export const RouteEdit = () => {
|
||||
],
|
||||
});
|
||||
|
||||
const { autocompleteProps: governorAppealAutocompleteProps } = useAutocomplete({
|
||||
resource: "article",
|
||||
|
||||
onSearch: (value) => [
|
||||
{
|
||||
field: "heading",
|
||||
operator: "contains",
|
||||
value,
|
||||
},
|
||||
{
|
||||
field: "media_type",
|
||||
operator: "contains",
|
||||
value,
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
return (
|
||||
<Edit saveButtonProps={saveButtonProps}>
|
||||
<Box
|
||||
component="form"
|
||||
sx={{ display: "flex", flexDirection: "column" }}
|
||||
autoComplete="off"
|
||||
sx={{display: "flex", flexDirection: "column", gap:1}}
|
||||
>
|
||||
<Controller
|
||||
<Box
|
||||
component="form"
|
||||
sx={{ display: "flex", flexDirection: "column"}}
|
||||
autoComplete="off"
|
||||
>
|
||||
<Controller
|
||||
control={control}
|
||||
name="carrier_id"
|
||||
rules={{ required: "Это поле является обязательным" }}
|
||||
defaultValue={null}
|
||||
render={({ field }) => (
|
||||
<Autocomplete
|
||||
{...carrierAutocompleteProps}
|
||||
value={
|
||||
carrierAutocompleteProps.options.find(
|
||||
(option) => option.id === field.value
|
||||
) || null
|
||||
}
|
||||
onChange={(_, value) => {
|
||||
field.onChange(value?.id || "");
|
||||
}}
|
||||
getOptionLabel={(item) => {
|
||||
return item ? item.short_name : "";
|
||||
}}
|
||||
isOptionEqualToValue={(option, value) => {
|
||||
return option.id === value?.id;
|
||||
}}
|
||||
filterOptions={(options, { inputValue }) => {
|
||||
return options.filter((option) =>
|
||||
option.short_name
|
||||
.toLowerCase()
|
||||
.includes(inputValue.toLowerCase())
|
||||
);
|
||||
}}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="Выберите перевозчика"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
error={!!errors.carrier_id}
|
||||
helperText={(errors as any)?.carrier_id?.message}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("route_number", {
|
||||
required: "Это поле является обязательным",
|
||||
setValueAs: (value) => String(value),
|
||||
})}
|
||||
error={!!(errors as any)?.route_number}
|
||||
helperText={(errors as any)?.route_number?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="text"
|
||||
label={"Номер маршрута"}
|
||||
name="route_number"
|
||||
/>
|
||||
<Controller
|
||||
name="route_direction" // boolean
|
||||
control={control}
|
||||
defaultValue={false}
|
||||
render={({ field }: { field: any }) => (
|
||||
<FormControlLabel
|
||||
label="Прямой маршрут?"
|
||||
control={
|
||||
<Checkbox
|
||||
{...field}
|
||||
checked={field.value}
|
||||
onChange={(e) => field.onChange(e.target.checked)}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="textSecondary"
|
||||
sx={{ mt: 0, mb: 1 }}
|
||||
>
|
||||
(Прямой / Обратный)
|
||||
</Typography>
|
||||
|
||||
<TextField
|
||||
{...register("path", {
|
||||
required: "Это поле является обязательным",
|
||||
setValueAs: (value: string) => {
|
||||
try {
|
||||
const lines = value.trim().split("\n");
|
||||
return lines.map((line) => {
|
||||
const [lat, lon] = line
|
||||
.trim()
|
||||
.split(/[\s,]+/)
|
||||
.map(Number);
|
||||
return [lat, lon];
|
||||
});
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
validate: (value: unknown) => {
|
||||
if (!Array.isArray(value)) return "Неверный формат";
|
||||
if (value.length === 0)
|
||||
return "Введите хотя бы одну пару координат";
|
||||
if (
|
||||
!value.every(
|
||||
(point: unknown) => Array.isArray(point) && point.length === 2
|
||||
)
|
||||
) {
|
||||
return "Каждая строка должна содержать две координаты";
|
||||
}
|
||||
if (
|
||||
!value.every((point: unknown[]) =>
|
||||
point.every(
|
||||
(coord: unknown) =>
|
||||
!isNaN(Number(coord)) && typeof coord === "number"
|
||||
)
|
||||
)
|
||||
) {
|
||||
return "Координаты должны быть числами";
|
||||
}
|
||||
return true;
|
||||
},
|
||||
})}
|
||||
error={!!(errors as any)?.path}
|
||||
helperText={(errors as any)?.path?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="text"
|
||||
label={"Координаты маршрута *"}
|
||||
name="path"
|
||||
placeholder="55.7558 37.6173
|
||||
55.7539 37.6208"
|
||||
multiline
|
||||
rows={4}
|
||||
sx={{
|
||||
marginBottom: 2,
|
||||
}}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("route_sys_number", {
|
||||
required: "Это поле является обязательным",
|
||||
})}
|
||||
error={!!(errors as any)?.route_sys_number}
|
||||
helperText={(errors as any)?.route_sys_number?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="number"
|
||||
label={"Системный номер маршрута *"}
|
||||
name="route_sys_number"
|
||||
/>
|
||||
|
||||
<Controller
|
||||
control={control}
|
||||
name="carrier_id"
|
||||
rules={{ required: "Это поле является обязательным" }}
|
||||
name="governor_appeal"
|
||||
defaultValue={null}
|
||||
render={({ field }) => (
|
||||
<Autocomplete
|
||||
{...carrierAutocompleteProps}
|
||||
{...governorAppealAutocompleteProps}
|
||||
value={
|
||||
carrierAutocompleteProps.options.find(
|
||||
governorAppealAutocompleteProps.options.find(
|
||||
(option) => option.id === field.value
|
||||
) || null
|
||||
) ?? null
|
||||
}
|
||||
onChange={(_, value) => {
|
||||
field.onChange(value?.id || "");
|
||||
field.onChange(value?.id ?? "");
|
||||
}}
|
||||
getOptionLabel={(item) => {
|
||||
return item ? item.short_name : "";
|
||||
return item ? item.heading : "";
|
||||
}}
|
||||
isOptionEqualToValue={(option, value) => {
|
||||
return option.id === value?.id;
|
||||
}}
|
||||
filterOptions={(options, { inputValue }) => {
|
||||
return options.filter((option) =>
|
||||
option.short_name
|
||||
option.heading
|
||||
.toLowerCase()
|
||||
.includes(inputValue.toLowerCase())
|
||||
);
|
||||
@ -92,242 +269,128 @@ export const RouteEdit = () => {
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
label="Выберите перевозчика"
|
||||
label="Обращение губернатора"
|
||||
margin="normal"
|
||||
variant="outlined"
|
||||
error={!!errors.carrier_id}
|
||||
helperText={(errors as any)?.carrier_id?.message}
|
||||
error={!!errors.arms}
|
||||
helperText={(errors as any)?.arms?.message}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("route_number", {
|
||||
required: "Это поле является обязательным",
|
||||
setValueAs: (value) => String(value),
|
||||
})}
|
||||
error={!!(errors as any)?.route_number}
|
||||
helperText={(errors as any)?.route_number?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="text"
|
||||
label={"Номер маршрута"}
|
||||
name="route_number"
|
||||
/>
|
||||
<Controller
|
||||
name="route_direction" // boolean
|
||||
control={control}
|
||||
defaultValue={false}
|
||||
render={({ field }: { field: any }) => (
|
||||
<FormControlLabel
|
||||
label="Прямой маршрут?"
|
||||
control={
|
||||
<Checkbox
|
||||
{...field}
|
||||
checked={field.value}
|
||||
onChange={(e) => field.onChange(e.target.checked)}
|
||||
/>
|
||||
}
|
||||
<TextField
|
||||
{...register("scale_min", {
|
||||
// required: 'Это поле является обязательным',
|
||||
setValueAs: (value) => Number(value),
|
||||
})}
|
||||
error={!!(errors as any)?.scale_min}
|
||||
helperText={(errors as any)?.scale_min?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="number"
|
||||
label={"Масштаб (мин)"}
|
||||
name="scale_min"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("scale_max", {
|
||||
// required: 'Это поле является обязательным',
|
||||
setValueAs: (value) => Number(value),
|
||||
})}
|
||||
error={!!(errors as any)?.scale_max}
|
||||
helperText={(errors as any)?.scale_max?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="number"
|
||||
label={"Масштаб (макс)"}
|
||||
name="scale_max"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("rotate", {
|
||||
// required: 'Это поле является обязательным',
|
||||
setValueAs: (value) => Number(value),
|
||||
})}
|
||||
error={!!(errors as any)?.rotate}
|
||||
helperText={(errors as any)?.rotate?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="number"
|
||||
label={"Поворот"}
|
||||
name="rotate"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("center_latitude", {
|
||||
// required: 'Это поле является обязательным',
|
||||
setValueAs: (value) => Number(value),
|
||||
})}
|
||||
error={!!(errors as any)?.center_latitude}
|
||||
helperText={(errors as any)?.center_latitude?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="number"
|
||||
label={"Центр. широта"}
|
||||
name="center_latitude"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("center_longitude", {
|
||||
// required: 'Это поле является обязательным',
|
||||
setValueAs: (value) => Number(value),
|
||||
})}
|
||||
error={!!(errors as any)?.center_longitude}
|
||||
helperText={(errors as any)?.center_longitude?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="number"
|
||||
label={"Центр. долгота"}
|
||||
name="center_longitude"
|
||||
/>
|
||||
|
||||
</Box>
|
||||
|
||||
{routeId && (
|
||||
<>
|
||||
<LinkedItems<StationItem>
|
||||
type="edit"
|
||||
parentId={routeId}
|
||||
parentResource="route"
|
||||
childResource="station"
|
||||
fields={stationFields}
|
||||
title="станции"
|
||||
dragAllowed={true}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
<Typography
|
||||
variant="caption"
|
||||
color="textSecondary"
|
||||
sx={{ mt: 0, mb: 1 }}
|
||||
>
|
||||
(Прямой / Обратный)
|
||||
</Typography>
|
||||
<LinkedItems<VehicleItem>
|
||||
type="edit"
|
||||
parentId={routeId}
|
||||
parentResource="route"
|
||||
childResource="vehicle"
|
||||
fields={vehicleFields}
|
||||
title="транспортные средства"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<TextField
|
||||
{...register("path", {
|
||||
required: "Это поле является обязательным",
|
||||
setValueAs: (value: string) => {
|
||||
try {
|
||||
const lines = value.trim().split("\n");
|
||||
return lines.map((line) => {
|
||||
const [lat, lon] = line
|
||||
.trim()
|
||||
.split(/[\s,]+/)
|
||||
.map(Number);
|
||||
return [lat, lon];
|
||||
});
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
validate: (value: unknown) => {
|
||||
if (!Array.isArray(value)) return "Неверный формат";
|
||||
if (value.length === 0)
|
||||
return "Введите хотя бы одну пару координат";
|
||||
if (
|
||||
!value.every(
|
||||
(point: unknown) => Array.isArray(point) && point.length === 2
|
||||
)
|
||||
) {
|
||||
return "Каждая строка должна содержать две координаты";
|
||||
}
|
||||
if (
|
||||
!value.every((point: unknown[]) =>
|
||||
point.every(
|
||||
(coord: unknown) =>
|
||||
!isNaN(Number(coord)) && typeof coord === "number"
|
||||
)
|
||||
)
|
||||
) {
|
||||
return "Координаты должны быть числами";
|
||||
}
|
||||
return true;
|
||||
},
|
||||
})}
|
||||
error={!!(errors as any)?.path}
|
||||
helperText={(errors as any)?.path?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="text"
|
||||
label={"Координаты маршрута *"}
|
||||
name="path"
|
||||
placeholder="55.7558 37.6173
|
||||
55.7539 37.6208"
|
||||
multiline
|
||||
rows={4}
|
||||
sx={{
|
||||
marginBottom: 2,
|
||||
}}
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("route_sys_number", {
|
||||
required: "Это поле является обязательным",
|
||||
})}
|
||||
error={!!(errors as any)?.route_sys_number}
|
||||
helperText={(errors as any)?.route_sys_number?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="number"
|
||||
label={"Системный номер маршрута *"}
|
||||
name="route_sys_number"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("governor_appeal", {
|
||||
// required: 'Это поле является обязательным',
|
||||
})}
|
||||
error={!!(errors as any)?.governor_appeal}
|
||||
helperText={(errors as any)?.governor_appeal?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="number"
|
||||
label={"Обращение губернатора"}
|
||||
name="governor_appeal"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("scale_min", {
|
||||
// required: 'Это поле является обязательным',
|
||||
setValueAs: (value) => Number(value),
|
||||
})}
|
||||
error={!!(errors as any)?.scale_min}
|
||||
helperText={(errors as any)?.scale_min?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="number"
|
||||
label={"Масштаб (мин)"}
|
||||
name="scale_min"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("scale_max", {
|
||||
// required: 'Это поле является обязательным',
|
||||
setValueAs: (value) => Number(value),
|
||||
})}
|
||||
error={!!(errors as any)?.scale_max}
|
||||
helperText={(errors as any)?.scale_max?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="number"
|
||||
label={"Масштаб (макс)"}
|
||||
name="scale_max"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("rotate", {
|
||||
// required: 'Это поле является обязательным',
|
||||
setValueAs: (value) => Number(value),
|
||||
})}
|
||||
error={!!(errors as any)?.rotate}
|
||||
helperText={(errors as any)?.rotate?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="number"
|
||||
label={"Поворот"}
|
||||
name="rotate"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("center_latitude", {
|
||||
// required: 'Это поле является обязательным',
|
||||
setValueAs: (value) => Number(value),
|
||||
})}
|
||||
error={!!(errors as any)?.center_latitude}
|
||||
helperText={(errors as any)?.center_latitude?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="number"
|
||||
label={"Центр. широта"}
|
||||
name="center_latitude"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
{...register("center_longitude", {
|
||||
// required: 'Это поле является обязательным',
|
||||
setValueAs: (value) => Number(value),
|
||||
})}
|
||||
error={!!(errors as any)?.center_longitude}
|
||||
helperText={(errors as any)?.center_longitude?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="number"
|
||||
label={"Центр. долгота"}
|
||||
name="center_longitude"
|
||||
/>
|
||||
<Box sx={{ display: 'flex', justifyContent: 'flex-start' }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={() => navigate(`/route-preview/${routeId}`)}
|
||||
>
|
||||
Предпросмотр маршрута
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
{routeId && (
|
||||
<>
|
||||
<LinkedItems<StationItem>
|
||||
type="edit"
|
||||
parentId={routeId}
|
||||
parentResource="route"
|
||||
childResource="station"
|
||||
fields={stationFields}
|
||||
title="станции"
|
||||
dragAllowed={true}
|
||||
/>
|
||||
|
||||
<LinkedItems<VehicleItem>
|
||||
type="edit"
|
||||
parentId={routeId}
|
||||
parentResource="route"
|
||||
childResource="vehicle"
|
||||
fields={vehicleFields}
|
||||
title="транспортные средства"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</Edit>
|
||||
);
|
||||
};
|
||||
|
@ -7,12 +7,15 @@ import {
|
||||
ShowButton,
|
||||
useDataGrid,
|
||||
} from "@refinedev/mui";
|
||||
import { Typography } from "@mui/material";
|
||||
import { Button, Typography } from "@mui/material";
|
||||
import React from "react";
|
||||
import MapIcon from '@mui/icons-material/Map';
|
||||
|
||||
import { localeText } from "../../locales/ru/localeText";
|
||||
import { useLink } from "@refinedev/core";
|
||||
|
||||
export const RouteList = () => {
|
||||
const Link = useLink();
|
||||
const { dataGridProps } = useDataGrid({
|
||||
resource: "route/",
|
||||
});
|
||||
@ -123,10 +126,10 @@ export const RouteList = () => {
|
||||
headerName: "Направление маршрута",
|
||||
type: "boolean",
|
||||
display: "flex",
|
||||
flex: 1,
|
||||
align: "left",
|
||||
headerAlign: "left",
|
||||
minWidth: 120,
|
||||
flex: 1,
|
||||
renderCell: ({ value }) => (
|
||||
<Typography style={{ color: value ? "#48989f" : "#7f6b58" }}>
|
||||
{value ? "прямое" : "обратное"}
|
||||
@ -139,7 +142,7 @@ export const RouteList = () => {
|
||||
cellClassName: "route-actions",
|
||||
align: "right",
|
||||
headerAlign: "center",
|
||||
minWidth: 120,
|
||||
minWidth: 160,
|
||||
display: "flex",
|
||||
sortable: false,
|
||||
filterable: false,
|
||||
@ -148,6 +151,11 @@ export const RouteList = () => {
|
||||
return (
|
||||
<>
|
||||
<EditButton hideText recordItemId={row.id} />
|
||||
<Link to={`/route-preview/${row.id}`}>
|
||||
<Button sx={{minWidth: 0}} >
|
||||
<MapIcon fontSize="small" />
|
||||
</Button>
|
||||
</Link>
|
||||
<ShowButton hideText recordItemId={row.id} />
|
||||
<DeleteButton
|
||||
hideText
|
||||
|
@ -5,6 +5,8 @@ import { LinkedItems } from "../../components/LinkedItems";
|
||||
import {
|
||||
StationItem,
|
||||
VehicleItem,
|
||||
SightItem,
|
||||
sightFields,
|
||||
stationFields,
|
||||
vehicleFields,
|
||||
} from "./types";
|
||||
@ -88,6 +90,15 @@ export const RouteShow = () => {
|
||||
fields={vehicleFields}
|
||||
title="транспортные средства"
|
||||
/>
|
||||
|
||||
<LinkedItems<SightItem>
|
||||
type="show"
|
||||
parentId={record.id}
|
||||
parentResource="route"
|
||||
childResource="sight"
|
||||
fields={sightFields}
|
||||
title="достопримечательности"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
@ -16,6 +16,15 @@ export type VehicleItem = {
|
||||
[key: string]: string | number;
|
||||
};
|
||||
|
||||
export type SightItem = {
|
||||
id: number;
|
||||
name: string;
|
||||
city: string;
|
||||
city_id: number;
|
||||
address: string;
|
||||
[key: string]: string | number;
|
||||
};
|
||||
|
||||
export type FieldType<T> = {
|
||||
label: string;
|
||||
data: keyof T;
|
||||
@ -27,6 +36,12 @@ export const stationFields: Array<FieldType<StationItem>> = [
|
||||
{ label: "Описание", data: "description" },
|
||||
];
|
||||
|
||||
export const sightFields: Array<FieldType<SightItem>> = [
|
||||
{ label: "Название", data: "name" },
|
||||
{ label: "Город", data: "city" },
|
||||
{ label: "Адрес", data: "address" },
|
||||
];
|
||||
|
||||
export const vehicleFields: Array<FieldType<VehicleItem>> = [
|
||||
{ label: "Бортовой номер", data: "tail_number" },
|
||||
{
|
||||
|
@ -2,13 +2,10 @@ import { Autocomplete, Box, TextField, Typography, Paper } from "@mui/material";
|
||||
import { Create, useAutocomplete } from "@refinedev/mui";
|
||||
import { useForm } from "@refinedev/react-hook-form";
|
||||
import { Controller } from "react-hook-form";
|
||||
import { cityStore } from "../../store/CityStore";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { TOKEN_KEY } from "../../authProvider";
|
||||
import { TOKEN_KEY } from "@providers";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import Cookies from "js-cookie";
|
||||
import { useLocation } from "react-router";
|
||||
import { languageStore } from "../../store/LanguageStore";
|
||||
import { Languages, languageStore, cityStore } from "@stores";
|
||||
export const SightCreate = observer(() => {
|
||||
const { language, setLanguageAction } = languageStore;
|
||||
const [sightData, setSightData] = useState({
|
||||
@ -27,7 +24,7 @@ export const SightCreate = observer(() => {
|
||||
});
|
||||
|
||||
// Состояния для предпросмотра
|
||||
const handleLanguageChange = (lang: string) => {
|
||||
const handleLanguageChange = (lang: Languages) => {
|
||||
setSightData((prevData) => ({
|
||||
...prevData,
|
||||
[language]: {
|
||||
|
@ -16,15 +16,14 @@ import React, { useState, useEffect } from "react";
|
||||
import { LinkedItems } from "../../components/LinkedItems";
|
||||
import { CreateSightArticle } from "../../components/CreateSightArticle";
|
||||
import { ArticleItem, articleFields } from "./types";
|
||||
import { TOKEN_KEY } from "../../authProvider";
|
||||
import { TOKEN_KEY } from "@providers";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
import { languageStore } from "../../store/LanguageStore";
|
||||
import { Languages, languageStore, articleStore } from "@stores";
|
||||
import axios from "axios";
|
||||
import { LanguageSwitch } from "../../components/LanguageSwitch/index";
|
||||
import { ReactPhotoSphereViewer } from "react-photo-sphere-viewer";
|
||||
import { ModelViewer } from "../media/ModelViewer";
|
||||
import { articleStore } from "../../store/ArticleStore";
|
||||
import { ModelViewer } from "@ui";
|
||||
import { ArticleEditModal } from "../../components/modals/ArticleEditModal/index";
|
||||
|
||||
function a11yProps(index: number) {
|
||||
@ -132,12 +131,7 @@ export const SightEdit = observer(() => {
|
||||
operator: "contains",
|
||||
value,
|
||||
},
|
||||
],
|
||||
meta: {
|
||||
headers: {
|
||||
"Accept-Language": language,
|
||||
},
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
const { autocompleteProps: articleAutocompleteProps } = useAutocomplete({
|
||||
@ -154,13 +148,7 @@ export const SightEdit = observer(() => {
|
||||
operator: "contains",
|
||||
value,
|
||||
},
|
||||
],
|
||||
|
||||
meta: {
|
||||
headers: {
|
||||
"Accept-Language": language,
|
||||
},
|
||||
},
|
||||
]
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@ -428,7 +416,7 @@ export const SightEdit = observer(() => {
|
||||
address: watch("address") ?? "",
|
||||
},
|
||||
}));
|
||||
setLanguageAction(lang);
|
||||
setLanguageAction(lang as Languages);
|
||||
};
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
@ -444,8 +432,8 @@ export const SightEdit = observer(() => {
|
||||
onChange={(_, newValue) => setTabValue(newValue)}
|
||||
aria-label="basic tabs example"
|
||||
>
|
||||
<Tab label="Левая статья" {...a11yProps(1)} />
|
||||
<Tab label="Правая статья" {...a11yProps(2)} />
|
||||
<Tab label="Левый виджет" {...a11yProps(1)} />
|
||||
<Tab label="Правый виджет" {...a11yProps(2)} />
|
||||
<Tab label="Основная информация" {...a11yProps(3)} />
|
||||
</Tabs>
|
||||
</Box>
|
||||
@ -1189,7 +1177,7 @@ export const SightEdit = observer(() => {
|
||||
/>
|
||||
)}
|
||||
|
||||
{mediaFile && mediaFile.src && mediaFile.media_type == 5 && (
|
||||
{mediaFile?.src && mediaFile.media_type == 5 && (
|
||||
<ReactPhotoSphereViewer
|
||||
src={mediaFile.src}
|
||||
height={"300px"}
|
||||
@ -1217,9 +1205,8 @@ export const SightEdit = observer(() => {
|
||||
}}
|
||||
>
|
||||
{previewSelected &&
|
||||
previewMedia &&
|
||||
previewMedia.src &&
|
||||
previewMedia.media_type === 1 && (
|
||||
previewMedia?.src &&
|
||||
previewMedia?.media_type === 1 && (
|
||||
<img
|
||||
src={previewMedia.src}
|
||||
alt={previewMedia.filename}
|
||||
@ -1233,8 +1220,7 @@ export const SightEdit = observer(() => {
|
||||
)}
|
||||
|
||||
{previewSelected &&
|
||||
previewMedia &&
|
||||
previewMedia.media_type === 2 && (
|
||||
previewMedia?.media_type === 2 && (
|
||||
<video
|
||||
src={previewMedia.src}
|
||||
style={{
|
||||
@ -1249,8 +1235,7 @@ export const SightEdit = observer(() => {
|
||||
/>
|
||||
)}
|
||||
{previewSelected &&
|
||||
previewMedia &&
|
||||
previewMedia.media_type === 3 && (
|
||||
previewMedia?.media_type === 3 && (
|
||||
<img
|
||||
src={previewMedia.src}
|
||||
alt={previewMedia.filename}
|
||||
@ -1263,8 +1248,7 @@ export const SightEdit = observer(() => {
|
||||
/>
|
||||
)}
|
||||
{previewSelected &&
|
||||
previewMedia &&
|
||||
previewMedia.media_type === 4 && (
|
||||
previewMedia?.media_type === 4 && (
|
||||
<img
|
||||
src={previewMedia.src}
|
||||
alt={previewMedia.filename}
|
||||
@ -1278,9 +1262,8 @@ export const SightEdit = observer(() => {
|
||||
)}
|
||||
|
||||
{previewSelected &&
|
||||
previewMedia &&
|
||||
previewMedia.src &&
|
||||
previewMedia.media_type == 5 && (
|
||||
previewMedia?.src &&
|
||||
previewMedia?.media_type == 5 && (
|
||||
<ReactPhotoSphereViewer
|
||||
src={previewMedia.src}
|
||||
height={"300px"}
|
||||
@ -1289,8 +1272,7 @@ export const SightEdit = observer(() => {
|
||||
)}
|
||||
|
||||
{previewSelected &&
|
||||
previewMedia &&
|
||||
previewMedia.media_type === 6 && (
|
||||
previewMedia?.media_type === 6 && (
|
||||
<ModelViewer height={"400px"} fileUrl={previewMedia.src} />
|
||||
)}
|
||||
|
||||
|
@ -4,6 +4,8 @@ import { useForm } from "@refinedev/react-hook-form";
|
||||
import { Controller } from "react-hook-form";
|
||||
|
||||
import { VEHICLE_TYPES } from "../../lib/constants";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { languageStore, META_LANGUAGE } from "@stores";
|
||||
|
||||
type VehicleFormValues = {
|
||||
tail_number: number;
|
||||
@ -11,13 +13,16 @@ type VehicleFormValues = {
|
||||
city_id: number;
|
||||
};
|
||||
|
||||
export const VehicleEdit = () => {
|
||||
export const VehicleEdit = observer(() => {
|
||||
const { language } = languageStore;
|
||||
const {
|
||||
saveButtonProps,
|
||||
register,
|
||||
control,
|
||||
formState: { errors },
|
||||
} = useForm<VehicleFormValues>({});
|
||||
} = useForm<VehicleFormValues>({
|
||||
refineCoreProps: META_LANGUAGE(language)
|
||||
});
|
||||
|
||||
const { autocompleteProps: carrierAutocompleteProps } = useAutocomplete({
|
||||
resource: "carrier",
|
||||
@ -136,4 +141,4 @@ export const VehicleEdit = () => {
|
||||
</Box>
|
||||
</Edit>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
import dataProvider from "@refinedev/simple-rest";
|
||||
|
||||
import { TOKEN_KEY } from "../authProvider";
|
||||
import { TOKEN_KEY } from "@providers";
|
||||
|
||||
import axios from "axios";
|
||||
import { languageStore } from "../store/LanguageStore";
|
||||
|
@ -2,7 +2,7 @@ import i18n from 'i18next'
|
||||
import {initReactI18next} from 'react-i18next'
|
||||
import {I18nProvider} from '@refinedev/core'
|
||||
|
||||
import translationRU from './locales/ru/translation.json'
|
||||
import translationRU from '../locales/ru/translation.json'
|
||||
|
||||
i18n.use(initReactI18next).init({
|
||||
resources: {
|
3
src/providers/index.ts
Normal file
3
src/providers/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './data'
|
||||
export * from './authProvider'
|
||||
export * from './i18nProvider'
|
@ -1,15 +1,34 @@
|
||||
import { makeAutoObservable } from "mobx";
|
||||
|
||||
export type Languages = "en" | "ru" | "zh";
|
||||
class LanguageStore {
|
||||
language = "ru";
|
||||
language: Languages = "ru";
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
setLanguageAction = (language: string) => {
|
||||
setLanguageAction = (language: Languages) => {
|
||||
this.language = language;
|
||||
};
|
||||
}
|
||||
|
||||
export const languageStore = new LanguageStore();
|
||||
|
||||
export const META_LANGUAGE = (language: Languages) => {
|
||||
return {
|
||||
meta: {
|
||||
headers: {
|
||||
"Accept-Language": language,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export const EVERY_LANGUAGE = (data: any) => {
|
||||
return {
|
||||
"en": data,
|
||||
"ru": data,
|
||||
"zh": data,
|
||||
}
|
||||
}
|
4
src/store/index.ts
Normal file
4
src/store/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './ArticleStore';
|
||||
export * from './CityStore';
|
||||
export * from './LanguageStore';
|
||||
export * from './StationStore';
|
@ -17,11 +17,12 @@
|
||||
"jsx": "react-jsx",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@mt/common-types": ["src/preview/types"],
|
||||
"@mt/components": ["src/preview/components"],
|
||||
"@mt/i18n": ["src/preview/i18n"],
|
||||
"@mt/widgets": ["src/preview/widgets"],
|
||||
"@mt/utils": ["src/preview/utils"]
|
||||
"@stores": ["./src/store"],
|
||||
"@ui": ["./src/components/ui"],
|
||||
"@providers": ["./src/providers"],
|
||||
"@lib": ["./src/lib"],
|
||||
"@components": ["./src/components"],
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src", "svg.d.ts"],
|
||||
|
@ -7,11 +7,12 @@ export default defineConfig({
|
||||
plugins: [svgr(), react()],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@mt/common-types": path.resolve(__dirname, "./src/preview/types"),
|
||||
"@mt/components": path.resolve(__dirname, "./src/preview/components"),
|
||||
"@mt/i18n": path.resolve(__dirname, "./src/preview/i18n"),
|
||||
"@mt/widgets": path.resolve(__dirname, "./src/preview/widgets"),
|
||||
"@mt/utils": path.resolve(__dirname, "./src/preview/utils"),
|
||||
"@ui": path.resolve(__dirname, "./src/components/ui"),
|
||||
"@stores": path.resolve(__dirname, "./src/store"),
|
||||
"@providers": path.resolve(__dirname, "./src/providers"),
|
||||
"@lib": path.resolve(__dirname, "./src/lib"),
|
||||
"@components": path.resolve(__dirname, "./src/components"),
|
||||
"@": path.resolve(__dirname, "./src/"),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
273
yarn.lock
273
yarn.lock
@ -453,10 +453,110 @@
|
||||
resolved "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz"
|
||||
integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==
|
||||
|
||||
"@esbuild/win32-x64@^0.25.3":
|
||||
version "0.25.3"
|
||||
resolved "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.3.tgz"
|
||||
integrity sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg==
|
||||
"@esbuild/android-arm@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz"
|
||||
integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==
|
||||
|
||||
"@esbuild/android-arm64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz"
|
||||
integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==
|
||||
|
||||
"@esbuild/android-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz"
|
||||
integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==
|
||||
|
||||
"@esbuild/darwin-arm64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz"
|
||||
integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==
|
||||
|
||||
"@esbuild/darwin-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz"
|
||||
integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==
|
||||
|
||||
"@esbuild/freebsd-arm64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz"
|
||||
integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==
|
||||
|
||||
"@esbuild/freebsd-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz"
|
||||
integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==
|
||||
|
||||
"@esbuild/linux-arm@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz"
|
||||
integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==
|
||||
|
||||
"@esbuild/linux-arm64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz"
|
||||
integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==
|
||||
|
||||
"@esbuild/linux-ia32@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz"
|
||||
integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==
|
||||
|
||||
"@esbuild/linux-loong64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz"
|
||||
integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==
|
||||
|
||||
"@esbuild/linux-mips64el@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz"
|
||||
integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==
|
||||
|
||||
"@esbuild/linux-ppc64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz"
|
||||
integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==
|
||||
|
||||
"@esbuild/linux-riscv64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz"
|
||||
integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==
|
||||
|
||||
"@esbuild/linux-s390x@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz"
|
||||
integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==
|
||||
|
||||
"@esbuild/linux-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz"
|
||||
integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==
|
||||
|
||||
"@esbuild/netbsd-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz"
|
||||
integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==
|
||||
|
||||
"@esbuild/openbsd-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz"
|
||||
integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==
|
||||
|
||||
"@esbuild/sunos-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz"
|
||||
integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==
|
||||
|
||||
"@esbuild/win32-arm64@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz"
|
||||
integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==
|
||||
|
||||
"@esbuild/win32-ia32@0.18.20":
|
||||
version "0.18.20"
|
||||
resolved "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz"
|
||||
integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==
|
||||
|
||||
"@esbuild/win32-x64@0.18.20":
|
||||
version "0.18.20"
|
||||
@ -758,31 +858,12 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.27.0"
|
||||
|
||||
"@mui/types@^7.4.1":
|
||||
version "7.4.1"
|
||||
resolved "https://registry.npmjs.org/@mui/types/-/types-7.4.1.tgz"
|
||||
integrity sha512-gUL8IIAI52CRXP/MixT1tJKt3SI6tVv4U/9soFsTtAsHzaJQptZ42ffdHZV3niX1ei0aUgMvOxBBN0KYqdG39g==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.27.0"
|
||||
|
||||
"@mui/types@~7.2.24":
|
||||
version "7.2.24"
|
||||
resolved "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz"
|
||||
integrity sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==
|
||||
|
||||
"@mui/utils@^5.16.6 || ^6.0.0 || ^7.0.0":
|
||||
version "7.0.2"
|
||||
resolved "https://registry.npmjs.org/@mui/utils/-/utils-7.0.2.tgz"
|
||||
integrity sha512-72gcuQjPzhj/MLmPHLCgZjy2VjOH4KniR/4qRtXTTXIEwbkgcN+Y5W/rC90rWtMmZbjt9svZev/z+QHUI4j74w==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.27.0"
|
||||
"@mui/types" "^7.4.1"
|
||||
"@types/prop-types" "^15.7.14"
|
||||
clsx "^2.1.1"
|
||||
prop-types "^15.8.1"
|
||||
react-is "^19.1.0"
|
||||
|
||||
"@mui/utils@^6.0.0-alpha.1", "@mui/utils@^6.0.0-alpha.3", "@mui/utils@^6.4.9":
|
||||
"@mui/utils@^5.16.6 || ^6.0.0 || ^7.0.0", "@mui/utils@^6.0.0-alpha.1", "@mui/utils@^6.0.0-alpha.3", "@mui/utils@^6.4.9":
|
||||
version "6.4.9"
|
||||
resolved "https://registry.npmjs.org/@mui/utils/-/utils-6.4.9.tgz"
|
||||
integrity sha512-Y12Q9hbK9g+ZY0T3Rxrx9m2m10gaphDuUMgWxyV5kNJevVxXYCLclYUCC9vXaIk1/NdNDTcW2Yfr2OGvNFNmHg==
|
||||
@ -1470,14 +1551,7 @@
|
||||
resolved "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz"
|
||||
integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==
|
||||
|
||||
"@types/node@*":
|
||||
version "22.15.2"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-22.15.2.tgz"
|
||||
integrity sha512-uKXqKN9beGoMdBfcaTY1ecwz6ctxuJAcUlwE55938g0ZJ8lRxwAZqRz2AJ4pzpt5dHdTPMB863UZ0ESiFUcP7A==
|
||||
dependencies:
|
||||
undici-types "~6.21.0"
|
||||
|
||||
"@types/node@^18.16.2":
|
||||
"@types/node@*", "@types/node@^18.16.2":
|
||||
version "18.19.87"
|
||||
resolved "https://registry.npmjs.org/@types/node/-/node-18.19.87.tgz"
|
||||
integrity sha512-OIAAu6ypnVZHmsHCeJ+7CCSub38QNBS9uceMQeg7K5Ur0Jr+wG9wEOEvvMbhp09pxD5czIUy/jND7s7Tb6Nw7A==
|
||||
@ -1541,14 +1615,7 @@
|
||||
resolved "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.12.tgz"
|
||||
integrity sha512-8TV6R3h2j7a91c+1DXdJi3Syo69zzIZbz7Lg5tORM5LEJG7X/E6a1V3drRyBRZq7/utz7A+c4OgYLiLcYGHG6w==
|
||||
|
||||
"@types/react@*":
|
||||
version "19.1.2"
|
||||
resolved "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz"
|
||||
integrity sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==
|
||||
dependencies:
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/react@^18.0.0":
|
||||
"@types/react@*", "@types/react@^18.0.0", "@types/react@16 || 17 || 18 || 19":
|
||||
version "18.3.20"
|
||||
resolved "https://registry.npmjs.org/@types/react/-/react-18.3.20.tgz"
|
||||
integrity sha512-IPaCZN7PShZK/3t6Q87pfTkRm6oLTd4vztyoj+cbHUF1g3FfVb2tFIL79uCRKEfv16AhqDMBywP2VW3KIZUvcg==
|
||||
@ -1556,13 +1623,6 @@
|
||||
"@types/prop-types" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/react@16 || 17 || 18 || 19":
|
||||
version "19.1.2"
|
||||
resolved "https://registry.npmjs.org/@types/react/-/react-19.1.2.tgz"
|
||||
integrity sha512-oxLPMytKchWGbnQM9O7D67uPa9paTNxO7jVoNMXgkkErULBPhPARCfkKL9ytcIJJRGjbsVwW4ugJzyFFvm/Tiw==
|
||||
dependencies:
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/semver@^7.3.12":
|
||||
version "7.7.0"
|
||||
resolved "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz"
|
||||
@ -1597,12 +1657,7 @@
|
||||
resolved "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz"
|
||||
integrity sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==
|
||||
|
||||
"@types/unist@^2", "@types/unist@^2.0.0", "@types/unist@^2.0.3":
|
||||
version "2.0.11"
|
||||
resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz"
|
||||
integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==
|
||||
|
||||
"@types/unist@^2.0.2":
|
||||
"@types/unist@^2", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3":
|
||||
version "2.0.11"
|
||||
resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz"
|
||||
integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==
|
||||
@ -2959,7 +3014,12 @@ estraverse@^4.1.1:
|
||||
resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz"
|
||||
integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
|
||||
|
||||
estraverse@^5.1.0, estraverse@^5.2.0:
|
||||
estraverse@^5.1.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
|
||||
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
||||
|
||||
estraverse@^5.2.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
|
||||
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
||||
@ -3282,6 +3342,11 @@ fs.realpath@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
|
||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||
|
||||
fsevents@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
|
||||
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
|
||||
|
||||
function-bind@^1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
|
||||
@ -4023,7 +4088,12 @@ kind-of@^5.0.2:
|
||||
resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz"
|
||||
integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
|
||||
|
||||
kind-of@^6.0.0, kind-of@^6.0.2:
|
||||
kind-of@^6.0.0:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
|
||||
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
||||
|
||||
kind-of@^6.0.2:
|
||||
version "6.0.3"
|
||||
resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
|
||||
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
|
||||
@ -4359,7 +4429,19 @@ mdast-util-to-hast@^13.0.0:
|
||||
unist-util-visit "^5.0.0"
|
||||
vfile "^6.0.0"
|
||||
|
||||
mdast-util-to-markdown@^0.6.0, mdast-util-to-markdown@^0.6.1, mdast-util-to-markdown@~0.6.0:
|
||||
mdast-util-to-markdown@^0.6.0:
|
||||
version "0.6.5"
|
||||
resolved "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz"
|
||||
integrity sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==
|
||||
dependencies:
|
||||
"@types/unist" "^2.0.0"
|
||||
longest-streak "^2.0.0"
|
||||
mdast-util-to-string "^2.0.0"
|
||||
parse-entities "^2.0.0"
|
||||
repeat-string "^1.0.0"
|
||||
zwitch "^1.0.0"
|
||||
|
||||
mdast-util-to-markdown@^0.6.1:
|
||||
version "0.6.5"
|
||||
resolved "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz"
|
||||
integrity sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==
|
||||
@ -4386,6 +4468,18 @@ mdast-util-to-markdown@^2.0.0:
|
||||
unist-util-visit "^5.0.0"
|
||||
zwitch "^2.0.0"
|
||||
|
||||
mdast-util-to-markdown@~0.6.0:
|
||||
version "0.6.5"
|
||||
resolved "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz"
|
||||
integrity sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==
|
||||
dependencies:
|
||||
"@types/unist" "^2.0.0"
|
||||
longest-streak "^2.0.0"
|
||||
mdast-util-to-string "^2.0.0"
|
||||
parse-entities "^2.0.0"
|
||||
repeat-string "^1.0.0"
|
||||
zwitch "^1.0.0"
|
||||
|
||||
mdast-util-to-string@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz"
|
||||
@ -4659,7 +4753,7 @@ micromark-util-types@^2.0.0:
|
||||
resolved "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz"
|
||||
integrity sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==
|
||||
|
||||
micromark@^2.11.3, micromark@~2.11.0, micromark@~2.11.3:
|
||||
micromark@^2.11.3:
|
||||
version "2.11.4"
|
||||
resolved "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz"
|
||||
integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==
|
||||
@ -4690,6 +4784,22 @@ micromark@^4.0.0:
|
||||
micromark-util-symbol "^2.0.0"
|
||||
micromark-util-types "^2.0.0"
|
||||
|
||||
micromark@~2.11.0:
|
||||
version "2.11.4"
|
||||
resolved "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz"
|
||||
integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==
|
||||
dependencies:
|
||||
debug "^4.0.0"
|
||||
parse-entities "^2.0.0"
|
||||
|
||||
micromark@~2.11.3:
|
||||
version "2.11.4"
|
||||
resolved "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz"
|
||||
integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==
|
||||
dependencies:
|
||||
debug "^4.0.0"
|
||||
parse-entities "^2.0.0"
|
||||
|
||||
micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz"
|
||||
@ -4978,7 +5088,14 @@ os-tmpdir@~1.0.2:
|
||||
resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz"
|
||||
integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==
|
||||
|
||||
p-limit@^2.0.0, p-limit@^2.2.0:
|
||||
p-limit@^2.0.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
|
||||
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
|
||||
dependencies:
|
||||
p-try "^2.0.0"
|
||||
|
||||
p-limit@^2.2.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
|
||||
integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
|
||||
@ -5456,7 +5573,7 @@ react-is@^17.0.2:
|
||||
resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
|
||||
integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
|
||||
|
||||
react-is@^19.0.0, react-is@^19.1.0:
|
||||
react-is@^19.0.0:
|
||||
version "19.1.0"
|
||||
resolved "https://registry.npmjs.org/react-is/-/react-is-19.1.0.tgz"
|
||||
integrity sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==
|
||||
@ -5636,7 +5753,14 @@ redeyed@~2.1.0:
|
||||
dependencies:
|
||||
esprima "~4.0.0"
|
||||
|
||||
redux@^4.0.0, redux@^4.0.4:
|
||||
redux@^4.0.0:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz"
|
||||
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.9.2"
|
||||
|
||||
redux@^4.0.4:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz"
|
||||
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
|
||||
@ -5857,18 +5981,18 @@ semver@^6.3.1:
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz"
|
||||
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
|
||||
|
||||
semver@^7.1.1, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3:
|
||||
version "7.7.1"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz"
|
||||
integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==
|
||||
|
||||
semver@7.5.2:
|
||||
semver@^7.1.1, semver@^7.3.5, semver@^7.3.7, semver@7.5.2:
|
||||
version "7.5.2"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz"
|
||||
integrity sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==
|
||||
dependencies:
|
||||
lru-cache "^6.0.0"
|
||||
|
||||
semver@^7.5.3:
|
||||
version "7.7.1"
|
||||
resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz"
|
||||
integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==
|
||||
|
||||
send@0.19.0:
|
||||
version "0.19.0"
|
||||
resolved "https://registry.npmjs.org/send/-/send-0.19.0.tgz"
|
||||
@ -6015,7 +6139,17 @@ source-map@^0.5.7:
|
||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
|
||||
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
|
||||
|
||||
source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
|
||||
source-map@^0.6.0:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
source-map@^0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
source-map@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
@ -6444,11 +6578,6 @@ undici-types@~5.26.4:
|
||||
resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz"
|
||||
integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
|
||||
|
||||
undici-types@~6.21.0:
|
||||
version "6.21.0"
|
||||
resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz"
|
||||
integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==
|
||||
|
||||
unicode-emoji-modifier-base@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz"
|
||||
|
Loading…
Reference in New Issue
Block a user