From 822ddc56e1ba335cec4bf0abc8784f94fdb26bd1 Mon Sep 17 00:00:00 2001 From: hzrd149 Date: Mon, 7 Aug 2023 13:55:55 -0500 Subject: [PATCH 1/5] simple files view --- package.json | 1 + src/app.tsx | 2 + src/components/blured-image.tsx | 23 +++ src/components/blurhash-image.tsx | 29 ++++ src/components/embed-types/common.tsx | 23 +-- src/components/icons.tsx | 6 + src/components/layout/desktop-side-nav.tsx | 4 + src/components/layout/mobile-side-drawer.tsx | 18 ++- src/helpers/nostr/files.ts | 44 +++++ src/types/nostr-query.ts | 1 + src/views/files/index.tsx | 160 +++++++++++++++++++ yarn.lock | 5 + 12 files changed, 293 insertions(+), 23 deletions(-) create mode 100644 src/components/blured-image.tsx create mode 100644 src/components/blurhash-image.tsx create mode 100644 src/helpers/nostr/files.ts create mode 100644 src/views/files/index.tsx diff --git a/package.json b/package.json index d86a7a8fb..dfb2b2f00 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@emotion/react": "^11.11.0", "@emotion/styled": "^11.11.0", "bech32": "^2.0.0", + "blurhash": "^2.0.5", "cheerio": "^1.0.0-rc.12", "dayjs": "^1.11.9", "debug": "^4.3.4", diff --git a/src/app.tsx b/src/app.tsx index ae21fd0b1..d0ee73d56 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -42,6 +42,7 @@ const StreamsView = React.lazy(() => import("./views/streams")); const StreamView = React.lazy(() => import("./views/streams/stream")); const SearchView = React.lazy(() => import("./views/search")); const MapView = React.lazy(() => import("./views/map")); +const FilesView = React.lazy(() => import("./views/files")); const RootPage = () => { useSetColorMode(); @@ -106,6 +107,7 @@ const router = createHashRouter([ element: , }, { path: "settings", element: }, + { path: "files", element: }, { path: "relays/reviews", element: }, { path: "relays", element: }, { path: "r/:relay", element: }, diff --git a/src/components/blured-image.tsx b/src/components/blured-image.tsx new file mode 100644 index 000000000..e76677c0c --- /dev/null +++ b/src/components/blured-image.tsx @@ -0,0 +1,23 @@ +import { Box, Image, ImageProps, useDisclosure } from "@chakra-ui/react"; + +export default function BlurredImage(props: ImageProps) { + const { isOpen, onOpen } = useDisclosure(); + return ( + + { + e.stopPropagation(); + e.preventDefault(); + onOpen(); + } + : undefined + } + cursor="pointer" + filter={isOpen ? "" : "blur(1.5rem)"} + {...props} + /> + + ); +} diff --git a/src/components/blurhash-image.tsx b/src/components/blurhash-image.tsx new file mode 100644 index 000000000..2ca970c2e --- /dev/null +++ b/src/components/blurhash-image.tsx @@ -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; + +export default function BlurhashImage({ blurhash, width, height, ...props }: BlurhashImageProps) { + const canvasRef = useRef(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 ; +} diff --git a/src/components/embed-types/common.tsx b/src/components/embed-types/common.tsx index 32804bc27..53e82ca87 100644 --- a/src/components/embed-types/common.tsx +++ b/src/components/embed-types/common.tsx @@ -3,28 +3,7 @@ import appSettings from "../../services/settings/app-settings"; import { ImageGalleryLink } from "../image-gallery"; import { useTrusted } from "../../providers/trust"; import OpenGraphCard from "../open-graph-card"; - -const BlurredImage = (props: ImageProps) => { - const { isOpen, onOpen } = useDisclosure(); - return ( - - { - e.stopPropagation(); - e.preventDefault(); - onOpen(); - } - : undefined - } - cursor="pointer" - filter={isOpen ? "" : "blur(1.5rem)"} - {...props} - /> - - ); -}; +import BlurredImage from "../blured-image"; const EmbeddedImage = ({ src }: { src: string }) => { const trusted = useTrusted(); diff --git a/src/components/icons.tsx b/src/components/icons.tsx index c51820633..a9b1e1d7d 100644 --- a/src/components/icons.tsx +++ b/src/components/icons.tsx @@ -301,3 +301,9 @@ export const StarHalfIcon = createIcon({ d: "M12.0006 15.968L16.2473 18.3451L15.2988 13.5717L18.8719 10.2674L14.039 9.69434L12.0006 5.27502V15.968ZM12.0006 18.26L4.94715 22.2082L6.52248 14.2799L0.587891 8.7918L8.61493 7.84006L12.0006 0.5L15.3862 7.84006L23.4132 8.7918L17.4787 14.2799L19.054 22.2082L12.0006 18.26Z", defaultProps, }); + +export const FileIcon = createIcon({ + displayName: "FileIcon", + d: "M9 2.00318V2H19.9978C20.5513 2 21 2.45531 21 2.9918V21.0082C21 21.556 20.5551 22 20.0066 22H3.9934C3.44476 22 3 21.5501 3 20.9932V8L9 2.00318ZM5.82918 8H9V4.83086L5.82918 8ZM11 4V9C11 9.55228 10.5523 10 10 10H5V20H19V4H11Z", + defaultProps, +}); diff --git a/src/components/layout/desktop-side-nav.tsx b/src/components/layout/desktop-side-nav.tsx index dc93d3f7a..e140e921b 100644 --- a/src/components/layout/desktop-side-nav.tsx +++ b/src/components/layout/desktop-side-nav.tsx @@ -8,6 +8,7 @@ import { ChatIcon, EditIcon, FeedIcon, + FileIcon, LiveStreamIcon, LogoutIcon, MapIcon, @@ -50,6 +51,9 @@ export default function DesktopSideNav(props: Omit) { + diff --git a/src/components/layout/mobile-side-drawer.tsx b/src/components/layout/mobile-side-drawer.tsx index 8e642e6a0..c647f3276 100644 --- a/src/components/layout/mobile-side-drawer.tsx +++ b/src/components/layout/mobile-side-drawer.tsx @@ -13,7 +13,17 @@ import { } from "@chakra-ui/react"; import { Link as RouterLink, useNavigate } from "react-router-dom"; import { ConnectedRelays } from "../connected-relays"; -import { HomeIcon, LiveStreamIcon, LogoutIcon, ProfileIcon, RelayIcon, SearchIcon, SettingsIcon } from "../icons"; +import { + FileIcon, + HomeIcon, + LiveStreamIcon, + LogoutIcon, + MapIcon, + ProfileIcon, + RelayIcon, + SearchIcon, + SettingsIcon, +} from "../icons"; import { UserAvatar } from "../user-avatar"; import { UserLink } from "../user-link"; import AccountSwitcher from "./account-switcher"; @@ -57,6 +67,12 @@ export default function MobileSideDrawer({ ...props }: Omit navigate("/streams")} leftIcon={}> Streams + + diff --git a/src/helpers/nostr/files.ts b/src/helpers/nostr/files.ts new file mode 100644 index 000000000..3d02b79be --- /dev/null +++ b/src/helpers/nostr/files.ts @@ -0,0 +1,44 @@ +import { NostrEvent } from "../../types/nostr-event"; + +export type ParsedImageFile = { + url: string; + mimeType: string; + width?: number; + height?: number; + size?: number; + magnet?: string; + sha256Hash?: string; + infoHash?: string; + blurhash?: string; +}; + +export function parseImageFile(event: NostrEvent): ParsedImageFile { + const url = event.tags.find((t) => t[0] === "url" && t[1])?.[1]; + 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 (!url) throw new Error("missing url"); + 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, + }; +} diff --git a/src/types/nostr-query.ts b/src/types/nostr-query.ts index dd08a8b94..ed86d5629 100644 --- a/src/types/nostr-query.ts +++ b/src/types/nostr-query.ts @@ -18,6 +18,7 @@ export type NostrQuery = { "#r"?: string[]; "#l"?: string[]; "#g"?: string[]; + "#m"?: string[]; since?: number; until?: number; limit?: number; diff --git a/src/views/files/index.tsx b/src/views/files/index.tsx new file mode 100644 index 000000000..12bc6fc0a --- /dev/null +++ b/src/views/files/index.tsx @@ -0,0 +1,160 @@ +import { + Button, + Checkbox, + Code, + Divider, + Flex, + Image, + Popover, + PopoverArrow, + PopoverBody, + PopoverCloseButton, + PopoverContent, + PopoverTrigger, + SimpleGrid, + Text, + useDisclosure, +} from "@chakra-ui/react"; +import { useCallback, useState } from "react"; +import useTimelineLoader from "../../hooks/use-timeline-loader"; +import { useReadRelayUrls } from "../../hooks/use-client-relays"; +import useSubject from "../../hooks/use-subject"; +import { NostrEvent } from "../../types/nostr-event"; +import { parseImageFile } from "../../helpers/nostr/files"; +import BlurhashImage from "../../components/blurhash-image"; +import { ErrorBoundary } from "../../components/error-boundary"; +import useAppSettings from "../../hooks/use-app-settings"; +import { useTrusted } from "../../providers/trust"; +import BlurredImage from "../../components/blured-image"; + +const FILE_KIND = 1063; +const VIDEO_TYPES = ["video/mp4", "video/webm"]; +const IMAGE_TYPES = ["image/png", "image/jpeg", "image/svg+xml", "image/webp", "image/gif"]; +const AUDIO_TYPES = ["audio/webm", "audio/wav", "audio/ogg"]; +const TEXT_TYPES = ["text/plain"]; + +function ImageFile({ event }: { event: NostrEvent }) { + const parsed = parseImageFile(event); + const settings = useAppSettings(); + const trust = useTrusted(); + + 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 ( + + ); + } + + const ImageComponent = shouldBlur ? BlurredImage : Image; + return ; +} + +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 ; + } + return Unknown mine type {mimeType}; +} + +export default function FilesView() { + const [selectedTypes, setSelectedTypes] = useState(IMAGE_TYPES); + const toggleType = useCallback( + (type: string) => { + setSelectedTypes((arr) => { + if (arr.includes(type)) { + return arr.filter((t) => t !== type); + } else return arr.concat(type); + }); + }, + [setSelectedTypes] + ); + + const relays = useReadRelayUrls(); + const timeline = useTimelineLoader( + "files", + relays, + { kinds: [FILE_KIND], "#m": selectedTypes }, + { enabled: selectedTypes.length > 0 } + ); + + const events = useSubject(timeline.timeline); + + return ( + + + + + + + + + + + + + Images + + {IMAGE_TYPES.map((type) => ( + toggleType(type)}> + {type} + + ))} + + + Videos + + {VIDEO_TYPES.map((type) => ( + toggleType(type)}> + {type} + + ))} + + + Audio + + {AUDIO_TYPES.map((type) => ( + toggleType(type)}> + {type} + + ))} + + + Text + + {TEXT_TYPES.map((type) => ( + toggleType(type)}> + {type} + + ))} + + + + + + + + + {events.map((event) => ( + + + {/* {JSON.stringify(event, null, 2)} */} + + ))} + + + ); +} diff --git a/yarn.lock b/yarn.lock index 518eb51d2..371aca2fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2964,6 +2964,11 @@ bluebird@^3.7.2: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== +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== + boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" From bd50ab2ec764241e5d9c77423dd5636562ff10b8 Mon Sep 17 00:00:00 2001 From: hzrd149 Date: Thu, 7 Sep 2023 11:27:01 -0500 Subject: [PATCH 2/5] some work --- src/components/layout/nav-items.tsx | 6 +- src/helpers/nostr/files.ts | 9 ++- src/views/files/index.tsx | 100 +++++++++++++++++++++------- 3 files changed, 85 insertions(+), 30 deletions(-) diff --git a/src/components/layout/nav-items.tsx b/src/components/layout/nav-items.tsx index 3a30f4214..9fee6c88d 100644 --- a/src/components/layout/nav-items.tsx +++ b/src/components/layout/nav-items.tsx @@ -48,6 +48,9 @@ export default function NavItems({ isInDrawer = false }: { isInDrawer?: boolean + @@ -57,9 +60,6 @@ export default function NavItems({ isInDrawer = false }: { isInDrawer?: boolean - diff --git a/src/helpers/nostr/files.ts b/src/helpers/nostr/files.ts index 3d02b79be..bc35bdd58 100644 --- a/src/helpers/nostr/files.ts +++ b/src/helpers/nostr/files.ts @@ -12,8 +12,14 @@ export type ParsedImageFile = { blurhash?: string; }; -export function parseImageFile(event: NostrEvent): ParsedImageFile { +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]; @@ -24,7 +30,6 @@ export function parseImageFile(event: NostrEvent): ParsedImageFile { const dimensions = event.tags.find((t) => t[0] === "dim" && t[1])?.[1]; const [width, height] = dimensions?.split("x").map((v) => parseInt(v)) ?? []; - if (!url) throw new Error("missing url"); 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"); diff --git a/src/views/files/index.tsx b/src/views/files/index.tsx index 12bc6fc0a..2d4298237 100644 --- a/src/views/files/index.tsx +++ b/src/views/files/index.tsx @@ -20,12 +20,19 @@ import useTimelineLoader from "../../hooks/use-timeline-loader"; import { useReadRelayUrls } from "../../hooks/use-client-relays"; import useSubject from "../../hooks/use-subject"; import { NostrEvent } from "../../types/nostr-event"; -import { parseImageFile } from "../../helpers/nostr/files"; +import { getFileUrl, parseImageFile } from "../../helpers/nostr/files"; import BlurhashImage from "../../components/blurhash-image"; import { ErrorBoundary } from "../../components/error-boundary"; import useAppSettings from "../../hooks/use-app-settings"; -import { useTrusted } from "../../providers/trust"; +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 { UserAvatar } from "../../components/user-avatar"; +import { UserAvatarLink } from "../../components/user-avatar-link"; +import { UserLink } from "../../components/user-link"; const FILE_KIND = 1063; const VIDEO_TYPES = ["video/mp4", "video/webm"]; @@ -40,23 +47,45 @@ function ImageFile({ event }: { event: NostrEvent }) { 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 ( - - ); - } + // const showImage = useDisclosure(); + // if (shouldBlur && parsed.blurhash && parsed.width && parsed.height && !showImage.isOpen) { + // const aspect = parsed.width / parsed.height; + // return ( + // + // ); + // } const ImageComponent = shouldBlur ? BlurredImage : Image; - return ; + return ( + + + + + + + + ); +} + +function VideoFile({ event }: { event: NostrEvent }) { + const url = getFileUrl(event); + + return ( + + + + + + + ); } function FileType({ event }: { event: NostrEvent }) { @@ -65,12 +94,22 @@ function FileType({ event }: { event: NostrEvent }) { if (!mimeType) throw new Error("missing MIME type"); if (IMAGE_TYPES.includes(mimeType)) { - return ; + return ( + + + + ); + } + if (VIDEO_TYPES.includes(mimeType)) { + return ; } return Unknown mine type {mimeType}; } -export default function FilesView() { +function FilesPage() { + const { listId, filter } = usePeopleListContext(); + const { relays } = useRelaySelectionContext(); + const [selectedTypes, setSelectedTypes] = useState(IMAGE_TYPES); const toggleType = useCallback( (type: string) => { @@ -80,22 +119,22 @@ export default function FilesView() { } else return arr.concat(type); }); }, - [setSelectedTypes] + [setSelectedTypes], ); - const relays = useReadRelayUrls(); const timeline = useTimelineLoader( - "files", + `${listId}-files`, relays, - { kinds: [FILE_KIND], "#m": selectedTypes }, - { enabled: selectedTypes.length > 0 } + { kinds: [FILE_KIND], "#m": selectedTypes, ...filter }, + { enabled: selectedTypes.length > 0 && !!filter }, ); const events = useSubject(timeline.timeline); return ( - + + @@ -145,6 +184,7 @@ export default function FilesView() { + @@ -158,3 +198,13 @@ export default function FilesView() { ); } + +export default function FilesView() { + return ( + + + + + + ); +} From 981ef92f95f4a93c52ac15e28b84f38680a7ae89 Mon Sep 17 00:00:00 2001 From: hzrd149 Date: Tue, 19 Dec 2023 20:22:10 -0600 Subject: [PATCH 3/5] add stl viewer --- package.json | 2 + src/app.tsx | 12 +- src/components/icons.tsx | 4 +- src/components/layout/nav-items.tsx | 22 +- src/components/stl-viewer.tsx | 185 ++++++++++++++ src/views/files/index.tsx | 5 +- src/views/things/index.tsx | 56 +++++ src/views/things/upload.tsx | 10 + yarn.lock | 372 +++++++++++++++++++++++++++- 9 files changed, 642 insertions(+), 26 deletions(-) create mode 100644 src/components/stl-viewer.tsx create mode 100644 src/views/things/index.tsx create mode 100644 src/views/things/upload.tsx diff --git a/package.json b/package.json index e5d044891..35838577c 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,8 @@ "@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", diff --git a/src/app.tsx b/src/app.tsx index a886c0342..22a2abe8b 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -90,7 +90,9 @@ const StreamView = lazy(() => import("./views/streams/stream")); const SearchView = lazy(() => import("./views/search")); const MapView = lazy(() => import("./views/map")); -const FilesView = lazy(() => import("./views/files")); + +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")); @@ -225,7 +227,6 @@ const router = createHashRouter([ element: , }, { path: "settings", element: }, - { path: "files", element: }, { path: "relays", children: [ @@ -266,6 +267,13 @@ const router = createHashRouter([ { path: "dm-feed", element: }, ], }, + { + path: "things", + children: [ + { path: "", element: }, + { path: "upload", element: }, + ], + }, { path: "lists", children: [ diff --git a/src/components/icons.tsx b/src/components/icons.tsx index eef970b90..ded13919d 100644 --- a/src/components/icons.tsx +++ b/src/components/icons.tsx @@ -63,7 +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 File01 from "./icons/file-01"; +import Package from "./icons/package"; const defaultProps: IconProps = { boxSize: 4 }; @@ -235,4 +235,4 @@ export const DownloadIcon = Download01; export const TranslateIcon = Translate01; export const ChannelsIcon = MessageChatSquare; export const ThreadIcon = MessageChatSquare; -export const FileIcon = File01; \ No newline at end of file +export const ThingsIcon = Package; diff --git a/src/components/layout/nav-items.tsx b/src/components/layout/nav-items.tsx index c4f2e2dcf..136a531e7 100644 --- a/src/components/layout/nav-items.tsx +++ b/src/components/layout/nav-items.tsx @@ -20,7 +20,7 @@ import { NotesIcon, LightningIcon, ChannelsIcon, - FileIcon, + ThingsIcon, } from "../icons"; import useCurrentAccount from "../../hooks/use-current-account"; import accountService from "../../services/account"; @@ -54,8 +54,8 @@ export default function NavItems() { else if (location.pathname.startsWith("/c/")) active = "communities"; else if (location.pathname.startsWith("/goals")) active = "goals"; else if (location.pathname.startsWith("/badges")) active = "badges"; - else if (location.pathname.startsWith("/files")) active = "files"; 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"; @@ -181,15 +181,6 @@ export default function NavItems() { > Lists - + + + + + + + + + ); +} + +export default function FilesView() { + return ( + + + + + + ); +} diff --git a/src/views/things/upload.tsx b/src/views/things/upload.tsx new file mode 100644 index 000000000..142fb12b6 --- /dev/null +++ b/src/views/things/upload.tsx @@ -0,0 +1,10 @@ +import STLViewer from "../../components/stl-viewer"; +import VerticalPageLayout from "../../components/vertical-page-layout"; + +export default function ThingUploadView() { + return ( + + + + ); +} diff --git a/yarn.lock b/yarn.lock index 9f107a6dc..a8bc38304 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2353,6 +2353,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" @@ -2428,6 +2433,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" @@ -2638,6 +2736,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" @@ -2742,6 +2845,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" @@ -2759,6 +2867,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" @@ -2817,6 +2939,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.0.4": version "4.1.1" resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-4.1.1.tgz#a10254dc76778027407d01b6ddbca53b23852a72" @@ -3024,7 +3163,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== @@ -3051,16 +3190,23 @@ better-path-resolve@1.0.0: resolved "https://registry.yarnpkg.com/bezier-js/-/bezier-js-6.1.4.tgz#c7828f6c8900562b69d5040afb881bcbdad82001" integrity sha512-PA0FW9ZpcHbojUCMu28z9Vg/fNkwTj5YhusSAjHHDfHDGLxJ6YUKrAN2vk1fP2MMOxVw4Oko16FMlRGVBGqLKg== -bn.js@^4.11.8: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== +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" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -3156,6 +3302,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" @@ -3337,6 +3488,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" @@ -3346,6 +3504,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" @@ -3579,6 +3746,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.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" @@ -3629,6 +3801,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" @@ -3690,6 +3869,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" @@ -3929,7 +4113,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== @@ -4171,6 +4355,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" @@ -4552,6 +4741,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" @@ -4723,6 +4919,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" @@ -4733,6 +4934,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" @@ -4782,6 +4993,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" @@ -4839,6 +5055,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" @@ -5113,6 +5334,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" @@ -5161,6 +5387,11 @@ postcss@^8.4.31: 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" @@ -5191,7 +5422,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== @@ -5248,6 +5479,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" @@ -5355,6 +5593,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" @@ -5385,6 +5628,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" @@ -5443,6 +5694,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" @@ -5704,6 +5962,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" @@ -5776,11 +6041,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" @@ -5920,6 +6197,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" @@ -6040,6 +6327,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" @@ -6091,6 +6383,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" @@ -6106,6 +6403,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" @@ -6167,6 +6476,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" @@ -6359,7 +6688,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== @@ -6401,6 +6735,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" @@ -6464,6 +6808,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" @@ -6728,6 +7079,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" From 1e99f8cbce70ea39d80e24f8b6cc90aaa3dc4082 Mon Sep 17 00:00:00 2001 From: hzrd149 Date: Wed, 20 Dec 2023 20:29:14 -0600 Subject: [PATCH 4/5] improve stl viewer --- src/components/stl-viewer.tsx | 149 ++++------------------------------ 1 file changed, 16 insertions(+), 133 deletions(-) diff --git a/src/components/stl-viewer.tsx b/src/components/stl-viewer.tsx index de6068245..1385fa859 100644 --- a/src/components/stl-viewer.tsx +++ b/src/components/stl-viewer.tsx @@ -1,136 +1,12 @@ import { useMemo, useRef, useState } from "react"; import { Box, BoxProps } from "@chakra-ui/react"; -import { PCFSoftShadowMap } from "three"; +import { Color, Fog, PCFSoftShadowMap } from "three"; import { Canvas, ThreeElements, useFrame, useLoader } from "@react-three/fiber"; import { OrbitControls } from "@react-three/drei"; import { STLLoader } from "three/examples/jsm/loaders/STLLoader"; // http://cdn.thingiverse.com/assets/3c/fe/bc/3b/9e/3dae334c-589e-4d59-97e6-3578426751d1.stl -// let camera, cameraTarget, scene, renderer, controls; -// function Stl(width, height, url, objectColor, gridLineColor, skyboxColor, groundColor, lightColor, volume) { -// // scene setup - -// scene = new THREE.Scene(); -// scene.background = new THREE.Color(skyboxColor); -// scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000); - -// // camera setup -// camera = new THREE.PerspectiveCamera(45, width / height, 1, 1000); -// camera.position.set(200, 100, 200); - -// cameraTarget = new THREE.Vector3(0, 0, 0); -// camera.position.z = 5 * 2; -// // renderer setup -// renderer = new THREE.WebGLRenderer({ -// antialias: true, -// alpha: true, -// preserveDrawingBuffer: true, -// }); -// renderer.setSize(width, height); - -// // where to render your scene -// document.getElementById("stlviewer").innerHTML = ""; -// document.getElementById("stlviewer").appendChild(renderer.domElement); - -// // controls -// controls = new OrbitControls(camera, renderer.domElement); -// controls.target.set(0, 0, 0); -// controls.update(); - -// // ground - -// const ground = new THREE.Mesh( -// new THREE.PlaneGeometry(2000, 2000), -// new THREE.MeshPhongMaterial({ color: groundColor, depthWrite: false }), -// ); -// ground.rotation.x = -Math.PI / 2; -// ground.receiveShadow = true; -// scene.add(ground); - -// // const grid = new THREE.GridHelper(2000, 20, gridLineColor, gridLineColor) -// // grid.material.opacity = 0.2 -// // grid.material.transparent = true -// // scene.add(grid) - -// // lights -// const hemiLight = new THREE.HemisphereLight(0xffffff, 0x444444); -// hemiLight.position.set(0, 200, 0); -// scene.add(hemiLight); - -// const directionalLight = new THREE.DirectionalLight(lightColor); -// directionalLight.position.set(0, 200, 100); -// directionalLight.castShadow = true; -// directionalLight.shadow.camera.top = 180; -// directionalLight.shadow.camera.bottom = -100; -// directionalLight.shadow.camera.left = -120; -// directionalLight.shadow.camera.right = 120; -// scene.add(directionalLight); - -// // adding stl to scene -// const loader = new STLLoader(); -// loader.load(url, (geometry) => { -// const material = new THREE.MeshPhongMaterial({ -// color: objectColor, -// specular: 0x111111, -// shininess: 200, -// }); -// const mesh = new THREE.Mesh(geometry, material); - -// mesh.position.set(0, 0, 0); -// mesh.rotation.set(-Math.PI / 2, 0, 0); -// mesh.scale.set(1.5, 1.5, 1.5); - -// mesh.castShadow = true; -// mesh.receiveShadow = true; - -// const signedVolumeOfTriangle = (p1, p2, p3) => { -// return p1.dot(p2.cross(p3)) / 6.0; -// }; -// let position = geometry.attributes.position; -// let faces = position.count / 3; -// let sum = 0; -// let p1 = new THREE.Vector3(), -// p2 = new THREE.Vector3(), -// p3 = new THREE.Vector3(); -// for (let i = 0; i < faces; i++) { -// p1.fromBufferAttribute(position, i * 3 + 0); -// p2.fromBufferAttribute(position, i * 3 + 1); -// p3.fromBufferAttribute(position, i * 3 + 2); -// sum += signedVolumeOfTriangle(p1, p2, p3); -// } -// volume(sum); - -// scene.add(mesh); -// }); - -// // renderer - -// renderer.setPixelRatio(window.devicePixelRatio); -// renderer.outputEncoding = THREE.sRGBEncoding; - -// renderer.shadowMap.enabled = true; - -// function onWindowResize() { -// camera.aspect = window.innerWidth / height; -// camera.updateProjectionMatrix(); - -// renderer.setSize(window.innerWidth, height); -// } - -// const animate = () => { -// requestAnimationFrame(animate); -// render(); -// }; - -// const render = () => { -// camera.lookAt(cameraTarget); -// renderer.render(scene, camera); -// }; -// animate(); -// // window.addEventListener('resize', onWindowResize) -// } - function Cube(props: ThreeElements["mesh"]) { const ref = useRef(null!); const [hovered, hover] = useState(false); @@ -165,19 +41,26 @@ export default function STLViewer({ url, ...props }: Omit - - - - - + + + + + + + + + + + + From cd05507da82b0fefb21f6236e65c37c016d775ed Mon Sep 17 00:00:00 2001 From: hzrd149 Date: Sun, 24 Dec 2023 11:53:18 -0600 Subject: [PATCH 5/5] More fixes for STL viewer --- src/components/back-button.tsx | 12 ++ src/components/stl-viewer.tsx | 121 ++++++++++--------- src/helpers/array.ts | 16 +++ src/hooks/use-object-url.ts | 15 +++ src/hooks/use-route-state-value.ts | 6 +- src/views/things/upload.tsx | 10 -- src/views/things/upload/confirm-step.tsx | 43 +++++++ src/views/things/upload/details-step.tsx | 46 +++++++ src/views/things/upload/index.tsx | 112 +++++++++++++++++ src/views/things/upload/preview-step.tsx | 54 +++++++++ src/views/things/upload/select-file-step.tsx | 87 +++++++++++++ 11 files changed, 449 insertions(+), 73 deletions(-) create mode 100644 src/components/back-button.tsx create mode 100644 src/hooks/use-object-url.ts delete mode 100644 src/views/things/upload.tsx create mode 100644 src/views/things/upload/confirm-step.tsx create mode 100644 src/views/things/upload/details-step.tsx create mode 100644 src/views/things/upload/index.tsx create mode 100644 src/views/things/upload/preview-step.tsx create mode 100644 src/views/things/upload/select-file-step.tsx diff --git a/src/components/back-button.tsx b/src/components/back-button.tsx new file mode 100644 index 000000000..5f629d5ef --- /dev/null +++ b/src/components/back-button.tsx @@ -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) { + const navigate = useNavigate(); + return ( + + ); +} diff --git a/src/components/stl-viewer.tsx b/src/components/stl-viewer.tsx index 1385fa859..cd9d0b22b 100644 --- a/src/components/stl-viewer.tsx +++ b/src/components/stl-viewer.tsx @@ -1,68 +1,69 @@ -import { useMemo, useRef, useState } from "react"; +import { forwardRef } from "react"; import { Box, BoxProps } from "@chakra-ui/react"; -import { Color, Fog, PCFSoftShadowMap } from "three"; -import { Canvas, ThreeElements, useFrame, useLoader } from "@react-three/fiber"; +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"; -// http://cdn.thingiverse.com/assets/3c/fe/bc/3b/9e/3dae334c-589e-4d59-97e6-3578426751d1.stl +const STLViewer = forwardRef & { url: string }>( + ({ url, ...props }, ref) => { + const geometry = useLoader(STLLoader, url); -function Cube(props: ThreeElements["mesh"]) { - const ref = useRef(null!); - const [hovered, hover] = useState(false); - const [clicked, click] = useState(false); - useFrame((state, delta) => (ref.current.rotation.x += delta)); + if (!geometry.boundingBox) geometry.computeBoundingBox(); + if (!geometry.boundingSphere) geometry.computeBoundingSphere(); - return ( - click(!clicked)} - onPointerOver={(event) => hover(true)} - onPointerOut={(event) => hover(false)} - > - - - - ); -} + const objectScale = 2 / geometry.boundingSphere!.radius; + const bb = geometry.boundingBox!; + const center = bb.getCenter(new Vector3()).multiplyScalar(objectScale); -export default function STLViewer({ url, ...props }: Omit & { url: string }) { - const geometry = useLoader(STLLoader, url); + return ( + + + + + + + + + + + + + + + + + + + ); + }, +); - const radius = useMemo(() => { - geometry.computeBoundingSphere(); - return geometry.boundingSphere?.radius ?? 10; - }, [geometry]); - - return ( - - - - - - - - - - - - - - - - - - - ); -} +export default STLViewer; diff --git a/src/helpers/array.ts b/src/helpers/array.ts index 2bfeb74b6..dea24849b 100644 --- a/src/helpers/array.ts +++ b/src/helpers/array.ts @@ -4,3 +4,19 @@ export function unique(arr: T[]): T[] { export function random(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(""); +} diff --git a/src/hooks/use-object-url.ts b/src/hooks/use-object-url.ts new file mode 100644 index 000000000..f6950158b --- /dev/null +++ b/src/hooks/use-object-url.ts @@ -0,0 +1,15 @@ +import { useEffect, useState } from "react"; + +export default function useObjectURL(object?: File | Blob | null) { + const [url, setUrl] = useState(); + + useEffect(() => { + if (object) { + const u = URL.createObjectURL(object); + setUrl(u); + return () => URL.revokeObjectURL(u); + } + }, [object]); + + return url; +} diff --git a/src/hooks/use-route-state-value.ts b/src/hooks/use-route-state-value.ts index f6297dd19..ec21880de 100644 --- a/src/hooks/use-route-state-value.ts +++ b/src/hooks/use-route-state-value.ts @@ -2,7 +2,7 @@ import { useCallback, useRef } from "react"; import { useLocation, useNavigate } from "react-router-dom"; type Actions = { - 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(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(key: string, fallb } else newState[key] = valueOrSetter; if (stateRef.current[key] !== newState[key]) { - navigate(".", { state: newState, replace: true }); + navigate(".", { state: newState, replace }); } }, [key], diff --git a/src/views/things/upload.tsx b/src/views/things/upload.tsx deleted file mode 100644 index 142fb12b6..000000000 --- a/src/views/things/upload.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import STLViewer from "../../components/stl-viewer"; -import VerticalPageLayout from "../../components/vertical-page-layout"; - -export default function ThingUploadView() { - return ( - - - - ); -} diff --git a/src/views/things/upload/confirm-step.tsx b/src/views/things/upload/confirm-step.tsx new file mode 100644 index 000000000..534dae673 --- /dev/null +++ b/src/views/things/upload/confirm-step.tsx @@ -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; +}) { + const [loading, setLoading] = useState(false); + const objectURL = useObjectURL(screenshot); + + const confirm = async () => { + setLoading(true); + await onConfirm(); + setLoading(false); + }; + + return ( + + + {name} + File Hash: {hash} + {summary} + + + + + + ); +} diff --git a/src/views/things/upload/details-step.tsx b/src/views/things/upload/details-step.tsx new file mode 100644 index 000000000..cfcc898b0 --- /dev/null +++ b/src/views/things/upload/details-step.tsx @@ -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({ + defaultValues: { + name: "", + summary: "", + }, + mode: "all", + }); + + const submit = handleSubmit(onSubmit); + + return ( + + + Name + + + + Summary +