feat: Add edit/create/list sight page
This commit is contained in:
@@ -1,60 +1,269 @@
|
||||
import { TextField } from "@mui/material";
|
||||
import { BackButton, TabPanel } from "@shared";
|
||||
import { Box, Button, TextField, Paper, Typography } from "@mui/material";
|
||||
import { BackButton, Sight, TabPanel } from "@shared";
|
||||
import { ReactMarkdownComponent, ReactMarkdownEditor } from "@widgets";
|
||||
import { Trash2 } from "lucide-react";
|
||||
import { Unlink } from "lucide-react";
|
||||
import { Unlink, Trash2, ImagePlus } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
// Мокап данных для левой статьи
|
||||
const mockLeftArticle = {
|
||||
title: "История основания",
|
||||
markdownContent: `## Заголовок статьи H2
|
||||
|
||||
Какой-то **текст** для левой статьи.
|
||||
Можно использовать *markdown*.
|
||||
|
||||
- Список 1
|
||||
- Список 2
|
||||
|
||||
[Ссылка на Яндекс](https://ya.ru)
|
||||
`,
|
||||
media: null, // null или URL/ID медиа
|
||||
};
|
||||
|
||||
export const LeftWidgetTab = ({
|
||||
value,
|
||||
index,
|
||||
data,
|
||||
}: {
|
||||
value: number;
|
||||
index: number;
|
||||
data?: Sight;
|
||||
}) => {
|
||||
const [leftArticleData, setLeftArticleData] = useState(" ");
|
||||
const [articleTitle, setArticleTitle] = useState(mockLeftArticle.title);
|
||||
const [markdownContent, setMarkdownContent] = useState(
|
||||
mockLeftArticle.markdownContent
|
||||
);
|
||||
const [articleMedia, setArticleMedia] = useState<string | null>(
|
||||
mockLeftArticle.media
|
||||
); // Для превью медиа
|
||||
|
||||
const handleSelectMediaForArticle = () => {
|
||||
// Логика открытия модального окна для выбора медиа для статьи
|
||||
console.log("Select media fo r left article");
|
||||
// Для примера, установим моковое изображение
|
||||
// setArticleMedia("https://via.placeholder.com/350x200.png?text=Article+Media");
|
||||
};
|
||||
|
||||
const handleUnlinkArticle = () => {
|
||||
console.log("Unlink left article");
|
||||
};
|
||||
|
||||
const handleDeleteArticle = () => {
|
||||
console.log("Delete left article");
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
console.log("Saving left widget...");
|
||||
};
|
||||
|
||||
return (
|
||||
<TabPanel value={value} index={index}>
|
||||
<div className="flex flex-col gap-5">
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 3,
|
||||
paddingBottom: "70px",
|
||||
position: "relative",
|
||||
}}
|
||||
>
|
||||
<BackButton />
|
||||
|
||||
<div className="flex items-center justify-between px-5 h-14 rounded-md border">
|
||||
<p className="text-2xl">Левая статья</p>
|
||||
<div className="flex items-center gap-5">
|
||||
<button className="flex items-center gap-2 border border-gray-300 bg-blue-100 rounded-md px-2 py-1">
|
||||
<Paper
|
||||
elevation={2}
|
||||
sx={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
paddingX: 2.5,
|
||||
paddingY: 1.5,
|
||||
borderRadius: 2,
|
||||
border: "1px solid",
|
||||
borderColor: "divider",
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6">Левая статья</Typography>
|
||||
<Box sx={{ display: "flex", alignItems: "center", gap: 2 }}>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
startIcon={<Unlink size={18} />}
|
||||
onClick={handleUnlinkArticle}
|
||||
size="small"
|
||||
>
|
||||
Открепить
|
||||
<Unlink />
|
||||
</button>
|
||||
<button className="flex items-center gap-2 border border-gray-300 bg-red-100 rounded-md px-2 py-1">
|
||||
</Button>
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="error"
|
||||
startIcon={<Trash2 size={18} />}
|
||||
onClick={handleDeleteArticle}
|
||||
size="small"
|
||||
>
|
||||
Удалить
|
||||
<Trash2 />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-5">
|
||||
<div className="flex flex-col gap-5 flex-1">
|
||||
<TextField sx={{ width: "30%" }} label="Название" />
|
||||
</Button>
|
||||
</Box>
|
||||
</Paper>
|
||||
|
||||
<ReactMarkdownEditor
|
||||
value={leftArticleData}
|
||||
onChange={setLeftArticleData}
|
||||
<Box sx={{ display: "flex", gap: 3, flexGrow: 1 }}>
|
||||
{/* Левая колонка: Редактирование */}
|
||||
<Box
|
||||
sx={{ flex: 2, display: "flex", flexDirection: "column", gap: 2 }}
|
||||
>
|
||||
<TextField
|
||||
label="Название информации" // На макете "Название" для статьи, потом "Информация"
|
||||
value={articleTitle}
|
||||
onChange={(e) => setArticleTitle(e.target.value)}
|
||||
variant="outlined"
|
||||
sx={{ width: "100%" }} // Примерная ширина как на макете
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<p>Предпросмотр</p>
|
||||
<div className="bg-yellow-200 w-[350px] h-full">
|
||||
<div className="bg-red-100 w-full h-[200px]"></div>
|
||||
<div className="bg-blue-100 w-full text-lg p-3"></div>
|
||||
<div className="bg-green-100 p-3 prose max-w-none">
|
||||
<ReactMarkdownComponent value={leftArticleData} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button className="bg-green-400 w-min ml-auto text-white py-2 rounded-2xl px-4">
|
||||
Сохранить
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Редактор Markdown */}
|
||||
<Typography variant="subtitle2" sx={{ mt: 1 }}>
|
||||
Текст
|
||||
</Typography>
|
||||
<ReactMarkdownEditor
|
||||
value={markdownContent}
|
||||
onChange={setMarkdownContent}
|
||||
/>
|
||||
|
||||
{/* Блок МЕДИА для статьи */}
|
||||
<Paper elevation={1} sx={{ padding: 2, mt: 1 }}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
МЕДИА
|
||||
</Typography>
|
||||
{/* Здесь будет UI для управления медиа статьи */}
|
||||
{articleMedia ? (
|
||||
<Box sx={{ mb: 1 }}>
|
||||
<img
|
||||
src={articleMedia}
|
||||
alt="Article media"
|
||||
style={{
|
||||
maxWidth: "100%",
|
||||
maxHeight: "150px",
|
||||
borderRadius: "4px",
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
) : (
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: 100,
|
||||
backgroundColor: "grey.100",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
borderRadius: 1,
|
||||
mb: 1,
|
||||
border: "2px dashed",
|
||||
borderColor: "grey.300",
|
||||
}}
|
||||
>
|
||||
<Typography color="text.secondary">Нет медиа</Typography>
|
||||
</Box>
|
||||
)}
|
||||
<Button variant="contained" onClick={handleSelectMediaForArticle}>
|
||||
Выбрать/Загрузить медиа
|
||||
</Button>
|
||||
</Paper>
|
||||
</Box>
|
||||
|
||||
{/* Правая колонка: Предпросмотр */}
|
||||
<Box sx={{ display: "flex", flexDirection: "column", gap: 1.5 }}>
|
||||
<Typography variant="h6">Предпросмотр</Typography>
|
||||
<Paper
|
||||
elevation={3}
|
||||
sx={{
|
||||
width: "100%", // Ширина как на макете ~350px
|
||||
minWidth: 320,
|
||||
maxWidth: 400,
|
||||
height: "auto", // Автоматическая высота или можно задать minHeight
|
||||
minHeight: 500,
|
||||
backgroundColor: "#877361", // Желтоватый фон
|
||||
overflowY: "auto",
|
||||
padding: 0,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
{/* Медиа в превью (если есть) */}
|
||||
{articleMedia && (
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: 200,
|
||||
backgroundColor: "grey.300",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={articleMedia}
|
||||
alt="Превью медиа"
|
||||
style={{
|
||||
objectFit: "cover",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
{!articleMedia && (
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%",
|
||||
height: 200,
|
||||
backgroundColor: "grey.300",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<ImagePlus size={48} color="grey" />
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Заголовок в превью */}
|
||||
<Box
|
||||
sx={{
|
||||
backgroundColor: "#877361",
|
||||
color: "white",
|
||||
padding: 1.5,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="h5"
|
||||
component="h2"
|
||||
sx={{ wordBreak: "break-word" }}
|
||||
>
|
||||
{articleTitle || "Название информации"}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
{/* Текст статьи в превью */}
|
||||
<Box
|
||||
sx={{
|
||||
padding: 2,
|
||||
backgroundColor: "#877361",
|
||||
flexGrow: 1,
|
||||
color: "white",
|
||||
"& img": { maxWidth: "100%" },
|
||||
}}
|
||||
>
|
||||
<ReactMarkdownComponent value={markdownContent} />
|
||||
</Box>
|
||||
</Paper>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
<Box sx={{ position: "absolute", bottom: 0, right: 0, padding: 2 }}>
|
||||
<Button variant="contained" color="success" onClick={handleSave}>
|
||||
Сохранить
|
||||
</Button>
|
||||
</Box>
|
||||
</Box>
|
||||
</TabPanel>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user