feat: Refactor old code with delete modal and icons for buttons

This commit is contained in:
Илья Куприец 2025-06-04 20:19:06 +03:00
parent 078f051e8a
commit 89488d9921
27 changed files with 2070 additions and 476 deletions

1303
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -12,6 +12,7 @@
"dependencies": {
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@hello-pangea/dnd": "^18.0.1",
"@mui/material": "^7.1.0",
"@photo-sphere-viewer/core": "^5.13.2",
"@react-three/drei": "^10.1.2",

View File

@ -1,7 +1,5 @@
import * as React from "react";
import { BrowserRouter } from "react-router-dom";
import { Router } from "./router";
import { CustomTheme } from "@shared";
import { ThemeProvider } from "@mui/material/styles";
@ -10,8 +8,7 @@ import { ToastContainer } from "react-toastify";
export const App: React.FC = () => (
<ThemeProvider theme={CustomTheme.Light}>
<ToastContainer />
<BrowserRouter>
<Router />
</BrowserRouter>
<Router />
</ThemeProvider>
);

View File

@ -9,37 +9,45 @@ import {
MediaListPage,
PreviewMediaPage,
EditMediaPage,
// CreateMediaPage,
} from "@pages";
import { authStore, createSightStore, editSightStore } from "@shared";
import { Layout } from "@widgets";
import { runInAction } from "mobx";
import { useEffect } from "react";
import React, { useEffect } from "react";
import { Navigate, Outlet, Route, Routes, useLocation } from "react-router-dom";
import {
createBrowserRouter,
RouterProvider,
Navigate,
Outlet,
useLocation,
} from "react-router-dom";
const PublicRoute = ({ children }: { children: React.ReactNode }) => {
const { isAuthenticated } = authStore;
if (isAuthenticated) {
return <Navigate to="/sight" />;
return <Navigate to="/sight" replace />;
}
return children;
return <>{children}</>;
};
const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
const { isAuthenticated } = authStore;
const pathname = useLocation();
const location = useLocation();
if (!isAuthenticated) {
return <Navigate to="/login" />;
return <Navigate to="/login" replace />;
}
if (pathname.pathname === "/") {
return <Navigate to="/sight" />;
if (location.pathname === "/") {
return <Navigate to="/sight" replace />;
}
return children;
return <>{children}</>;
};
export const Router = () => {
const pathname = useLocation();
// Чтобы очистка сторов происходила при смене локации
const ClearStoresWrapper: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const location = useLocation();
useEffect(() => {
editSightStore.clearSightInfo();
@ -47,41 +55,46 @@ export const Router = () => {
runInAction(() => {
editSightStore.hasLoadedCommon = false;
});
}, [pathname]);
}, [location]);
return (
<Routes>
<Route
path="/login"
element={
<PublicRoute>
<LoginPage />
</PublicRoute>
}
/>
{/* Protected routes with layout */}
<Route
path="/"
element={
<ProtectedRoute>
<Layout>
<Outlet />
</Layout>
</ProtectedRoute>
}
>
<Route index element={<MainPage />} />
<Route path="sight" element={<SightPage />} />
<Route path="sight/:id" element={<EditSightPage />} />
<Route path="sight/create" element={<CreateSightPage />} />
<Route path="devices" element={<DevicesPage />} />
<Route path="map" element={<MapPage />} />
<Route path="media" element={<MediaListPage />} />
<Route path="media/:id" element={<PreviewMediaPage />} />
<Route path="media/:id/edit" element={<EditMediaPage />} />
{/* <Route path="media/create" element={<CreateMediaPage />} /> */}
</Route>
</Routes>
);
return <>{children}</>;
};
const router = createBrowserRouter([
{
path: "/login",
element: (
<PublicRoute>
<LoginPage />
</PublicRoute>
),
},
{
path: "/",
element: (
<ProtectedRoute>
<Layout>
<ClearStoresWrapper>
<Outlet />
</ClearStoresWrapper>
</Layout>
</ProtectedRoute>
),
children: [
{ index: true, element: <MainPage /> },
{ path: "sight", element: <SightPage /> },
{ path: "sight/create", element: <CreateSightPage /> },
{ path: "sight/:id", element: <EditSightPage /> },
{ path: "devices", element: <DevicesPage /> },
{ path: "map", element: <MapPage /> },
{ path: "media", element: <MediaListPage /> },
{ path: "media/:id", element: <PreviewMediaPage /> },
{ path: "media/:id/edit", element: <EditMediaPage /> },
// { path: "media/create", element: <CreateMediaPage /> },
],
},
]);
export const Router = () => {
return <RouterProvider router={router} />;
};

View File

