mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-04-10 04:39:19 +02:00
Merge branch 'things' into next
This commit is contained in:
commit
a901b10e98
@ -25,8 +25,11 @@
|
||||
"@getalby/bitcoin-connect-react": "^2.4.2",
|
||||
"@noble/hashes": "^1.3.2",
|
||||
"@noble/secp256k1": "^1.7.0",
|
||||
"@react-three/drei": "^9.92.5",
|
||||
"@react-three/fiber": "^8.15.12",
|
||||
"@webscopeio/react-textarea-autocomplete": "^4.9.2",
|
||||
"bech32": "^2.0.0",
|
||||
"blurhash": "^2.0.5",
|
||||
"cheerio": "^1.0.0-rc.12",
|
||||
"chroma-js": "^2.4.2",
|
||||
"dayjs": "^1.11.9",
|
||||
|
10
src/app.tsx
10
src/app.tsx
@ -93,6 +93,9 @@ const StreamView = lazy(() => import("./views/streams/stream"));
|
||||
const SearchView = lazy(() => import("./views/search"));
|
||||
const MapView = lazy(() => import("./views/map"));
|
||||
|
||||
const ThingsView = lazy(() => import("./views/things/index"));
|
||||
const ThingUploadView = lazy(() => import("./views/things/upload"));
|
||||
|
||||
const ChannelsHomeView = lazy(() => import("./views/channels"));
|
||||
const ChannelView = lazy(() => import("./views/channels/channel"));
|
||||
|
||||
@ -268,6 +271,13 @@ const router = createHashRouter([
|
||||
{ path: "satellite-cdn", element: <SatelliteCDNView /> },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "things",
|
||||
children: [
|
||||
{ path: "", element: <ThingsView /> },
|
||||
{ path: "upload", element: <ThingUploadView /> },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "lists",
|
||||
children: [
|
||||
|
12
src/components/back-button.tsx
Normal file
12
src/components/back-button.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { Button, ButtonProps } from "@chakra-ui/react";
|
||||
import { ChevronLeftIcon } from "./icons";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
export default function BackButton({ ...props }: Omit<ButtonProps, "onClick" | "children">) {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<Button leftIcon={<ChevronLeftIcon />} {...props} onClick={() => navigate(-1)}>
|
||||
Back
|
||||
</Button>
|
||||
);
|
||||
}
|
23
src/components/blured-image.tsx
Normal file
23
src/components/blured-image.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import { Box, Image, ImageProps, useDisclosure } from "@chakra-ui/react";
|
||||
|
||||
export default function BlurredImage(props: ImageProps) {
|
||||
const { isOpen, onOpen } = useDisclosure();
|
||||
return (
|
||||
<Box overflow="hidden">
|
||||
<Image
|
||||
onClick={
|
||||
!isOpen
|
||||
? (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
onOpen();
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
cursor="pointer"
|
||||
filter={isOpen ? "" : "blur(1.5rem)"}
|
||||
{...props}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
29
src/components/blurhash-image.tsx
Normal file
29
src/components/blurhash-image.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import { Box, BoxProps } from "@chakra-ui/react";
|
||||
import { decode } from "blurhash";
|
||||
import { useEffect, useRef } from "react";
|
||||
|
||||
export type BlurhashImageProps = {
|
||||
blurhash: string;
|
||||
width: number;
|
||||
height: number;
|
||||
} & Omit<BoxProps, "width" | "height" | "children">;
|
||||
|
||||
export default function BlurhashImage({ blurhash, width, height, ...props }: BlurhashImageProps) {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!canvasRef.current) return;
|
||||
const ctx = canvasRef.current.getContext("2d");
|
||||
if (!ctx) return;
|
||||
|
||||
ctx.canvas.width = width;
|
||||
ctx.canvas.height = height;
|
||||
|
||||
const imageData = ctx.createImageData(width, height);
|
||||
const pixels = decode(blurhash, width, height);
|
||||
imageData.data.set(pixels);
|
||||
ctx.putImageData(imageData, 0, 0);
|
||||
}, [blurhash, width, height]);
|
||||
|
||||
return <Box as="canvas" ref={canvasRef} {...props} />;
|
||||
}
|
@ -63,6 +63,7 @@ import ReverseLeft from "./icons/reverse-left";
|
||||
import Pin01 from "./icons/pin-01";
|
||||
import Translate01 from "./icons/translate-01";
|
||||
import MessageChatSquare from "./icons/message-chat-square";
|
||||
import Package from "./icons/package";
|
||||
|
||||
const defaultProps: IconProps = { boxSize: 4 };
|
||||
|
||||
@ -232,7 +233,6 @@ export const WalletIcon = Wallet02;
|
||||
export const DownloadIcon = Download01;
|
||||
|
||||
export const TranslateIcon = Translate01;
|
||||
|
||||
export const ChannelsIcon = MessageChatSquare;
|
||||
|
||||
export const ThreadIcon = MessageChatSquare;
|
||||
export const ThingsIcon = Package;
|
||||
|
@ -20,6 +20,7 @@ import {
|
||||
NotesIcon,
|
||||
LightningIcon,
|
||||
ChannelsIcon,
|
||||
ThingsIcon,
|
||||
} from "../icons";
|
||||
import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import accountService from "../../services/account";
|
||||
@ -54,6 +55,7 @@ export default function NavItems() {
|
||||
else if (location.pathname.startsWith("/goals")) active = "goals";
|
||||
else if (location.pathname.startsWith("/badges")) active = "badges";
|
||||
else if (location.pathname.startsWith("/emojis")) active = "emojis";
|
||||
else if (location.pathname.startsWith("/things")) active = "things";
|
||||
else if (location.pathname.startsWith("/settings")) active = "settings";
|
||||
else if (location.pathname.startsWith("/tools")) active = "tools";
|
||||
else if (location.pathname.startsWith("/search")) active = "search";
|
||||
@ -206,6 +208,15 @@ export default function NavItems() {
|
||||
>
|
||||
Emojis
|
||||
</Button>
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to="/things"
|
||||
leftIcon={<ThingsIcon boxSize={6} />}
|
||||
colorScheme={active === "things" ? "primary" : undefined}
|
||||
{...buttonProps}
|
||||
>
|
||||
Things
|
||||
</Button>
|
||||
<Button
|
||||
as={RouterLink}
|
||||
to="/tools"
|
||||
|
69
src/components/stl-viewer.tsx
Normal file
69
src/components/stl-viewer.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
import { forwardRef } from "react";
|
||||
import { Box, BoxProps } from "@chakra-ui/react";
|
||||
import { Color, Fog, Vector3 } from "three";
|
||||
import { Canvas, useLoader } from "@react-three/fiber";
|
||||
import { OrbitControls } from "@react-three/drei";
|
||||
import { STLLoader } from "three/examples/jsm/loaders/STLLoader";
|
||||
|
||||
const STLViewer = forwardRef<HTMLCanvasElement, Omit<BoxProps, "children"> & { url: string }>(
|
||||
({ url, ...props }, ref) => {
|
||||
const geometry = useLoader(STLLoader, url);
|
||||
|
||||
if (!geometry.boundingBox) geometry.computeBoundingBox();
|
||||
if (!geometry.boundingSphere) geometry.computeBoundingSphere();
|
||||
|
||||
const objectScale = 2 / geometry.boundingSphere!.radius;
|
||||
const bb = geometry.boundingBox!;
|
||||
const center = bb.getCenter(new Vector3()).multiplyScalar(objectScale);
|
||||
|
||||
return (
|
||||
<Box {...props} position="relative">
|
||||
<Canvas
|
||||
shadows
|
||||
gl={{
|
||||
antialias: true,
|
||||
shadowMapEnabled: true,
|
||||
preserveDrawingBuffer: true,
|
||||
}}
|
||||
style={{ width: "100%", height: "100%" }}
|
||||
scene={{ background: new Color(0xa0a0a0), fog: new Fog(0xa0a0a0, 4, 20) }}
|
||||
camera={{ position: [-2, 2, -2.5] }}
|
||||
ref={ref}
|
||||
>
|
||||
<OrbitControls enableDamping enablePan enableRotate enableZoom />
|
||||
<hemisphereLight color={0xffffff} groundColor={0x444444} intensity={3} position={[0, 20, 0]} />
|
||||
<ambientLight color={0xffffff} intensity={0.5} />
|
||||
<directionalLight color={0xffffff} position={[-5, 15, 10]} castShadow>
|
||||
<orthographicCamera attach="shadow-camera" args={[-2, 2, 2, -2]} />
|
||||
</directionalLight>
|
||||
<mesh
|
||||
rotation={[-Math.PI / 2, 0, 0]}
|
||||
receiveShadow
|
||||
position={[0, ((bb.min.z - bb.max.z) / 2) * objectScale, 0]}
|
||||
>
|
||||
<planeGeometry args={[40, 40]} />
|
||||
<meshPhongMaterial color={0xbbbbbb} depthWrite={false} />
|
||||
</mesh>
|
||||
<gridHelper
|
||||
args={[40, 40, 0x000000, 0x000000]}
|
||||
material-opacity={0.2}
|
||||
material-transparent={true}
|
||||
position={[0, ((bb.min.z - bb.max.z) / 2) * objectScale, 0]}
|
||||
/>
|
||||
<mesh
|
||||
geometry={geometry}
|
||||
scale={objectScale}
|
||||
rotation={[Math.PI * -0.5, 0, 0]}
|
||||
castShadow
|
||||
receiveShadow
|
||||
position={[-center.x, -center.z, center.y]}
|
||||
>
|
||||
<meshPhongMaterial color={0x1a5fb4} shininess={60} flatShading />
|
||||
</mesh>
|
||||
</Canvas>
|
||||
</Box>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export default STLViewer;
|
@ -4,3 +4,19 @@ export function unique<T>(arr: T[]): T[] {
|
||||
export function random<T>(arr: T[]): T {
|
||||
return arr[Math.round(Math.random() * (arr.length - 1))];
|
||||
}
|
||||
|
||||
// copied from https://stackoverflow.com/a/55200387
|
||||
const byteToHex: string[] = [];
|
||||
for (let n = 0; n <= 0xff; ++n) {
|
||||
const hexOctet = n.toString(16).padStart(2, "0");
|
||||
byteToHex.push(hexOctet);
|
||||
}
|
||||
|
||||
export function arrayBufferToHex(arrayBuffer: ArrayBufferLike) {
|
||||
const buff = new Uint8Array(arrayBuffer);
|
||||
const hexOctets = []; // new Array(buff.length) is even faster (preallocates necessary array size), then use hexOctets[i] instead of .push()
|
||||
|
||||
for (let i = 0; i < buff.length; ++i) hexOctets.push(byteToHex[buff[i]]);
|
||||
|
||||
return hexOctets.join("");
|
||||
}
|
||||
|
55
src/helpers/nostr/files.ts
Normal file
55
src/helpers/nostr/files.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
|
||||
export const FILE_KIND = 1063;
|
||||
export const VIDEO_TYPES = ["video/mp4", "video/webm"];
|
||||
export const IMAGE_TYPES = ["image/png", "image/jpeg", "image/svg+xml", "image/webp", "image/gif"];
|
||||
export const AUDIO_TYPES = ["audio/webm", "audio/wav", "audio/ogg"];
|
||||
export const TEXT_TYPES = ["text/plain"];
|
||||
|
||||
export type ParsedImageFile = {
|
||||
url: string;
|
||||
mimeType: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
size?: number;
|
||||
magnet?: string;
|
||||
sha256Hash?: string;
|
||||
infoHash?: string;
|
||||
blurhash?: string;
|
||||
};
|
||||
|
||||
export function getFileUrl(event: NostrEvent) {
|
||||
const url = event.tags.find((t) => t[0] === "url" && t[1])?.[1];
|
||||
if (!url) throw new Error("Missing url");
|
||||
return url;
|
||||
}
|
||||
|
||||
export function parseImageFile(event: NostrEvent): ParsedImageFile {
|
||||
const url = getFileUrl(event);
|
||||
const mimeType = event.tags.find((t) => t[0] === "m" && t[1])?.[1];
|
||||
const magnet = event.tags.find((t) => t[0] === "magnet" && t[1])?.[1];
|
||||
const infoHash = event.tags.find((t) => t[0] === "i" && t[1])?.[1];
|
||||
const size = event.tags.find((t) => t[0] === "i" && t[1])?.[1];
|
||||
const sha256Hash = event.tags.find((t) => t[0] === "x" && t[1])?.[1];
|
||||
const blurhash = event.tags.find((t) => t[0] === "blurhash" && t[1])?.[1];
|
||||
|
||||
const dimensions = event.tags.find((t) => t[0] === "dim" && t[1])?.[1];
|
||||
const [width, height] = dimensions?.split("x").map((v) => parseInt(v)) ?? [];
|
||||
|
||||
if (!mimeType) throw new Error("missing MIME Type");
|
||||
if (width !== undefined && height !== undefined) {
|
||||
if (!Number.isFinite(width) || !Number.isFinite(height)) throw new Error("bad dimensions");
|
||||
}
|
||||
|
||||
return {
|
||||
url,
|
||||
mimeType,
|
||||
width,
|
||||
height,
|
||||
magnet,
|
||||
infoHash,
|
||||
sha256Hash,
|
||||
blurhash,
|
||||
size: size ? parseInt(size) : undefined,
|
||||
};
|
||||
}
|
15
src/hooks/use-object-url.ts
Normal file
15
src/hooks/use-object-url.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export default function useObjectURL(object?: File | Blob | null) {
|
||||
const [url, setUrl] = useState<string>();
|
||||
|
||||
useEffect(() => {
|
||||
if (object) {
|
||||
const u = URL.createObjectURL(object);
|
||||
setUrl(u);
|
||||
return () => URL.revokeObjectURL(u);
|
||||
}
|
||||
}, [object]);
|
||||
|
||||
return url;
|
||||
}
|
@ -2,7 +2,7 @@ import { useCallback, useRef } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
|
||||
type Actions<T> = {
|
||||
setValue: (v: T | ((v: T | undefined) => T)) => void;
|
||||
setValue: (v: T | ((v: T | undefined) => T), replace?: boolean) => void;
|
||||
clearValue: () => void;
|
||||
};
|
||||
|
||||
@ -21,7 +21,7 @@ export default function useRouteStateValue<T extends unknown>(key: string, fallb
|
||||
valueRef.current = stateRef.current[key] ?? fallback;
|
||||
|
||||
const setValue = useCallback(
|
||||
(valueOrSetter: T | ((v: T) => T)) => {
|
||||
(valueOrSetter: T | ((v: T) => T), replace = true) => {
|
||||
const newState = { ...stateRef.current };
|
||||
if (typeof valueOrSetter === "function") {
|
||||
// @ts-ignore
|
||||
@ -29,7 +29,7 @@ export default function useRouteStateValue<T extends unknown>(key: string, fallb
|
||||
} else newState[key] = valueOrSetter;
|
||||
|
||||
if (stateRef.current[key] !== newState[key]) {
|
||||
navigate(".", { state: newState, replace: true });
|
||||
navigate(".", { state: newState, replace });
|
||||
}
|
||||
},
|
||||
[key],
|
||||
|
@ -21,6 +21,10 @@ export type NostrQuery = {
|
||||
"#p"?: string[];
|
||||
"#r"?: string[];
|
||||
"#t"?: string[];
|
||||
"#r"?: string[];
|
||||
"#l"?: string[];
|
||||
"#g"?: string[];
|
||||
"#m"?: string[];
|
||||
since?: number;
|
||||
until?: number;
|
||||
limit?: number;
|
||||
|
157
src/views/files/index.tsx
Normal file
157
src/views/files/index.tsx
Normal file
@ -0,0 +1,157 @@
|
||||
import { Flex, Image, SimpleGrid, Spacer, Text } from "@chakra-ui/react";
|
||||
import { useRef, useState } from "react";
|
||||
|
||||
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||
import useSubject from "../../hooks/use-subject";
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
import { FILE_KIND, IMAGE_TYPES, VIDEO_TYPES, getFileUrl, parseImageFile } from "../../helpers/nostr/files";
|
||||
import { ErrorBoundary } from "../../components/error-boundary";
|
||||
import useAppSettings from "../../hooks/use-app-settings";
|
||||
import { TrustProvider, useTrusted } from "../../providers/trust";
|
||||
import BlurredImage from "../../components/blured-image";
|
||||
import PeopleListProvider, { usePeopleListContext } from "../../providers/people-list-provider";
|
||||
import RelaySelectionProvider, { useRelaySelectionContext } from "../../providers/relay-selection-provider";
|
||||
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
|
||||
import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
|
||||
import { UserAvatarLink } from "../../components/user-avatar-link";
|
||||
import UserLink from "../../components/user-link";
|
||||
import MimeTypePicker from "./mime-type-picker";
|
||||
import TimelineActionAndStatus from "../../components/timeline-page/timeline-action-and-status";
|
||||
import VerticalPageLayout from "../../components/vertical-page-layout";
|
||||
import Timestamp from "../../components/timestamp";
|
||||
import NoteZapButton from "../../components/note/note-zap-button";
|
||||
import IntersectionObserverProvider, { useRegisterIntersectionEntity } from "../../providers/intersection-observer";
|
||||
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
||||
|
||||
function ImageFile({ event }: { event: NostrEvent }) {
|
||||
const parsed = parseImageFile(event);
|
||||
const settings = useAppSettings();
|
||||
const trust = useTrusted();
|
||||
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
useRegisterIntersectionEntity(ref, event.id);
|
||||
|
||||
const shouldBlur = settings.blurImages && !trust;
|
||||
|
||||
// const showImage = useDisclosure();
|
||||
// if (shouldBlur && parsed.blurhash && parsed.width && parsed.height && !showImage.isOpen) {
|
||||
// const aspect = parsed.width / parsed.height;
|
||||
// return (
|
||||
// <BlurhashImage
|
||||
// blurhash={parsed.blurhash}
|
||||
// width={64 * aspect}
|
||||
// height={64}
|
||||
// onClick={showImage.onOpen}
|
||||
// cursor="pointer"
|
||||
// w="full"
|
||||
// />
|
||||
// );
|
||||
// }
|
||||
|
||||
const ImageComponent = shouldBlur ? BlurredImage : Image;
|
||||
return (
|
||||
<Flex
|
||||
direction="column"
|
||||
gap="2"
|
||||
aspectRatio={1}
|
||||
backgroundImage={parsed.url}
|
||||
backgroundPosition="center"
|
||||
backgroundSize="cover"
|
||||
backgroundRepeat="no-repeat"
|
||||
borderRadius="lg"
|
||||
overflow="hidden"
|
||||
ref={ref}
|
||||
>
|
||||
<Flex gap="2" alignItems="center" backgroundColor="blackAlpha.500" mt="auto" p="2">
|
||||
<UserAvatarLink pubkey={event.pubkey} size="sm" />
|
||||
<UserLink pubkey={event.pubkey} fontWeight="bold" isTruncated />
|
||||
<Timestamp timestamp={event.created_at} />
|
||||
<Spacer />
|
||||
<NoteZapButton event={event} size="sm" colorScheme="yellow" variant="outline" />
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
function VideoFile({ event }: { event: NostrEvent }) {
|
||||
const url = getFileUrl(event);
|
||||
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
useRegisterIntersectionEntity(ref, event.id);
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap="2" ref={ref}>
|
||||
<Flex gap="2" alignItems="center">
|
||||
<UserAvatarLink pubkey={event.pubkey} size="sm" />
|
||||
<UserLink pubkey={event.pubkey} fontWeight="bold" />
|
||||
</Flex>
|
||||
<video src={url} controls />
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
|
||||
function FileType({ event }: { event: NostrEvent }) {
|
||||
const mimeType = event.tags.find((t) => t[0] === "m" && t[1])?.[1];
|
||||
|
||||
if (!mimeType) throw new Error("Missing MIME type");
|
||||
|
||||
if (IMAGE_TYPES.includes(mimeType)) {
|
||||
return (
|
||||
<TrustProvider trust>
|
||||
<ImageFile event={event} />
|
||||
</TrustProvider>
|
||||
);
|
||||
}
|
||||
if (VIDEO_TYPES.includes(mimeType)) {
|
||||
return <VideoFile event={event} />;
|
||||
}
|
||||
return <Text>Unknown mine type {mimeType}</Text>;
|
||||
}
|
||||
|
||||
function FilesPage() {
|
||||
const { listId, filter } = usePeopleListContext();
|
||||
const { relays } = useRelaySelectionContext();
|
||||
|
||||
const [selectedTypes, setSelectedTypes] = useState<string[]>(IMAGE_TYPES);
|
||||
|
||||
const timeline = useTimelineLoader(
|
||||
`${listId}-files`,
|
||||
relays,
|
||||
{ kinds: [FILE_KIND], "#m": selectedTypes, ...filter },
|
||||
{ enabled: selectedTypes.length > 0 && !!filter },
|
||||
);
|
||||
|
||||
const events = useSubject(timeline.timeline);
|
||||
const callback = useTimelineCurserIntersectionCallback(timeline);
|
||||
|
||||
return (
|
||||
<VerticalPageLayout>
|
||||
<Flex gap="2">
|
||||
<PeopleListSelection />
|
||||
<MimeTypePicker selected={selectedTypes} onChange={(v) => setSelectedTypes(v)} />
|
||||
<RelaySelectionButton ml="auto" />
|
||||
</Flex>
|
||||
|
||||
<IntersectionObserverProvider callback={callback}>
|
||||
<SimpleGrid minChildWidth="20rem" spacing="2">
|
||||
{events.map((event) => (
|
||||
<ErrorBoundary>
|
||||
<FileType key={event.id} event={event} />
|
||||
</ErrorBoundary>
|
||||
))}
|
||||
</SimpleGrid>
|
||||
</IntersectionObserverProvider>
|
||||
<TimelineActionAndStatus timeline={timeline} />
|
||||
</VerticalPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
export default function FilesView() {
|
||||
return (
|
||||
<PeopleListProvider>
|
||||
<RelaySelectionProvider>
|
||||
<FilesPage />
|
||||
</RelaySelectionProvider>
|
||||
</PeopleListProvider>
|
||||
);
|
||||
}
|
123
src/views/files/mime-type-picker.tsx
Normal file
123
src/views/files/mime-type-picker.tsx
Normal file
@ -0,0 +1,123 @@
|
||||
import { useCallback } from "react";
|
||||
import {
|
||||
Button,
|
||||
Checkbox,
|
||||
Divider,
|
||||
Flex,
|
||||
Popover,
|
||||
PopoverArrow,
|
||||
PopoverBody,
|
||||
PopoverCloseButton,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@chakra-ui/react";
|
||||
|
||||
import { AUDIO_TYPES, IMAGE_TYPES, TEXT_TYPES, VIDEO_TYPES } from "../../helpers/nostr/files";
|
||||
import { unique } from "../../helpers/array";
|
||||
|
||||
export default function MimeTypePicker({
|
||||
selected,
|
||||
onChange,
|
||||
}: {
|
||||
selected: string[];
|
||||
onChange: (selected: string[]) => void;
|
||||
}) {
|
||||
const toggleType = useCallback(
|
||||
(type: string) => {
|
||||
if (selected.includes(type)) {
|
||||
onChange(selected.filter((t) => t !== type));
|
||||
} else onChange(selected.concat(type));
|
||||
},
|
||||
[selected, onChange],
|
||||
);
|
||||
const toggleCategory = useCallback(
|
||||
(types: string[]) => {
|
||||
const selectedTypes = selected.filter((t) => types.includes(t));
|
||||
|
||||
if (selectedTypes.length !== types.length) onChange(unique([...selected, ...types]));
|
||||
else onChange(selected.filter((t) => !types.includes(t)));
|
||||
},
|
||||
[selected, onChange],
|
||||
);
|
||||
|
||||
const selectedImageTypes = selected.filter((t) => IMAGE_TYPES.includes(t));
|
||||
const selectedVideoTypes = selected.filter((t) => VIDEO_TYPES.includes(t));
|
||||
const selectedAudioTypes = selected.filter((t) => AUDIO_TYPES.includes(t));
|
||||
const selectedTextTypes = selected.filter((t) => TEXT_TYPES.includes(t));
|
||||
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger>
|
||||
<Button>{selected.length} Selected types</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent w="xl">
|
||||
<PopoverArrow />
|
||||
<PopoverCloseButton />
|
||||
<PopoverBody>
|
||||
<Flex gap="4">
|
||||
<Flex gap="2" direction="column">
|
||||
<Checkbox
|
||||
isIndeterminate={selectedImageTypes.length > 0 && selectedImageTypes.length !== IMAGE_TYPES.length}
|
||||
isChecked={selectedImageTypes.length === IMAGE_TYPES.length}
|
||||
onChange={() => toggleCategory(IMAGE_TYPES)}
|
||||
>
|
||||
Images
|
||||
</Checkbox>
|
||||
<Divider />
|
||||
{IMAGE_TYPES.map((type) => (
|
||||
<Checkbox key={type} isChecked={selected.includes(type)} onChange={() => toggleType(type)}>
|
||||
{type}
|
||||
</Checkbox>
|
||||
))}
|
||||
</Flex>
|
||||
<Flex gap="2" direction="column">
|
||||
<Checkbox
|
||||
isIndeterminate={selectedVideoTypes.length > 0 && selectedVideoTypes.length !== VIDEO_TYPES.length}
|
||||
isChecked={selectedVideoTypes.length === VIDEO_TYPES.length}
|
||||
onChange={() => toggleCategory(VIDEO_TYPES)}
|
||||
>
|
||||
Videos
|
||||
</Checkbox>
|
||||
<Divider />
|
||||
{VIDEO_TYPES.map((type) => (
|
||||
<Checkbox key={type} isChecked={selected.includes(type)} onChange={() => toggleType(type)}>
|
||||
{type}
|
||||
</Checkbox>
|
||||
))}
|
||||
</Flex>
|
||||
<Flex gap="2" direction="column">
|
||||
<Checkbox
|
||||
isIndeterminate={selectedAudioTypes.length > 0 && selectedAudioTypes.length !== AUDIO_TYPES.length}
|
||||
isChecked={selectedAudioTypes.length === AUDIO_TYPES.length}
|
||||
onChange={() => toggleCategory(AUDIO_TYPES)}
|
||||
>
|
||||
Audio
|
||||
</Checkbox>
|
||||
<Divider />
|
||||
{AUDIO_TYPES.map((type) => (
|
||||
<Checkbox key={type} isChecked={selected.includes(type)} onChange={() => toggleType(type)}>
|
||||
{type}
|
||||
</Checkbox>
|
||||
))}
|
||||
</Flex>
|
||||
<Flex gap="2" direction="column">
|
||||
<Checkbox
|
||||
isIndeterminate={selectedTextTypes.length > 0 && selectedTextTypes.length !== TEXT_TYPES.length}
|
||||
isChecked={selectedTextTypes.length === TEXT_TYPES.length}
|
||||
onChange={() => toggleCategory(TEXT_TYPES)}
|
||||
>
|
||||
Text
|
||||
</Checkbox>
|
||||
<Divider />
|
||||
{TEXT_TYPES.map((type) => (
|
||||
<Checkbox key={type} isChecked={selected.includes(type)} onChange={() => toggleType(type)}>
|
||||
{type}
|
||||
</Checkbox>
|
||||
))}
|
||||
</Flex>
|
||||
</Flex>
|
||||
</PopoverBody>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
56
src/views/things/index.tsx
Normal file
56
src/views/things/index.tsx
Normal file
@ -0,0 +1,56 @@
|
||||
import { Button, Flex, SimpleGrid } from "@chakra-ui/react";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
|
||||
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||
import useSubject from "../../hooks/use-subject";
|
||||
import { FILE_KIND } from "../../helpers/nostr/files";
|
||||
import PeopleListProvider, { usePeopleListContext } from "../../providers/people-list-provider";
|
||||
import RelaySelectionProvider, { useRelaySelectionContext } from "../../providers/relay-selection-provider";
|
||||
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
|
||||
import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
|
||||
import TimelineActionAndStatus from "../../components/timeline-page/timeline-action-and-status";
|
||||
import VerticalPageLayout from "../../components/vertical-page-layout";
|
||||
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
||||
import Upload01 from "../../components/icons/upload-01";
|
||||
import IntersectionObserverProvider from "../../providers/intersection-observer";
|
||||
|
||||
function FilesPage() {
|
||||
const { listId, filter } = usePeopleListContext();
|
||||
const { relays } = useRelaySelectionContext();
|
||||
|
||||
const timeline = useTimelineLoader(
|
||||
`${listId}-files`,
|
||||
relays,
|
||||
filter && { kinds: [FILE_KIND], "#m": ["model/stl"], ...filter },
|
||||
);
|
||||
|
||||
const files = useSubject(timeline.timeline);
|
||||
const callback = useTimelineCurserIntersectionCallback(timeline);
|
||||
|
||||
return (
|
||||
<VerticalPageLayout>
|
||||
<Flex gap="2">
|
||||
<PeopleListSelection />
|
||||
<RelaySelectionButton />
|
||||
<Button as={RouterLink} colorScheme="primary" ml="auto" leftIcon={<Upload01 />} to="/things/upload">
|
||||
New Thing
|
||||
</Button>
|
||||
</Flex>
|
||||
|
||||
<IntersectionObserverProvider callback={callback}>
|
||||
<SimpleGrid minChildWidth="20rem" spacing="2"></SimpleGrid>
|
||||
</IntersectionObserverProvider>
|
||||
<TimelineActionAndStatus timeline={timeline} />
|
||||
</VerticalPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
export default function FilesView() {
|
||||
return (
|
||||
<PeopleListProvider initList="global">
|
||||
<RelaySelectionProvider>
|
||||
<FilesPage />
|
||||
</RelaySelectionProvider>
|
||||
</PeopleListProvider>
|
||||
);
|
||||
}
|
43
src/views/things/upload/confirm-step.tsx
Normal file
43
src/views/things/upload/confirm-step.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import { useState } from "react";
|
||||
import { Button, ButtonGroup, Flex, Heading, Image, Text } from "@chakra-ui/react";
|
||||
|
||||
import useObjectURL from "../../../hooks/use-object-url";
|
||||
import BackButton from "../../../components/back-button";
|
||||
|
||||
export default function ConfirmStep({
|
||||
screenshot,
|
||||
name,
|
||||
hash,
|
||||
summary,
|
||||
onConfirm,
|
||||
}: {
|
||||
screenshot: Blob;
|
||||
name: string;
|
||||
summary: string;
|
||||
hash: string;
|
||||
onConfirm: () => Promise<void>;
|
||||
}) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const objectURL = useObjectURL(screenshot);
|
||||
|
||||
const confirm = async () => {
|
||||
setLoading(true);
|
||||
await onConfirm();
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex gap="2" direction="column" maxW="40rem" w="full" mx="auto">
|
||||
<Image src={objectURL} maxW="2xl" />
|
||||
<Heading size="md">{name}</Heading>
|
||||
<Text>File Hash: {hash}</Text>
|
||||
<Text whiteSpace="pre-line">{summary}</Text>
|
||||
<ButtonGroup ml="auto">
|
||||
<BackButton />
|
||||
<Button onClick={confirm} isLoading={loading} colorScheme="primary">
|
||||
Upload
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
);
|
||||
}
|
46
src/views/things/upload/details-step.tsx
Normal file
46
src/views/things/upload/details-step.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import { Button, ButtonGroup, Flex, FormControl, FormLabel, Input, Textarea } from "@chakra-ui/react";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import BackButton from "../../../components/back-button";
|
||||
|
||||
type FormValues = {
|
||||
name: string;
|
||||
summary: string;
|
||||
};
|
||||
|
||||
export default function DetailsStep({ onSubmit }: { onSubmit: (values: FormValues) => void }) {
|
||||
const { register, getValues, setValue, handleSubmit, watch } = useForm<FormValues>({
|
||||
defaultValues: {
|
||||
name: "",
|
||||
summary: "",
|
||||
},
|
||||
mode: "all",
|
||||
});
|
||||
|
||||
const submit = handleSubmit(onSubmit);
|
||||
|
||||
return (
|
||||
<Flex as="form" onSubmit={submit} gap="2" direction="column" maxW="40rem" w="full" mx="auto">
|
||||
<FormControl isRequired>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<Input {...register("name", { required: true })} placeholder="Thing name" autoComplete="off" />
|
||||
</FormControl>
|
||||
<FormControl isRequired>
|
||||
<FormLabel>Summary</FormLabel>
|
||||
<Textarea
|
||||
rows={3}
|
||||
isRequired
|
||||
placeholder="A short summary of the thing"
|
||||
autoComplete="off"
|
||||
{...register("summary", { required: true })}
|
||||
/>
|
||||
</FormControl>
|
||||
<ButtonGroup ml="auto">
|
||||
<BackButton />
|
||||
<Button type="submit" colorScheme="primary">
|
||||
Next
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
);
|
||||
}
|
112
src/views/things/upload/index.tsx
Normal file
112
src/views/things/upload/index.tsx
Normal file
@ -0,0 +1,112 @@
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
Step,
|
||||
StepDescription,
|
||||
StepIcon,
|
||||
StepIndicator,
|
||||
StepNumber,
|
||||
StepSeparator,
|
||||
StepStatus,
|
||||
StepTitle,
|
||||
Stepper,
|
||||
useToast,
|
||||
} from "@chakra-ui/react";
|
||||
|
||||
import VerticalPageLayout from "../../../components/vertical-page-layout";
|
||||
import { useSigningContext } from "../../../providers/signing-provider";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import useRouteStateValue from "../../../hooks/use-route-state-value";
|
||||
import SelectFileStep from "./select-file-step";
|
||||
import DetailsStep from "./details-step";
|
||||
import PreviewStep from "./preview-step";
|
||||
import ConfirmStep from "./confirm-step";
|
||||
|
||||
const steps = [{ title: "Select File" }, { title: "Details" }, { title: "Upload" }];
|
||||
|
||||
export default function ThingUploadView() {
|
||||
const navigate = useNavigate();
|
||||
const toast = useToast();
|
||||
const { requestSignature } = useSigningContext();
|
||||
|
||||
const step = useRouteStateValue("step", 0);
|
||||
|
||||
const [file, setFile] = useState<Blob>();
|
||||
const [fileURL, setFileURL] = useState<string>();
|
||||
const [hash, setHash] = useState<string>();
|
||||
const [name, setName] = useState<string>();
|
||||
const [summary, setSummary] = useState<string>();
|
||||
const [screenshot, setScreenshot] = useState<Blob>();
|
||||
|
||||
const upload = async () => {
|
||||
try {
|
||||
// const signed = await requestSignature(getDraft());
|
||||
// const pub = new NostrPublishAction("Post", clientRelaysService.getWriteUrls(), signed);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
toast({ description: e.message, status: "error" });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const renderContent = () => {
|
||||
switch (step.value) {
|
||||
case 0:
|
||||
return (
|
||||
<SelectFileStep
|
||||
onSubmit={(values) => {
|
||||
setFile(values.file);
|
||||
if (values.fileURL) setFileURL(values.fileURL);
|
||||
setHash(values.hash);
|
||||
step.setValue(1, false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
case 1:
|
||||
return (
|
||||
<DetailsStep
|
||||
onSubmit={(values) => {
|
||||
setName(values.name);
|
||||
setSummary(values.summary);
|
||||
step.setValue(2, false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
case 2:
|
||||
return (
|
||||
<PreviewStep
|
||||
file={file!}
|
||||
onSubmit={(values) => {
|
||||
setScreenshot(values.screenshot);
|
||||
step.setValue(3, false);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
case 3:
|
||||
return <ConfirmStep name={name!} hash={hash!} summary={summary!} screenshot={screenshot!} onConfirm={upload} />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<VerticalPageLayout>
|
||||
<Stepper index={step.value}>
|
||||
{steps.map((step, index) => (
|
||||
<Step key={index}>
|
||||
<StepIndicator>
|
||||
<StepStatus complete={<StepIcon />} incomplete={<StepNumber />} active={<StepNumber />} />
|
||||
</StepIndicator>
|
||||
|
||||
<Box flexShrink="0">
|
||||
<StepTitle>{step.title}</StepTitle>
|
||||
{/* {step.description && <StepDescription>{step.description}</StepDescription>} */}
|
||||
</Box>
|
||||
|
||||
<StepSeparator />
|
||||
</Step>
|
||||
))}
|
||||
</Stepper>
|
||||
{renderContent()}
|
||||
</VerticalPageLayout>
|
||||
);
|
||||
}
|
54
src/views/things/upload/preview-step.tsx
Normal file
54
src/views/things/upload/preview-step.tsx
Normal file
@ -0,0 +1,54 @@
|
||||
import { useRef } from "react";
|
||||
import { Button, ButtonGroup, Flex, useToast } from "@chakra-ui/react";
|
||||
|
||||
import STLViewer from "../../../components/stl-viewer";
|
||||
import useObjectURL from "../../../hooks/use-object-url";
|
||||
import BackButton from "../../../components/back-button";
|
||||
|
||||
type FormValues = {
|
||||
screenshot: Blob;
|
||||
};
|
||||
|
||||
function canvasToBlob(canvas: HTMLCanvasElement, type?: string): Promise<Blob> {
|
||||
return new Promise((res, rej) => {
|
||||
canvas.toBlob((blob) => {
|
||||
if (blob) res(blob);
|
||||
else rej(new Error("Failed to get blob"));
|
||||
}, type);
|
||||
});
|
||||
}
|
||||
|
||||
export default function PreviewStep({ file, onSubmit }: { file: Blob; onSubmit: (values: FormValues) => void }) {
|
||||
const toast = useToast();
|
||||
|
||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||
const takeScreenshot = async () => {
|
||||
if (!canvasRef.current) return;
|
||||
try {
|
||||
const blob = await canvasToBlob(canvasRef.current, "image/jpeg");
|
||||
onSubmit({ screenshot: blob });
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
toast({ description: e.message, status: "error" });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const previewURL = useObjectURL(file);
|
||||
|
||||
return (
|
||||
<Flex gap="2" direction="column">
|
||||
{previewURL && (
|
||||
<>
|
||||
<STLViewer aspectRatio={16 / 10} url={previewURL} ref={canvasRef} />
|
||||
<ButtonGroup ml="auto">
|
||||
<BackButton />
|
||||
<Button onClick={takeScreenshot} colorScheme="primary">
|
||||
Take Screenshot
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
);
|
||||
}
|
87
src/views/things/upload/select-file-step.tsx
Normal file
87
src/views/things/upload/select-file-step.tsx
Normal file
@ -0,0 +1,87 @@
|
||||
import { ChangeEventHandler, useCallback } from "react";
|
||||
import { Button, ButtonGroup, Divider, Flex, FormControl, FormLabel, Heading, Input, useToast } from "@chakra-ui/react";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import useObjectURL from "../../../hooks/use-object-url";
|
||||
import { arrayBufferToHex } from "../../../helpers/array";
|
||||
import BackButton from "../../../components/back-button";
|
||||
|
||||
type FormValues = {
|
||||
file: Blob;
|
||||
fileURL?: string;
|
||||
hash: string;
|
||||
};
|
||||
|
||||
// example file https://tonybox.net/objects/keystone/keystone.stl
|
||||
|
||||
export default function SelectFileStep({ onSubmit }: { onSubmit: (values: FormValues) => void }) {
|
||||
const toast = useToast();
|
||||
const { register, getValues, setValue, handleSubmit, watch, resetField } = useForm<FormValues>({
|
||||
defaultValues: {
|
||||
fileURL: "",
|
||||
},
|
||||
mode: "all",
|
||||
});
|
||||
watch("file");
|
||||
watch("fileURL");
|
||||
|
||||
const handleFileChange = useCallback<ChangeEventHandler<HTMLInputElement>>(
|
||||
(e) => {
|
||||
const file = e.target.files?.[0];
|
||||
if (file) setValue("file", file);
|
||||
else resetField("file");
|
||||
},
|
||||
[setValue, resetField],
|
||||
);
|
||||
|
||||
const submit = handleSubmit(async (values) => {
|
||||
try {
|
||||
let file: Blob | undefined = values.file;
|
||||
if (!file && values.fileURL) file = await fetch(values.fileURL).then((res) => res.blob());
|
||||
if (!file) throw new Error("Cant access file");
|
||||
|
||||
// get file hash
|
||||
const buffer = await file.arrayBuffer();
|
||||
const hash = await window.crypto.subtle.digest("SHA-256", buffer);
|
||||
onSubmit({ hash: arrayBufferToHex(hash), file, fileURL: values.fileURL });
|
||||
|
||||
// const signed = await requestSignature(getDraft());
|
||||
// const pub = new NostrPublishAction("Post", clientRelaysService.getWriteUrls(), signed);
|
||||
} catch (e) {
|
||||
if (e instanceof Error) {
|
||||
toast({ description: e.message, status: "error" });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const fileObjectURL = useObjectURL(getValues().file);
|
||||
const stlURL = fileObjectURL || getValues().fileURL;
|
||||
let step = 0;
|
||||
if (getValues().file) step = 1;
|
||||
|
||||
return (
|
||||
<Flex as="form" onSubmit={submit} direction="column" gap="2" maxW="40rem" w="full" mx="auto">
|
||||
<Heading size="md">Upload File</Heading>
|
||||
<Input type="file" accept="model/stl" placeholder="Select STL file" onChange={handleFileChange} isDisabled />
|
||||
<Flex gap="4" alignItems="center" my="4">
|
||||
<Divider />
|
||||
<Heading size="sm">OR</Heading>
|
||||
<Divider />
|
||||
</Flex>
|
||||
<Heading size="md">Use Remote File</Heading>
|
||||
<Input
|
||||
type="url"
|
||||
{...register("fileURL", { validate: (str) => str && str.endsWith(".stl"), required: true })}
|
||||
placeholder="https://example.com/files/things/cube.stl"
|
||||
onChange={handleFileChange}
|
||||
autoComplete="off"
|
||||
/>
|
||||
<ButtonGroup ml="auto">
|
||||
<BackButton />
|
||||
<Button type="submit" colorScheme="primary">
|
||||
Next
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
);
|
||||
}
|
369
yarn.lock
369
yarn.lock
@ -2466,6 +2466,11 @@
|
||||
globby "^11.0.0"
|
||||
read-yaml-file "^1.1.0"
|
||||
|
||||
"@mediapipe/tasks-vision@0.10.8":
|
||||
version "0.10.8"
|
||||
resolved "https://registry.yarnpkg.com/@mediapipe/tasks-vision/-/tasks-vision-0.10.8.tgz#a78e137018a19933b7a1d0e887d553d4ab833d10"
|
||||
integrity sha512-Rp7ll8BHrKB3wXaRFKhrltwZl1CiXGdibPxuWXvqGnKTnv8fqa/nvftYNuSbf+pbJWKYCXdBtYTITdAUTGGh0Q==
|
||||
|
||||
"@noble/ciphers@0.2.0":
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.2.0.tgz#a12cda60f3cf1ab5d7c77068c3711d2366649ed7"
|
||||
@ -2541,6 +2546,99 @@
|
||||
resolved "https://registry.yarnpkg.com/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz#d1b4befa423f692fa4abf1c79209702e7d8ae4b4"
|
||||
integrity sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==
|
||||
|
||||
"@react-spring/animated@~9.6.1":
|
||||
version "9.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-spring/animated/-/animated-9.6.1.tgz#ccc626d847cbe346f5f8815d0928183c647eb425"
|
||||
integrity sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==
|
||||
dependencies:
|
||||
"@react-spring/shared" "~9.6.1"
|
||||
"@react-spring/types" "~9.6.1"
|
||||
|
||||
"@react-spring/core@~9.6.1":
|
||||
version "9.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-spring/core/-/core-9.6.1.tgz#ebe07c20682b360b06af116ea24e2b609e778c10"
|
||||
integrity sha512-3HAAinAyCPessyQNNXe5W0OHzRfa8Yo5P748paPcmMowZ/4sMfaZ2ZB6e5x5khQI8NusOHj8nquoutd6FRY5WQ==
|
||||
dependencies:
|
||||
"@react-spring/animated" "~9.6.1"
|
||||
"@react-spring/rafz" "~9.6.1"
|
||||
"@react-spring/shared" "~9.6.1"
|
||||
"@react-spring/types" "~9.6.1"
|
||||
|
||||
"@react-spring/rafz@~9.6.1":
|
||||
version "9.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-spring/rafz/-/rafz-9.6.1.tgz#d71aafb92b78b24e4ff84639f52745afc285c38d"
|
||||
integrity sha512-v6qbgNRpztJFFfSE3e2W1Uz+g8KnIBs6SmzCzcVVF61GdGfGOuBrbjIcp+nUz301awVmREKi4eMQb2Ab2gGgyQ==
|
||||
|
||||
"@react-spring/shared@~9.6.1":
|
||||
version "9.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-spring/shared/-/shared-9.6.1.tgz#4e2e4296910656c02bd9fd54c559702bc836ac4e"
|
||||
integrity sha512-PBFBXabxFEuF8enNLkVqMC9h5uLRBo6GQhRMQT/nRTnemVENimgRd+0ZT4yFnAQ0AxWNiJfX3qux+bW2LbG6Bw==
|
||||
dependencies:
|
||||
"@react-spring/rafz" "~9.6.1"
|
||||
"@react-spring/types" "~9.6.1"
|
||||
|
||||
"@react-spring/three@~9.6.1":
|
||||
version "9.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-spring/three/-/three-9.6.1.tgz#095fcd1dc6509127c33c14486d88289b89baeb9d"
|
||||
integrity sha512-Tyw2YhZPKJAX3t2FcqvpLRb71CyTe1GvT3V+i+xJzfALgpk10uPGdGaQQ5Xrzmok1340DAeg2pR/MCfaW7b8AA==
|
||||
dependencies:
|
||||
"@react-spring/animated" "~9.6.1"
|
||||
"@react-spring/core" "~9.6.1"
|
||||
"@react-spring/shared" "~9.6.1"
|
||||
"@react-spring/types" "~9.6.1"
|
||||
|
||||
"@react-spring/types@~9.6.1":
|
||||
version "9.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@react-spring/types/-/types-9.6.1.tgz#913d3a68c5cbc1124fdb18eff919432f7b6abdde"
|
||||
integrity sha512-POu8Mk0hIU3lRXB3bGIGe4VHIwwDsQyoD1F394OK7STTiX9w4dG3cTLljjYswkQN+hDSHRrj4O36kuVa7KPU8Q==
|
||||
|
||||
"@react-three/drei@^9.92.5":
|
||||
version "9.92.5"
|
||||
resolved "https://registry.yarnpkg.com/@react-three/drei/-/drei-9.92.5.tgz#4677667af82e60f0792633eb3460596f2868aab6"
|
||||
integrity sha512-uH1wMCVO5N0iOyf1J1XjaoHHWALKuF89Nj+6fyW/LMtl8RrtmCGbo5kKJiXAKNZvXtjvuMmhfkZyNFWUT3C4Fw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.11.2"
|
||||
"@mediapipe/tasks-vision" "0.10.8"
|
||||
"@react-spring/three" "~9.6.1"
|
||||
"@use-gesture/react" "^10.2.24"
|
||||
camera-controls "^2.4.2"
|
||||
cross-env "^7.0.3"
|
||||
detect-gpu "^5.0.28"
|
||||
glsl-noise "^0.0.0"
|
||||
lodash.clamp "^4.0.3"
|
||||
lodash.omit "^4.5.0"
|
||||
lodash.pick "^4.4.0"
|
||||
maath "^0.10.7"
|
||||
meshline "^3.1.6"
|
||||
react-composer "^5.0.3"
|
||||
react-merge-refs "^1.1.0"
|
||||
stats-gl "^2.0.0"
|
||||
stats.js "^0.17.0"
|
||||
suspend-react "^0.1.3"
|
||||
three-mesh-bvh "^0.6.7"
|
||||
three-stdlib "^2.28.0"
|
||||
troika-three-text "^0.47.2"
|
||||
utility-types "^3.10.0"
|
||||
uuid "^9.0.1"
|
||||
zustand "^3.5.13"
|
||||
|
||||
"@react-three/fiber@^8.15.12":
|
||||
version "8.15.12"
|
||||
resolved "https://registry.yarnpkg.com/@react-three/fiber/-/fiber-8.15.12.tgz#0bc08730eec32e53373482fbb518d116d3aa3df3"
|
||||
integrity sha512-yg0CyXVHIdSbNjM/GAgDrGJnKLTsfTlaR5FoJGEh9IgVKptOoudnFZhBt/Cau4rzx2X6eLmB1+aWOm1dEHSUpg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.17.8"
|
||||
"@types/react-reconciler" "^0.26.7"
|
||||
"@types/webxr" "*"
|
||||
base64-js "^1.5.1"
|
||||
buffer "^6.0.3"
|
||||
its-fine "^1.0.6"
|
||||
react-reconciler "^0.27.0"
|
||||
react-use-measure "^2.1.1"
|
||||
scheduler "^0.21.0"
|
||||
suspend-react "^0.1.3"
|
||||
zustand "^3.7.1"
|
||||
|
||||
"@remix-run/router@1.11.0":
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.11.0.tgz#e0e45ac3fff9d8a126916f166809825537e9f955"
|
||||
@ -2751,6 +2849,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/dom-serial/-/dom-serial-1.0.6.tgz#48462122c0e943195d0611027ff9de979f04f43f"
|
||||
integrity sha512-eUHKbc6mdMgMm75/oBLocs3wkOQkPQ/oNCT+b5OgUT6mLgIvDTp3wCCE9tYZNvDPPh6Cj9lVg2IguWfS/mDrrQ==
|
||||
|
||||
"@types/draco3d@^1.4.0":
|
||||
version "1.4.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/draco3d/-/draco3d-1.4.9.tgz#eb3eb7c5fd6f3490ab86ed7ebf36e595a9dc179b"
|
||||
integrity sha512-4MMUjMQb4yA5fJ4osXx+QxGHt0/ZSy4spT6jL1HM7Tn8OJEC35siqdnpOo+HxPhYjqEFumKfGVF9hJfdyKBIBA==
|
||||
|
||||
"@types/estree@0.0.39":
|
||||
version "0.0.39"
|
||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
|
||||
@ -2855,6 +2958,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901"
|
||||
integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==
|
||||
|
||||
"@types/offscreencanvas@^2019.6.4":
|
||||
version "2019.7.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz#90267db13f64d6e9ccb5ae3eac92786a7c77a516"
|
||||
integrity sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==
|
||||
|
||||
"@types/parse-json@^4.0.0":
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239"
|
||||
@ -2872,6 +2980,20 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-reconciler@^0.26.7":
|
||||
version "0.26.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-reconciler/-/react-reconciler-0.26.7.tgz#0c4643f30821ae057e401b0d9037e03e8e9b2a36"
|
||||
integrity sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-reconciler@^0.28.0":
|
||||
version "0.28.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-reconciler/-/react-reconciler-0.28.8.tgz#e51710572bcccf214306833c2438575d310b3e98"
|
||||
integrity sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*", "@types/react@^16.9.35", "@types/react@^18.2.22":
|
||||
version "18.2.37"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.37.tgz#0f03af69e463c0f19a356c2660dbca5d19c44cae"
|
||||
@ -2930,6 +3052,23 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/webxr/-/webxr-0.5.8.tgz#904535c778318d434d9236872404fca47ce43260"
|
||||
integrity sha512-9vRpV4nMzuZIdJiu/nHUk1AQV0cguaBI32DIauJXBxpvG3wiXk3VD+kQKx111V7I/YvAoGyJZTyhaWODYEbZ0w==
|
||||
|
||||
"@types/webxr@^0.5.2":
|
||||
version "0.5.10"
|
||||
resolved "https://registry.yarnpkg.com/@types/webxr/-/webxr-0.5.10.tgz#19c76208ec015ca3f139505e14d94d6b740f518a"
|
||||
integrity sha512-n3u5sqXQJhf1CS68mw3Wf16FQ4cRPNBBwdYLFzq3UddiADOim1Pn3Y6PBdDilz1vOJF3ybLxJ8ZEDlLIzrOQZg==
|
||||
|
||||
"@use-gesture/core@10.3.0":
|
||||
version "10.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@use-gesture/core/-/core-10.3.0.tgz#9afd3777a45b2a08990a5dcfcf8d9ddd55b00db9"
|
||||
integrity sha512-rh+6MND31zfHcy9VU3dOZCqGY511lvGcfyJenN4cWZe0u1BH6brBpBddLVXhF2r4BMqWbvxfsbL7D287thJU2A==
|
||||
|
||||
"@use-gesture/react@^10.2.24":
|
||||
version "10.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@use-gesture/react/-/react-10.3.0.tgz#180534c821fd635c2853cbcfa813f92c94f27e3f"
|
||||
integrity sha512-3zc+Ve99z4usVP6l9knYVbVnZgfqhKah7sIG+PS2w+vpig2v2OLct05vs+ZXMzwxdNCMka8B+8WlOo0z6Pn6DA==
|
||||
dependencies:
|
||||
"@use-gesture/core" "10.3.0"
|
||||
|
||||
"@vitejs/plugin-react@^4.2.1":
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz#744d8e4fcb120fc3dbaa471dadd3483f5a304bb9"
|
||||
@ -3137,7 +3276,7 @@ balanced-match@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
|
||||
|
||||
base64-js@^1.3.1:
|
||||
base64-js@^1.3.1, base64-js@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||
@ -3164,6 +3303,18 @@ better-path-resolve@1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/bezier-js/-/bezier-js-6.1.4.tgz#c7828f6c8900562b69d5040afb881bcbdad82001"
|
||||
integrity sha512-PA0FW9ZpcHbojUCMu28z9Vg/fNkwTj5YhusSAjHHDfHDGLxJ6YUKrAN2vk1fP2MMOxVw4Oko16FMlRGVBGqLKg==
|
||||
|
||||
bidi-js@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/bidi-js/-/bidi-js-1.0.3.tgz#6f8bcf3c877c4d9220ddf49b9bb6930c88f877d2"
|
||||
integrity sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==
|
||||
dependencies:
|
||||
require-from-string "^2.0.2"
|
||||
|
||||
blurhash@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/blurhash/-/blurhash-2.0.5.tgz#efde729fc14a2f03571a6aa91b49cba80d1abe4b"
|
||||
integrity sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==
|
||||
|
||||
bn.js@^4.11.8:
|
||||
version "4.12.0"
|
||||
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
|
||||
@ -3274,6 +3425,11 @@ camelcase@^8.0.0:
|
||||
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-8.0.0.tgz#c0d36d418753fb6ad9c5e0437579745c1c14a534"
|
||||
integrity sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==
|
||||
|
||||
camera-controls@^2.4.2:
|
||||
version "2.7.3"
|
||||
resolved "https://registry.yarnpkg.com/camera-controls/-/camera-controls-2.7.3.tgz#99e0449f68d203bf5f98f6c4ac0021c10b5c13a8"
|
||||
integrity sha512-L4mxjBd3u8qiOLozdWrH2P8ZybSsDXBF7iyNyqNEFJhPUkovmuARWR8JTc1B/qlclOIg6FvZZA/0uAZMMim0mw==
|
||||
|
||||
caniuse-lite@^1.0.30001541:
|
||||
version "1.0.30001561"
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz#752f21f56f96f1b1a52e97aae98c57c562d5d9da"
|
||||
@ -3460,6 +3616,13 @@ cosmiconfig@^7.0.0:
|
||||
path-type "^4.0.0"
|
||||
yaml "^1.10.0"
|
||||
|
||||
cross-env@^7.0.3:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
|
||||
integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
|
||||
dependencies:
|
||||
cross-spawn "^7.0.1"
|
||||
|
||||
cross-spawn@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
|
||||
@ -3469,6 +3632,15 @@ cross-spawn@^5.1.0:
|
||||
shebang-command "^1.2.0"
|
||||
which "^1.2.9"
|
||||
|
||||
cross-spawn@^7.0.1:
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
|
||||
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
|
||||
dependencies:
|
||||
path-key "^3.1.0"
|
||||
shebang-command "^2.0.0"
|
||||
which "^2.0.1"
|
||||
|
||||
crypto-js@4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf"
|
||||
@ -3702,6 +3874,11 @@ dayjs@^1.11.9:
|
||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0"
|
||||
integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==
|
||||
|
||||
debounce@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
|
||||
integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
|
||||
|
||||
debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||
@ -3752,6 +3929,13 @@ define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0:
|
||||
has-property-descriptors "^1.0.0"
|
||||
object-keys "^1.1.1"
|
||||
|
||||
detect-gpu@^5.0.28:
|
||||
version "5.0.37"
|
||||
resolved "https://registry.yarnpkg.com/detect-gpu/-/detect-gpu-5.0.37.tgz#27febe44d478ef4d35cd38007355da795ba075d5"
|
||||
integrity sha512-EraWs84faI4iskB4qvE39bevMIazEvd1RpoyGLOBesRLbiz6eMeJqqRPHjEFClfRByYZzi9IzU35rBXIO76oDw==
|
||||
dependencies:
|
||||
webgl-constants "^1.1.1"
|
||||
|
||||
detect-indent@^6.0.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6"
|
||||
@ -3813,6 +3997,11 @@ domutils@^3.0.1:
|
||||
domelementtype "^2.3.0"
|
||||
domhandler "^5.0.3"
|
||||
|
||||
draco3d@^1.4.1:
|
||||
version "1.5.6"
|
||||
resolved "https://registry.yarnpkg.com/draco3d/-/draco3d-1.5.6.tgz#0d570a9792e3a3a9fafbfea065b692940441c626"
|
||||
integrity sha512-+3NaRjWktb5r61ZFoDejlykPEFKT5N/LkbXsaddlw6xNSXBanUYpFc2AXXpbJDilPHazcSreU/DpQIaxfX0NfQ==
|
||||
|
||||
ejs@^3.1.6:
|
||||
version "3.1.9"
|
||||
resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361"
|
||||
@ -4057,7 +4246,7 @@ fastq@^1.6.0:
|
||||
dependencies:
|
||||
reusify "^1.0.4"
|
||||
|
||||
fflate@~0.6.10:
|
||||
fflate@^0.6.9, fflate@~0.6.10:
|
||||
version "0.6.10"
|
||||
resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.6.10.tgz#5f40f9659205936a2d18abf88b2e7781662b6d43"
|
||||
integrity sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==
|
||||
@ -4299,6 +4488,11 @@ globby@^11.0.0:
|
||||
merge2 "^1.4.1"
|
||||
slash "^3.0.0"
|
||||
|
||||
glsl-noise@^0.0.0:
|
||||
version "0.0.0"
|
||||
resolved "https://registry.yarnpkg.com/glsl-noise/-/glsl-noise-0.0.0.tgz#367745f3a33382c0eeec4cb54b7e99cfc1d7670b"
|
||||
integrity sha512-b/ZCF6amfAUb7dJM/MxRs7AetQEahYzJ8PtgfrmEdtw6uyGOr+ZSGtgjFm6mfsBkxJ4d2W7kg+Nlqzqvn3Bc0w==
|
||||
|
||||
gopd@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
|
||||
@ -4685,6 +4879,13 @@ iso-language-codes@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/iso-language-codes/-/iso-language-codes-2.0.0.tgz#2506da1becda1e5e7e9245734f4872ecbcca497a"
|
||||
integrity sha512-krdJem8Yu0DfublYzvHViZxTXGjkvqV5j8wcDzrGNgWiISW1Ow9Su5cy1R+HyuWL84zpuZ/MuYFg3fawbx9IjA==
|
||||
|
||||
its-fine@^1.0.6:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/its-fine/-/its-fine-1.1.1.tgz#e74b93fddd487441f978a50f64f0f5af4d2fc38e"
|
||||
integrity sha512-v1Ia1xl20KbuSGlwoaGsW0oxsw8Be+TrXweidxD9oT/1lAh6O3K3/GIM95Tt6WCiv6W+h2M7RB1TwdoAjQyyKw==
|
||||
dependencies:
|
||||
"@types/react-reconciler" "^0.28.0"
|
||||
|
||||
jake@^10.8.5:
|
||||
version "10.8.7"
|
||||
resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.7.tgz#63a32821177940c33f356e0ba44ff9d34e1c7d8f"
|
||||
@ -4856,6 +5057,11 @@ lodash-es@4:
|
||||
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
|
||||
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
|
||||
|
||||
lodash.clamp@^4.0.3:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/lodash.clamp/-/lodash.clamp-4.0.3.tgz#5c24bedeeeef0753560dc2b4cb4671f90a6ddfaa"
|
||||
integrity sha512-HvzRFWjtcguTW7yd8NJBshuNaCa8aqNFtnswdT7f/cMd/1YKy5Zzoq4W/Oxvnx9l7aeY258uSdDfM793+eLsVg==
|
||||
|
||||
lodash.debounce@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
|
||||
@ -4866,6 +5072,16 @@ lodash.mergewith@4.6.2:
|
||||
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
|
||||
integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
|
||||
|
||||
lodash.omit@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60"
|
||||
integrity sha512-XeqSp49hNGmlkj2EJlfrQFIzQ6lXdNro9sddtQzcJY8QaoC2GO0DT7xaIokHeyM+mIT0mPMlPvkYzg2xCuHdZg==
|
||||
|
||||
lodash.pick@^4.4.0:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
|
||||
integrity sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q==
|
||||
|
||||
lodash.sortby@^4.7.0:
|
||||
version "4.7.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||
@ -4915,6 +5131,11 @@ lru-cache@^6.0.0:
|
||||
dependencies:
|
||||
yallist "^4.0.0"
|
||||
|
||||
maath@^0.10.7:
|
||||
version "0.10.7"
|
||||
resolved "https://registry.yarnpkg.com/maath/-/maath-0.10.7.tgz#9289b42a5db8ac5b26407b3bfca4e3bebefe50b4"
|
||||
integrity sha512-zQ2xd7dNOIVTjAS+hj22fyj1EFYmOJX6tzKjZ92r6WDoq8hyFxjuGA2q950tmR4iC/EKXoMQdSipkaJVuUHDTg==
|
||||
|
||||
magic-string@^0.25.0, magic-string@^0.25.7:
|
||||
version "0.25.9"
|
||||
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
|
||||
@ -4972,6 +5193,11 @@ merge2@^1.3.0, merge2@^1.4.1:
|
||||
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
|
||||
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||
|
||||
meshline@^3.1.6:
|
||||
version "3.1.7"
|
||||
resolved "https://registry.yarnpkg.com/meshline/-/meshline-3.1.7.tgz#f60fef8c5b859740078a60c701b4c95bcc6f794d"
|
||||
integrity sha512-uf9fPI9wy0Ie0kZjvKuIkf2n7gi3ih0wdTeb/kmSvmzpPyEL5d9lFohg9+JV9VC4sQUBOZDgxu6fnjn57goSHg==
|
||||
|
||||
meshoptimizer@~0.18.1:
|
||||
version "0.18.1"
|
||||
resolved "https://registry.yarnpkg.com/meshoptimizer/-/meshoptimizer-0.18.1.tgz#cdb90907f30a7b5b1190facd3b7ee6b7087797d8"
|
||||
@ -5251,6 +5477,11 @@ path-is-absolute@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
|
||||
|
||||
path-key@^3.1.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
|
||||
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
|
||||
|
||||
path-parse@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
|
||||
@ -5299,6 +5530,11 @@ postcss@^8.4.32:
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^1.0.2"
|
||||
|
||||
potpack@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.2.tgz#23b99e64eb74f5741ffe7656b5b5c4ddce8dfc14"
|
||||
integrity sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ==
|
||||
|
||||
preferred-pm@^3.0.0:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/preferred-pm/-/preferred-pm-3.1.2.tgz#aedb70550734a574dffcbf2ce82642bd1753bdd6"
|
||||
@ -5329,7 +5565,7 @@ pretty-bytes@^6.1.1:
|
||||
resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-6.1.1.tgz#38cd6bb46f47afbf667c202cfc754bffd2016a3b"
|
||||
integrity sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==
|
||||
|
||||
prop-types@15, prop-types@^15.6.2, prop-types@^15.8.1:
|
||||
prop-types@15, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.8.1:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
@ -5386,6 +5622,13 @@ react-clientside-effect@^1.2.6:
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.13"
|
||||
|
||||
react-composer@^5.0.3:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/react-composer/-/react-composer-5.0.3.tgz#7beb9513da5e8687f4f434ea1333ef36a4f3091b"
|
||||
integrity sha512-1uWd07EME6XZvMfapwZmc7NgCZqDemcvicRi3wMJzXsQLvZ3L7fTHVyPy1bZdnWXM4iPjYuNE+uJ41MLKeTtnA==
|
||||
dependencies:
|
||||
prop-types "^15.6.0"
|
||||
|
||||
react-dnd-html5-backend@^16.0.1:
|
||||
version "16.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz#87faef15845d512a23b3c08d29ecfd34871688b6"
|
||||
@ -5493,6 +5736,11 @@ react-kapsule@2:
|
||||
fromentries "^1.3.2"
|
||||
jerrypick "^1.1.1"
|
||||
|
||||
react-merge-refs@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-merge-refs/-/react-merge-refs-1.1.0.tgz#73d88b892c6c68cbb7a66e0800faa374f4c38b06"
|
||||
integrity sha512-alTKsjEL0dKH/ru1Iyn7vliS2QRcBp9zZPGoWxUOvRGWPUYgjo+V01is7p04It6KhgrzhJGnIj9GgX8W4bZoCQ==
|
||||
|
||||
react-mosaic-component@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-mosaic-component/-/react-mosaic-component-6.1.0.tgz#67383085680e8604d0fcb6d61387be19665da308"
|
||||
@ -5523,6 +5771,14 @@ react-qr-barcode-scanner@^1.0.6:
|
||||
"@zxing/library" "^0.17.0"
|
||||
react-webcam "^5.0.1"
|
||||
|
||||
react-reconciler@^0.27.0:
|
||||
version "0.27.0"
|
||||
resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.27.0.tgz#360124fdf2d76447c7491ee5f0e04503ed9acf5b"
|
||||
integrity sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
scheduler "^0.21.0"
|
||||
|
||||
react-refresh@^0.14.0:
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
|
||||
@ -5581,6 +5837,13 @@ react-universal-interface@^0.6.2:
|
||||
resolved "https://registry.yarnpkg.com/react-universal-interface/-/react-universal-interface-0.6.2.tgz#5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b"
|
||||
integrity sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw==
|
||||
|
||||
react-use-measure@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-use-measure/-/react-use-measure-2.1.1.tgz#5824537f4ee01c9469c45d5f7a8446177c6cc4ba"
|
||||
integrity sha512-nocZhN26cproIiIduswYpV5y5lQpSQS1y/4KuvUCjSKmw7ZWIS/+g3aFnX3WdBkyuGUtTLif3UTqnLLhbDoQig==
|
||||
dependencies:
|
||||
debounce "^1.2.1"
|
||||
|
||||
react-use@^17.4.0:
|
||||
version "17.4.0"
|
||||
resolved "https://registry.yarnpkg.com/react-use/-/react-use-17.4.0.tgz#cefef258b0a6c534a5c8021c2528ac6e1a4cdc6d"
|
||||
@ -5842,6 +6105,13 @@ safe-regex-test@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
scheduler@^0.21.0:
|
||||
version "0.21.0"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.21.0.tgz#6fd2532ff5a6d877b6edb12f00d8ab7e8f308820"
|
||||
integrity sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
|
||||
scheduler@^0.23.0:
|
||||
version "0.23.0"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
|
||||
@ -5914,11 +6184,23 @@ shebang-command@^1.2.0:
|
||||
dependencies:
|
||||
shebang-regex "^1.0.0"
|
||||
|
||||
shebang-command@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
|
||||
integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
|
||||
dependencies:
|
||||
shebang-regex "^3.0.0"
|
||||
|
||||
shebang-regex@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
|
||||
integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==
|
||||
|
||||
shebang-regex@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
|
||||
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
|
||||
|
||||
side-channel@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"
|
||||
@ -6058,6 +6340,16 @@ stacktrace-js@^2.0.2:
|
||||
stack-generator "^2.0.5"
|
||||
stacktrace-gps "^3.0.4"
|
||||
|
||||
stats-gl@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/stats-gl/-/stats-gl-2.0.1.tgz#4626a1575af00f0c5daba41ebc8f8e29a0a1998a"
|
||||
integrity sha512-EhFm1AxoSBK3MflkFawZ4jmOX1dWu0nBAtCpvGxGsondEvCpsohbpRpM8pi8UAcxG5eRsDsCiRcxdH20j3Rp9A==
|
||||
|
||||
stats.js@^0.17.0:
|
||||
version "0.17.0"
|
||||
resolved "https://registry.yarnpkg.com/stats.js/-/stats.js-0.17.0.tgz#b1c3dc46d94498b578b7fd3985b81ace7131cc7d"
|
||||
integrity sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==
|
||||
|
||||
stream-transform@^2.1.3:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/stream-transform/-/stream-transform-2.1.3.tgz#a1c3ecd72ddbf500aa8d342b0b9df38f5aa598e3"
|
||||
@ -6178,6 +6470,11 @@ supports-preserve-symlinks-flag@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
|
||||
integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
|
||||
|
||||
suspend-react@^0.1.3:
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/suspend-react/-/suspend-react-0.1.3.tgz#a52f49d21cfae9a2fb70bd0c68413d3f9d90768e"
|
||||
integrity sha512-aqldKgX9aZqpoDp3e8/BZ8Dm7x1pJl+qI3ZKxDN0i/IQTWUwBx/ManmlVJ3wowqbno6c2bmiIfs+Um6LbsjJyQ==
|
||||
|
||||
temp-dir@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e"
|
||||
@ -6229,6 +6526,11 @@ three-forcegraph@1:
|
||||
ngraph.graph "20"
|
||||
tinycolor2 "1"
|
||||
|
||||
three-mesh-bvh@^0.6.7:
|
||||
version "0.6.8"
|
||||
resolved "https://registry.yarnpkg.com/three-mesh-bvh/-/three-mesh-bvh-0.6.8.tgz#f27d18ca75bdc59316dff0f561af8fb316621a54"
|
||||
integrity sha512-EGebF9DZx1S8+7OZYNNTT80GXJZVf+UYXD/HyTg/e2kR/ApofIFfUS4ZzIHNnUVIadpnLSzM4n96wX+l7GMbnQ==
|
||||
|
||||
three-render-objects@^1.29:
|
||||
version "1.29.0"
|
||||
resolved "https://registry.yarnpkg.com/three-render-objects/-/three-render-objects-1.29.0.tgz#fb9769e62784f02682d7d26626dda4fec2655deb"
|
||||
@ -6244,6 +6546,18 @@ three-spritetext@^1.8.1:
|
||||
resolved "https://registry.yarnpkg.com/three-spritetext/-/three-spritetext-1.8.1.tgz#e554230b6f80c75251e0275b8408b8cf2dc2b101"
|
||||
integrity sha512-pohv5CcdeUtAPLi9KhG0kcDLj3gmzdIFK/QlgsTJe+U07oQFSj+K0DLPQKbNDPWAK+7YzhulkRcjWdVIQ5F7nw==
|
||||
|
||||
three-stdlib@^2.28.0:
|
||||
version "2.28.7"
|
||||
resolved "https://registry.yarnpkg.com/three-stdlib/-/three-stdlib-2.28.7.tgz#677ad2ce4d57375f7582e5fd62eadfd07ef6059a"
|
||||
integrity sha512-E7NuztilCswBKnEoyqydvA7N4dy0cf/gLA0bKrrg6+Q6j4WtusGa/+t9oK2HVq47S1AHRH2CvFHpdIGNjPKo/A==
|
||||
dependencies:
|
||||
"@types/draco3d" "^1.4.0"
|
||||
"@types/offscreencanvas" "^2019.6.4"
|
||||
"@types/webxr" "^0.5.2"
|
||||
draco3d "^1.4.1"
|
||||
fflate "^0.6.9"
|
||||
potpack "^1.0.1"
|
||||
|
||||
"three@>=0.118 <1":
|
||||
version "0.158.0"
|
||||
resolved "https://registry.yarnpkg.com/three/-/three-0.158.0.tgz#03ddd5b60ce9c31be8fb69f27a6d9efd49908ac3"
|
||||
@ -6305,6 +6619,26 @@ trim-newlines@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
|
||||
integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==
|
||||
|
||||
troika-three-text@^0.47.2:
|
||||
version "0.47.2"
|
||||
resolved "https://registry.yarnpkg.com/troika-three-text/-/troika-three-text-0.47.2.tgz#fdf89059c010563bb829262b20c41f69ca79b712"
|
||||
integrity sha512-qylT0F+U7xGs+/PEf3ujBdJMYWbn0Qci0kLqI5BJG2kW1wdg4T1XSxneypnF05DxFqJhEzuaOR9S2SjiyknMng==
|
||||
dependencies:
|
||||
bidi-js "^1.0.2"
|
||||
troika-three-utils "^0.47.2"
|
||||
troika-worker-utils "^0.47.2"
|
||||
webgl-sdf-generator "1.1.1"
|
||||
|
||||
troika-three-utils@^0.47.2:
|
||||
version "0.47.2"
|
||||
resolved "https://registry.yarnpkg.com/troika-three-utils/-/troika-three-utils-0.47.2.tgz#af49ca694245dce631963d5fefe4e8e1b8af9044"
|
||||
integrity sha512-/28plhCxfKtH7MSxEGx8e3b/OXU5A0xlwl+Sbdp0H8FXUHKZDoksduEKmjQayXYtxAyuUiCRunYIv/8Vi7aiyg==
|
||||
|
||||
troika-worker-utils@^0.47.2:
|
||||
version "0.47.2"
|
||||
resolved "https://registry.yarnpkg.com/troika-worker-utils/-/troika-worker-utils-0.47.2.tgz#e7c5de5f37d56c072b13fa8112bb844e048ff46c"
|
||||
integrity sha512-mzss4MeyzUkYBppn4x5cdAqrhBHFEuVmMMgLMTyFV23x6GvQMyo+/R5E5Lsbrt7WSt5RfvewjcwD1DChRTA9lA==
|
||||
|
||||
ts-custom-error@^3.0.0:
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/ts-custom-error/-/ts-custom-error-3.3.1.tgz#8bd3c8fc6b8dc8e1cb329267c45200f1e17a65d1"
|
||||
@ -6497,7 +6831,12 @@ use-sync-external-store@1.2.0:
|
||||
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
|
||||
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
|
||||
|
||||
uuid@^9.0.0:
|
||||
utility-types@^3.10.0:
|
||||
version "3.10.0"
|
||||
resolved "https://registry.yarnpkg.com/utility-types/-/utility-types-3.10.0.tgz#ea4148f9a741015f05ed74fd615e1d20e6bed82b"
|
||||
integrity sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==
|
||||
|
||||
uuid@^9.0.0, uuid@^9.0.1:
|
||||
version "9.0.1"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30"
|
||||
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
|
||||
@ -6539,6 +6878,16 @@ wcwidth@^1.0.1:
|
||||
dependencies:
|
||||
defaults "^1.0.3"
|
||||
|
||||
webgl-constants@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/webgl-constants/-/webgl-constants-1.1.1.tgz#f9633ee87fea56647a60b9ce735cbdfb891c6855"
|
||||
integrity sha512-LkBXKjU5r9vAW7Gcu3T5u+5cvSvh5WwINdr0C+9jpzVB41cjQAP5ePArDtk/WHYdVj0GefCgM73BA7FlIiNtdg==
|
||||
|
||||
webgl-sdf-generator@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz#3e1b422b3d87cd3cc77f2602c9db63bc0f6accbd"
|
||||
integrity sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==
|
||||
|
||||
webidl-conversions@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||
@ -6602,6 +6951,13 @@ which@^1.2.9:
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
which@^2.0.1:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
|
||||
integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
|
||||
dependencies:
|
||||
isexe "^2.0.0"
|
||||
|
||||
workbox-background-sync@7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-7.0.0.tgz#2b84b96ca35fec976e3bd2794b70e4acec46b3a5"
|
||||
@ -6866,6 +7222,11 @@ yocto-queue@^0.1.0:
|
||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||
|
||||
zustand@^3.5.13, zustand@^3.7.1:
|
||||
version "3.7.2"
|
||||
resolved "https://registry.yarnpkg.com/zustand/-/zustand-3.7.2.tgz#7b44c4f4a5bfd7a8296a3957b13e1c346f42514d"
|
||||
integrity sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA==
|
||||
|
||||
zustand@^4.4.1:
|
||||
version "4.4.6"
|
||||
resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.4.6.tgz#03c78e3e2686c47095c93714c0c600b72a6512bd"
|
||||
|
Loading…
x
Reference in New Issue
Block a user