feat: Add edit/create/list sight page

This commit is contained in:
2025-05-29 16:25:18 +03:00
parent 17de7e495f
commit e2ca6b4132
25 changed files with 1519 additions and 240 deletions

View File

@@ -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>
);
};