@ -1,6 +1,11 @@
import { Box, Tab, Tabs } from "@mui/material";
import { Box, Button, Tab, Tabs } from "@mui/material";
import { articlesStore, cityStore, languageStore } from "@shared";
import { CreateInformationTab, CreateLeftTab, CreateRightTab } from "@widgets";
import {
CreateInformationTab,
CreateLeftTab,
CreateRightTab,
LeaveAgree,
} from "@widgets";
import { useEffect, useState } from "react";
import { observer } from "mobx-react-lite";
@ -11,6 +16,8 @@ function a11yProps(index: number) {
};
}
import { useBlocker } from "react-router";
export const CreateSightPage = observer(() => {
const [value, setValue] = useState(0);
const { getCities } = cityStore;
@ -19,6 +26,11 @@ export const CreateSightPage = observer(() => {
setValue(newValue);
};
let blocker = useBlocker(
({ currentLocation, nextLocation }) =>
true && currentLocation.pathname !== nextLocation.pathname
);
useEffect(() => {
const fetchData = async () => {
await getCities();
@ -34,6 +46,7 @@ export const CreateSightPage = observer(() => {
display: "flex",
flexDirection: "column",
minHeight: "100vh",
z: 10,
}}
>
<Box
@ -66,6 +79,8 @@ export const CreateSightPage = observer(() => {
<CreateLeftTab value={value} index={1} />
<CreateRightTab value={value} index={2} />
</div>
{blocker.state === "blocked" ? <LeaveAgree blocker={blocker} /> : null}
</Box>
);
});

View File

@ -34,6 +34,7 @@ export const EditMediaPage = observer(() => {
const [mediaName, setMediaName] = useState(media?.media_name ?? "");
const [mediaFilename, setMediaFilename] = useState(media?.filename ?? "");
const [mediaType, setMediaType] = useState(media?.media_type ?? 1);
const [availableMediaTypes, setAvailableMediaTypes] = useState<number[]>([]);
useEffect(() => {
if (id) {
@ -48,6 +49,18 @@ export const EditMediaPage = observer(() => {
setMediaName(media.media_name);
setMediaFilename(media.filename);
setMediaType(media.media_type);
// Set available media types based on current file extension
const extension = media.filename.split(".").pop()?.toLowerCase();
if (extension) {
if (["glb", "gltf"].includes(extension)) {
setAvailableMediaTypes([6]); // 3D model
} else if (["jpg", "jpeg", "png", "gif"].includes(extension)) {
setAvailableMediaTypes([1, 3, 4, 5]); // Photo, Icon, Watermark, Panorama
} else if (["mp4", "webm", "mov"].includes(extension)) {
setAvailableMediaTypes([2]); // Video
}
}
}
}, [media]);
@ -76,8 +89,25 @@ export const EditMediaPage = observer(() => {
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files;
if (files && files.length > 0) {
setNewFile(files[0]);
setMediaFilename(files[0].name);
const file = files[0];
setNewFile(file);
setMediaFilename(file.name);
// Determine media type based on file extension
const extension = file.name.split(".").pop()?.toLowerCase();
if (extension) {
if (["glb", "gltf"].includes(extension)) {
setAvailableMediaTypes([6]); // 3D model
setMediaType(6);
} else if (["jpg", "jpeg", "png", "gif"].includes(extension)) {
setAvailableMediaTypes([1, 3, 4, 5]); // Photo, Icon, Watermark, Panorama
setMediaType(1); // Default to Photo
} else if (["mp4", "webm", "mov"].includes(extension)) {
setAvailableMediaTypes([2]); // Video
setMediaType(2);
}
}
setUploadDialogOpen(true); // Open dialog on file selection
}
};
@ -175,11 +205,21 @@ export const EditMediaPage = observer(() => {
onChange={(e) => setMediaType(Number(e.target.value))}
disabled={isLoading}
>
{Object.entries(MEDIA_TYPE_LABELS).map(([type, label]) => (
<MenuItem key={type} value={Number(type)}>
{label}
</MenuItem>
))}
{availableMediaTypes.length > 0
? availableMediaTypes.map((type) => (
<MenuItem key={type} value={type}>
{
MEDIA_TYPE_LABELS[
type as keyof typeof MEDIA_TYPE_LABELS
]
}
</MenuItem>
))
: Object.entries(MEDIA_TYPE_LABELS).map(([type, label]) => (
<MenuItem key={type} value={Number(type)}>
{label}
</MenuItem>
))}
</Select>
</FormControl>

View File

@ -1,5 +1,5 @@
import { Box, Tab, Tabs } from "@mui/material";
import { InformationTab, RightWidgetTab } from "@widgets";
import { InformationTab, LeaveAgree, RightWidgetTab } from "@widgets";
import { LeftWidgetTab } from "@widgets";
import { useEffect, useState } from "react";
import { observer } from "mobx-react-lite";
@ -9,7 +9,7 @@ import {
editSightStore,
languageStore,
} from "@shared";
import { useParams } from "react-router-dom";
import { useBlocker, useParams } from "react-router-dom";
function a11yProps(index: number) {
return {
@ -26,6 +26,11 @@ export const EditSightPage = observer(() => {
const { id } = useParams();
const { getCities } = cityStore;
let blocker = useBlocker(
({ currentLocation, nextLocation }) =>
true && currentLocation.pathname !== nextLocation.pathname
);
const handleChange = (_: React.SyntheticEvent, newValue: number) => {
setValue(newValue);
};
@ -82,6 +87,8 @@ export const EditSightPage = observer(() => {
<RightWidgetTab value={value} index={2} />
</div>
)}
{blocker.state === "blocked" ? <LeaveAgree blocker={blocker} /> : null}
</Box>
);
});

View File

@ -28,8 +28,8 @@ import { FeatureLike } from "ol/Feature";
// --- CONFIGURATION ---
export const mapConfig = {
center: [37.6173, 55.7558] as [number, number],
zoom: 10,
center: [30.311, 59.94] as [number, number],
zoom: 13,
};
// --- SVG ICONS ---
@ -1128,7 +1128,7 @@ const MapControls: React.FC<MapControlsProps> = ({
const controls = [
{
mode: "edit",
title: "Редакт.",
title: "Редактировать",
longTitle: "Редактирование",
icon: <EditIcon />,
action: () => mapService.activateEditMode(),
@ -1156,7 +1156,7 @@ const MapControls: React.FC<MapControlsProps> = ({
},
];
return (
<div className="absolute top-4 left-1/2 -translate-x-1/2 z-20 flex flex-wrap justify-center p-2 bg-white/90 backdrop-blur-sm rounded-lg shadow-xl space-x-1 sm:space-x-2">
<div className="absolute top-4 left-1/2 -translate-x-1/2 z-20 flex flex-nowrap justify-center p-2 bg-white/90 backdrop-blur-sm rounded-lg shadow-xl space-x-1 sm:space-x-2">
{controls.map((c) => (
<button
key={c.mode}

View File

@ -2,10 +2,11 @@ import { TableBody } from "@mui/material";
import { TableRow, TableCell } from "@mui/material";
import { Table, TableHead } from "@mui/material";
import { mediaStore, MEDIA_TYPE_LABELS } from "@shared";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { observer } from "mobx-react-lite";
import { Eye, Pencil, Trash2 } from "lucide-react";
import { useNavigate } from "react-router-dom";
import { DeleteModal } from "@widgets";
const rows = (media: any[]) => {
return media.map((row) => ({
@ -24,7 +25,8 @@ export const MediaListPage = observer(() => {
}, []);
const currentRows = rows(media);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [rowId, setRowId] = useState<number | null>(null);
return (
<>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
@ -53,7 +55,12 @@ export const MediaListPage = observer(() => {
<Pencil size={20} className="text-blue-500" />
</button>
<button onClick={() => deleteMedia(row.id)}>
<button
onClick={() => {
setIsDeleteModalOpen(true);
setRowId(row.id);
}}
>
<Trash2 size={20} className="text-red-500" />
</button>
</div>
@ -62,6 +69,20 @@ export const MediaListPage = observer(() => {
))}
</TableBody>
</Table>
<DeleteModal
open={isDeleteModalOpen}
onDelete={async () => {
if (rowId) {
await deleteMedia(rowId.toString());
}
setIsDeleteModalOpen(false);
setRowId(null);
}}
onCancel={() => {
setIsDeleteModalOpen(false);
setRowId(null);
}}
/>
</>
);
});

View File

@ -7,3 +7,14 @@ export const MEDIA_TYPE_LABELS = {
5: "Панорама",
6: "3Д-модель",
};
export const MEDIA_TYPE_VALUES = {
photo: 1,
video: 2,
icon: 3,
thumbnail: 3,
watermark_lu: 4,
watermark_rd: 4,
panorama: 5,
model: 6,
};

View File

@ -1,4 +1,4 @@
import { articlesStore, authInstance, languageStore } from "@shared";
import { articlesStore, authInstance, Language, languageStore } from "@shared";
import { observer } from "mobx-react-lite";
import { useEffect, useState } from "react";
import {
@ -17,7 +17,7 @@ import {
InputAdornment,
} from "@mui/material";
import { ImagePlus, Search } from "lucide-react";
import { ReactMarkdownComponent } from "@widgets";
import { MediaViewer, ReactMarkdownComponent } from "@widgets";
interface SelectArticleModalProps {
open: boolean;
@ -128,10 +128,12 @@ export const SelectArticleModal = observer(
height: "600px",
display: "flex",
flexDirection: "row",
alignItems: "center",
p: 2,
}}
>
<Paper className="w-[66%] flex flex-col" elevation={2}>
<Paper className="w-[66%] flex flex-col h-full" elevation={2}>
<TextField
fullWidth
placeholder="Поиск статей..."
@ -201,108 +203,86 @@ export const SelectArticleModal = observer(
)}
</List>
</Paper>
<Paper className="flex-1 flex flex-col" elevation={2}>
<Paper
elevation={3}
sx={{
width: "100%",
minWidth: 320,
maxWidth: 310,
background:
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
padding: 0,
margin: "0px auto",
display: "flex",
flexDirection: "column",
}}
>
<Box
className="rounded-2xl overflow-hidden"
sx={{
width: "100%",
height: "100%",
background: "#877361",
borderColor: "grey.300",
height: 175,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
padding: "3px",
}}
>
{isLoading ? (
<Box
sx={{
width: "100%",
height: "100%",
display: "flex",
alignItems: "center",
justifyContent: "center",
{articlesStore.articleMedia ? (
<MediaViewer
media={{
id: articlesStore.articleMedia.id,
media_type: articlesStore.articleMedia.media_type,
filename: articlesStore.articleMedia.filename,
}}
>
<Typography color="white">Загрузка...</Typography>
</Box>
/>
) : (
<>
{articlesStore.articleMedia && (
<Box sx={{ p: 2, backgroundColor: "rgba(0,0,0,0.1)" }}>
<img
src={`${import.meta.env.VITE_KRBL_MEDIA}${
articlesStore.articleMedia.id
}/download?token=${token}`}
alt={articlesStore.articleMedia.filename}
style={{
maxWidth: "100%",
height: "auto",
maxHeight: "300px",
objectFit: "contain",
borderRadius: 8,
}}
/>
</Box>
)}
{!articlesStore.articleMedia && (
<Box
sx={{
width: "100%",
height: 200,
flexShrink: 0,
backgroundColor: "rgba(0,0,0,0.1)",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<ImagePlus size={48} color="white" />
</Box>
)}
<Box
sx={{
width: "100%",
minHeight: "70px",
background: "#877361",
display: "flex",
flexShrink: 0,
alignItems: "center",
borderBottom: "1px solid rgba(255,255,255,0.1)",
px: 2,
}}
>
<Typography variant="h6" color="white">
{articlesStore.articleData?.heading || "Выберите статью"}
</Typography>
</Box>
<Box
sx={{
px: 2,
flexGrow: 1,
overflowY: "auto",
backgroundColor: "#877361",
color: "white",
py: 1,
}}
>
{articlesStore.articleData?.body ? (
<ReactMarkdownComponent
value={articlesStore.articleData.body}
/>
) : (
<Typography
color="rgba(255,255,255,0.7)"
sx={{ textAlign: "center", mt: 4 }}
>
Предпросмотр статьи появится здесь
</Typography>
)}
</Box>
</>
<ImagePlus size={48} color="white" />
)}
</Box>
<Box
sx={{
background:
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
color: "white",
margin: "5px 0px 5px 0px",
display: "flex",
flexDirection: "column",
gap: 1,
padding: 1,
}}
>
<Typography
variant="h5"
component="h2"
sx={{
wordBreak: "break-word",
fontSize: "24px",
fontWeight: 700,
lineHeight: "120%",
}}
>
{articlesStore.articleData?.heading || "Название cтатьи"}
</Typography>
</Box>
{articlesStore.articleData?.body && (
<Box
sx={{
padding: 1,
maxHeight: "200px",
overflowY: "scroll",
background:
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
}}
>
<ReactMarkdownComponent
value={articlesStore.articleData?.body || "Описание"}
/>
</Box>
)}
</Paper>
</DialogContent>
<DialogActions sx={{ p: 2 }}>

View File

@ -1,4 +1,4 @@
import { mediaStore } from "@shared";
import { Media, mediaStore } from "@shared";
import { observer } from "mobx-react-lite";
import { useEffect, useState } from "react";
import {
@ -29,6 +29,7 @@ interface SelectMediaDialogProps {
}) => void; // Renamed from onSelectArticle
onSelectForSightMedia?: (mediaId: string) => void;
linkedMediaIds?: string[]; // Renamed from linkedArticleIds, assuming it refers to media already in use
mediaType?: number;
}
export const SelectMediaDialog = observer(
@ -38,12 +39,29 @@ export const SelectMediaDialog = observer(
onSelectMedia, // Renamed prop
onSelectForSightMedia,
linkedMediaIds = [], // Default to empty array if not provided, renamed
mediaType,
}: SelectMediaDialogProps) => {
const { media, getMedia } = mediaStore;
const [searchQuery, setSearchQuery] = useState("");
const [hoveredMediaId, setHoveredMediaId] = useState<string | null>(null);
const [currentHoveredMedia, setCurrentHoveredMedia] =
useState<Media | null>(null);
useEffect(() => {
if (hoveredMediaId) {
setCurrentHoveredMedia(
media.find((m) => m.id === hoveredMediaId) ?? null
);
}
}, [hoveredMediaId]);
const handleClose = () => {
setHoveredMediaId(null);
setCurrentHoveredMedia(null);
onClose();
setSearchQuery("");
};
// Fetch media on component mount
useEffect(() => {
getMedia();
}, [getMedia]);
@ -63,7 +81,7 @@ export const SelectMediaDialog = observer(
onSelectMedia(mediaItem);
}
}
onClose();
handleClose();
}
}
};
@ -74,19 +92,21 @@ export const SelectMediaDialog = observer(
};
}, [hoveredMediaId, onSelectMedia, onClose]); // Dependencies for keyboard listener
const filteredMedia = media
let filteredMedia = media
.filter((mediaItem) => !linkedMediaIds.includes(mediaItem.id)) // Use mediaItem to avoid name collision
.filter((mediaItem) =>
mediaItem.media_name.toLowerCase().includes(searchQuery.toLowerCase())
);
// Find the currently hovered media object for MediaViewer
const currentHoveredMedia = hoveredMediaId
? media.find((m) => m.id === hoveredMediaId)
: null;
if (mediaType) {
filteredMedia = filteredMedia.filter(
(mediaItem) => mediaItem.media_type === mediaType
);
console.log(filteredMedia);
}
return (
<Dialog open={open} onClose={onClose} maxWidth="lg" fullWidth>
<Dialog open={open} onClose={handleClose} maxWidth="lg" fullWidth>
<DialogTitle>Выберите существующее медиа</DialogTitle>
<DialogContent
className="flex gap-4"
@ -125,14 +145,22 @@ export const SelectMediaDialog = observer(
} else if (onSelectMedia) {
onSelectMedia(mediaItem);
}
onClose();
handleClose();
}}
selected={hoveredMediaId === mediaItem.id}
sx={{
borderRadius: 1,
mb: 0.5,
"&:hover": {
backgroundColor: "action.hover",
},
"&.Mui-selected": {
backgroundColor: "primary.main",
color: "primary.contrastText",
"&:hover": {
backgroundColor: "primary.dark",
},
},
}}
>
<ListItemText primary={mediaItem.media_name} />
@ -149,7 +177,7 @@ export const SelectMediaDialog = observer(
)}
</List>
</Paper>
{currentHoveredMedia ? ( // Only render MediaViewer if currentHoveredMedia is found
{currentHoveredMedia !== null && hoveredMediaId !== null ? ( // Only render MediaViewer if currentHoveredMedia is found
<Paper className="w-[33%] h-[100%] flex justify-center items-center">
<MediaViewer
media={{
@ -167,8 +195,28 @@ export const SelectMediaDialog = observer(
</Paper>
)}
</DialogContent>
<DialogActions>
<Button onClick={onClose}>Отмена</Button>
<DialogActions sx={{ p: 2 }}>
<Button onClick={handleClose}>Отмена</Button>
<Button
variant="contained"
onClick={() => {
if (hoveredMediaId) {
const mediaItem = media.find((m) => m.id === hoveredMediaId);
if (mediaItem) {
if (onSelectForSightMedia) {
onSelectForSightMedia(mediaItem.id);
} else if (onSelectMedia) {
onSelectMedia(mediaItem);
}
}
handleClose();
}
}}
disabled={hoveredMediaId === null}
>
Выбрать
</Button>
</DialogActions>
</Dialog>
);

View File

@ -1,7 +1,7 @@
import { makeAutoObservable, runInAction } from "mobx";
import { authInstance } from "@shared";
type Media = {
export type Media = {
id: string;
filename: string;
media_name: string;

View File

@ -0,0 +1,33 @@
import { Button } from "@mui/material";
export const DeleteModal = ({
onDelete,
onCancel,
open,
}: {
onDelete: () => void;
onCancel: () => void;
open: boolean;
}) => {
return (
<div
className={`fixed top-0 left-0 w-screen h-screen flex justify-center items-center z-10000 bg-black/30 transition-all duration-300 ${
open ? "block" : "hidden"
}`}
>
<div className="bg-white p-4 w-100 rounded-lg flex flex-col gap-4 items-center">
<p className="text-black w-100 text-center">
Вы уверены, что хотите удалить этот элемент?
</p>
<div className="flex gap-4 justify-center">
<Button variant="contained" color="error" onClick={onDelete}>
Да
</Button>
<Button variant="outlined" onClick={onCancel}>
Нет
</Button>
</div>
</div>
</div>
);
};

View File

@ -1,6 +1,6 @@
import React, { useRef, useState, DragEvent, useEffect } from "react";
import { Paper, Box, Typography, Button, Tooltip } from "@mui/material";
import { X, Info } from "lucide-react"; // Assuming lucide-react for icons
import { X, Info, MousePointer } from "lucide-react"; // Assuming lucide-react for icons
import { editSightStore } from "@shared";
interface ImageUploadCardProps {
@ -159,6 +159,7 @@ export const ImageUploadCard: React.FC<ImageUploadCardProps> = ({
<Button
variant="contained"
color="primary"
startIcon={<MousePointer color="white" size={18} />}
onClick={(e) => {
e.stopPropagation(); // Prevent `handleZoneClick` from firing
onSelectFileClick(); // This button might trigger a different modal

View File

@ -0,0 +1,21 @@
import { Button } from "@mui/material";
export const LeaveAgree = ({ blocker }: { blocker: any }) => {
return (
<div className="fixed top-0 left-0 w-screen h-screen flex justify-center items-center z-10000 bg-black/30">
<div className="bg-white p-4 w-100 rounded-lg flex flex-col gap-4 items-center">
<p className="text-black w-100 text-center">
При выходе со страницы, несохраненные данные будут потеряны.
</p>
<div className="flex gap-4 justify-center">
<Button variant="contained" onClick={() => blocker.proceed()}>
Да
</Button>
<Button variant="outlined" onClick={() => blocker.reset()}>
Нет
</Button>
</div>
</div>
</div>
);
};

View File

@ -69,7 +69,7 @@ export const MediaAreaForSight = observer(
<Box className="w-full flex flex-col items-center justify-center border rounded-md p-4">
<div className="w-full flex flex-col items-center justify-center">
<div
className={`w-full h-40 flex flex-col justify-center items-center text-gray-400 border-dashed border-2 rounded-md border-gray-400 p-4 cursor-pointer hover:bg-gray-50 ${
className={`w-full h-40 flex text-center flex-col justify-center items-center text-gray-400 border-dashed border-2 rounded-md border-gray-400 p-4 cursor-pointer hover:bg-gray-50 ${
isDragging ? "bg-blue-100 border-blue-400" : ""
}`}
onDrop={handleDrop}

View File

@ -17,13 +17,11 @@ export function MediaViewer({
return (
<Box
sx={{
width: "80%",
width: "100%",
height: "100%",
maxWidth: "600px",
display: "flex",
flexGrow: 1,
justifyContent: "center",
margin: "0 auto",
}}
className={className}
>
@ -34,10 +32,9 @@ export function MediaViewer({
}/download?token=${token}`}
alt={media?.filename}
style={{
maxWidth: "100%",
height: "auto",
objectFit: "contain",
borderRadius: 8,
width: "100%",
height: "100%",
objectFit: "cover",
}}
/>
)}
@ -48,9 +45,7 @@ export function MediaViewer({
media?.id
}/download?token=${token}`}
style={{
margin: "auto 0",
height: "fit-content",
width: "fit-content",
height: "100%",
objectFit: "contain",
borderRadius: 30,
}}
@ -66,7 +61,7 @@ export function MediaViewer({
}/download?token=${token}`}
alt={media?.filename}
style={{
maxWidth: "100%",
width: "100%",
height: "100%",
objectFit: "contain",
borderRadius: 8,
@ -80,7 +75,7 @@ export function MediaViewer({
}/download?token=${token}`}
alt={media?.filename}
style={{
maxWidth: "100%",
width: "100%",
height: "100%",
objectFit: "contain",
borderRadius: 8,

View File

@ -18,8 +18,10 @@ import {
SightCommonInfo,
createSightStore,
UploadMediaDialog,
MEDIA_TYPE_VALUES,
} from "@shared";
import { ImageUploadCard, LanguageSwitcher } from "@widgets";
import { Save } from "lucide-react";
import { observer } from "mobx-react-lite";
import { useEffect, useState } from "react";
@ -331,6 +333,7 @@ export const CreateInformationTab = observer(
<Button
variant="contained"
color="success"
startIcon={<Save color="white" size={18} />}
onClick={async () => {
await createSight(language);
toast.success("Достопримечательность создана");
@ -369,6 +372,13 @@ export const CreateInformationTab = observer(
onSelectMedia={(media) => {
handleMediaSelect(media, activeMenuType ?? "thumbnail");
}}
mediaType={
activeMenuType
? MEDIA_TYPE_VALUES[
activeMenuType as keyof typeof MEDIA_TYPE_VALUES
]
: undefined
}
/>
<PreviewMediaDialog

View File

@ -16,8 +16,16 @@ import {
ReactMarkdownComponent,
ReactMarkdownEditor,
MediaViewer,
DeleteModal,
} from "@widgets";
import { Trash2, ImagePlus } from "lucide-react";
import {
Trash2,
ImagePlus,
Unlink,
MousePointer,
Plus,
Save,
} from "lucide-react";
import { useState, useCallback } from "react";
import { observer } from "mobx-react-lite";
import { toast } from "react-toastify";
@ -47,7 +55,7 @@ export const CreateLeftTab = observer(
useState(false);
const [isSelectMediaDialogOpen, setIsSelectMediaDialogOpen] =
useState(false);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
// const handleMediaSelected = useCallback(() => {
// // При выборе медиа, обновляем данные для ТЕКУЩЕГО ЯЗЫКА
// // сохраняя текущие heading и body.
@ -123,6 +131,7 @@ export const CreateLeftTab = observer(
color="primary"
size="small"
style={{ transition: "0" }}
startIcon={<Unlink size={18} />}
onClick={() => {
unlinkLeftArticle();
toast.success("Статья откреплена");
@ -136,10 +145,7 @@ export const CreateLeftTab = observer(
style={{ transition: "0" }}
startIcon={<Trash2 size={18} />}
size="small"
onClick={() => {
deleteLeftArticle(sight.left_article);
toast.success("Статья откреплена");
}}
onClick={() => setIsDeleteModalOpen(true)}
>
Удалить
</Button>
@ -150,6 +156,7 @@ export const CreateLeftTab = observer(
variant="contained"
color="primary"
size="small"
startIcon={<MousePointer color="white" size={18} />}
onClick={() => setIsSelectArticleDialogOpen(true)}
>
Выбрать статью
@ -158,6 +165,7 @@ export const CreateLeftTab = observer(
variant="contained"
color="primary"
size="small"
startIcon={<Plus color="white" size={18} />}
style={{ transition: "0" }}
onClick={createLeftArticle}
>
@ -301,6 +309,7 @@ export const CreateLeftTab = observer(
display: "flex",
flexDirection: "column",
gap: 1.5,
maxWidth: "320px",
}}
>
<Paper
@ -405,10 +414,11 @@ export const CreateLeftTab = observer(
<Button
variant="contained"
color="success"
startIcon={<Save color="white" size={18} />}
onClick={async () => {
try {
await createSight(language);
toast.success("Странца создана");
toast.success("Страница создана");
} catch (error) {
console.error(error);
}
@ -445,6 +455,14 @@ export const CreateLeftTab = observer(
onClose={handleCloseArticleDialog}
onSelectArticle={handleArticleSelect}
/>
<DeleteModal
open={isDeleteModalOpen}
onDelete={() => {
deleteLeftArticle(sight.left_article);
toast.success("Статья откреплена");
}}
onCancel={() => setIsDeleteModalOpen(false)}
/>
</TabPanel>
);
}

View File

@ -14,7 +14,8 @@ import {
SelectArticleModal,
TabPanel,
SelectMediaDialog, // Import
UploadMediaDialog, // Import
UploadMediaDialog,
Media, // Import
} from "@shared";
import {
LanguageSwitcher,
@ -22,12 +23,14 @@ import {
MediaAreaForSight, // Import
ReactMarkdownComponent,
ReactMarkdownEditor,
DeleteModal,
} from "@widgets";
import { ImagePlus, Plus, X } from "lucide-react"; // Import X
import { ImagePlus, Plus, Save, Trash2, Unlink, X } from "lucide-react"; // Import X
import { observer } from "mobx-react-lite";
import { useState, useEffect } from "react"; // Added useEffect
import { MediaViewer } from "../../MediaViewer/index";
import { toast } from "react-toastify";
import { authInstance } from "@shared";
type MediaItemShared = {
// Define if not already available from @shared
@ -65,14 +68,27 @@ export const CreateRightTab = observer(
null
);
const [type, setType] = useState<"article" | "media">("media");
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isSelectMediaDialogOpen, setIsSelectMediaDialogOpen] =
useState(false);
const [mediaTarget, setMediaTarget] = useState<
"sightPreview" | "rightArticle" | null
>(null);
const [previewMedia, setPreviewMedia] = useState<Media | null>(null);
// Reset activeArticleIndex if language changes and index is out of bounds
useEffect(() => {
if (sight.preview_media) {
const fetchMedia = async () => {
const response = await authInstance.get(
`/media/${sight.preview_media}`
);
setPreviewMedia(response.data);
};
fetchMedia();
}
}, [sight.preview_media]);
useEffect(() => {
if (
activeArticleIndex !== null &&
@ -168,6 +184,7 @@ export const CreateRightTab = observer(
const handleMediaSelectedFromDialog = async (media: MediaItemShared) => {
setIsSelectMediaDialogOpen(false);
if (mediaTarget === "sightPreview") {
await linkPreviewMedia(media.id);
} else if (mediaTarget === "rightArticle" && currentRightArticle) {
@ -176,6 +193,11 @@ export const CreateRightTab = observer(
setMediaTarget(null);
};
const handleUnlinkPreviewMedia = async () => {
await unlinkPreviewMedia();
setPreviewMedia(null);
};
const handleMediaUploaded = async (media: MediaItemShared) => {
// After UploadMediaDialog finishes
setUploadMediaOpen(false);
@ -273,12 +295,13 @@ export const CreateRightTab = observer(
{/* Main content area: Article Editor or Sight Media Preview */}
{type === "article" && currentRightArticle ? (
<Box className="w-[80%] border border-gray-300 rounded-2xl p-3 flex flex-col gap-2 overflow-hidden">
<Box className="w-[80%] border border-gray-300 p-3 flex flex-col gap-2 overflow-hidden">
<Box className="flex justify-end gap-2 mb-1 flex-shrink-0">
<Button
variant="outlined"
color="warning"
color="primary"
size="small"
startIcon={<Unlink color="white" size={18} />}
onClick={() => {
if (currentRightArticle) {
unlinkRightAritcle(currentRightArticle.id); // Corrected function name
@ -293,22 +316,9 @@ export const CreateRightTab = observer(
variant="contained"
color="error"
size="small"
startIcon={<Trash2 size={18} />}
onClick={async () => {
if (
currentRightArticle &&
window.confirm(
`Удалить статью "${currentRightArticle.heading}" окончательно?`
)
) {
try {
await deleteRightArticle(currentRightArticle.id);
setActiveArticleIndex(null);
setType("media");
toast.success("Статья удалена");
} catch {
toast.error("Не удалось удалить статью");
}
}
setIsDeleteModalOpen(true);
}}
>
Удалить
@ -373,28 +383,30 @@ export const CreateRightTab = observer(
) : type === "media" ? (
<Box className="w-[80%] h-[70vh] border border-gray-300 rounded-2xl p-3 relative flex justify-center items-center">
{type === "media" && (
<Box className="w-[80%] border border-gray-300 rounded-2xl relative">
{sight.preview_media && (
<Box className="w-[80%] border border-gray-300 rounded-2xl relative flex items-center justify-center">
{previewMedia && (
<>
<Box className="absolute top-4 right-4">
<Box className="absolute top-4 right-4 z-10">
<button
className="w-10 h-10 flex items-center justify-center"
onClick={unlinkPreviewMedia}
className="w-10 h-10 flex items-center justify-center z-10"
onClick={handleUnlinkPreviewMedia}
>
<X size={20} color="red" />
</button>
</Box>
<MediaViewer
media={{
id: sight.preview_media || "",
media_type: 1,
filename: sight.preview_media || "",
}}
/>
<Box sx={{}}>
<MediaViewer
media={{
id: previewMedia.id || "",
media_type: previewMedia.media_type,
filename: previewMedia.filename || "",
}}
/>
</Box>
</>
)}
{!sight.preview_media && (
{!previewMedia && (
<MediaAreaForSight
onFinishUpload={(mediaId) => {
linkPreviewMedia(mediaId);
@ -505,33 +517,6 @@ export const CreateRightTab = observer(
</Box>
</Paper>
)}
{/* Optional: Preview for sight.preview_media when type === "media" */}
{type === "media" && sight.preview_media && (
<Paper
className="flex-1 flex flex-col rounded-2xl"
elevation={2}
sx={{ height: "75vh", overflow: "hidden" }}
>
<Box
sx={{
width: "100%",
height: "100%",
background: "#877361",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<MediaViewer
media={{
id: sight.preview_media,
filename: sight.preview_media,
media_type: 1,
}}
/>
</Box>
</Paper>
)}
</Box>
</Box>
@ -539,17 +524,15 @@ export const CreateRightTab = observer(
<Box
sx={{
position: "absolute",
bottom: 0,
bottom: "-20px",
left: 0, // ensure it spans from left
right: 0,
padding: 2,
backgroundColor: "background.paper",
borderTop: "1px solid", // Add a subtle top border
borderColor: "divider", // Use theme's divider color
width: "100%",
display: "flex",
justifyContent: "flex-end",
boxShadow: "0 -2px 5px rgba(0,0,0,0.1)", // Optional shadow
}}
>
<Button
@ -557,8 +540,9 @@ export const CreateRightTab = observer(
color="success"
onClick={handleSave}
size="large"
startIcon={<Save color="white" size={18} />}
>
Сохранить достопримечательность
Сохранить
</Button>
</Box>
</Box>
@ -588,6 +572,20 @@ export const CreateRightTab = observer(
}}
onSelectMedia={handleMediaSelectedFromDialog}
/>
<DeleteModal
open={isDeleteModalOpen}
onDelete={async () => {
try {
await deleteRightArticle(currentRightArticle?.id || 0);
setActiveArticleIndex(null);
setType("media");
toast.success("Статья удалена");
} catch {
toast.error("Не удалось удалить статью");
}
}}
onCancel={() => setIsDeleteModalOpen(false)}
/>
</TabPanel>
);
}

View File

@ -18,8 +18,10 @@ import {
SightLanguageInfo,
SightCommonInfo,
UploadMediaDialog,
MEDIA_TYPE_VALUES,
} from "@shared";
import { ImageUploadCard, LanguageSwitcher } from "@widgets";
import { Save } from "lucide-react";
import { observer } from "mobx-react-lite";
import { useEffect, useState } from "react";
@ -335,6 +337,7 @@ export const InformationTab = observer(
<Button
variant="contained"
color="success"
startIcon={<Save color="white" size={18} />}
onClick={async () => {
await updateSight();
toast.success("Достопримечательность сохранена");
@ -371,6 +374,13 @@ export const InformationTab = observer(
setActiveMenuType(null);
}}
onSelectMedia={handleMediaSelect}
mediaType={
activeMenuType
? MEDIA_TYPE_VALUES[
activeMenuType as keyof typeof MEDIA_TYPE_VALUES
]
: undefined
}
/>
<UploadMediaDialog

View File

@ -8,6 +8,7 @@ import {
editSightStore,
SelectArticleModal,
UploadMediaDialog,
Language,
} from "@shared";
import {
LanguageSwitcher,
@ -15,8 +16,16 @@ import {
ReactMarkdownEditor,
MediaArea,
MediaViewer,
DeleteModal,
} from "@widgets";
import { Trash2, ImagePlus } from "lucide-react";
import {
Trash2,
ImagePlus,
Unlink,
Plus,
MousePointer,
Save,
} from "lucide-react";
import { useState, useCallback } from "react";
import { observer } from "mobx-react-lite";
import { toast } from "react-toastify";
@ -40,12 +49,18 @@ export const LeftWidgetTab = observer(
const { language } = languageStore;
const data = sight[language];
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isSelectMediaDialogOpen, setIsSelectMediaDialogOpen] =
useState(false);
const [isSelectArticleDialogOpen, setIsSelectArticleDialogOpen] =
useState(false);
const handleDeleteLeftArticle = useCallback(() => {
deleteLeftArticle(sight.common.left_article);
setIsDeleteModalOpen(false);
}, [deleteLeftArticle, sight.common.left_article]);
const handleMediaSelected = useCallback(
async (media: {
id: string;
@ -130,6 +145,7 @@ export const LeftWidgetTab = observer(
color="primary"
size="small"
style={{ transition: "0" }}
startIcon={<Unlink size={18} />}
onClick={() => {
unlinkLeftArticle();
toast.success("Статья откреплена");
@ -144,8 +160,7 @@ export const LeftWidgetTab = observer(
startIcon={<Trash2 size={18} />}
size="small"
onClick={() => {
deleteLeftArticle(sight.common.left_article);
toast.success("Статья откреплена");
setIsDeleteModalOpen(true);
}}
>
Удалить
@ -157,6 +172,7 @@ export const LeftWidgetTab = observer(
variant="contained"
color="primary"
size="small"
startIcon={<MousePointer color="white" size={18} />}
onClick={() => setIsSelectArticleDialogOpen(true)}
>
Выбрать статью
@ -166,6 +182,7 @@ export const LeftWidgetTab = observer(
color="primary"
size="small"
style={{ transition: "0" }}
startIcon={<Plus color="white" size={18} />}
onClick={() => {
createLeftArticle();
toast.success("Статья создана");
@ -234,7 +251,8 @@ export const LeftWidgetTab = observer(
flex: 1,
display: "flex",
flexDirection: "column",
gap: 1.5,
maxWidth: "320px",
gap: 0.5,
}}
>
<Paper
@ -242,10 +260,9 @@ export const LeftWidgetTab = observer(
sx={{
width: "100%",
minWidth: 320,
maxWidth: 400,
height: "auto",
minHeight: 500,
backgroundColor: "#877361",
background:
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
overflowY: "auto",
padding: 0,
display: "flex",
@ -255,11 +272,10 @@ export const LeftWidgetTab = observer(
<Box
sx={{
width: "100%",
height: 200,
backgroundColor: "grey.300",
height: 175,
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: "3px",
}}
>
{data.left.media.length > 0 ? (
@ -277,24 +293,50 @@ export const LeftWidgetTab = observer(
<Box
sx={{
backgroundColor: "#877361",
background:
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
color: "white",
padding: 1.5,
margin: "5px 0px 5px 0px",
display: "flex",
flexDirection: "column",
gap: 1,
padding: 1,
}}
>
<Typography
variant="h5"
component="h2"
sx={{ wordBreak: "break-word" }}
sx={{
wordBreak: "break-word",
fontSize: "24px",
fontWeight: 700,
lineHeight: "120%",
}}
>
{data?.left?.heading || "Название информации"}
</Typography>
<Typography
variant="h6"
component="h2"
sx={{
wordBreak: "break-word",
fontSize: "18px",
lineHeight: "120%",
}}
>
{sight[language as Language].address}
</Typography>
</Box>
{data?.left?.body && (
<Box
sx={{
padding: 2,
padding: 1,
maxHeight: "300px",
overflowY: "scroll",
background:
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
flexGrow: 1,
}}
>
@ -310,6 +352,7 @@ export const LeftWidgetTab = observer(
<Button
variant="contained"
color="success"
startIcon={<Save color="white" size={18} />}
onClick={async () => {
await updateSight();
toast.success("Достопримечательность сохранена");
@ -339,6 +382,11 @@ export const LeftWidgetTab = observer(
onClose={handleCloseArticleDialog}
onSelectArticle={handleSelectArticle}
/>
<DeleteModal
open={isDeleteModalOpen}
onDelete={handleDeleteLeftArticle}
onCancel={() => setIsDeleteModalOpen(false)}
/>
</>
);
}

View File

@ -23,7 +23,7 @@ import {
ReactMarkdownComponent,
ReactMarkdownEditor,
} from "@widgets";
import { ImagePlus, Plus, X } from "lucide-react";
import { ImagePlus, Plus, Save, Trash2, Unlink, X } from "lucide-react";
import { observer } from "mobx-react-lite";
import { useEffect, useState } from "react";
import { toast } from "react-toastify";
@ -49,6 +49,19 @@ export const RightWidgetTab = observer(
createNewRightArticle,
} = editSightStore;
const [previewMedia, setPreviewMedia] = useState<any | null>(null);
useEffect(() => {
if (sight.common.preview_media) {
setPreviewMedia(sight.common.preview_media);
}
}, [sight.common.preview_media]);
const handleUnlinkPreviewMedia = () => {
unlinkPreviewMedia();
setPreviewMedia(null);
};
const [uploadMediaOpen, setUploadMediaOpen] = useState(false);
const { language } = languageStore;
const [type, setType] = useState<"article" | "media">("media");
@ -194,6 +207,7 @@ export const RightWidgetTab = observer(
<Button
variant="contained"
color="primary"
startIcon={<Unlink color="white" size={18} />}
onClick={() => {
unlinkRightArticle(
sight[language].right[activeArticleIndex].id
@ -205,7 +219,8 @@ export const RightWidgetTab = observer(
</Button>
<Button
variant="contained"
color="success"
color="error"
startIcon={<Trash2 size={18} />}
onClick={() => {
deleteRightArticle(
sight[language].right[activeArticleIndex].id
@ -285,31 +300,65 @@ export const RightWidgetTab = observer(
<Box className="w-[80%] border border-gray-300 rounded-2xl relative">
{sight.common.preview_media && (
<>
<Box className="absolute top-4 right-4">
<button
className="w-10 h-10 flex items-center justify-center"
onClick={unlinkPreviewMedia}
>
<X size={20} color="red" />
</button>
</Box>
<Box className="w-[80%] h-[70vh] border border-gray-300 rounded-2xl p-3 relative flex justify-center items-center">
{type === "media" && (
<Box className="w-[80%] border border-gray-300 rounded-2xl relative flex items-center justify-center">
{previewMedia && (
<>
<Box className="absolute top-4 right-4 z-10">
<button
className="w-10 h-10 flex items-center justify-center z-10"
onClick={handleUnlinkPreviewMedia}
>
<X size={20} color="red" />
</button>
</Box>
<MediaViewer
media={{
id: sight.common.preview_media || "",
media_type: 1,
filename: sight.common.preview_media || "",
}}
/>
<Box sx={{}}>
<MediaViewer
media={{
id: previewMedia.id || "",
media_type: previewMedia.media_type,
filename: previewMedia.filename || "",
}}
/>
</Box>
</>
)}
{!previewMedia && (
<MediaAreaForSight
onFinishUpload={(mediaId) => {
linkPreviewMedia(mediaId);
}}
onFilesDrop={() => {}}
/>
)}
</Box>
)}
</Box>
</>
)}
{!sight.common.preview_media && (
<MediaAreaForSight
onFinishUpload={(mediaId) => {
linkPreviewMedia(mediaId);
}}
onFilesDrop={() => {}}
/>
<Box className="w-full h-full flex justify-center items-center">
<Box
sx={{
maxWidth: "500px",
maxHeight: "100%",
display: "flex",
flexGrow: 1,
margin: "0 auto",
justifyContent: "center",
}}
>
<MediaAreaForSight
onFinishUpload={(mediaId) => {
linkPreviewMedia(mediaId);
}}
onFilesDrop={() => {}}
/>
</Box>
</Box>
)}
</Box>
)}
@ -423,8 +472,13 @@ export const RightWidgetTab = observer(
justifyContent: "flex-end",
}}
>
<Button variant="contained" color="success" onClick={handleSave}>
Сохранить изменения
<Button
variant="contained"
startIcon={<Save color="white" size={18} />}
color="success"
onClick={handleSave}
>
Сохранить
</Button>
</Box>
</Box>

View File

@ -6,10 +6,10 @@ import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import Paper from "@mui/material/Paper";
import { authInstance, cityStore, languageStore, sightsStore } from "@shared";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { observer } from "mobx-react-lite";
import { Button } from "@mui/material";
import { LanguageSwitcher } from "@widgets";
import { DeleteModal, LanguageSwitcher } from "@widgets";
import { Pencil, Trash2 } from "lucide-react";
import { useNavigate } from "react-router-dom";
@ -29,6 +29,8 @@ export const SightsTable = observer(() => {
const { language } = languageStore;
const { sights, getSights } = sightsStore;
const { cities, getCities } = cityStore;
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [rowId, setRowId] = useState<number | null>(null);
useEffect(() => {
const fetchData = async () => {
@ -92,7 +94,10 @@ export const SightsTable = observer(() => {
</button>
<button
className="rounded-md px-3 py-1.5 transition-transform transform hover:scale-105"
onClick={() => handleDelete(row?.id)}
onClick={() => {
setIsDeleteModalOpen(true);
setRowId(row?.id);
}}
>
<Trash2 size={18} className="text-red-500" />
</button>
@ -103,6 +108,17 @@ export const SightsTable = observer(() => {
</TableBody>
</Table>
</TableContainer>
<DeleteModal
open={isDeleteModalOpen}
onDelete={async () => {
if (rowId) {
await handleDelete(rowId);
}
setIsDeleteModalOpen(false);
setRowId(null);
}}
onCancel={() => setIsDeleteModalOpen(false)}
/>
</>
);
});

View File

@ -12,3 +12,5 @@ export * from "./MediaArea";
export * from "./ModelViewer3D";
export * from "./MediaAreaForSight";
export * from "./ImageUploadCard";
export * from "./LeaveAgree";
export * from "./DeleteModal";

286
yarn.lock
View File

@ -133,12 +133,12 @@
dependencies:
"@babel/helper-plugin-utils" "^7.27.1"
"@babel/runtime@^7.12.5", "@babel/runtime@^7.18.3", "@babel/runtime@^7.27.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
"@babel/runtime@^7.12.5", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.26.0", "@babel/runtime@^7.27.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
version "7.27.3"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.3.tgz"
integrity sha512-7EYtGezsdiDMyY80+65EzwiGmcJqpmcZCojSXaRgdrBaGtWTgDZKq69cPIVped6MkIM78cTQ2GOiEYjwOlG4xw==
"@babel/runtime@^7.17.8", "@babel/runtime@^7.26.0":
"@babel/runtime@^7.26.7":
version "7.27.4"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.4.tgz#a91ec580e6c00c67118127777c316dfd5a5a6abf"
integrity sha512-t3yaEOuGu9NlIZ+hIeGbBjFtZT7j2cb2tg0fuaJKeGotchRjjLfrBA9Kwf8quhpP1EUuxModQg04q/mBwyg8uA==
@ -173,9 +173,9 @@
"@babel/helper-string-parser" "^7.27.1"
"@babel/helper-validator-identifier" "^7.27.1"
"@dimforge/rapier3d-compat@^0.12.0":
"@dimforge/rapier3d-compat@~0.12.0":
version "0.12.0"
resolved "https://registry.yarnpkg.com/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz#7b3365e1dfdc5cd957b45afe920b4ac06c7cd389"
resolved "https://registry.npmjs.org/@dimforge/rapier3d-compat/-/rapier3d-compat-0.12.0.tgz"
integrity sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==
"@emnapi/core@^1.4.3":
@ -498,6 +498,17 @@
"@eslint/core" "^0.14.0"
levn "^0.4.1"
"@hello-pangea/dnd@^18.0.1":
version "18.0.1"
resolved "https://registry.yarnpkg.com/@hello-pangea/dnd/-/dnd-18.0.1.tgz#7d5ef7fe8bddf195307b16e03635b1be582b7b8d"
integrity sha512-xojVWG8s/TGrKT1fC8K2tIWeejJYTAeJuj36zM//yEm/ZrnZUSFGS15BpO+jGZT1ybWvyXmeDJwPYb4dhWlbZQ==
dependencies:
"@babel/runtime" "^7.26.7"
css-box-model "^1.2.1"
raf-schd "^4.0.3"
react-redux "^9.2.0"
redux "^5.0.1"
"@humanfs/core@^0.19.1":
version "0.19.1"
resolved "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz"
@ -567,12 +578,12 @@
"@mediapipe/tasks-vision@0.10.17":
version "0.10.17"
resolved "https://registry.yarnpkg.com/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz#2c1c73ed81902b21d37336a587b96183bb6882d5"
resolved "https://registry.npmjs.org/@mediapipe/tasks-vision/-/tasks-vision-0.10.17.tgz"
integrity sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==
"@monogrid/gainmap-js@^3.0.6":
version "3.1.0"
resolved "https://registry.yarnpkg.com/@monogrid/gainmap-js/-/gainmap-js-3.1.0.tgz#4ac1f88abd6affdf0b51d79318109183b499c502"
resolved "https://registry.npmjs.org/@monogrid/gainmap-js/-/gainmap-js-3.1.0.tgz"
integrity sha512-Obb0/gEd/HReTlg8ttaYk+0m62gQJmCblMOjHSMHRrBP2zdfKMHLCRbh/6ex9fSUJMKdjjIEiohwkbGD3wj2Nw==
dependencies:
promise-worker-transferable "^1.0.4"
@ -686,12 +697,12 @@
"@petamoriken/float16@^3.4.7":
version "3.9.2"
resolved "https://registry.yarnpkg.com/@petamoriken/float16/-/float16-3.9.2.tgz#217a5d349f3655b8e286be447e0ed1eae063a78f"
resolved "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.2.tgz"
integrity sha512-VgffxawQde93xKxT3qap3OH+meZf7VaSB5Sqd4Rqc+FP5alWbpOyan/7tRbOAvynjpG3GpdtAuGU/NdhQpmrog==
"@photo-sphere-viewer/core@^5.13.2":
version "5.13.2"
resolved "https://registry.yarnpkg.com/@photo-sphere-viewer/core/-/core-5.13.2.tgz#518f27a2b7ca5a80068d8922183a9999a1b33ad1"
resolved "https://registry.npmjs.org/@photo-sphere-viewer/core/-/core-5.13.2.tgz"
integrity sha512-rL4Ey39Prx4Iyxt1f2tAqlXvqu4/ovXfUvIpLt540OpZJiFjWccs6qLywof9vuhBJ7PXHudHWCjRPce0W8kx8w==
dependencies:
three "^0.175.0"
@ -703,7 +714,7 @@
"@react-three/drei@^10.1.2":
version "10.1.2"
resolved "https://registry.yarnpkg.com/@react-three/drei/-/drei-10.1.2.tgz#3c41a0b19460aee7604067309cebe737147cf85a"
resolved "https://registry.npmjs.org/@react-three/drei/-/drei-10.1.2.tgz"
integrity sha512-CCcLAqZEvYiUErOcJgGzovY3RH6KgdrqD4ubeAx1nyGbSPLnKR9a8ynYbPdtZhIyiWqGc07z+RYQzpaOfN4ZIA==
dependencies:
"@babel/runtime" "^7.26.0"
@ -730,7 +741,7 @@
"@react-three/fiber@^9.1.2":
version "9.1.2"
resolved "https://registry.yarnpkg.com/@react-three/fiber/-/fiber-9.1.2.tgz#c988f3aa916f64771483784ca3bb6ba4b116395e"
resolved "https://registry.npmjs.org/@react-three/fiber/-/fiber-9.1.2.tgz"
integrity sha512-k8FR9yVHV9kIF3iuOD0ds5hVymXYXfgdKklqziBVod9ZEJ8uk05Zjw29J/omU3IKeUfLNAIHfxneN3TUYM4I2w==
dependencies:
"@babel/runtime" "^7.17.8"
@ -973,7 +984,7 @@
"@tweenjs/tween.js@~23.1.3":
version "23.1.3"
resolved "https://registry.yarnpkg.com/@tweenjs/tween.js/-/tween.js-23.1.3.tgz#eff0245735c04a928bb19c026b58c2a56460539d"
resolved "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz"
integrity sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==
"@tybys/wasm-util@^0.9.0":
@ -1032,7 +1043,7 @@
"@types/draco3d@^1.4.0":
version "1.4.10"
resolved "https://registry.yarnpkg.com/@types/draco3d/-/draco3d-1.4.10.tgz#63ec0ba78b30bd58203ec031f4e4f0198c596dca"
resolved "https://registry.npmjs.org/@types/draco3d/-/draco3d-1.4.10.tgz"
integrity sha512-AX22jp8Y7wwaBgAixaSvkoG4M/+PlAcm3Qs4OW8yT9DM4xUpWKeFhLueTAyZF39pviAdcDdeJoACapiAceqNcw==
"@types/estree-jsx@^1.0.0":
@ -1085,7 +1096,7 @@
"@types/offscreencanvas@^2019.6.4":
version "2019.7.3"
resolved "https://registry.yarnpkg.com/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz#90267db13f64d6e9ccb5ae3eac92786a7c77a516"
resolved "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz"
integrity sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==
"@types/parse-json@^4.0.0":
@ -1100,7 +1111,7 @@
"@types/rbush@4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/rbush/-/rbush-4.0.0.tgz#b327bf54952e9c924ea6702c36904c2ce1d47f35"
resolved "https://registry.npmjs.org/@types/rbush/-/rbush-4.0.0.tgz"
integrity sha512-+N+2H39P8X+Hy1I5mC6awlTX54k3FhiUmvt7HWzGJZvF+syUAAxP/stwppS8JE84YHqFgRMv6fCy31202CMFxQ==
"@types/react-dom@^19.1.2":
@ -1110,7 +1121,7 @@
"@types/react-reconciler@^0.28.9":
version "0.28.9"
resolved "https://registry.yarnpkg.com/@types/react-reconciler/-/react-reconciler-0.28.9.tgz#d24b4864c384e770c83275b3fe73fba00269c83b"
resolved "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.9.tgz"
integrity sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==
"@types/react-transition-group@^4.4.12":
@ -1127,7 +1138,7 @@
"@types/stats.js@*":
version "0.17.4"
resolved "https://registry.yarnpkg.com/@types/stats.js/-/stats.js-0.17.4.tgz#1933e5ff153a23c7664487833198d685c22e791e"
resolved "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.4.tgz"
integrity sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==
"@types/tern@*":
@ -1138,11 +1149,11 @@
"@types/estree" "*"
"@types/three@*":
version "0.176.0"
resolved "https://registry.yarnpkg.com/@types/three/-/three-0.176.0.tgz#b6eced2b05e839395a6171e066c4631bc5b0a1e0"
integrity sha512-FwfPXxCqOtP7EdYMagCFePNKoG1AGBDUEVKtluv2BTVRpSt7b+X27xNsirPCTCqY1pGYsPUzaM3jgWP7dXSxlw==
version "0.177.0"
resolved "https://registry.npmjs.org/@types/three/-/three-0.177.0.tgz"
integrity sha512-/ZAkn4OLUijKQySNci47lFO+4JLE1TihEjsGWPUT+4jWqxtwOPPEwJV1C3k5MEx0mcBPCdkFjzRzDOnHEI1R+A==
dependencies:
"@dimforge/rapier3d-compat" "^0.12.0"
"@dimforge/rapier3d-compat" "~0.12.0"
"@tweenjs/tween.js" "~23.1.3"
"@types/stats.js" "*"
"@types/webxr" "*"
@ -1160,9 +1171,14 @@
resolved "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz"
integrity sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==
"@types/use-sync-external-store@^0.0.6":
version "0.0.6"
resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz#60be8d21baab8c305132eb9cb912ed497852aadc"
integrity sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==
"@types/webxr@*", "@types/webxr@^0.5.2":
version "0.5.22"
resolved "https://registry.yarnpkg.com/@types/webxr/-/webxr-0.5.22.tgz#d8a14c12bbfaaa4a13de21ec2d4a8197b3e1b532"
resolved "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.22.tgz"
integrity sha512-Vr6Stjv5jPRqH690f5I5GLjVk8GSsoQSYJ2FVd/3jJF7KaqfwPi3ehfBS96mlQ2kPCwZaX6U0rG2+NGHBKkA/A==
"@typescript-eslint/eslint-plugin@8.33.0":
@ -1269,12 +1285,12 @@
"@use-gesture/core@10.3.1":
version "10.3.1"
resolved "https://registry.yarnpkg.com/@use-gesture/core/-/core-10.3.1.tgz#976c9421e905f0079d49822cfd5c2e56b808fc56"
resolved "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz"
integrity sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==
"@use-gesture/react@^10.3.1":
version "10.3.1"
resolved "https://registry.yarnpkg.com/@use-gesture/react/-/react-10.3.1.tgz#17a743a894d9bd9a0d1980c618f37f0164469867"
resolved "https://registry.npmjs.org/@use-gesture/react/-/react-10.3.1.tgz"
integrity sha512-Yy19y6O2GJq8f7CHf7L0nxL8bf4PZCPaVOCgJrusOeFHY1LvHgYXnmnXg6N5iwAnbgbZCDjo60SiM6IPJi9C5g==
dependencies:
"@use-gesture/core" "10.3.1"
@ -1293,7 +1309,7 @@
"@webgpu/types@*":
version "0.1.61"
resolved "https://registry.yarnpkg.com/@webgpu/types/-/types-0.1.61.tgz#60ac1756bbeeae778b5357a94d4e6e160592d6f1"
resolved "https://registry.npmjs.org/@webgpu/types/-/types-0.1.61.tgz"
integrity sha512-w2HbBvH+qO19SB5pJOJFKs533CdZqxl3fcGonqL321VHkW7W/iBo6H8bjDy6pr/+pbMwIu5dnuaAxH7NxBqUrQ==
acorn-jsx@^5.3.2:
@ -1330,17 +1346,17 @@ argparse@^2.0.1:
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
attr-accept@^2.2.4:
version "2.2.5"
resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.5.tgz#d7061d958e6d4f97bf8665c68b75851a0713ab5e"
resolved "https://registry.npmjs.org/attr-accept/-/attr-accept-2.2.5.tgz"
integrity sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ==
axios@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-1.9.0.tgz#25534e3b72b54540077d33046f77e3b8d7081901"
resolved "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz"
integrity sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==
dependencies:
follow-redirects "^1.15.6"
@ -1368,12 +1384,12 @@ balanced-match@^1.0.0:
base64-js@^1.3.1, base64-js@^1.5.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
bidi-js@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/bidi-js/-/bidi-js-1.0.3.tgz#6f8bcf3c877c4d9220ddf49b9bb6930c88f877d2"
resolved "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz"
integrity sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==
dependencies:
require-from-string "^2.0.2"
@ -1412,7 +1428,7 @@ browserslist@^4.24.0:
buffer@^6.0.3:
version "6.0.3"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz"
integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
dependencies:
base64-js "^1.3.1"
@ -1420,7 +1436,7 @@ buffer@^6.0.3:
call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6"
resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz"
integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==
dependencies:
es-errors "^1.3.0"
@ -1433,7 +1449,7 @@ callsites@^3.0.0:
camera-controls@^2.9.0:
version "2.10.1"
resolved "https://registry.yarnpkg.com/camera-controls/-/camera-controls-2.10.1.tgz#78bc58001a2d5925c29312154ce77d16967dec56"
resolved "https://registry.npmjs.org/camera-controls/-/camera-controls-2.10.1.tgz"
integrity sha512-KnaKdcvkBJ1Irbrzl8XD6WtZltkRjp869Jx8c0ujs9K+9WD+1D7ryBsCiVqJYUqt6i/HR5FxT7RLASieUD+Q5w==
caniuse-lite@^1.0.30001716:
@ -1510,7 +1526,7 @@ color-name@~1.1.4:
combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
dependencies:
delayed-stream "~1.0.0"
@ -1537,7 +1553,7 @@ convert-source-map@^2.0.0:
cookie@^1.0.1:
version "1.0.2"
resolved "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-1.0.2.tgz#27360701532116bd3f1f9416929d176afe1e4610"
integrity sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==
cosmiconfig@^7.0.0:
@ -1553,7 +1569,7 @@ cosmiconfig@^7.0.0:
cross-env@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz"
integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
dependencies:
cross-spawn "^7.0.1"
@ -1567,6 +1583,13 @@ cross-spawn@^7.0.1, cross-spawn@^7.0.6:
shebang-command "^2.0.0"
which "^2.0.1"
css-box-model@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1"
integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==
dependencies:
tiny-invariant "^1.0.6"
cssesc@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz"
@ -1598,7 +1621,7 @@ deep-is@^0.1.3:
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
dequal@^2.0.0:
@ -1608,7 +1631,7 @@ dequal@^2.0.0:
detect-gpu@^5.0.56:
version "5.0.70"
resolved "https://registry.yarnpkg.com/detect-gpu/-/detect-gpu-5.0.70.tgz#db2202d3cd440714ba6e789ff8b62d1b584eabf7"
resolved "https://registry.npmjs.org/detect-gpu/-/detect-gpu-5.0.70.tgz"
integrity sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==
dependencies:
webgl-constants "^1.1.1"
@ -1635,12 +1658,12 @@ dom-helpers@^5.0.1:
draco3d@^1.4.1:
version "1.5.7"
resolved "https://registry.yarnpkg.com/draco3d/-/draco3d-1.5.7.tgz#94f9bce293eb8920c159dc91a4ce9124a9e899e0"
resolved "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz"
integrity sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==
dunder-proto@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz"
integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
dependencies:
call-bind-apply-helpers "^1.0.1"
@ -1649,7 +1672,7 @@ dunder-proto@^1.0.1:
earcut@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/earcut/-/earcut-3.0.1.tgz#f60b3f671c5657cca9d3e131c5527c5dde00ef38"
resolved "https://registry.npmjs.org/earcut/-/earcut-3.0.1.tgz"
integrity sha512-0l1/0gOjESMeQyYaK5IDiPNvFeu93Z/cO0TjZh9eZ1vyCtZnA7KMZ8rQggpsJHIbGSdrqYq9OhuveadOVHCshw==
easymde@^2.20.0:
@ -1690,24 +1713,24 @@ error-ex@^1.3.1:
es-define-property@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz"
integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
es-errors@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz"
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
es-object-atoms@^1.0.0, es-object-atoms@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1"
resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz"
integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==
dependencies:
es-errors "^1.3.0"
es-set-tostringtag@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d"
resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz"
integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==
dependencies:
es-errors "^1.3.0"
@ -1865,7 +1888,7 @@ esutils@^2.0.2:
eventemitter3@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4"
resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz"
integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==
extend@^3.0.0:
@ -1913,12 +1936,12 @@ fdir@^6.4.4:
fflate@^0.6.9:
version "0.6.10"
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.6.10.tgz#5f40f9659205936a2d18abf88b2e7781662b6d43"
resolved "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz"
integrity sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==
fflate@~0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea"
resolved "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz"
integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==
file-entry-cache@^8.0.0:
@ -1930,7 +1953,7 @@ file-entry-cache@^8.0.0:
file-selector@^2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-2.1.2.tgz#fe7c7ee9e550952dfbc863d73b14dc740d7de8b4"
resolved "https://registry.npmjs.org/file-selector/-/file-selector-2.1.2.tgz"
integrity sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig==
dependencies:
tslib "^2.7.0"
@ -1970,12 +1993,12 @@ flatted@^3.2.9:
follow-redirects@^1.15.6:
version "1.15.9"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1"
resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz"
integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==
form-data@^4.0.0:
version "4.0.2"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.2.tgz#35cabbdd30c3ce73deb2c42d3c8d3ed9ca51794c"
resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz"
integrity sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==
dependencies:
asynckit "^0.4.0"
@ -2000,7 +2023,7 @@ gensync@^1.0.0-beta.2:
geotiff@^2.1.3:
version "2.1.3"
resolved "https://registry.yarnpkg.com/geotiff/-/geotiff-2.1.3.tgz#993f40f2aa6aa65fb1e0451d86dd22ca8e66910c"
resolved "https://registry.npmjs.org/geotiff/-/geotiff-2.1.3.tgz"
integrity sha512-PT6uoF5a1+kbC3tHmZSUsLHBp2QJlHasxxxxPW47QIY1VBKpFB+FcDvX+MxER6UzgLQZ0xDzJ9s48B9JbOCTqA==
dependencies:
"@petamoriken/float16" "^3.4.7"
@ -2014,7 +2037,7 @@ geotiff@^2.1.3:
get-intrinsic@^1.2.6:
version "1.3.0"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz"
integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==
dependencies:
call-bind-apply-helpers "^1.0.2"
@ -2030,7 +2053,7 @@ get-intrinsic@^1.2.6:
get-proto@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1"
resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz"
integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==
dependencies:
dunder-proto "^1.0.1"
@ -2067,12 +2090,12 @@ globals@^16.0.0:
glsl-noise@^0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/glsl-noise/-/glsl-noise-0.0.0.tgz#367745f3a33382c0eeec4cb54b7e99cfc1d7670b"
resolved "https://registry.npmjs.org/glsl-noise/-/glsl-noise-0.0.0.tgz"
integrity sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==
gopd@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz"
integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
graceful-fs@^4.2.4:
@ -2092,12 +2115,12 @@ has-flag@^4.0.0:
has-symbols@^1.0.3, has-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz"
integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
has-tostringtag@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz"
integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
dependencies:
has-symbols "^1.0.3"
@ -2202,9 +2225,9 @@ hastscript@^9.0.0:
space-separated-tokens "^2.0.0"
hls.js@^1.5.17:
version "1.6.4"
resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-1.6.4.tgz#0c4070f5f719eda2687e2ab13b061dbb01967dd8"
integrity sha512-sxFS61suCMJBvpOhmi4WLnarOZ8S8JAxK5J1icvrkopE8aRMc1pRB9WZWMX5Obh9nieVEML6uLLeyGksapyX5A==
version "1.6.5"
resolved "https://registry.npmjs.org/hls.js/-/hls.js-1.6.5.tgz"
integrity sha512-KMn5n7JBK+olC342740hDPHnGWfE8FiHtGMOdJPfUjRdARTWj9OB+8c13fnsf9sk1VtpuU2fKSgUjHvg4rNbzQ==
hoist-non-react-statics@^3.3.1:
version "3.3.2"
@ -2225,7 +2248,7 @@ html-void-elements@^3.0.0:
ieee754@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
ignore@^5.2.0:
@ -2240,7 +2263,7 @@ ignore@^7.0.0:
immediate@~3.0.5:
version "3.0.6"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz"
integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==
import-fresh@^3.2.1:
@ -2325,7 +2348,7 @@ is-plain-obj@^4.0.0:
is-promise@^2.1.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1"
resolved "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz"
integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==
isexe@^2.0.0:
@ -2335,7 +2358,7 @@ isexe@^2.0.0:
its-fine@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/its-fine/-/its-fine-2.0.0.tgz#a90b18a3ee4c211a1fb6faac2abcc2b682ce1f21"
resolved "https://registry.npmjs.org/its-fine/-/its-fine-2.0.0.tgz"
integrity sha512-KLViCmWx94zOvpLwSlsx6yOCeMhZYaxrJV87Po5k/FoZzcPSahvK5qJ7fYhS61sZi5ikmh2S3Hz55A2l3U69ng==
dependencies:
"@types/react-reconciler" "^0.28.9"
@ -2396,7 +2419,7 @@ keyv@^4.5.4:
lerc@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/lerc/-/lerc-3.0.0.tgz#36f36fbd4ba46f0abf4833799fff2e7d6865f5cb"
resolved "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz"
integrity sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==
levn@^0.4.1:
@ -2409,7 +2432,7 @@ levn@^0.4.1:
lie@^3.0.2:
version "3.3.0"
resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a"
resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz"
integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==
dependencies:
immediate "~3.0.5"
@ -2535,7 +2558,7 @@ lucide-react@^0.511.0:
maath@^0.10.8:
version "0.10.8"
resolved "https://registry.yarnpkg.com/maath/-/maath-0.10.8.tgz#cf647544430141bf6982da6e878abb6c4b804e24"
resolved "https://registry.npmjs.org/maath/-/maath-0.10.8.tgz"
integrity sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==
magic-string@^0.30.17:
@ -2552,7 +2575,7 @@ marked@^4.1.0:
math-intrinsics@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz"
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
mdast-util-from-markdown@^2.0.0:
@ -2667,12 +2690,12 @@ merge2@^1.3.0:
meshline@^3.3.1:
version "3.3.1"
resolved "https://registry.yarnpkg.com/meshline/-/meshline-3.3.1.tgz#20decfd5cdd25c8469e862ddf0ab1ad167759734"
resolved "https://registry.npmjs.org/meshline/-/meshline-3.3.1.tgz"
integrity sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==
meshoptimizer@~0.18.1:
version "0.18.1"
resolved "https://registry.yarnpkg.com/meshoptimizer/-/meshoptimizer-0.18.1.tgz#cdb90907f30a7b5b1190facd3b7ee6b7087797d8"
resolved "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz"
integrity sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==
micromark-core-commonmark@^2.0.0:
@ -2879,12 +2902,12 @@ micromatch@^4.0.8:
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
mime-db "1.52.0"
@ -2959,7 +2982,7 @@ object-assign@^4.1.1:
ol@^10.5.0:
version "10.5.0"
resolved "https://registry.yarnpkg.com/ol/-/ol-10.5.0.tgz#5831dc55fe5eb5a09cb4193c9289c1b5a0a0f0ca"
resolved "https://registry.npmjs.org/ol/-/ol-10.5.0.tgz"
integrity sha512-nHFx8gkGmvYImsa7iKkwUnZidd5gn1XbMZd9GNOorvm9orjW9gQvT3Naw/MjIasVJ3cB9EJUdCGR2EFAulMHsQ==
dependencies:
"@types/rbush" "4.0.0"
@ -2996,7 +3019,7 @@ p-locate@^5.0.0:
pako@^2.0.4:
version "2.1.0"
resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86"
resolved "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz"
integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==
parent-module@^1.0.0:
@ -3021,7 +3044,7 @@ parse-entities@^4.0.0:
parse-headers@^2.0.2:
version "2.0.6"
resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.6.tgz#7940f0abe5fe65df2dd25d4ce8800cb35b49d01c"
resolved "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.6.tgz"
integrity sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A==
parse-json@^5.0.0:
@ -3071,7 +3094,7 @@ path@^0.12.7:
pbf@4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/pbf/-/pbf-4.0.1.tgz#ad9015e022b235dcdbe05fc468a9acadf483f0d4"
resolved "https://registry.npmjs.org/pbf/-/pbf-4.0.1.tgz"
integrity sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA==
dependencies:
resolve-protobuf-schema "^2.1.0"
@ -3110,7 +3133,7 @@ postcss@^8.5.3:
potpack@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.2.tgz#23b99e64eb74f5741ffe7656b5b5c4ddce8dfc14"
resolved "https://registry.npmjs.org/potpack/-/potpack-1.0.2.tgz"
integrity sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==
prelude-ls@^1.2.1:
@ -3125,7 +3148,7 @@ process@^0.11.1:
promise-worker-transferable@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz#2c72861ba053e5ae42b487b4a83b1ed3ae3786e8"
resolved "https://registry.npmjs.org/promise-worker-transferable/-/promise-worker-transferable-1.0.4.tgz"
integrity sha512-bN+0ehEnrXfxV2ZQvU2PetO0n4gqBD4ulq3MI1WOPLgr7/Mg9yRQkX5+0v1vagr74ZTsl7XtzlaYDo2EuCeYJw==
dependencies:
is-promise "^2.1.0"
@ -3152,12 +3175,12 @@ property-information@^7.0.0:
protocol-buffers-schema@^3.3.1:
version "3.6.0"
resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz#77bc75a48b2ff142c1ad5b5b90c94cd0fa2efd03"
resolved "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz"
integrity sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==
proxy-from-env@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
punycode@^2.1.0:
@ -3172,17 +3195,22 @@ queue-microtask@^1.2.2:
quick-lru@^6.1.1:
version "6.1.2"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-6.1.2.tgz#e9a90524108629be35287d0b864e7ad6ceb3659e"
resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.2.tgz"
integrity sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==
quickselect@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/quickselect/-/quickselect-3.0.0.tgz#a37fc953867d56f095a20ac71c6d27063d2de603"
resolved "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz"
integrity sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==
raf-schd@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a"
integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
rbush@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/rbush/-/rbush-4.0.1.tgz#1f55afa64a978f71bf9e9a99bc14ff84f3cb0d6d"
resolved "https://registry.npmjs.org/rbush/-/rbush-4.0.1.tgz"
integrity sha512-IP0UpfeWQujYC8Jg162rMNc01Rf0gWMMAb2Uxus/Q0qOFw4lCcq6ZnQEZwUoJqWyUGJ9th7JjwI4yIWo+uvoAQ==
dependencies:
quickselect "^3.0.0"
@ -3196,7 +3224,7 @@ react-dom@^19.1.0:
react-dropzone@^14.3.8:
version "14.3.8"
resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-14.3.8.tgz#a7eab118f8a452fe3f8b162d64454e81ba830582"
resolved "https://registry.npmjs.org/react-dropzone/-/react-dropzone-14.3.8.tgz"
integrity sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug==
dependencies:
attr-accept "^2.2.4"
@ -3232,34 +3260,42 @@ react-markdown@^10.1.0:
react-photo-sphere-viewer@^6.2.3:
version "6.2.3"
resolved "https://registry.yarnpkg.com/react-photo-sphere-viewer/-/react-photo-sphere-viewer-6.2.3.tgz#bdbe33a03315077b1d49f2d4690f0dc72563ac9a"
resolved "https://registry.npmjs.org/react-photo-sphere-viewer/-/react-photo-sphere-viewer-6.2.3.tgz"
integrity sha512-VzG0aY9CI8OIQjdIoJCjYF1QlnLFpN2pM+zKm1JrpAKQrBZ6B+Uxy94vpVQkGDERgn8FWE0+LIntTgAr60pLyQ==
dependencies:
eventemitter3 "^5.0.1"
react-reconciler@^0.31.0:
version "0.31.0"
resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.31.0.tgz#6b7390fe8fab59210daf523d7400943973de1458"
resolved "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.31.0.tgz"
integrity sha512-7Ob7Z+URmesIsIVRjnLoDGwBEG/tVitidU0nMsqX/eeJaLY89RISO/10ERe0MqmzuKUUB1rmY+h1itMbUHg9BQ==
dependencies:
scheduler "^0.25.0"
react-redux@^9.2.0:
version "9.2.0"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.2.0.tgz#96c3ab23fb9a3af2cb4654be4b51c989e32366f5"
integrity sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==
dependencies:
"@types/use-sync-external-store" "^0.0.6"
use-sync-external-store "^1.4.0"
react-refresh@^0.17.0:
version "0.17.0"
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz"
integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==
react-router-dom@^7.6.1:
version "7.6.1"
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.6.1.tgz"
integrity sha512-vxU7ei//UfPYQ3iZvHuO1D/5fX3/JOqhNTbRR+WjSBWxf9bIvpWK+ftjmdfJHzPOuMQKe2fiEdG+dZX6E8uUpA==
version "7.6.2"
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-7.6.2.tgz#e97e386ab390b6503a2a7968124b7a3237fb10c7"
integrity sha512-Q8zb6VlTbdYKK5JJBLQEN06oTUa/RAbG/oQS1auK1I0TbJOXktqm+QENEVJU6QvWynlXPRBXI3fiOQcSEA78rA==
dependencies:
react-router "7.6.1"
react-router "7.6.2"
react-router@7.6.1:
version "7.6.1"
resolved "https://registry.npmjs.org/react-router/-/react-router-7.6.1.tgz"
integrity sha512-hPJXXxHJZEsPFNVbtATH7+MMX43UDeOauz+EAU4cgqTn7ojdI9qQORqS8Z0qmDlL1TclO/6jLRYUEtbWidtdHQ==
react-router@7.6.2:
version "7.6.2"
resolved "https://registry.yarnpkg.com/react-router/-/react-router-7.6.2.tgz#9f48b343bead7d0a94e28342fc4f9ae29131520e"
integrity sha512-U7Nv3y+bMimgWjhlT5CRdzHPu2/KVmqPwKUCChW8en5P3znxUqwlYFlbmyj8Rgp1SF6zs5X4+77kBVknkg6a0w==
dependencies:
cookie "^1.0.1"
set-cookie-parser "^2.6.0"
@ -3273,7 +3309,7 @@ react-simplemde-editor@^5.2.0:
react-toastify@^11.0.5:
version "11.0.5"
resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-11.0.5.tgz#ce4c42d10eeb433988ab2264d3e445c4e9d13313"
resolved "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz"
integrity sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==
dependencies:
clsx "^2.1.1"
@ -3290,7 +3326,7 @@ react-transition-group@^4.4.5:
react-use-measure@^2.1.7:
version "2.1.7"
resolved "https://registry.yarnpkg.com/react-use-measure/-/react-use-measure-2.1.7.tgz#36b8a2e7fd2fa58109ab851b3addcb0aad66ad1d"
resolved "https://registry.npmjs.org/react-use-measure/-/react-use-measure-2.1.7.tgz"
integrity sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==
react@^19.1.0:
@ -3298,6 +3334,11 @@ react@^19.1.0:
resolved "https://registry.npmjs.org/react/-/react-19.1.0.tgz"
integrity sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==
redux@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b"
integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==
rehype-raw@^7.0.0:
version "7.0.0"
resolved "https://registry.npmjs.org/rehype-raw/-/rehype-raw-7.0.0.tgz"
@ -3330,7 +3371,7 @@ remark-rehype@^11.0.0:
require-from-string@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz"
integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
resolve-from@^4.0.0:
@ -3340,7 +3381,7 @@ resolve-from@^4.0.0:
resolve-protobuf-schema@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz#9ca9a9e69cf192bbdaf1006ec1973948aa4a3758"
resolved "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz"
integrity sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==
dependencies:
protocol-buffers-schema "^3.3.1"
@ -3397,7 +3438,7 @@ run-parallel@^1.1.9:
scheduler@^0.25.0:
version "0.25.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015"
resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz"
integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==
scheduler@^0.26.0:
@ -3417,7 +3458,7 @@ semver@^7.6.0:
set-cookie-parser@^2.6.0:
version "2.7.1"
resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz"
resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz#3016f150072202dfbe90fadee053573cc89d2943"
integrity sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==
shebang-command@^2.0.0:
@ -3449,7 +3490,7 @@ space-separated-tokens@^2.0.0:
stats-gl@^2.2.8:
version "2.4.2"
resolved "https://registry.yarnpkg.com/stats-gl/-/stats-gl-2.4.2.tgz#28a6c869fc3a36a8be608ef21df63c0aad99d1ba"
resolved "https://registry.npmjs.org/stats-gl/-/stats-gl-2.4.2.tgz"
integrity sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==
dependencies:
"@types/three" "*"
@ -3457,7 +3498,7 @@ stats-gl@^2.2.8:
stats.js@^0.17.0:
version "0.17.0"
resolved "https://registry.yarnpkg.com/stats.js/-/stats.js-0.17.0.tgz#b1c3dc46d94498b578b7fd3985b81ace7131cc7d"
resolved "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz"
integrity sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==
stringify-entities@^4.0.0:
@ -3506,7 +3547,7 @@ supports-preserve-symlinks-flag@^1.0.0:
suspend-react@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/suspend-react/-/suspend-react-0.1.3.tgz#a52f49d21cfae9a2fb70bd0c68413d3f9d90768e"
resolved "https://registry.npmjs.org/suspend-react/-/suspend-react-0.1.3.tgz"
integrity sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==
tailwindcss@4.1.8, tailwindcss@^4.1.8:
@ -3533,12 +3574,12 @@ tar@^7.4.3:
three-mesh-bvh@^0.8.3:
version "0.8.3"
resolved "https://registry.yarnpkg.com/three-mesh-bvh/-/three-mesh-bvh-0.8.3.tgz#c5e72472e7f062ff79084157a25c122d73184163"
resolved "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.8.3.tgz"
integrity sha512-4G5lBaF+g2auKX3P0yqx+MJC6oVt6sB5k+CchS6Ob0qvH0YIhuUk1eYr7ktsIpY+albCqE80/FVQGV190PmiAg==
three-stdlib@^2.35.6:
version "2.36.0"
resolved "https://registry.yarnpkg.com/three-stdlib/-/three-stdlib-2.36.0.tgz#1d806b8db9156a6c87ed10f61f56f8a3ab634b42"
resolved "https://registry.npmjs.org/three-stdlib/-/three-stdlib-2.36.0.tgz"
integrity sha512-kv0Byb++AXztEGsULgMAs8U2jgUdz6HPpAB/wDJnLiLlaWQX2APHhiTJIN7rqW+Of0eRgcp7jn05U1BsCP3xBA==
dependencies:
"@types/draco3d" "^1.4.0"
@ -3550,19 +3591,24 @@ three-stdlib@^2.35.6:
three@^0.170.0:
version "0.170.0"
resolved "https://registry.yarnpkg.com/three/-/three-0.170.0.tgz#6087f97aab79e9e9312f9c89fcef6808642dfbb7"
resolved "https://registry.npmjs.org/three/-/three-0.170.0.tgz"
integrity sha512-FQK+LEpYc0fBD+J8g6oSEyyNzjp+Q7Ks1C568WWaoMRLW+TkNNWmenWeGgJjV105Gd+p/2ql1ZcjYvNiPZBhuQ==
three@^0.175.0:
version "0.175.0"
resolved "https://registry.yarnpkg.com/three/-/three-0.175.0.tgz#67b357b0b1ee8ef0445b9a768f59363ab1fa7921"
resolved "https://registry.npmjs.org/three/-/three-0.175.0.tgz"
integrity sha512-nNE3pnTHxXN/Phw768u0Grr7W4+rumGg/H6PgeseNJojkJtmeHJfZWi41Gp2mpXl1pg1pf1zjwR4McM1jTqkpg==
three@^0.177.0:
version "0.177.0"
resolved "https://registry.yarnpkg.com/three/-/three-0.177.0.tgz#e51f2eb2b921fbab535bdfa81c403f9993b9dd83"
resolved "https://registry.npmjs.org/three/-/three-0.177.0.tgz"
integrity sha512-EiXv5/qWAaGI+Vz2A+JfavwYCMdGjxVsrn3oBwllUoqYeaBO75J63ZfyaQKoiLrqNHoTlUc6PFgMXnS0kI45zg==
tiny-invariant@^1.0.6:
version "1.3.3"
resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127"
integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==
tinyglobby@^0.2.13:
version "0.2.14"
resolved "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz"
@ -3585,7 +3631,7 @@ trim-lines@^3.0.0:
troika-three-text@^0.52.4:
version "0.52.4"
resolved "https://registry.yarnpkg.com/troika-three-text/-/troika-three-text-0.52.4.tgz#f7b2389a2067d9506a5757457771cf4f6356e738"
resolved "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.52.4.tgz"
integrity sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==
dependencies:
bidi-js "^1.0.2"
@ -3595,12 +3641,12 @@ troika-three-text@^0.52.4:
troika-three-utils@^0.52.4:
version "0.52.4"
resolved "https://registry.yarnpkg.com/troika-three-utils/-/troika-three-utils-0.52.4.tgz#9292019e93cab97582af1cf491c4c895e5c03b66"
resolved "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.52.4.tgz"
integrity sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==
troika-worker-utils@^0.52.0:
version "0.52.0"
resolved "https://registry.yarnpkg.com/troika-worker-utils/-/troika-worker-utils-0.52.0.tgz#ba5525fc444345006ebab0bc9cabdd66f1561e66"
resolved "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.52.0.tgz"
integrity sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==
trough@^2.0.0:
@ -3620,7 +3666,7 @@ tslib@^2.4.0, tslib@^2.7.0, tslib@^2.8.0:
tunnel-rat@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/tunnel-rat/-/tunnel-rat-0.1.2.tgz#1717efbc474ea2d8aa05a91622457a6e201c0aeb"
resolved "https://registry.npmjs.org/tunnel-rat/-/tunnel-rat-0.1.2.tgz"
integrity sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==
dependencies:
zustand "^4.3.2"
@ -3741,7 +3787,7 @@ util@^0.10.3:
utility-types@^3.11.0:
version "3.11.0"
resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.11.0.tgz#607c40edb4f258915e901ea7995607fdf319424c"
resolved "https://registry.npmjs.org/utility-types/-/utility-types-3.11.0.tgz"
integrity sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==
vfile-location@^5.0.0:
@ -3789,17 +3835,17 @@ web-namespaces@^2.0.0:
web-worker@^1.2.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/web-worker/-/web-worker-1.5.0.tgz#71b2b0fbcc4293e8f0aa4f6b8a3ffebff733dcc5"
resolved "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz"
integrity sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==
webgl-constants@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/webgl-constants/-/webgl-constants-1.1.1.tgz#f9633ee87fea56647a60b9ce735cbdfb891c6855"
resolved "https://registry.npmjs.org/webgl-constants/-/webgl-constants-1.1.1.tgz"
integrity sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==
webgl-sdf-generator@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz#3e1b422b3d87cd3cc77f2602c9db63bc0f6accbd"
resolved "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz"
integrity sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==
which@^2.0.1:
@ -3816,7 +3862,7 @@ word-wrap@^1.2.5:
xml-utils@^1.0.2:
version "1.10.2"
resolved "https://registry.yarnpkg.com/xml-utils/-/xml-utils-1.10.2.tgz#436b39ccc25a663ce367ea21abb717afdea5d6b1"
resolved "https://registry.npmjs.org/xml-utils/-/xml-utils-1.10.2.tgz"
integrity sha512-RqM+2o1RYs6T8+3DzDSoTRAUfrvaejbVHcp3+thnAtDKo8LskR+HomLajEy5UjTz24rpka7AxVBRR3g2wTUkJA==
yallist@^3.0.2:
@ -3841,19 +3887,19 @@ yocto-queue@^0.1.0:
zstddec@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/zstddec/-/zstddec-0.1.0.tgz#7050f3f0e0c3978562d0c566b3e5a427d2bad7ec"
resolved "https://registry.npmjs.org/zstddec/-/zstddec-0.1.0.tgz"
integrity sha512-w2NTI8+3l3eeltKAdK8QpiLo/flRAr2p8AGeakfMZOXBxOg9HIu4LVDxBi81sYgVhFhdJjv1OrB5ssI8uFPoLg==
zustand@^4.3.2:
version "4.5.7"
resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.5.7.tgz#7d6bb2026a142415dd8be8891d7870e6dbe65f55"
resolved "https://registry.npmjs.org/zustand/-/zustand-4.5.7.tgz"
integrity sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==
dependencies:
use-sync-external-store "^1.2.2"
zustand@^5.0.1, zustand@^5.0.3:
version "5.0.5"
resolved "https://registry.yarnpkg.com/zustand/-/zustand-5.0.5.tgz#3e236f6a953142d975336d179bc735d97db17e84"
resolved "https://registry.npmjs.org/zustand/-/zustand-5.0.5.tgz"
integrity sha512-mILtRfKW9xM47hqxGIxCv12gXusoY/xTSHBYApXozR0HmQv299whhBeeAcRy+KrPPybzosvJBCOmVjq6x12fCg==
zwitch@^2.0.0: