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
package-lock.jsonpackage.json
src
app
pages
CreateSightPage
EditMediaPage
EditSightPage
MapPage
MediaListPage
shared
const
modals
SelectArticleDialog
SelectMediaDialog
store
MediaStore
widgets
DeleteModal
ImageUploadCard
LeaveAgree
MediaAreaForSight
MediaViewer
SightTabs
CreateInformationTab
CreateLeftTab
CreateRightTab
InformationTab
LeftWidgetTab
RightWidgetTab
SightsTable
index.ts
yarn.lock

1303
package-lock.json generated

File diff suppressed because it is too large Load Diff

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

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

@ -9,37 +9,45 @@ import {
MediaListPage, MediaListPage,
PreviewMediaPage, PreviewMediaPage,
EditMediaPage, EditMediaPage,
// CreateMediaPage,
} from "@pages"; } from "@pages";
import { authStore, createSightStore, editSightStore } from "@shared"; import { authStore, createSightStore, editSightStore } from "@shared";
import { Layout } from "@widgets"; import { Layout } from "@widgets";
import { runInAction } from "mobx"; 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 PublicRoute = ({ children }: { children: React.ReactNode }) => {
const { isAuthenticated } = authStore; const { isAuthenticated } = authStore;
if (isAuthenticated) { if (isAuthenticated) {
return <Navigate to="/sight" />; return <Navigate to="/sight" replace />;
} }
return children; return <>{children}</>;
}; };
const ProtectedRoute = ({ children }: { children: React.ReactNode }) => { const ProtectedRoute = ({ children }: { children: React.ReactNode }) => {
const { isAuthenticated } = authStore; const { isAuthenticated } = authStore;
const pathname = useLocation(); const location = useLocation();
if (!isAuthenticated) { if (!isAuthenticated) {
return <Navigate to="/login" />; return <Navigate to="/login" replace />;
} }
if (pathname.pathname === "/") { if (location.pathname === "/") {
return <Navigate to="/sight" />; 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(() => { useEffect(() => {
editSightStore.clearSightInfo(); editSightStore.clearSightInfo();
@ -47,41 +55,46 @@ export const Router = () => {
runInAction(() => { runInAction(() => {
editSightStore.hasLoadedCommon = false; editSightStore.hasLoadedCommon = false;
}); });
}, [pathname]); }, [location]);
return ( return <>{children}</>;
<Routes> };
<Route
path="/login" const router = createBrowserRouter([
element={ {
<PublicRoute> path: "/login",
<LoginPage /> element: (
</PublicRoute> <PublicRoute>
} <LoginPage />
/> </PublicRoute>
),
{/* Protected routes with layout */} },
<Route {
path="/" path: "/",
element={ element: (
<ProtectedRoute> <ProtectedRoute>
<Layout> <Layout>
<Outlet /> <ClearStoresWrapper>
</Layout> <Outlet />
</ProtectedRoute> </ClearStoresWrapper>
} </Layout>
> </ProtectedRoute>
<Route index element={<MainPage />} /> ),
<Route path="sight" element={<SightPage />} /> children: [
<Route path="sight/:id" element={<EditSightPage />} /> { index: true, element: <MainPage /> },
<Route path="sight/create" element={<CreateSightPage />} /> { path: "sight", element: <SightPage /> },
<Route path="devices" element={<DevicesPage />} /> { path: "sight/create", element: <CreateSightPage /> },
<Route path="map" element={<MapPage />} /> { path: "sight/:id", element: <EditSightPage /> },
<Route path="media" element={<MediaListPage />} /> { path: "devices", element: <DevicesPage /> },
<Route path="media/:id" element={<PreviewMediaPage />} /> { path: "map", element: <MapPage /> },
<Route path="media/:id/edit" element={<EditMediaPage />} /> { path: "media", element: <MediaListPage /> },
{/* <Route path="media/create" element={<CreateMediaPage />} /> */} { path: "media/:id", element: <PreviewMediaPage /> },
</Route> { path: "media/:id/edit", element: <EditMediaPage /> },
</Routes> // { path: "media/create", element: <CreateMediaPage /> },
); ],
},
]);
export const Router = () => {
return <RouterProvider router={router} />;
}; };

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

@ -34,6 +34,7 @@ export const EditMediaPage = observer(() => {
const [mediaName, setMediaName] = useState(media?.media_name ?? ""); const [mediaName, setMediaName] = useState(media?.media_name ?? "");
const [mediaFilename, setMediaFilename] = useState(media?.filename ?? ""); const [mediaFilename, setMediaFilename] = useState(media?.filename ?? "");
const [mediaType, setMediaType] = useState(media?.media_type ?? 1); const [mediaType, setMediaType] = useState(media?.media_type ?? 1);
const [availableMediaTypes, setAvailableMediaTypes] = useState<number[]>([]);
useEffect(() => { useEffect(() => {
if (id) { if (id) {
@ -48,6 +49,18 @@ export const EditMediaPage = observer(() => {
setMediaName(media.media_name); setMediaName(media.media_name);
setMediaFilename(media.filename); setMediaFilename(media.filename);
setMediaType(media.media_type); 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]); }, [media]);
@ -76,8 +89,25 @@ export const EditMediaPage = observer(() => {
const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => { const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
const files = e.target.files; const files = e.target.files;
if (files && files.length > 0) { if (files && files.length > 0) {
setNewFile(files[0]); const file = files[0];
setMediaFilename(files[0].name); 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 setUploadDialogOpen(true); // Open dialog on file selection
} }
}; };
@ -175,11 +205,21 @@ export const EditMediaPage = observer(() => {
onChange={(e) => setMediaType(Number(e.target.value))} onChange={(e) => setMediaType(Number(e.target.value))}
disabled={isLoading} disabled={isLoading}
> >
{Object.entries(MEDIA_TYPE_LABELS).map(([type, label]) => ( {availableMediaTypes.length > 0
<MenuItem key={type} value={Number(type)}> ? availableMediaTypes.map((type) => (
{label} <MenuItem key={type} value={type}>
</MenuItem> {
))} 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> </Select>
</FormControl> </FormControl>

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

@ -28,8 +28,8 @@ import { FeatureLike } from "ol/Feature";
// --- CONFIGURATION --- // --- CONFIGURATION ---
export const mapConfig = { export const mapConfig = {
center: [37.6173, 55.7558] as [number, number], center: [30.311, 59.94] as [number, number],
zoom: 10, zoom: 13,
}; };
// --- SVG ICONS --- // --- SVG ICONS ---
@ -1128,7 +1128,7 @@ const MapControls: React.FC<MapControlsProps> = ({
const controls = [ const controls = [
{ {
mode: "edit", mode: "edit",
title: "Редакт.", title: "Редактировать",
longTitle: "Редактирование", longTitle: "Редактирование",
icon: <EditIcon />, icon: <EditIcon />,
action: () => mapService.activateEditMode(), action: () => mapService.activateEditMode(),
@ -1156,7 +1156,7 @@ const MapControls: React.FC<MapControlsProps> = ({
}, },
]; ];
return ( 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) => ( {controls.map((c) => (
<button <button
key={c.mode} key={c.mode}

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

@ -7,3 +7,14 @@ export const MEDIA_TYPE_LABELS = {
5: "Панорама", 5: "Панорама",
6: "3Д-модель", 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,
};

@ -1,4 +1,4 @@
import { articlesStore, authInstance, languageStore } from "@shared"; import { articlesStore, authInstance, Language, languageStore } from "@shared";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { import {
@ -17,7 +17,7 @@ import {
InputAdornment, InputAdornment,
} from "@mui/material"; } from "@mui/material";
import { ImagePlus, Search } from "lucide-react"; import { ImagePlus, Search } from "lucide-react";
import { ReactMarkdownComponent } from "@widgets"; import { MediaViewer, ReactMarkdownComponent } from "@widgets";
interface SelectArticleModalProps { interface SelectArticleModalProps {
open: boolean; open: boolean;
@ -128,10 +128,12 @@ export const SelectArticleModal = observer(
height: "600px", height: "600px",
display: "flex", display: "flex",
flexDirection: "row", flexDirection: "row",
alignItems: "center",
p: 2, p: 2,
}} }}
> >
<Paper className="w-[66%] flex flex-col" elevation={2}> <Paper className="w-[66%] flex flex-col h-full" elevation={2}>
<TextField <TextField
fullWidth fullWidth
placeholder="Поиск статей..." placeholder="Поиск статей..."
@ -201,108 +203,86 @@ export const SelectArticleModal = observer(
)} )}
</List> </List>
</Paper> </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 <Box
className="rounded-2xl overflow-hidden"
sx={{ sx={{
width: "100%", width: "100%",
height: "100%", height: 175,
background: "#877361",
borderColor: "grey.300",
display: "flex", display: "flex",
flexDirection: "column", alignItems: "center",
justifyContent: "center",
padding: "3px",
}} }}
> >
{isLoading ? ( {articlesStore.articleMedia ? (
<Box <MediaViewer
sx={{ media={{
width: "100%", id: articlesStore.articleMedia.id,
height: "100%", media_type: articlesStore.articleMedia.media_type,
display: "flex", filename: articlesStore.articleMedia.filename,
alignItems: "center",
justifyContent: "center",
}} }}
> />
<Typography color="white">Загрузка...</Typography>
</Box>
) : ( ) : (
<> <ImagePlus size={48} color="white" />
{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>
</>
)} )}
</Box> </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> </Paper>
</DialogContent> </DialogContent>
<DialogActions sx={{ p: 2 }}> <DialogActions sx={{ p: 2 }}>

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

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

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

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

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

@ -69,7 +69,7 @@ export const MediaAreaForSight = observer(
<Box className="w-full flex flex-col items-center justify-center border rounded-md p-4"> <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 flex flex-col items-center justify-center">
<div <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" : "" isDragging ? "bg-blue-100 border-blue-400" : ""
}`} }`}
onDrop={handleDrop} onDrop={handleDrop}

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

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

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

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

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

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

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

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

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

286
yarn.lock

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