diff --git a/.vscode/settings.json b/.vscode/settings.json index a1d2c3bd..a87c8622 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,6 +20,7 @@ "heroicons", "IELTS", "immer", + "Majesticons", "pako", "romaji", "svgr", diff --git a/components.json b/components.json new file mode 100644 index 00000000..12f72053 --- /dev/null +++ b/components.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.css", + "baseColor": "slate", + "cssVariables": false + }, + "aliases": { + "components": "@/components", + "utils": "@/utils/ui" + } +} diff --git a/package.json b/package.json index 7e4e8b27..8d01ec0b 100644 --- a/package.json +++ b/package.json @@ -7,12 +7,21 @@ "@floating-ui/react": "^0.20.1", "@headlessui/react": "^1.7.13", "@headlessui/tailwindcss": "^0.1.2", + "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-progress": "^1.0.2", "@radix-ui/react-radio-group": "^1.1.2", - "@radix-ui/react-scroll-area": "^1.0.3", + "@radix-ui/react-scroll-area": "^1.0.5", "@radix-ui/react-slider": "^1.1.1", + "@radix-ui/react-slot": "^1.0.2", + "@radix-ui/react-tabs": "^1.0.4", + "@radix-ui/react-toggle": "^1.0.3", + "@radix-ui/react-toggle-group": "^1.0.4", + "@radix-ui/react-tooltip": "^1.0.7", + "@tanstack/react-table": "^8.10.7", "canvas-confetti": "^1.6.0", + "class-variance-authority": "^0.7.0", "classnames": "^2.3.2", + "clsx": "^2.0.0", "daisyui": "^3.5.1", "dayjs": "^1.11.8", "dexie": "^3.2.3", @@ -24,6 +33,7 @@ "html-to-image": "^1.11.11", "immer": "^9.0.21", "jotai": "^2.0.3", + "lucide-react": "^0.294.0", "mixpanel-browser": "^2.45.0", "pako": "^2.1.0", "react": "^18.2.0", @@ -36,6 +46,8 @@ "react-tooltip": "^5.18.0", "source-map-explorer": "^2.5.2", "swr": "^2.0.4", + "tailwind-merge": "^2.1.0", + "tailwindcss-animate": "^1.0.7", "typescript": "^4.0.3", "use-immer": "^0.9.0", "use-sound": "^4.0.1", diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 70fae0fd..760a6de1 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -21,13 +21,7 @@ "depends": [] }, "externalBin": [], - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ], + "icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"], "identifier": "com.litongjava.qwerty.learner", "longDescription": "", "macOS": { diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 00000000..60e3f69a --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,43 @@ +import { cn } from '@/utils/ui' +import { Slot } from '@radix-ui/react-slot' +import { type VariantProps, cva } from 'class-variance-authority' +import * as React from 'react' + +const buttonVariants = cva( + 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300', + { + variants: { + variant: { + default: 'bg-indigo-500 shadow text-white hover:opacity-90 dark:text-opacity-80 focus:outline-none rounded-lg', + destructive: 'bg-red-500 text-slate-50 hover:bg-red-500/90 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/90', + outline: + 'border border-slate-200 bg-white hover:bg-slate-100 hover:text-slate-900 dark:border-slate-800 dark:bg-slate-950 dark:hover:bg-slate-800 dark:hover:text-slate-50', + secondary: 'bg-slate-100 text-slate-900 hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50 dark:hover:bg-slate-800/80', + ghost: 'hover:bg-slate-100 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-50', + link: 'text-slate-900 underline-offset-4 hover:underline dark:text-slate-50', + }, + size: { + default: 'h-10 px-4 py-2', + sm: 'h-9 rounded-md px-3', + lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +) + +export interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : 'button' + return +}) +Button.displayName = 'Button' + +export { Button, buttonVariants } diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx new file mode 100644 index 00000000..75944a5a --- /dev/null +++ b/src/components/ui/dialog.tsx @@ -0,0 +1,91 @@ +/* eslint-disable react/prop-types */ +import { cn } from '@/utils/ui' +import * as DialogPrimitive from '@radix-ui/react-dialog' +import { X } from 'lucide-react' +import * as React from 'react' + +const Dialog = DialogPrimitive.Root + +const DialogTrigger = DialogPrimitive.Trigger + +const DialogPortal = DialogPrimitive.Portal + +const DialogClose = DialogPrimitive.Close + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)) +DialogContent.displayName = DialogPrimitive.Content.displayName + +const DialogHeader = ({ className, ...props }: React.HTMLAttributes) => ( +
+) +DialogHeader.displayName = 'DialogHeader' + +const DialogFooter = ({ className, ...props }: React.HTMLAttributes) => ( +
+) +DialogFooter.displayName = 'DialogFooter' + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogTitle.displayName = DialogPrimitive.Title.displayName + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +DialogDescription.displayName = DialogPrimitive.Description.displayName + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} diff --git a/src/components/ui/scroll-area.tsx b/src/components/ui/scroll-area.tsx new file mode 100644 index 00000000..bd79056c --- /dev/null +++ b/src/components/ui/scroll-area.tsx @@ -0,0 +1,38 @@ +/* eslint-disable react/prop-types */ +import { cn } from '@/utils/ui' +import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area' +import * as React from 'react' + +const ScrollArea = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + {children} + + + +)) +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName + +const ScrollBar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, orientation = 'vertical', ...props }, ref) => ( + + + +)) +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName + +export { ScrollArea, ScrollBar } diff --git a/src/components/ui/table.tsx b/src/components/ui/table.tsx new file mode 100644 index 00000000..24e97a42 --- /dev/null +++ b/src/components/ui/table.tsx @@ -0,0 +1,69 @@ +/* eslint-disable react/prop-types */ +import { cn } from '@/utils/ui' +import * as React from 'react' + +const Table = React.forwardRef>(({ className, ...props }, ref) => ( +
+ + +)) +Table.displayName = 'Table' + +const TableHeader = React.forwardRef>( + ({ className, ...props }, ref) => , +) +TableHeader.displayName = 'TableHeader' + +const TableBody = React.forwardRef>( + ({ className, ...props }, ref) => , +) +TableBody.displayName = 'TableBody' + +const TableFooter = React.forwardRef>( + ({ className, ...props }, ref) => ( + tr]:last:border-b-0', className)} + {...props} + /> + ), +) +TableFooter.displayName = 'TableFooter' + +const TableRow = React.forwardRef>(({ className, ...props }, ref) => ( + +)) +TableRow.displayName = 'TableRow' + +const TableHead = React.forwardRef>(({ className, ...props }, ref) => ( + onChange(index)} - > - - - - - - - ) -} diff --git a/src/pages/Gallery-N/ChapterList/index.tsx b/src/pages/Gallery-N/ChapterList/index.tsx deleted file mode 100644 index b04a90fc..00000000 --- a/src/pages/Gallery-N/ChapterList/index.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import { GalleryContext } from '..' -import ChapterRow from './ChapterRow' -import { currentChapterAtom, currentDictIdAtom } from '@/store' -import { calcChapterCount } from '@/utils' -import range from '@/utils/range' -import { Dialog, Transition } from '@headlessui/react' -import { useAtom } from 'jotai' -import { Fragment, useCallback, useContext, useEffect, useState } from 'react' -import { useNavigate } from 'react-router-dom' -import IconX from '~icons/tabler/x' - -export default function ChapterList() { - const { - state: { chapterListDict: dict }, - setState, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - } = useContext(GalleryContext)! - - const [currentChapter, setCurrentChapter] = useAtom(currentChapterAtom) - const [currentDictId, setCurrentDictId] = useAtom(currentDictIdAtom) - const [checkedChapter, setCheckedChapter] = useState(dict?.id === currentDictId ? currentChapter : 0) - const navigate = useNavigate() - - const chapterCount = calcChapterCount(dict?.length ?? 0) - const showChapterList = dict !== null - - useEffect(() => { - if (dict) { - setCheckedChapter(dict.id === currentDictId ? currentChapter : 0) - } - }, [currentChapter, currentDictId, dict]) - - const onChangeChapter = (index: number) => { - setCheckedChapter(index) - } - - const onConfirm = useCallback(() => { - if (dict) { - setCurrentChapter(checkedChapter) - setCurrentDictId(dict.id) - setState((state) => { - state.chapterListDict = null - }) - navigate('/') - } - }, [checkedChapter, dict, navigate, setCurrentChapter, setCurrentDictId, setState]) - - const onCloseDialog = () => { - setState((state) => { - state.chapterListDict = null - }) - } - - return ( - <> - - - -
- - -
- - - {dict && ( - <> -
- {dict.name} - -
-
-
+)) +TableHead.displayName = 'TableHead' + +const TableCell = React.forwardRef>(({ className, ...props }, ref) => ( + +)) +TableCell.displayName = 'TableCell' + +const TableCaption = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ), +) +TableCaption.displayName = 'TableCaption' + +export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption } diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx new file mode 100644 index 00000000..2e4b01c9 --- /dev/null +++ b/src/components/ui/tabs.tsx @@ -0,0 +1,43 @@ +/* eslint-disable react/prop-types */ +import { cn } from '@/utils/ui' +import * as TabsPrimitive from '@radix-ui/react-tabs' +import * as React from 'react' + +const Tabs = TabsPrimitive.Root + +const TabsList = React.forwardRef, React.ComponentPropsWithoutRef>( + ({ className, ...props }, ref) => ( + + ), +) +TabsList.displayName = TabsPrimitive.List.displayName + +const TabsTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName + +const TabsContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ) +TabsContent.displayName = TabsPrimitive.Content.displayName + +export { Tabs, TabsList, TabsTrigger, TabsContent } diff --git a/src/components/ui/toggle-group.tsx b/src/components/ui/toggle-group.tsx new file mode 100644 index 00000000..15bbeb2a --- /dev/null +++ b/src/components/ui/toggle-group.tsx @@ -0,0 +1,49 @@ +import { toggleVariants } from '@/components/ui/toggle' +import { cn } from '@/utils/ui' +import * as ToggleGroupPrimitive from '@radix-ui/react-toggle-group' +import type { VariantProps } from 'class-variance-authority' +import * as React from 'react' + +const ToggleGroupContext = React.createContext>({ + size: 'default', + variant: 'default', +}) + +const ToggleGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & VariantProps +>(({ className, variant, size, children, ...props }, ref) => ( + + {children} + +)) + +ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName + +const ToggleGroupItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & VariantProps +>(({ className, children, variant, size, ...props }, ref) => { + const context = React.useContext(ToggleGroupContext) + + return ( + + {children} + + ) +}) + +ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName + +export { ToggleGroup, ToggleGroupItem } diff --git a/src/components/ui/toggle.tsx b/src/components/ui/toggle.tsx new file mode 100644 index 00000000..bb0fec6f --- /dev/null +++ b/src/components/ui/toggle.tsx @@ -0,0 +1,37 @@ +import { cn } from '@/utils/ui' +import * as TogglePrimitive from '@radix-ui/react-toggle' +import { type VariantProps, cva } from 'class-variance-authority' +import * as React from 'react' + +const toggleVariants = cva( + 'inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-white transition-colors hover:bg-slate-100 hover:text-slate-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-slate-100 data-[state=on]:text-slate-900 dark:ring-offset-slate-950 dark:hover:bg-slate-800 dark:hover:text-slate-400 dark:focus-visible:ring-slate-300 dark:data-[state=on]:bg-slate-800 dark:data-[state=on]:text-slate-50', + { + variants: { + variant: { + default: 'bg-transparent', + outline: + 'border border-slate-200 bg-transparent hover:bg-slate-100 hover:text-slate-900 dark:border-slate-800 dark:hover:bg-slate-800 dark:hover:text-slate-50', + }, + size: { + default: 'h-10 px-3', + sm: 'h-9 px-2.5', + lg: 'h-11 px-5', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +) + +const Toggle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & VariantProps +>(({ className, variant, size, ...props }, ref) => ( + +)) + +Toggle.displayName = TogglePrimitive.Root.displayName + +export { Toggle, toggleVariants } diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx new file mode 100644 index 00000000..6fa3e4df --- /dev/null +++ b/src/components/ui/tooltip.tsx @@ -0,0 +1,28 @@ +/* eslint-disable react/prop-types */ +import { cn } from '@/utils/ui' +import * as TooltipPrimitive from '@radix-ui/react-tooltip' +import * as React from 'react' + +const TooltipProvider = TooltipPrimitive.Provider + +const Tooltip = TooltipPrimitive.Root + +const TooltipTrigger = TooltipPrimitive.Trigger + +const TooltipContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + +)) +TooltipContent.displayName = TooltipPrimitive.Content.displayName + +export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } diff --git a/src/pages/Gallery-N/CategoryDicts.tsx b/src/pages/Gallery-N/CategoryDicts.tsx index e95602df..d1f267f3 100644 --- a/src/pages/Gallery-N/CategoryDicts.tsx +++ b/src/pages/Gallery-N/CategoryDicts.tsx @@ -1,15 +1,12 @@ import DictTagSwitcher from './DictTagSwitcher' import DictionaryComponent from './DictionaryWithoutCover' -import { GalleryContext } from './index' import { currentDictInfoAtom } from '@/store' import type { Dictionary } from '@/typings' import { findCommonValues } from '@/utils' import { useAtomValue } from 'jotai' -import { useCallback, useContext, useEffect, useMemo, useState } from 'react' +import { useCallback, useEffect, useMemo, useState } from 'react' export default function DictionaryGroup({ groupedDictsByTag }: { groupedDictsByTag: Record }) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const { setState } = useContext(GalleryContext)! const tagList = useMemo(() => Object.keys(groupedDictsByTag), [groupedDictsByTag]) const [currentTag, setCurrentTag] = useState(tagList[0]) const currentDictInfo = useAtomValue(currentDictInfoAtom) @@ -18,15 +15,6 @@ export default function DictionaryGroup({ groupedDictsByTag }: { groupedDictsByT setCurrentTag(tag) }, []) - const onClickDict = useCallback( - (dict: Dictionary) => { - setState((state) => { - state.chapterListDict = dict - }) - }, - [setState], - ) - useEffect(() => { const commonTags = findCommonValues(tagList, currentDictInfo.tags) if (commonTags.length > 0) { @@ -39,7 +27,7 @@ export default function DictionaryGroup({ groupedDictsByTag }: { groupedDictsByT
{groupedDictsByTag[currentTag].map((dict) => ( - onClickDict(dict)} /> + ))}
diff --git a/src/pages/Gallery-N/Chapter/index.tsx b/src/pages/Gallery-N/Chapter/index.tsx new file mode 100644 index 00000000..29d2f94a --- /dev/null +++ b/src/pages/Gallery-N/Chapter/index.tsx @@ -0,0 +1,49 @@ +import { useChapterStats } from '../hooks/useChapterStats' +import useIntersectionObserver from '@/hooks/useIntersectionObserver' +import { useEffect, useRef } from 'react' +import IconCheckCircle from '~icons/heroicons/check-circle-solid' + +export default function Chapter({ + index, + checked, + dictID, + onChange, +}: { + index: number + checked: boolean + dictID: string + onChange: (index: number) => void +}) { + const ref = useRef(null) + + const entry = useIntersectionObserver(ref, {}) + const isVisible = !!entry?.isIntersecting + const chapterStatus = useChapterStats(index, dictID, isVisible) + + useEffect(() => { + if (checked && ref.current !== null) { + const button = ref.current + const container = button.parentElement?.parentElement?.parentElement + container?.scroll({ + top: button.offsetTop - container.offsetTop - 300, + behavior: 'smooth', + }) + } + }, [checked]) + + return ( +
onChange(index)} + > +

第 {index + 1} 章

+

+ {chapterStatus ? (chapterStatus.exerciseCount > 0 ? `练习 ${chapterStatus.exerciseCount} 次` : '未练习') : '加载中...'} +

+ {checked && ( + + )} +
+ ) +} diff --git a/src/pages/Gallery-N/ChapterList/ChapterRow.tsx b/src/pages/Gallery-N/ChapterList/ChapterRow.tsx deleted file mode 100644 index 1f64e569..00000000 --- a/src/pages/Gallery-N/ChapterList/ChapterRow.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import useIntersectionObserver from '@/hooks/useIntersectionObserver' -import { useChapterStats } from '@/pages/Gallery-N/hooks/useChapterStats' -import noop from '@/utils/noop' -import { useEffect, useRef } from 'react' - -type ChapterRowProps = { - index: number - checked: boolean - dictID: string - onChange: (index: number) => void -} -export default function ChapterRow({ index, dictID, checked, onChange }: ChapterRowProps) { - const rowRef = useRef(null) - - const entry = useIntersectionObserver(rowRef, {}) - const isVisible = !!entry?.isIntersecting - const chapterStatus = useChapterStats(index, dictID, isVisible) - - useEffect(() => { - if (checked && rowRef.current !== null) { - const button = rowRef.current - const container = button.parentElement?.parentElement?.parentElement - container?.scroll({ - top: button.offsetTop - container.offsetTop - 300, - behavior: 'smooth', - }) - } - }, [checked]) - - return ( -
- - {index + 1} - {chapterStatus ? chapterStatus.exerciseCount : 0} - - {chapterStatus ? chapterStatus.avgWrongWordCount : 0} - - {chapterStatus ? chapterStatus.avgWrongInputCount : 0} -
- - - - - - - - - - - {range(0, chapterCount, 1).map((index) => ( - - ))} - -
- Chapter - - 练习次数 - - 平均错误单词数 - - 平均错误输入数 -
-
- - - )} - - -
- - - - ) -} diff --git a/src/pages/Gallery-N/DictDetail/index.tsx b/src/pages/Gallery-N/DictDetail/index.tsx new file mode 100644 index 00000000..960f1171 --- /dev/null +++ b/src/pages/Gallery-N/DictDetail/index.tsx @@ -0,0 +1,107 @@ +import Chapter from '../Chapter' +import { ErrorTable } from '../ErrorTable' +import { getRowsFromErrorWordData } from '../ErrorTable/columns' +import { ReviewDetail } from '../ReviewDetail' +import useErrorWordData from '../hooks/useErrorWords' +import { ScrollArea } from '@/components/ui/scroll-area' +import { Tabs, TabsContent } from '@/components/ui/tabs' +import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group' +import { currentChapterAtom, currentDictIdAtom, reviewModeInfoAtom } from '@/store' +import type { Dictionary } from '@/typings' +import range from '@/utils/range' +import { useAtom, useSetAtom } from 'jotai' +import { useCallback, useMemo, useState } from 'react' +import { useNavigate } from 'react-router-dom' +import IcOutlineCollectionsBookmark from '~icons/ic/outline-collections-bookmark' +import MajesticonsPaperFoldTextLine from '~icons/majesticons/paper-fold-text-line' +import PajamasReviewList from '~icons/pajamas/review-list' + +enum Tab { + Chapters = 'chapters', + Errors = 'errors', + Review = 'review', +} + +export default function DictDetail({ dictionary: dict }: { dictionary: Dictionary }) { + const [currentChapter, setCurrentChapter] = useAtom(currentChapterAtom) + const [currentDictId, setCurrentDictId] = useAtom(currentDictIdAtom) + const [curTab, setCurTab] = useState(Tab.Chapters) + const setReviewModeInfo = useSetAtom(reviewModeInfoAtom) + const navigate = useNavigate() + + const chapter = useMemo(() => (dict.id === currentDictId ? currentChapter : 0), [currentChapter, currentDictId, dict.id]) + const { errorWordData, isLoading, error } = useErrorWordData(dict) + const tableData = useMemo(() => getRowsFromErrorWordData(errorWordData), [errorWordData]) + + const onChangeChapter = useCallback( + (index: number) => { + setCurrentDictId(dict.id) + setCurrentChapter(index) + setReviewModeInfo((old) => ({ ...old, isReviewMode: false })) + navigate('/') + }, + [dict.id, navigate, setCurrentChapter, setCurrentDictId, setReviewModeInfo], + ) + + return ( +
+
+

{dict.name}

+

{dict.chapterCount} 章节

+

共 {dict.length} 词

+

{dict.description}

+
+ { + setCurTab(value) + }} + > + + + 章节选择 + + {errorWordData.length > 0 && ( + <> + + + 查看错题 + + + + 错题回顾 + + + )} + +
+
+
+ + + +
+ {range(0, dict.chapterCount, 1).map((index) => ( + + ))} +
+
+
+ + + + + + +
+
+
+ ) +} diff --git a/src/pages/Gallery-N/DictionaryWithoutCover.tsx b/src/pages/Gallery-N/DictionaryWithoutCover.tsx index 078a8cce..c96d32b3 100644 --- a/src/pages/Gallery-N/DictionaryWithoutCover.tsx +++ b/src/pages/Gallery-N/DictionaryWithoutCover.tsx @@ -1,6 +1,8 @@ +import DictDetail from './DictDetail' import { useDictStats } from './hooks/useDictStats' import bookCover from '@/assets/book-cover.png' -import Tooltip from '@/components/Tooltip' +import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog' +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip' import useIntersectionObserver from '@/hooks/useIntersectionObserver' import { currentDictIdAtom } from '@/store' import type { Dictionary } from '@/typings' @@ -11,10 +13,9 @@ import { useMemo, useRef } from 'react' interface Props { dictionary: Dictionary - onClick?: () => void } -export default function DictionaryComponent({ dictionary, onClick }: Props) { +export default function DictionaryComponent({ dictionary }: Props) { const currentDictID = useAtomValue(currentDictIdAtom) const divRef = useRef(null) @@ -29,45 +30,63 @@ export default function DictionaryComponent({ dictionary, onClick }: Props) { ) return ( -
-
-

+ +
- {dictionary.name} -

- -

- {dictionary.description} -

-
- -

{dictionary.length} 词

-
- {progress > 0 && ( - +

- - - )} - + {dictionary.name} +

+ + + +

+ {dictionary.description} +

+
+ +

{`${dictionary.description}`}

+
+
+
+ +

{dictionary.length} 词

+
+ {progress > 0 && ( + + + + )} + +
+
-
-
+ + + + + ) } diff --git a/src/pages/Gallery-N/ErrorTable/columns.tsx b/src/pages/Gallery-N/ErrorTable/columns.tsx new file mode 100644 index 00000000..44806489 --- /dev/null +++ b/src/pages/Gallery-N/ErrorTable/columns.tsx @@ -0,0 +1,68 @@ +import type { TErrorWordData } from '../hooks/useErrorWords' +import { Button } from '@/components/ui/button' +import type { ColumnDef } from '@tanstack/react-table' +import PhArrowsDownUpFill from '~icons/ph/arrows-down-up-fill' + +export type ErrorColumn = { + word: string + trans: string + errorCount: number + errorChar: string[] +} + +export const errorColumns: ColumnDef[] = [ + { + accessorKey: 'word', + size: 100, + header: ({ column }) => { + return ( + + ) + }, + }, + { + accessorKey: 'trans', + size: 500, + header: '释义', + }, + { + accessorKey: 'errorCount', + size: 40, + header: ({ column }) => { + return ( + + ) + }, + }, + { + accessorKey: 'errorChar', + header: '易错字母', + size: 80, + cell: ({ row }) => { + return ( +

+ {(row.getValue('errorChar') as string[]).map((char, index) => ( + {char + ' '} + ))} +

+ ) + }, + }, +] + +export function getRowsFromErrorWordData(data: TErrorWordData[]): ErrorColumn[] { + return data.map((item) => { + return { + word: item.word, + trans: item.originData.trans.join(',') ?? '', + errorCount: item.errorCount, + errorChar: item.errorChar, + } + }) +} diff --git a/src/pages/Gallery-N/ErrorTable/index.tsx b/src/pages/Gallery-N/ErrorTable/index.tsx new file mode 100644 index 00000000..c6116990 --- /dev/null +++ b/src/pages/Gallery-N/ErrorTable/index.tsx @@ -0,0 +1,81 @@ +import type { ErrorColumn } from './columns' +import { errorColumns } from './columns' +import { LoadingUI } from '@/components/Loading' +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' +import type { SortingState } from '@tanstack/react-table' +import { flexRender, getCoreRowModel, getSortedRowModel, useReactTable } from '@tanstack/react-table' +import { useState } from 'react' + +interface DataTableProps { + data: ErrorColumn[] + isLoading: boolean + error: unknown +} + +export function ErrorTable({ data, isLoading, error }: DataTableProps) { + const [sorting, setSorting] = useState([]) + const table = useReactTable({ + data, + columns: errorColumns, + getCoreRowModel: getCoreRowModel(), + onSortingChange: setSorting, + getSortedRowModel: getSortedRowModel(), + state: { + sorting, + }, + }) + + return ( +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())} + + ) + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + {isLoading ? : error ? '好像遇到错误啦!尝试刷新下' : '暂无数据, 快去练习吧!'} + + + )} + +
+
+ ) +} diff --git a/src/pages/Gallery-N/ReviewDetail/index.tsx b/src/pages/Gallery-N/ReviewDetail/index.tsx new file mode 100644 index 00000000..985684b2 --- /dev/null +++ b/src/pages/Gallery-N/ReviewDetail/index.tsx @@ -0,0 +1,85 @@ +import type { TErrorWordData } from '../hooks/useErrorWords' +import { Button } from '@/components/ui/button' +import { currentChapterAtom, currentDictIdAtom, reviewModeInfoAtom } from '@/store' +import type { Dictionary } from '@/typings' +import { timeStamp2String } from '@/utils' +import { generateNewWordReviewRecord, useGetLatestReviewRecord } from '@/utils/db/review-record' +import * as Progress from '@radix-ui/react-progress' +import { useSetAtom } from 'jotai' +import { useNavigate } from 'react-router-dom' +import MdiRobotAngry from '~icons/mdi/robot-angry' + +export function ReviewDetail({ errorData, dict }: { errorData: TErrorWordData[]; dict: Dictionary }) { + const latestReviewRecord = useGetLatestReviewRecord(dict.id) + const setReviewModeInfo = useSetAtom(reviewModeInfoAtom) + const setCurrentDictId = useSetAtom(currentDictIdAtom) + const navigate = useNavigate() + const setCurrentChapter = useSetAtom(currentChapterAtom) + + const startReview = async () => { + setCurrentDictId(dict.id) + setCurrentChapter(-1) + + const record = await generateNewWordReviewRecord(dict.id, errorData) + setReviewModeInfo({ isReviewMode: true, reviewRecord: record }) + navigate('/') + } + + const continueReview = () => { + setCurrentDictId(dict.id) + setCurrentChapter(-1) + + setReviewModeInfo({ isReviewMode: true, reviewRecord: latestReviewRecord }) + navigate('/') + } + + return ( +
+
+ +
+

+ 我们将使用您在该词典的历史练习数据、错误次数、练习时间来智能生成练习列表 +
+ 目前该生成方式还处于实验阶段,我们会逐步完善该生成方式 +

+
+
+
+ {latestReviewRecord && ( + <> +
+ + + + + {latestReviewRecord.index + 1}/{latestReviewRecord.words.length} + +
+
{`( 创建于 ${timeStamp2String(latestReviewRecord.createTime)} )`}
+ + )} + + {!latestReviewRecord &&
当前词典错词数: {errorData.length}
} + +
+ {latestReviewRecord && ( + + )} + +
+
+
+ ) +} diff --git a/src/pages/Gallery-N/hooks/useDictStats.ts b/src/pages/Gallery-N/hooks/useDictStats.ts index 7da9552d..d0315d42 100644 --- a/src/pages/Gallery-N/hooks/useDictStats.ts +++ b/src/pages/Gallery-N/hooks/useDictStats.ts @@ -30,7 +30,6 @@ async function getDictStats(dict: string): Promise { const uniqueChapter = allChapter.filter((value, index, self) => { return self.indexOf(value) === index }) - const exercisedChapterCount = uniqueChapter.length return { exercisedChapterCount } diff --git a/src/pages/Gallery-N/hooks/useErrorWords.ts b/src/pages/Gallery-N/hooks/useErrorWords.ts new file mode 100644 index 00000000..fd535ad8 --- /dev/null +++ b/src/pages/Gallery-N/hooks/useErrorWords.ts @@ -0,0 +1,88 @@ +import type { Dictionary, Word } from '@/typings' +import { db } from '@/utils/db' +import type { WordRecord } from '@/utils/db/record' +import { wordListFetcher } from '@/utils/wordListFetcher' +import { useEffect, useState } from 'react' +import useSWR from 'swr' + +type groupRecord = { + word: string + records: WordRecord[] +} + +export type TErrorWordData = { + word: string + originData: Word + errorCount: number + errorLetters: Record + errorChar: string[] + latestErrorTime: number +} + +export default function useErrorWordData(dict: Dictionary) { + const { data: wordList, error, isLoading } = useSWR(dict?.url, wordListFetcher) + + const [errorWordData, setErrorData] = useState([]) + + useEffect(() => { + if (!wordList) return + + db.wordRecords + .where('wrongCount') + .above(0) + .filter((record) => record.dict === dict.id) + .toArray() + .then((records) => { + const groupRecords: groupRecord[] = [] + + records.forEach((record) => { + let groupRecord = groupRecords.find((g) => g.word === record.word) + if (!groupRecord) { + groupRecord = { word: record.word, records: [] } + groupRecords.push(groupRecord) + } + groupRecord.records.push(record as WordRecord) + }) + + const res: TErrorWordData[] = [] + + groupRecords.forEach((groupRecord) => { + const errorLetters = {} as Record + groupRecord.records.forEach((record) => { + for (const index in record.mistakes) { + const mistakes = record.mistakes[index] + if (mistakes.length > 0) { + errorLetters[index] = (errorLetters[index] ?? 0) + mistakes.length + } + } + }) + + const word = wordList.find((word) => word.name === groupRecord.word) + if (!word) return + + const errorData: TErrorWordData = { + word: groupRecord.word, + originData: word, + errorCount: groupRecord.records.reduce((acc, cur) => { + acc += cur.wrongCount + return acc + }, 0), + errorLetters, + errorChar: Object.entries(errorLetters) + .sort((a, b) => b[1] - a[1]) + .map(([index]) => groupRecord.word[Number(index)]), + + latestErrorTime: groupRecord.records.reduce((acc, cur) => { + acc = Math.max(acc, cur.timeStamp) + return acc + }, 0), + } + res.push(errorData) + }) + + setErrorData(res) + }) + }, [dict.id, wordList]) + + return { errorWordData, isLoading, error } +} diff --git a/src/pages/Gallery-N/hooks/useRevisionWordCount.ts b/src/pages/Gallery-N/hooks/useRevisionWordCount.ts new file mode 100644 index 00000000..b3e0cb3c --- /dev/null +++ b/src/pages/Gallery-N/hooks/useRevisionWordCount.ts @@ -0,0 +1,34 @@ +import { db } from '@/utils/db' +import { useEffect, useState } from 'react' + +export function useRevisionWordCount(dictID: string) { + const [wordCount, setWordCount] = useState(0) + + useEffect(() => { + const fetchWordCount = async () => { + const count = await getRevisionWordCount(dictID) + setWordCount(count) + } + + if (dictID) { + fetchWordCount() + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [dictID]) + + return wordCount +} + +async function getRevisionWordCount(dict: string): Promise { + const wordCount = await db.wordRecords + .where('dict') + .equals(dict) + .and((wordRecord) => wordRecord.wrongCount > 0) + .toArray() + .then((wordRecords) => { + const res = new Map() + const reducedRecords = wordRecords.filter((item) => !res.has(item['word'] + item['dict']) && res.set(item['word'] + item['dict'], 1)) + return reducedRecords.length + }) + return wordCount +} diff --git a/src/pages/Gallery-N/index.tsx b/src/pages/Gallery-N/index.tsx index 823d2f9a..c94e83cc 100644 --- a/src/pages/Gallery-N/index.tsx +++ b/src/pages/Gallery-N/index.tsx @@ -1,5 +1,4 @@ import DictionaryGroup from './CategoryDicts' -import ChapterList from './ChapterList' import DictRequest from './DictRequest' import { LanguageTabSwitcher } from './LanguageTabSwitcher' import Layout from '@/components/Layout' @@ -19,12 +18,10 @@ import IconX from '~icons/tabler/x' export type GalleryState = { currentLanguageTab: LanguageCategoryType - chapterListDict: Dictionary | null } const initialGalleryState: GalleryState = { currentLanguageTab: 'en', - chapterListDict: null, } export const GalleryContext = createContext<{ @@ -66,7 +63,6 @@ export default function GalleryPage() { return ( -
diff --git a/src/pages/Typing/components/DictChapterButton/index.tsx b/src/pages/Typing/components/DictChapterButton/index.tsx index db7c951b..c75faaee 100644 --- a/src/pages/Typing/components/DictChapterButton/index.tsx +++ b/src/pages/Typing/components/DictChapterButton/index.tsx @@ -1,5 +1,5 @@ import Tooltip from '@/components/Tooltip' -import { currentChapterAtom, currentDictInfoAtom } from '@/store' +import { currentChapterAtom, currentDictInfoAtom, isReviewModeAtom } from '@/store' import range from '@/utils/range' import { Listbox, Transition } from '@headlessui/react' import { useAtom, useAtomValue } from 'jotai' @@ -11,6 +11,7 @@ export const DictChapterButton = () => { const currentDictInfo = useAtomValue(currentDictInfoAtom) const [currentChapter, setCurrentChapter] = useAtom(currentChapterAtom) const chapterCount = currentDictInfo.chapterCount + const isReviewMode = useAtomValue(isReviewModeAtom) return ( <> @@ -19,34 +20,36 @@ export const DictChapterButton = () => { className="block rounded-lg px-3 py-1 text-lg transition-colors duration-300 ease-in-out hover:bg-indigo-400 hover:text-white focus:outline-none dark:text-white dark:text-opacity-60 dark:hover:text-opacity-100" to="/gallery" > - {currentDictInfo.name} + {currentDictInfo.name} {isReviewMode && '错题复习'} - - - - 第 {currentChapter + 1} 章 - - - - {range(0, chapterCount, 1).map((index) => ( - - {({ selected }) => ( -
- {selected ? ( - - - - ) : null} - 第 {index + 1} 章 -
- )} -
- ))} -
-
-
-
+ {!isReviewMode && ( + + + + 第 {currentChapter + 1} 章 + + + + {range(0, chapterCount, 1).map((index) => ( + + {({ selected }) => ( +
+ {selected ? ( + + + + ) : null} + 第 {index + 1} 章 +
+ )} +
+ ))} +
+
+
+
+ )} ) } diff --git a/src/pages/Typing/components/ResultScreen/index.tsx b/src/pages/Typing/components/ResultScreen/index.tsx index 143695b0..3bb90d65 100644 --- a/src/pages/Typing/components/ResultScreen/index.tsx +++ b/src/pages/Typing/components/ResultScreen/index.tsx @@ -5,13 +5,22 @@ import RemarkRing from './RemarkRing' import WordChip from './WordChip' import styles from './index.module.css' import Tooltip from '@/components/Tooltip' -import { currentChapterAtom, currentDictInfoAtom, infoPanelStateAtom, randomConfigAtom, wordDictationConfigAtom } from '@/store' +import { + currentChapterAtom, + currentDictInfoAtom, + infoPanelStateAtom, + isReviewModeAtom, + randomConfigAtom, + reviewModeInfoAtom, + wordDictationConfigAtom, +} from '@/store' import type { InfoPanelType } from '@/typings' import { recordOpenInfoPanelAction } from '@/utils' import { Transition } from '@headlessui/react' import { useAtom, useAtomValue, useSetAtom } from 'jotai' import { useCallback, useContext, useEffect, useMemo } from 'react' import { useHotkeys } from 'react-hotkeys-hook' +import { useNavigate } from 'react-router-dom' import IexportWords from '~icons/icon-park-outline/excel' import IconCoffee from '~icons/mdi/coffee' import IconXiaoHongShu from '~icons/my-icons/xiaohongshu' @@ -28,6 +37,10 @@ const ResultScreen = () => { const [currentChapter, setCurrentChapter] = useAtom(currentChapterAtom) const setInfoPanelState = useSetAtom(infoPanelStateAtom) const randomConfig = useAtomValue(randomConfigAtom) + const navigate = useNavigate() + + const setReviewModeInfo = useSetAtom(reviewModeInfoAtom) + const isReviewMode = useAtomValue(isReviewModeAtom) useEffect(() => { // tick a zero timer to calc the stats @@ -98,7 +111,11 @@ const ResultScreen = () => { return `${minuteString}:${secondString}` }, [state.timerData.time]) - const repeatButtonHandler = useCallback(() => { + const repeatButtonHandler = useCallback(async () => { + if (isReviewMode) { + return + } + setWordDictationConfig((old) => { if (old.isOpen) { if (old.openBy === 'auto') { @@ -108,15 +125,22 @@ const ResultScreen = () => { return old }) dispatch({ type: TypingStateActionType.REPEAT_CHAPTER, shouldShuffle: randomConfig.isOpen }) - }, [dispatch, randomConfig.isOpen, setWordDictationConfig]) + }, [isReviewMode, setWordDictationConfig, dispatch, randomConfig.isOpen]) + + const dictationButtonHandler = useCallback(async () => { + if (isReviewMode) { + return + } - const dictationButtonHandler = useCallback(() => { setWordDictationConfig((old) => ({ ...old, isOpen: true, openBy: 'auto' })) - dispatch({ type: TypingStateActionType.REPEAT_CHAPTER, shouldShuffle: randomConfig.isOpen }) - }, [dispatch, randomConfig.isOpen, setWordDictationConfig]) + }, [isReviewMode, setWordDictationConfig, dispatch, randomConfig.isOpen]) const nextButtonHandler = useCallback(() => { + if (isReviewMode) { + return + } + setWordDictationConfig((old) => { if (old.isOpen) { if (old.openBy === 'auto') { @@ -129,11 +153,23 @@ const ResultScreen = () => { setCurrentChapter((old) => old + 1) dispatch({ type: TypingStateActionType.NEXT_CHAPTER }) } - }, [dispatch, isLastChapter, setCurrentChapter, setWordDictationConfig]) + }, [dispatch, isLastChapter, isReviewMode, setCurrentChapter, setWordDictationConfig]) const exitButtonHandler = useCallback(() => { - dispatch({ type: TypingStateActionType.REPEAT_CHAPTER, shouldShuffle: false }) - }, [dispatch]) + if (isReviewMode) { + setCurrentChapter(0) + setReviewModeInfo((old) => ({ ...old, isReviewMode: false })) + } else { + dispatch({ type: TypingStateActionType.REPEAT_CHAPTER, shouldShuffle: false }) + } + }, [dispatch, isReviewMode, setCurrentChapter, setReviewModeInfo]) + + const onNavigateToGallery = useCallback(() => { + setCurrentChapter(0) + setReviewModeInfo((old) => ({ ...old, isReviewMode: false })) + navigate('/gallery') + }, [navigate, setCurrentChapter, setReviewModeInfo]) + useHotkeys( 'enter', () => { @@ -183,7 +219,7 @@ const ResultScreen = () => {
- {`${currentDictInfo.name} 第 ${currentChapter + 1} 章`} + {`${currentDictInfo.name} ${isReviewMode ? '错题复习' : '第' + (currentChapter + 1) + '章'}`}
- - + {!isReviewMode && ( + <> + + + + )} {
- - - - - - - {!isLastChapter && ( + {!isReviewMode && ( + <> + + + + + + + + )} + {!isLastChapter && !isReviewMode && ( )} + + {isReviewMode && ( + + )}
diff --git a/src/pages/Typing/components/WordList/index.tsx b/src/pages/Typing/components/WordList/index.tsx index bfc8fe81..e5275b38 100644 --- a/src/pages/Typing/components/WordList/index.tsx +++ b/src/pages/Typing/components/WordList/index.tsx @@ -2,7 +2,7 @@ import { TypingContext, TypingStateActionType } from '../../store' import WordCard from './WordCard' import Drawer from '@/components/Drawer' import Tooltip from '@/components/Tooltip' -import { currentChapterAtom, currentDictInfoAtom } from '@/store' +import { currentChapterAtom, currentDictInfoAtom, isReviewModeAtom } from '@/store' import { Dialog } from '@headlessui/react' import * as ScrollArea from '@radix-ui/react-scroll-area' import { atom, useAtomValue } from 'jotai' @@ -11,7 +11,13 @@ import ListIcon from '~icons/tabler/list' import IconX from '~icons/tabler/x' const currentDictTitle = atom((get) => { - return `${get(currentDictInfoAtom).name} 第 ${get(currentChapterAtom) + 1} 章` + const isReviewMode = get(isReviewModeAtom) + + if (isReviewMode) { + return `${get(currentDictInfoAtom).name} 错题复习` + } else { + return `${get(currentDictInfoAtom).name} 第 ${get(currentChapterAtom) + 1} 章` + } }) export default function WordList() { diff --git a/src/pages/Typing/components/WordPanel/components/Word/index.tsx b/src/pages/Typing/components/WordPanel/components/Word/index.tsx index ab318cc7..7bb0f6f9 100644 --- a/src/pages/Typing/components/WordPanel/components/Word/index.tsx +++ b/src/pages/Typing/components/WordPanel/components/Word/index.tsx @@ -167,6 +167,12 @@ export default function WordComponent({ word, onFinish }: { word: Word; onFinish useEffect(() => { const inputLength = wordState.inputWord.length + /** + * TODO: 当用户输入错误时,会报错 + * Cannot update a component (`App`) while rendering a different component (`WordComponent`). To locate the bad setState() call inside `WordComponent`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render + * 目前不影响生产环境,猜测是因为开发环境下 react 会两次调用 useEffect 从而展示了这个 warning + * 但这终究是一个 bug,需要修复 + */ if (wordState.hasWrong || inputLength === 0 || wordState.displayWord.length === 0) { return } diff --git a/src/pages/Typing/components/WordPanel/index.tsx b/src/pages/Typing/components/WordPanel/index.tsx index b6296c0d..10835799 100644 --- a/src/pages/Typing/components/WordPanel/index.tsx +++ b/src/pages/Typing/components/WordPanel/index.tsx @@ -1,13 +1,14 @@ import { TypingContext, TypingStateActionType } from '../../store' +import type { TypingState } from '../../store/type' import PrevAndNextWord from '../PrevAndNextWord' import Progress from '../Progress' import Phonetic from './components/Phonetic' import Translation from './components/Translation' import WordComponent from './components/Word' import { usePrefetchPronunciationSound } from '@/hooks/usePronunciation' -import { isShowPrevAndNextWordAtom, loopWordConfigAtom, phoneticConfigAtom } from '@/store' +import { isReviewModeAtom, isShowPrevAndNextWordAtom, loopWordConfigAtom, phoneticConfigAtom, reviewModeInfoAtom } from '@/store' import type { Word } from '@/typings' -import { useAtomValue } from 'jotai' +import { useAtomValue, useSetAtom } from 'jotai' import { useCallback, useContext, useMemo, useState } from 'react' import { useHotkeys } from 'react-hotkeys-hook' @@ -22,6 +23,9 @@ export default function WordPanel() { const currentWord = state.chapterData.words[state.chapterData.index] const nextWord = state.chapterData.words[state.chapterData.index + 1] as Word | undefined + const setReviewModeInfo = useSetAtom(reviewModeInfoAtom) + const isReviewMode = useAtomValue(isReviewModeAtom) + const prevIndex = useMemo(() => { const newIndex = state.chapterData.index - 1 return newIndex < 0 ? 0 : newIndex @@ -37,6 +41,16 @@ export default function WordPanel() { setWordComponentKey((old) => old + 1) }, []) + const updateReviewRecord = useCallback( + (state: TypingState) => { + setReviewModeInfo((old) => ({ + ...old, + reviewRecord: old.reviewRecord ? { ...old.reviewRecord, index: state.chapterData.index } : undefined, + })) + }, + [setReviewModeInfo], + ) + const onFinish = useCallback(() => { if (state.chapterData.index < state.chapterData.words.length - 1 || currentWordExerciseCount < loopWordTimes - 1) { // 用户完成当前单词 @@ -46,11 +60,23 @@ export default function WordPanel() { reloadCurrentWordComponent() } else { setCurrentWordExerciseCount(0) - dispatch({ type: TypingStateActionType.NEXT_WORD }) + if (isReviewMode) { + dispatch({ + type: TypingStateActionType.NEXT_WORD, + payload: { + updateReviewRecord, + }, + }) + } else { + dispatch({ type: TypingStateActionType.NEXT_WORD }) + } } } else { // 用户完成当前章节 dispatch({ type: TypingStateActionType.FINISH_CHAPTER }) + if (isReviewMode) { + setReviewModeInfo((old) => ({ ...old, reviewRecord: old.reviewRecord ? { ...old.reviewRecord, isFinished: true } : undefined })) + } } }, [ state.chapterData.index, @@ -59,6 +85,9 @@ export default function WordPanel() { loopWordTimes, dispatch, reloadCurrentWordComponent, + isReviewMode, + updateReviewRecord, + setReviewModeInfo, ]) const onSkipWord = useCallback( diff --git a/src/pages/Typing/hooks/useWordList.ts b/src/pages/Typing/hooks/useWordList.ts index 24842e85..98b9af7c 100644 --- a/src/pages/Typing/hooks/useWordList.ts +++ b/src/pages/Typing/hooks/useWordList.ts @@ -1,13 +1,13 @@ import { CHAPTER_LENGTH } from '@/constants' -import { currentChapterAtom, currentDictInfoAtom } from '@/store' -import type { WordWithIndex } from '@/typings/index' +import { currentChapterAtom, currentDictInfoAtom, reviewModeInfoAtom } from '@/store' +import type { Word, WordWithIndex } from '@/typings/index' import { wordListFetcher } from '@/utils/wordListFetcher' import { useAtom, useAtomValue } from 'jotai' import { useMemo } from 'react' import useSWR from 'swr' export type UseWordListResult = { - words: WordWithIndex[] | undefined + words: WordWithIndex[] isLoading: boolean error: Error | undefined } @@ -18,23 +18,29 @@ export type UseWordListResult = { export function useWordList(): UseWordListResult { const currentDictInfo = useAtomValue(currentDictInfoAtom) const [currentChapter, setCurrentChapter] = useAtom(currentChapterAtom) - - const isFirstChapter = currentDictInfo.id === 'cet4' && currentChapter === 0 + const { isReviewMode, reviewRecord } = useAtomValue(reviewModeInfoAtom) // Reset current chapter to 0, when currentChapter is greater than chapterCount. if (currentChapter >= currentDictInfo.chapterCount) { setCurrentChapter(0) } + const isFirstChapter = !isReviewMode && currentDictInfo.id === 'cet4' && currentChapter === 0 const { data: wordList, error, isLoading } = useSWR(currentDictInfo.url, wordListFetcher) const words: WordWithIndex[] = useMemo(() => { - const newWords = isFirstChapter - ? firstChapter - : wordList - ? wordList.slice(currentChapter * CHAPTER_LENGTH, (currentChapter + 1) * CHAPTER_LENGTH) - : [] + let newWords: Word[] + if (isFirstChapter) { + newWords = firstChapter + } else if (isReviewMode) { + newWords = reviewRecord?.words ?? [] + } else if (wordList) { + newWords = wordList.slice(currentChapter * CHAPTER_LENGTH, (currentChapter + 1) * CHAPTER_LENGTH) + } else { + newWords = [] + } + // 记录原始 index, 并对 word.trans 做兜底处理 return newWords.map((word, index) => { let trans: string[] if (Array.isArray(word.trans)) { @@ -50,9 +56,9 @@ export function useWordList(): UseWordListResult { trans, } }) - }, [isFirstChapter, wordList, currentChapter]) + }, [isFirstChapter, isReviewMode, wordList, reviewRecord?.words, currentChapter]) - return { words: wordList === undefined ? undefined : words, isLoading, error } + return { words, isLoading, error } } const firstChapter = [ diff --git a/src/pages/Typing/index.tsx b/src/pages/Typing/index.tsx index 3d83127c..7b835ea4 100644 --- a/src/pages/Typing/index.tsx +++ b/src/pages/Typing/index.tsx @@ -15,11 +15,11 @@ import Header from '@/components/Header' import StarCard from '@/components/StarCard' import Tooltip from '@/components/Tooltip' import { idDictionaryMap } from '@/resources/dictionary' -import { currentDictIdAtom, randomConfigAtom } from '@/store' +import { currentChapterAtom, currentDictIdAtom, isReviewModeAtom, randomConfigAtom, reviewModeInfoAtom } from '@/store' import { IsDesktop, isLegal } from '@/utils' import { useSaveChapterRecord } from '@/utils/db' import { useMixPanelChapterLogUploader } from '@/utils/mixpanel' -import { useAtom, useAtomValue } from 'jotai' +import { useAtom, useAtomValue, useSetAtom } from 'jotai' import type React from 'react' import { useCallback, useEffect, useState } from 'react' import { useImmerReducer } from 'use-immer' @@ -30,11 +30,14 @@ const App: React.FC = () => { const { words } = useWordList() const [currentDictId, setCurrentDictId] = useAtom(currentDictIdAtom) + const setCurrentChapter = useSetAtom(currentChapterAtom) const randomConfig = useAtomValue(randomConfigAtom) - const chapterLogUploader = useMixPanelChapterLogUploader(state) const saveChapterRecord = useSaveChapterRecord() + const reviewModeInfo = useAtomValue(reviewModeInfoAtom) + const isReviewMode = useAtomValue(isReviewModeAtom) + useEffect(() => { // 检测用户设备 if (!IsDesktop()) { @@ -51,8 +54,10 @@ const App: React.FC = () => { const id = currentDictId if (!(id in idDictionaryMap)) { setCurrentDictId('cet4') + setCurrentChapter(0) + return } - }, [currentDictId, setCurrentDictId]) + }, [currentDictId, setCurrentChapter, setCurrentDictId]) const skipWord = useCallback(() => { dispatch({ type: TypingStateActionType.SKIP_WORD }) @@ -89,9 +94,11 @@ const App: React.FC = () => { useEffect(() => { if (words !== undefined) { + const initialIndex = isReviewMode && reviewModeInfo.reviewRecord?.index ? reviewModeInfo.reviewRecord.index : 0 + dispatch({ type: TypingStateActionType.SETUP_CHAPTER, - payload: { words, shouldShuffle: randomConfig.isOpen }, + payload: { words, shouldShuffle: randomConfig.isOpen, initialIndex }, }) } // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/src/pages/Typing/store/index.ts b/src/pages/Typing/store/index.ts index b1d457bb..fabd5ea0 100644 --- a/src/pages/Typing/store/index.ts +++ b/src/pages/Typing/store/index.ts @@ -1,6 +1,7 @@ import type { TypingState, UserInputLog } from './type' import type { WordWithIndex } from '@/typings' import type { LetterMistakes } from '@/utils/db/record' +import '@/utils/db/review-record' import { mergeLetterMistake } from '@/utils/db/utils' import shuffle from '@/utils/shuffle' import { createContext } from 'react' @@ -57,16 +58,22 @@ export enum TypingStateActionType { SET_IS_SAVING_RECORD = 'SET_IS_SAVING_RECORD', SET_IS_LOOP_SINGLE_WORD = 'SET_IS_LOOP_SINGLE_WORD', TOGGLE_IS_LOOP_SINGLE_WORD = 'TOGGLE_IS_LOOP_SINGLE_WORD', + SET_REVISION_INDEX = 'SET_REVISION_INDEX', } export type TypingStateAction = - | { type: TypingStateActionType.SETUP_CHAPTER; payload: { words: WordWithIndex[]; shouldShuffle: boolean } } + | { type: TypingStateActionType.SETUP_CHAPTER; payload: { words: WordWithIndex[]; shouldShuffle: boolean; initialIndex?: number } } | { type: TypingStateActionType.SET_IS_SKIP; payload: boolean } | { type: TypingStateActionType.SET_IS_TYPING; payload: boolean } | { type: TypingStateActionType.TOGGLE_IS_TYPING } | { type: TypingStateActionType.REPORT_WRONG_WORD; payload: { letterMistake: LetterMistakes } } | { type: TypingStateActionType.REPORT_CORRECT_WORD } - | { type: TypingStateActionType.NEXT_WORD } + | { + type: TypingStateActionType.NEXT_WORD + payload?: { + updateReviewRecord?: (state: TypingState) => void + } + } | { type: TypingStateActionType.LOOP_CURRENT_WORD } | { type: TypingStateActionType.FINISH_CHAPTER } | { type: TypingStateActionType.SKIP_WORD } @@ -87,6 +94,11 @@ export const typingReducer = (state: TypingState, action: TypingStateAction) => case TypingStateActionType.SETUP_CHAPTER: { const newState = structuredClone(initialState) const words = action.payload.shouldShuffle ? shuffle(action.payload.words) : action.payload.words + let initialIndex = action.payload.initialIndex ?? 0 + if (initialIndex >= words.length) { + initialIndex = 0 + } + newState.chapterData.index = initialIndex newState.chapterData.words = words newState.chapterData.userInputLogs = words.map((_, index) => ({ ...structuredClone(initialUserInputLog), index })) @@ -118,11 +130,16 @@ export const typingReducer = (state: TypingState, action: TypingStateAction) => wordLog.LetterMistakes = mergeLetterMistake(wordLog.LetterMistakes, letterMistake) break } - case TypingStateActionType.NEXT_WORD: + case TypingStateActionType.NEXT_WORD: { state.chapterData.index += 1 state.chapterData.wordCount += 1 state.isShowSkip = false + + if (action?.payload?.updateReviewRecord) { + action.payload.updateReviewRecord(state) + } break + } case TypingStateActionType.LOOP_CURRENT_WORD: state.isShowSkip = false state.chapterData.wordCount += 1 diff --git a/src/store/index.ts b/src/store/index.ts index fed1200a..7d7dd819 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,4 +1,5 @@ import atomForConfig from './atomForConfig' +import { reviewInfoAtom } from './reviewInfoAtom' import { DISMISS_START_CARD_DATE_KEY, defaultFontSizeConfig } from '@/constants' import { idDictionaryMap } from '@/resources/dictionary' import { correctSoundResources, keySoundResources, wrongSoundResources } from '@/resources/soundResource' @@ -11,6 +12,7 @@ import type { WordDictationOpenBy, WordDictationType, } from '@/typings' +import type { ReviewRecord } from '@/utils/db/record' import { atom } from 'jotai' import { atomWithStorage } from 'jotai/utils' @@ -76,6 +78,12 @@ export const isShowAnswerOnHoverAtom = atomWithStorage('isShowAnswerOnHover', tr export const isTextSelectableAtom = atomWithStorage('isTextSelectable', false) +export const reviewModeInfoAtom = reviewInfoAtom({ + isReviewMode: false, + reviewRecord: undefined as ReviewRecord | undefined, +}) +export const isReviewModeAtom = atom((get) => get(reviewModeInfoAtom).isReviewMode) + export const phoneticConfigAtom = atomForConfig('phoneticConfig', { isOpen: true, type: 'us' as PhoneticType, diff --git a/src/store/reviewInfoAtom.ts b/src/store/reviewInfoAtom.ts new file mode 100644 index 00000000..41120080 --- /dev/null +++ b/src/store/reviewInfoAtom.ts @@ -0,0 +1,28 @@ +import type { ReviewRecord } from '@/utils/db/record' +import { putWordReviewRecord } from '@/utils/db/review-record' +import { atom } from 'jotai' +import { atomWithStorage } from 'jotai/utils' + +type TReviewInfoAtomData = { + isReviewMode: boolean + reviewRecord: ReviewRecord | undefined +} + +export function reviewInfoAtom(initialValue: TReviewInfoAtomData) { + const storageAtom = atomWithStorage('reviewModeInfo', initialValue) + + return atom( + (get) => { + return get(storageAtom) + }, + (get, set, updater: TReviewInfoAtomData | ((oldValue: TReviewInfoAtomData) => TReviewInfoAtomData)) => { + const newValue = typeof updater === 'function' ? updater(get(storageAtom)) : updater + + // update reviewRecord to indexdb + if (newValue.reviewRecord?.id) { + putWordReviewRecord(newValue.reviewRecord) + } + set(storageAtom, newValue) + }, + ) +} diff --git a/src/utils/db/index.ts b/src/utils/db/index.ts index efde47a0..1c24de96 100644 --- a/src/utils/db/index.ts +++ b/src/utils/db/index.ts @@ -1,8 +1,8 @@ -import type { IChapterRecord, IWordRecord, LetterMistakes } from './record' -import { ChapterRecord, WordRecord } from './record' +import type { IChapterRecord, IReviewRecord, IRevisionDictRecord, IWordRecord, LetterMistakes } from './record' +import { ChapterRecord, ReviewRecord, WordRecord } from './record' import { TypingContext, TypingStateActionType } from '@/pages/Typing/store' import type { TypingState } from '@/pages/Typing/store/type' -import { currentChapterAtom, currentDictIdAtom } from '@/store' +import { currentChapterAtom, currentDictIdAtom, isReviewModeAtom } from '@/store' import type { Table } from 'dexie' import Dexie from 'dexie' import { useAtomValue } from 'jotai' @@ -11,6 +11,10 @@ import { useCallback, useContext } from 'react' class RecordDB extends Dexie { wordRecords!: Table chapterRecords!: Table + reviewRecords!: Table + + revisionDictRecords!: Table + revisionWordRecords!: Table constructor() { super('RecordDB') @@ -22,6 +26,11 @@ class RecordDB extends Dexie { wordRecords: '++id,word,timeStamp,dict,chapter,wrongCount,[dict+chapter]', chapterRecords: '++id,timeStamp,dict,chapter,time,[dict+chapter]', }) + this.version(3).stores({ + wordRecords: '++id,word,timeStamp,dict,chapter,wrongCount,[dict+chapter]', + chapterRecords: '++id,timeStamp,dict,chapter,time,[dict+chapter]', + reviewRecords: '++id,dict,createTime,isFinished', + }) } } @@ -29,9 +38,11 @@ export const db = new RecordDB() db.wordRecords.mapToClass(WordRecord) db.chapterRecords.mapToClass(ChapterRecord) +db.reviewRecords.mapToClass(ReviewRecord) export function useSaveChapterRecord() { const currentChapter = useAtomValue(currentChapterAtom) + const isRevision = useAtomValue(isReviewModeAtom) const dictID = useAtomValue(currentDictIdAtom) const saveChapterRecord = useCallback( @@ -44,7 +55,7 @@ export function useSaveChapterRecord() { const chapterRecord = new ChapterRecord( dictID, - currentChapter, + isRevision ? -1 : currentChapter, time, correctCount, wrongCount, @@ -55,7 +66,7 @@ export function useSaveChapterRecord() { ) db.chapterRecords.add(chapterRecord) }, - [currentChapter, dictID], + [currentChapter, dictID, isRevision], ) return saveChapterRecord @@ -67,6 +78,7 @@ export type WordKeyLogger = { } export function useSaveWordRecord() { + const isRevision = useAtomValue(isReviewModeAtom) const currentChapter = useAtomValue(currentChapterAtom) const dictID = useAtomValue(currentDictIdAtom) @@ -90,7 +102,7 @@ export function useSaveWordRecord() { timing.push(diff) } - const wordRecord = new WordRecord(word, dictID, currentChapter, timing, wrongCount, letterMistake) + const wordRecord = new WordRecord(word, dictID, isRevision ? -1 : currentChapter, timing, wrongCount, letterMistake) let dbID = -1 try { @@ -103,7 +115,7 @@ export function useSaveWordRecord() { dispatch({ type: TypingStateActionType.SET_IS_SAVING_RECORD, payload: false }) } }, - [currentChapter, dictID, dispatch], + [currentChapter, dictID, dispatch, isRevision], ) return saveWordRecord diff --git a/src/utils/db/record.ts b/src/utils/db/record.ts index 78806f80..78b7d6ed 100644 --- a/src/utils/db/record.ts +++ b/src/utils/db/record.ts @@ -1,4 +1,5 @@ import { getUTCUnixTimestamp } from '../index' +import type { Word } from '@/typings' export interface IWordRecord { word: string @@ -47,7 +48,7 @@ export class WordRecord implements IWordRecord { export interface IChapterRecord { // 正常章节为 dictKey, 其他功能则为对应的类型 dict: string - // 用户可能是在 错题/其他类似组件中 进行的练习则为 null + // 在错题场景中为 -1 chapter: number | null timeStamp: number // 单位为 s,章节的记录没必要到毫秒级 @@ -113,3 +114,72 @@ export class ChapterRecord implements IChapterRecord { return Math.round((this.correctWordIndexes.length / this.wordNumber) * 100) } } + +export interface IReviewRecord { + id?: number + dict: string + // 当前练习进度 + index: number + // 创建时间 + createTime: number + // 是否已经完成 + isFinished: boolean + // 单词列表, 根据复习算法生成和修改,可能会有重复值 + words: Word[] +} + +export class ReviewRecord implements IReviewRecord { + id?: number + dict: string + index: number + createTime: number + isFinished: boolean + words: Word[] + + constructor(dict: string, words: Word[]) { + this.dict = dict + this.index = 0 + this.createTime = getUTCUnixTimestamp() + this.words = words + this.isFinished = false + } +} + +export interface IRevisionDictRecord { + dict: string + revisionIndex: number + createdTime: number +} + +export class RevisionDictRecord implements IRevisionDictRecord { + dict: string + revisionIndex: number + createdTime: number + + constructor(dict: string, revisionIndex: number, createdTime: number) { + this.dict = dict + this.revisionIndex = revisionIndex + this.createdTime = createdTime + } +} + +export interface IRevisionWordRecord { + word: string + timeStamp: number + dict: string + errorCount: number +} + +export class RevisionWordRecord implements IRevisionWordRecord { + word: string + timeStamp: number + dict: string + errorCount: number + + constructor(word: string, dict: string, errorCount: number) { + this.word = word + this.timeStamp = getUTCUnixTimestamp() + this.dict = dict + this.errorCount = errorCount + } +} diff --git a/src/utils/db/review-record.ts b/src/utils/db/review-record.ts new file mode 100644 index 00000000..b6c1be71 --- /dev/null +++ b/src/utils/db/review-record.ts @@ -0,0 +1,68 @@ +import { db } from '.' +import { ReviewRecord } from './record' +import type { TErrorWordData } from '@/pages/Gallery-N/hooks/useErrorWords' +import type { Word } from '@/typings' +import { useEffect, useState } from 'react' + +export function useGetLatestReviewRecord(dictID: string) { + const [wordReviewRecord, setWordReviewRecord] = useState(undefined) + useEffect(() => { + const fetchWordReviewRecords = async () => { + const record = await getReviewRecords(dictID) + setWordReviewRecord(record) + } + if (dictID) { + fetchWordReviewRecords() + } + }, [dictID]) + return wordReviewRecord +} + +async function getReviewRecords(dictID: string): Promise { + const records = await db.reviewRecords.where('dict').equals(dictID).toArray() + + const latestRecord = records.sort((a, b) => a.createTime - b.createTime).pop() + + return latestRecord && (latestRecord.isFinished ? undefined : latestRecord) +} + +type TRankedErrorWordData = TErrorWordData & { + errorCountScore: number + latestErrorTimeScore: number +} + +export async function generateNewWordReviewRecord(dictID: string, errorData: TErrorWordData[]) { + const errorCountRankings = [...errorData].sort((a, b) => a.errorCount - b.errorCount) + const latestErrorTimeRankings = [...errorData].sort((a, b) => a.latestErrorTime - b.latestErrorTime) + + // 计算每个对象的排名得分 + const errorDataWithRank: TRankedErrorWordData[] = errorData.map((item) => ({ + ...item, + errorCountScore: errorCountRankings.indexOf(item) + 1, + latestErrorTimeScore: latestErrorTimeRankings.indexOf(item) + 1, + })) + + // 根据加权排名进行排序 + const errorCountWeight = 0.6 + const latestErrorTimeWeight = 0.4 + + const sortedWords: Word[] = errorDataWithRank + .sort((a, b) => { + // 计算 a 和 b 的得分 + const scoreA = a.errorCountScore * errorCountWeight + a.latestErrorTimeScore * latestErrorTimeWeight + const scoreB = b.errorCountScore * errorCountWeight + b.latestErrorTimeScore * latestErrorTimeWeight + + // 根据得分进行排序 + return scoreA - scoreB + }) + .map((item) => item.originData) + + const record = new ReviewRecord(dictID, sortedWords) + + await db.reviewRecords.put(record) + return record +} + +export async function putWordReviewRecord(record: ReviewRecord) { + db.reviewRecords.put(record) +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 0d3002dc..8e254ef5 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -118,3 +118,12 @@ export function getUTCUnixTimestamp() { ) / 1000, ) } + +export function timeStamp2String(timestamp: number) { + const date = new Date(timestamp * 1000) + + const dateString = date.toLocaleDateString('zh-CN', { month: '2-digit', day: '2-digit' }) + const timeString = date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit', hour12: false }) + + return `${dateString} ${timeString}` +} diff --git a/src/utils/ui.ts b/src/utils/ui.ts new file mode 100644 index 00000000..d32b0fe6 --- /dev/null +++ b/src/utils/ui.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from 'clsx' +import { twMerge } from 'tailwind-merge' + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/tailwind.config.js b/tailwind.config.js index e51eb5b6..9bfca68c 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,8 +1,23 @@ +/** @type {import('tailwindcss').Config} */ module.exports = { + darkMode: ['class'], content: ['./src/**/*.{js,jsx,ts,tsx}', './index.html'], - darkMode: 'class', theme: { extend: { + keyframes: { + 'accordion-down': { + from: { height: 0 }, + to: { height: 'var(--radix-accordion-content-height)' }, + }, + 'accordion-up': { + from: { height: 'var(--radix-accordion-content-height)' }, + to: { height: 0 }, + }, + }, + animation: { + 'accordion-down': 'accordion-down 0.2s ease-out', + 'accordion-up': 'accordion-up 0.2s ease-out', + }, transitionDuration: { 0: '0ms', }, @@ -55,7 +70,7 @@ module.exports = { backgroundOpacity: ['dark'], }, }, - plugins: [require('@headlessui/tailwindcss'), require('@tailwindcss/forms'), require('daisyui')], + plugins: [require('@headlessui/tailwindcss'), require('@tailwindcss/forms'), require('daisyui'), require('tailwindcss-animate')], daisyui: { themes: [ { diff --git a/yarn.lock b/yarn.lock index cb18e369..8bb426b4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -45,7 +45,7 @@ resolved "https://registry.npmmirror.com/@babel/compat-data/-/compat-data-7.21.9.tgz" integrity sha512-FUGed8kfhyWvbYug/Un/VPJD41rDIgoVVcR+FuzhzOYyRz5uED+Gd3SLZml0Uw2l2aHFb7ZgdW5mGA3G2cCCnQ== -"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.12.0", "@babel/core@^7.13.0", "@babel/core@^7.16.0", "@babel/core@^7.20.12", "@babel/core@^7.21.3", "@babel/core@^7.4.0-0", "@babel/core@>=7.11.0": +"@babel/core@^7.16.0", "@babel/core@^7.20.12", "@babel/core@^7.21.3": version "7.21.8" resolved "https://registry.npmmirror.com/@babel/core/-/core-7.21.8.tgz" integrity sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ== @@ -75,7 +75,7 @@ eslint-visitor-keys "^2.1.0" semver "^6.3.0" -"@babel/generator@^7.17.3", "@babel/generator@7.17.7": +"@babel/generator@7.17.7", "@babel/generator@^7.17.3": version "7.17.7" resolved "https://registry.npmmirror.com/@babel/generator/-/generator-7.17.7.tgz" integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== @@ -504,7 +504,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-syntax-flow@^7.14.5", "@babel/plugin-syntax-flow@^7.18.6": +"@babel/plugin-syntax-flow@^7.18.6": version "7.23.3" resolved "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.23.3.tgz" integrity sha512-YZiAIpkJAwQXBJLIQbRFayR5c+gJ35Vcz3bg954k7cd73zqjvhacJuL9RbrzPz8qPmZdgqP6EUKwy0PCNhaaPA== @@ -823,7 +823,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.19.0" -"@babel/plugin-transform-react-jsx@^7.14.9", "@babel/plugin-transform-react-jsx@^7.18.6": +"@babel/plugin-transform-react-jsx@^7.18.6": version "7.23.4" resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz" integrity sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA== @@ -1051,13 +1051,27 @@ resolved "https://registry.npmmirror.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.16.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.8.4": +"@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.16.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.8.4": version "7.21.5" resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.21.5.tgz" integrity sha512-8jI69toZqqcsnqGGqwGS4Qb1VwLOEp4hz+CXPywcvjs60u3B4Pom/U/7rm4W8tMOYEB+E9wgD0mW1l3r8qlI9Q== dependencies: regenerator-runtime "^0.13.11" +"@babel/runtime@^7.21.0": + version "7.22.6" + resolved "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438" + integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/runtime@^7.23.5": + version "7.23.5" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz#11edb98f8aeec529b82b211028177679144242db" + integrity sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.18.10", "@babel/template@^7.20.7": version "7.21.9" resolved "https://registry.npmmirror.com/@babel/template/-/template-7.21.9.tgz" @@ -1067,22 +1081,6 @@ "@babel/parser" "^7.21.9" "@babel/types" "^7.21.5" -"@babel/traverse@^7.20.5", "@babel/traverse@^7.21.5": - version "7.21.5" - resolved "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.21.5.tgz" - integrity sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw== - dependencies: - "@babel/code-frame" "^7.21.4" - "@babel/generator" "^7.21.5" - "@babel/helper-environment-visitor" "^7.21.5" - "@babel/helper-function-name" "^7.21.0" - "@babel/helper-hoist-variables" "^7.18.6" - "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.21.5" - "@babel/types" "^7.21.5" - debug "^4.1.0" - globals "^11.1.0" - "@babel/traverse@7.17.3": version "7.17.3" resolved "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.17.3.tgz" @@ -1099,7 +1097,23 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.17.0", "@babel/types@7.17.0": +"@babel/traverse@^7.20.5", "@babel/traverse@^7.21.5": + version "7.21.5" + resolved "https://registry.npmmirror.com/@babel/traverse/-/traverse-7.21.5.tgz" + integrity sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw== + dependencies: + "@babel/code-frame" "^7.21.4" + "@babel/generator" "^7.21.5" + "@babel/helper-environment-visitor" "^7.21.5" + "@babel/helper-function-name" "^7.21.0" + "@babel/helper-hoist-variables" "^7.18.6" + "@babel/helper-split-export-declaration" "^7.18.6" + "@babel/parser" "^7.21.5" + "@babel/types" "^7.21.5" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@7.17.0", "@babel/types@^7.17.0": version "7.17.0" resolved "https://registry.npmmirror.com/@babel/types/-/types-7.17.0.tgz" integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== @@ -1116,11 +1130,116 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@esbuild/android-arm64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd" + integrity sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA== + +"@esbuild/android-arm@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.17.19.tgz#5898f7832c2298bc7d0ab53701c57beb74d78b4d" + integrity sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A== + +"@esbuild/android-x64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.17.19.tgz#658368ef92067866d95fb268719f98f363d13ae1" + integrity sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww== + "@esbuild/darwin-arm64@0.17.19": version "0.17.19" resolved "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz" integrity sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg== +"@esbuild/darwin-x64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz#7751d236dfe6ce136cce343dce69f52d76b7f6cb" + integrity sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw== + +"@esbuild/freebsd-arm64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz#cacd171665dd1d500f45c167d50c6b7e539d5fd2" + integrity sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ== + +"@esbuild/freebsd-x64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz#0769456eee2a08b8d925d7c00b79e861cb3162e4" + integrity sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ== + +"@esbuild/linux-arm64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz#38e162ecb723862c6be1c27d6389f48960b68edb" + integrity sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg== + +"@esbuild/linux-arm@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz#1a2cd399c50040184a805174a6d89097d9d1559a" + integrity sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA== + +"@esbuild/linux-ia32@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz#e28c25266b036ce1cabca3c30155222841dc035a" + integrity sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ== + +"@esbuild/linux-loong64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz#0f887b8bb3f90658d1a0117283e55dbd4c9dcf72" + integrity sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ== + +"@esbuild/linux-mips64el@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz#f5d2a0b8047ea9a5d9f592a178ea054053a70289" + integrity sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A== + +"@esbuild/linux-ppc64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz#876590e3acbd9fa7f57a2c7d86f83717dbbac8c7" + integrity sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg== + +"@esbuild/linux-riscv64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz#7f49373df463cd9f41dc34f9b2262d771688bf09" + integrity sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA== + +"@esbuild/linux-s390x@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz#e2afd1afcaf63afe2c7d9ceacd28ec57c77f8829" + integrity sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q== + +"@esbuild/linux-x64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz#8a0e9738b1635f0c53389e515ae83826dec22aa4" + integrity sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw== + +"@esbuild/netbsd-x64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz#c29fb2453c6b7ddef9a35e2c18b37bda1ae5c462" + integrity sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q== + +"@esbuild/openbsd-x64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz#95e75a391403cb10297280d524d66ce04c920691" + integrity sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g== + +"@esbuild/sunos-x64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz#722eaf057b83c2575937d3ffe5aeb16540da7273" + integrity sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg== + +"@esbuild/win32-arm64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz#9aa9dc074399288bdcdd283443e9aeb6b9552b6f" + integrity sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag== + +"@esbuild/win32-ia32@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz#95ad43c62ad62485e210f6299c7b2571e48d2b03" + integrity sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw== + +"@esbuild/win32-x64@0.17.19": + version "0.17.19" + resolved "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz#8cfaf2ff603e9aabb910e9c0558c26cf32744061" + integrity sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA== + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" @@ -1158,13 +1277,40 @@ resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-1.2.6.tgz" integrity sha512-EvYTiXet5XqweYGClEmpu3BoxmsQ4hkj3QaYA6qEnigCWffTP3vNRwBReTdrwDwo7OoJ3wM8Uoe9Uk4n+d4hfg== -"@floating-ui/dom@^1.0.0", "@floating-ui/dom@^1.2.1": +"@floating-ui/core@^1.3.1": + version "1.3.1" + resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-1.3.1.tgz#4d795b649cc3b1cbb760d191c80dcb4353c9a366" + integrity sha512-Bu+AMaXNjrpjh41znzHqaz3r2Nr8hHuHZT6V2LBKMhyMl0FgKA62PNYbqnfgmzOhoWZj70Zecisbo4H1rotP5g== + +"@floating-ui/core@^1.4.2": + version "1.5.2" + resolved "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.2.tgz#53a0f7a98c550e63134d504f26804f6b83dbc071" + integrity sha512-Ii3MrfY/GAIN3OhXNzpCKaLxHQfJF9qvwq/kEJYdqDxeIHa01K8sldugal6TmeeXl+WMvhv9cnVzUTaFFJF09A== + dependencies: + "@floating-ui/utils" "^0.1.3" + +"@floating-ui/dom@^1.0.0": + version "1.4.5" + resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.4.5.tgz#336dfb9870c98b471ff5802002982e489b8bd1c5" + integrity sha512-96KnRWkRnuBSSFbj0sFGwwOUd8EkiecINVl0O9wiZlZ64EkpyAOG3Xc2vKKNJmru0Z7RqWNymA+6b8OZqjgyyw== + dependencies: + "@floating-ui/core" "^1.3.1" + +"@floating-ui/dom@^1.2.1": version "1.2.8" resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.2.8.tgz" integrity sha512-XLwhYV90MxiHDq6S0rzFZj00fnDM+A1R9jhSioZoMsa7G0Q0i+Q4x40ajR8FHSdYDE1bgjG45mIWe6jtv9UPmg== dependencies: "@floating-ui/core" "^1.2.6" +"@floating-ui/dom@^1.5.1": + version "1.5.3" + resolved "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz#54e50efcb432c06c23cd33de2b575102005436fa" + integrity sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA== + dependencies: + "@floating-ui/core" "^1.4.2" + "@floating-ui/utils" "^0.1.3" + "@floating-ui/react-dom@^1.3.0": version "1.3.0" resolved "https://registry.npmmirror.com/@floating-ui/react-dom/-/react-dom-1.3.0.tgz" @@ -1172,6 +1318,13 @@ dependencies: "@floating-ui/dom" "^1.2.1" +"@floating-ui/react-dom@^2.0.0": + version "2.0.4" + resolved "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz#b076fafbdfeb881e1d86ae748b7ff95150e9f3ec" + integrity sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ== + dependencies: + "@floating-ui/dom" "^1.5.1" + "@floating-ui/react@^0.20.1": version "0.20.1" resolved "https://registry.npmmirror.com/@floating-ui/react/-/react-0.20.1.tgz" @@ -1181,6 +1334,11 @@ aria-hidden "^1.1.3" tabbable "^6.0.1" +"@floating-ui/utils@^0.1.3": + version "0.1.6" + resolved "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz#22958c042e10b67463997bd6ea7115fe28cbcaf9" + integrity sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A== + "@headlessui/react@^1.7.13": version "1.7.14" resolved "https://registry.npmmirror.com/@headlessui/react/-/react-1.7.14.tgz" @@ -1256,16 +1414,16 @@ resolved "https://registry.npmmirror.com/@jridgewell/set-array/-/set-array-1.1.2.tgz" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13": - version "1.4.15" - resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== - "@jridgewell/sourcemap-codec@1.4.14": version "1.4.14" resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13": + version "1.4.15" + resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": version "0.3.18" resolved "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz" @@ -1289,7 +1447,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -1309,6 +1467,13 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/number@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz#644161a3557f46ed38a042acf4a770e826021674" + integrity sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive@1.0.0": version "1.0.0" resolved "https://registry.npmmirror.com/@radix-ui/primitive/-/primitive-1.0.0.tgz" @@ -1316,6 +1481,21 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/primitive@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd" + integrity sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-arrow@1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.3.tgz#c24f7968996ed934d57fe6cde5d6ec7266e1d25d" + integrity sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-collection@1.0.2": version "1.0.2" resolved "https://registry.npmmirror.com/@radix-ui/react-collection/-/react-collection-1.0.2.tgz" @@ -1327,6 +1507,17 @@ "@radix-ui/react-primitive" "1.0.2" "@radix-ui/react-slot" "1.0.1" +"@radix-ui/react-collection@1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz#9595a66e09026187524a36c6e7e9c7d286469159" + integrity sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-compose-refs@1.0.0": version "1.0.0" resolved "https://registry.npmmirror.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz" @@ -1334,6 +1525,13 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-compose-refs@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989" + integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-context@1.0.0": version "1.0.0" resolved "https://registry.npmmirror.com/@radix-ui/react-context/-/react-context-1.0.0.tgz" @@ -1341,6 +1539,34 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-context@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c" + integrity sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-dialog@^1.0.5": + version "1.0.5" + resolved "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz#71657b1b116de6c7a0b03242d7d43e01062c7300" + integrity sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.5" + "@radix-ui/react-focus-guards" "1.0.1" + "@radix-ui/react-focus-scope" "1.0.4" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-portal" "1.0.4" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-use-controllable-state" "1.0.1" + aria-hidden "^1.1.1" + react-remove-scroll "2.5.5" + "@radix-ui/react-direction@1.0.0": version "1.0.0" resolved "https://registry.npmmirror.com/@radix-ui/react-direction/-/react-direction-1.0.0.tgz" @@ -1348,6 +1574,42 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-direction@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz#9cb61bf2ccf568f3421422d182637b7f47596c9b" + integrity sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-dismissable-layer@1.0.5": + version "1.0.5" + resolved "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.5.tgz#3f98425b82b9068dfbab5db5fff3df6ebf48b9d4" + integrity sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-escape-keydown" "1.0.3" + +"@radix-ui/react-focus-guards@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz#1ea7e32092216b946397866199d892f71f7f98ad" + integrity sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA== + dependencies: + "@babel/runtime" "^7.13.10" + +"@radix-ui/react-focus-scope@1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz#2ac45fce8c5bb33eb18419cdc1905ef4f1906525" + integrity sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-id@1.0.0": version "1.0.0" resolved "https://registry.npmmirror.com/@radix-ui/react-id/-/react-id-1.0.0.tgz" @@ -1356,6 +1618,39 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-use-layout-effect" "1.0.0" +"@radix-ui/react-id@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.1.tgz#73cdc181f650e4df24f0b6a5b7aa426b912c88c0" + integrity sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect" "1.0.1" + +"@radix-ui/react-popper@1.1.3": + version "1.1.3" + resolved "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.3.tgz#24c03f527e7ac348fabf18c89795d85d21b00b42" + integrity sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w== + dependencies: + "@babel/runtime" "^7.13.10" + "@floating-ui/react-dom" "^2.0.0" + "@radix-ui/react-arrow" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-use-rect" "1.0.1" + "@radix-ui/react-use-size" "1.0.1" + "@radix-ui/rect" "1.0.1" + +"@radix-ui/react-portal@1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.4.tgz#df4bfd353db3b1e84e639e9c63a5f2565fb00e15" + integrity sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-presence@1.0.0": version "1.0.0" resolved "https://registry.npmmirror.com/@radix-ui/react-presence/-/react-presence-1.0.0.tgz" @@ -1365,6 +1660,15 @@ "@radix-ui/react-compose-refs" "1.0.0" "@radix-ui/react-use-layout-effect" "1.0.0" +"@radix-ui/react-presence@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz#491990ba913b8e2a5db1b06b203cb24b5cdef9ba" + integrity sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" + "@radix-ui/react-primitive@1.0.2": version "1.0.2" resolved "https://registry.npmmirror.com/@radix-ui/react-primitive/-/react-primitive-1.0.2.tgz" @@ -1373,6 +1677,14 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-slot" "1.0.1" +"@radix-ui/react-primitive@1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0" + integrity sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-progress@^1.0.2": version "1.0.2" resolved "https://registry.npmmirror.com/@radix-ui/react-progress/-/react-progress-1.0.2.tgz" @@ -1415,21 +1727,37 @@ "@radix-ui/react-use-callback-ref" "1.0.0" "@radix-ui/react-use-controllable-state" "1.0.0" -"@radix-ui/react-scroll-area@^1.0.3": - version "1.0.3" - resolved "https://registry.npmmirror.com/@radix-ui/react-scroll-area/-/react-scroll-area-1.0.3.tgz" - integrity sha512-sBX9j8Q+0/jReNObEAveKIGXJtk3xUoSIx4cMKygGtO128QJyVDn01XNOFsyvihKDCTcu7SINzQ2jPAZEhIQtw== +"@radix-ui/react-roving-focus@1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz#e90c4a6a5f6ac09d3b8c1f5b5e81aab2f0db1974" + integrity sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ== dependencies: "@babel/runtime" "^7.13.10" - "@radix-ui/number" "1.0.0" - "@radix-ui/primitive" "1.0.0" - "@radix-ui/react-compose-refs" "1.0.0" - "@radix-ui/react-context" "1.0.0" - "@radix-ui/react-direction" "1.0.0" - "@radix-ui/react-presence" "1.0.0" - "@radix-ui/react-primitive" "1.0.2" - "@radix-ui/react-use-callback-ref" "1.0.0" - "@radix-ui/react-use-layout-effect" "1.0.0" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-collection" "1.0.3" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-controllable-state" "1.0.1" + +"@radix-ui/react-scroll-area@^1.0.5": + version "1.0.5" + resolved "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.0.5.tgz#01160c6893f24a2ddb5aa399ae5b3ba84ad4d3cc" + integrity sha512-b6PAgH4GQf9QEn8zbT2XUHpW5z8BzqEc7Kl11TwDrvuTrxlkcjTD5qa/bxgKr+nmuXKu4L/W5UZ4mlP/VG/5Gw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/number" "1.0.1" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-layout-effect" "1.0.1" "@radix-ui/react-slider@^1.1.1": version "1.1.1" @@ -1457,6 +1785,72 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-compose-refs" "1.0.0" +"@radix-ui/react-slot@1.0.2", "@radix-ui/react-slot@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab" + integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + +"@radix-ui/react-tabs@^1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.0.4.tgz#993608eec55a5d1deddd446fa9978d2bc1053da2" + integrity sha512-egZfYY/+wRNCflXNHx+dePvnz9FbmssDTJBtgRfDY7e8SE5oIo3Py2eCB1ckAbh1Q7cQ/6yJZThJ++sgbxibog== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-roving-focus" "1.0.4" + "@radix-ui/react-use-controllable-state" "1.0.1" + +"@radix-ui/react-toggle-group@^1.0.4": + version "1.0.4" + resolved "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.0.4.tgz#f5b5c8c477831b013bec3580c55e20a68179d6ec" + integrity sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-direction" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-roving-focus" "1.0.4" + "@radix-ui/react-toggle" "1.0.3" + "@radix-ui/react-use-controllable-state" "1.0.1" + +"@radix-ui/react-toggle@1.0.3", "@radix-ui/react-toggle@^1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz#aecb2945630d1dc5c512997556c57aba894e539e" + integrity sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-use-controllable-state" "1.0.1" + +"@radix-ui/react-tooltip@^1.0.7": + version "1.0.7" + resolved "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz#8f55070f852e7e7450cc1d9210b793d2e5a7686e" + integrity sha512-lPh5iKNFVQ/jav/j6ZrWq3blfDJ0OH9R6FlNUHPMqdLuQ9vwDgFsRxvl8b7Asuy5c8xmoojHUxKHQSOAvMHxyw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "1.0.1" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-context" "1.0.1" + "@radix-ui/react-dismissable-layer" "1.0.5" + "@radix-ui/react-id" "1.0.1" + "@radix-ui/react-popper" "1.1.3" + "@radix-ui/react-portal" "1.0.4" + "@radix-ui/react-presence" "1.0.1" + "@radix-ui/react-primitive" "1.0.3" + "@radix-ui/react-slot" "1.0.2" + "@radix-ui/react-use-controllable-state" "1.0.1" + "@radix-ui/react-visually-hidden" "1.0.3" + "@radix-ui/react-use-callback-ref@1.0.0": version "1.0.0" resolved "https://registry.npmmirror.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz" @@ -1464,6 +1858,13 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-use-callback-ref@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a" + integrity sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-controllable-state@1.0.0": version "1.0.0" resolved "https://registry.npmmirror.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.0.tgz" @@ -1472,6 +1873,22 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-use-callback-ref" "1.0.0" +"@radix-ui/react-use-controllable-state@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz#ecd2ced34e6330caf89a82854aa2f77e07440286" + integrity sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "1.0.1" + +"@radix-ui/react-use-escape-keydown@1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.3.tgz#217b840c250541609c66f67ed7bab2b733620755" + integrity sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "1.0.1" + "@radix-ui/react-use-layout-effect@1.0.0": version "1.0.0" resolved "https://registry.npmmirror.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz" @@ -1479,6 +1896,13 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-use-layout-effect@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz#be8c7bc809b0c8934acf6657b577daf948a75399" + integrity sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-previous@1.0.0": version "1.0.0" resolved "https://registry.npmmirror.com/@radix-ui/react-use-previous/-/react-use-previous-1.0.0.tgz" @@ -1486,6 +1910,14 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-use-rect@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.1.tgz#fde50b3bb9fd08f4a1cd204572e5943c244fcec2" + integrity sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/rect" "1.0.1" + "@radix-ui/react-use-size@1.0.0": version "1.0.0" resolved "https://registry.npmmirror.com/@radix-ui/react-use-size/-/react-use-size-1.0.0.tgz" @@ -1494,6 +1926,29 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-use-layout-effect" "1.0.0" +"@radix-ui/react-use-size@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.0.1.tgz#1c5f5fea940a7d7ade77694bb98116fb49f870b2" + integrity sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect" "1.0.1" + +"@radix-ui/react-visually-hidden@1.0.3": + version "1.0.3" + resolved "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.0.3.tgz#51aed9dd0fe5abcad7dee2a234ad36106a6984ac" + integrity sha512-D4w41yN5YRKtu464TLnByKzMDG/JlMPHtfZgQAu9v6mNakUqGUI9vUrfQKz8NK41VMm/xbZbh76NUTVtIYqOMA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "1.0.3" + +"@radix-ui/rect@1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.1.tgz#bf8e7d947671996da2e30f4904ece343bc4a883f" + integrity sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@remix-run/router@1.6.2": version "1.6.2" resolved "https://registry.npmmirror.com/@remix-run/router/-/router-1.6.2.tgz" @@ -1558,7 +2013,7 @@ "@svgr/babel-plugin-transform-react-native-svg" "^7.0.0" "@svgr/babel-plugin-transform-svg-component" "^7.0.0" -"@svgr/core@^7.0.0", "@svgr/core@>=7.0.0": +"@svgr/core@^7.0.0": version "7.0.0" resolved "https://registry.npmmirror.com/@svgr/core/-/core-7.0.0.tgz" integrity sha512-ztAoxkaKhRVloa3XydohgQQCb0/8x9T63yXovpmHzKMkHO6pkjdsIAWKOS4bE95P/2quVh1NtjSKlMRNzSBffw== @@ -1634,7 +2089,19 @@ resolve "^1.20.0" tmp "^0.2.1" -"@trivago/prettier-plugin-sort-imports@*", "@trivago/prettier-plugin-sort-imports@^4.1.1": +"@tanstack/react-table@^8.10.7": + version "8.10.7" + resolved "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.10.7.tgz#733f4bee8cf5aa19582f944dd0fd3224b21e8c94" + integrity sha512-bXhjA7xsTcsW8JPTTYlUg/FuBpn8MNjiEPhkNhIGCUR6iRQM2+WEco4OBpvDeVcR9SE+bmWLzdfiY7bCbCSVuA== + dependencies: + "@tanstack/table-core" "8.10.7" + +"@tanstack/table-core@8.10.7": + version "8.10.7" + resolved "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.10.7.tgz#577e8a635048875de4c9d6d6a3c21d26ff9f9d08" + integrity sha512-KQk5OMg5OH6rmbHZxuNROvdI+hKDIUxANaHlV+dPlNN7ED3qYQ/WkpY2qlXww1SIdeMlkIhpN/2L00rof0fXFw== + +"@trivago/prettier-plugin-sort-imports@^4.1.1": version "4.1.1" resolved "https://registry.npmmirror.com/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.1.1.tgz" integrity sha512-dQ2r2uzNr1x6pJsuh/8x0IRA3CBUB+pWEW3J/7N98axqt7SQSm+2fy0FLNXvXGg77xEDC7KHxJlHfLYyi7PDcw== @@ -1693,7 +2160,7 @@ resolved "https://registry.npmmirror.com/@types/mixpanel-browser/-/mixpanel-browser-2.38.1.tgz" integrity sha512-XzQbwgiOPsFXUQnjz3vSwcwrvJDbQ35bCiwa/1VXGrHvU1ti9+eqO1GY91DShzkEzKkkEEkxfNshS5dbBZqd7w== -"@types/node@>= 14", "@types/node@18.14.6": +"@types/node@18.14.6": version "18.14.6" resolved "https://registry.npmmirror.com/@types/node/-/node-18.14.6.tgz" integrity sha512-93+VvleD3mXwlLI/xASjw0FzKcwzl3OdTCzm1LaRfqgS21gfFtK3zDXM5Op9TeeMsJVOaJ2VRDpT9q4Y3d0AvA== @@ -1751,7 +2218,7 @@ "@types/history" "^4.7.11" "@types/react" "*" -"@types/react@*", "@types/react@^18.0.28", "@types/react@>=16": +"@types/react@*", "@types/react@^18.0.28": version "18.2.6" resolved "https://registry.npmmirror.com/@types/react/-/react-18.2.6.tgz" integrity sha512-wRZClXn//zxCFW+ye/D2qY65UsYP1Fpex2YXorHc8awoNamkMZSvBxwxdYVInsHOZZd2Ppq8isnSzJL5Mpf8OA== @@ -1775,7 +2242,7 @@ resolved "https://registry.npmjs.org/@types/zrender/-/zrender-4.0.3.tgz" integrity sha512-EPI269lkHNsObwILJ1k1z7znLjKyePuWRy/XKK0shSGpBb9cIX307arcwJV4+2NeZj5wEjN06r4D8yFv7sI06g== -"@typescript-eslint/eslint-plugin@^4.0.0 || ^5.0.0", "@typescript-eslint/eslint-plugin@^5.5.0": +"@typescript-eslint/eslint-plugin@^5.5.0": version "5.59.6" resolved "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.6.tgz" integrity sha512-sXtOgJNEuRU5RLwPUb1jxtToZbgvq3M6FPpY4QENxoOggK+UpTxUBpj6tD8+Qh2g46Pi9We87E+eHnUw8YcGsw== @@ -1798,7 +2265,7 @@ dependencies: "@typescript-eslint/utils" "5.59.6" -"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.5.0": +"@typescript-eslint/parser@^5.5.0": version "5.59.6" resolved "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-5.59.6.tgz" integrity sha512-7pCa6al03Pv1yf/dUg/s1pXz/yGMUBAw5EeWqNTFiSueKvRNonze3hma3lhdsOrQcaOXhbk5gKu2Fludiho9VA== @@ -1844,7 +2311,7 @@ semver "^7.3.7" tsutils "^3.21.0" -"@typescript-eslint/utils@^5.58.0", "@typescript-eslint/utils@5.59.6": +"@typescript-eslint/utils@5.59.6", "@typescript-eslint/utils@^5.58.0": version "5.59.6" resolved "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-5.59.6.tgz" integrity sha512-vzaaD6EXbTS29cVH0JjXBdzMt6VBlv+hE31XktDRMX1j3462wZCJa7VzO2AxXEXcIl8GQqZPcOPuW/Z1tZVogg== @@ -1896,17 +2363,12 @@ acorn-walk@^7.0.0: resolved "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-7.2.0.tgz" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^7.0.0: +acorn@^7.0.0: version "7.4.1" resolved "https://registry.npmmirror.com/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.8.0: - version "8.8.2" - resolved "https://registry.npmmirror.com/acorn/-/acorn-8.8.2.tgz" - integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== - -acorn@^8.8.2: +acorn@^8.8.0, acorn@^8.8.2: version "8.8.2" resolved "https://registry.npmmirror.com/acorn/-/acorn-8.8.2.tgz" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== @@ -1958,14 +2420,7 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0: - version "4.3.0" - resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -2000,7 +2455,7 @@ argparse@^2.0.1: resolved "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -aria-hidden@^1.1.3: +aria-hidden@^1.1.1, aria-hidden@^1.1.3: version "1.2.3" resolved "https://registry.npmmirror.com/aria-hidden/-/aria-hidden-1.2.3.tgz" integrity sha512-xcLxITLe2HYa1cnYnwCjkOO1PqUHQpozB8x9AR0OgWN2woOBi5kSDVxKfd0b7sb1hw5qFeJhXm9H1nu3xSfLeQ== @@ -2223,7 +2678,7 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.12.0, browserslist@^4.21.3, browserslist@^4.21.5, "browserslist@>= 4.21.0": +browserslist@^4.12.0, browserslist@^4.21.3, browserslist@^4.21.5: version "4.21.5" resolved "https://registry.npmmirror.com/browserslist/-/browserslist-4.21.5.tgz" integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== @@ -2284,6 +2739,11 @@ cfb@~1.2.1: adler-32 "~1.3.0" crc-32 "~1.2.0" +chalk@5.2.0: + version "5.2.0" + resolved "https://registry.npmmirror.com/chalk/-/chalk-5.2.0.tgz" + integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== + chalk@^2.0.0, chalk@^2.4.1: version "2.4.2" resolved "https://registry.npmmirror.com/chalk/-/chalk-2.4.2.tgz" @@ -2293,7 +2753,7 @@ chalk@^2.0.0, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0: +chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -2301,36 +2761,7 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.2: - version "4.1.2" - resolved "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -chalk@5.2.0: - version "5.2.0" - resolved "https://registry.npmmirror.com/chalk/-/chalk-5.2.0.tgz" - integrity sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA== - -chokidar@^3.5.2, chokidar@^3.5.3, "chokidar@>=3.0.0 <4.0.0": +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.2, chokidar@^3.5.3: version "3.5.3" resolved "https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -2350,6 +2781,13 @@ chroma-js@^2.4.0: resolved "https://registry.npmmirror.com/chroma-js/-/chroma-js-2.4.2.tgz" integrity sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A== +class-variance-authority@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz#1c3134d634d80271b1837452b06d821915954522" + integrity sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A== + dependencies: + clsx "2.0.0" + classnames@^2.3.0, classnames@^2.3.2: version "2.3.2" resolved "https://registry.npmmirror.com/classnames/-/classnames-2.3.2.tgz" @@ -2406,6 +2844,11 @@ cliui@^8.0.1: strip-ansi "^6.0.1" wrap-ansi "^7.0.0" +clsx@2.0.0, clsx@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz#12658f3fd98fafe62075595a5c30e43d18f3d00b" + integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q== + codepage@~1.15.0: version "1.15.0" resolved "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz" @@ -2425,7 +2868,7 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@^1.0.0, color-name@1.1.3: +color-name@1.1.3, color-name@^1.0.0: version "1.1.3" resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== @@ -2510,18 +2953,7 @@ core-js@^3.19.2: resolved "https://registry.npmmirror.com/core-js/-/core-js-3.30.2.tgz" integrity sha512-uBJiDmwqsbJCWHAwjrx3cvjbMXP7xD72Dmsn5LOJpiRmE3WbBbN5rCqQ2Qh6Ek6/eOrjlWngEynBWo4VxerQhg== -cosmiconfig@^7.0.0: - version "7.1.0" - resolved "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz" - integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" - -cosmiconfig@^7.0.1: +cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: version "7.1.0" resolved "https://registry.npmmirror.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz" integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== @@ -2619,14 +3051,7 @@ dayjs@^1.11.8: resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.8.tgz" integrity sha512-LcgxzFoWMEPO7ggRv1Y2N31hUf2R0Vj7fuy/m+Bg1K8rr+KAs1AEy4y9jd5DXe8pbHgX+srkHNS7TH6Q6ZhYeQ== -debug@^3.2.6: - version "3.2.7" - resolved "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -debug@^3.2.7: +debug@^3.2.6, debug@^3.2.7: version "3.2.7" resolved "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -2687,6 +3112,11 @@ defined@^1.0.0: resolved "https://registry.npmmirror.com/defined/-/defined-1.0.1.tgz" integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q== +detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + detective@^5.2.0: version "5.2.1" resolved "https://registry.npmmirror.com/detective/-/detective-5.2.1.tgz" @@ -2706,7 +3136,7 @@ dexie-react-hooks@^1.1.3: resolved "https://registry.npmmirror.com/dexie-react-hooks/-/dexie-react-hooks-1.1.3.tgz" integrity sha512-bXXE1gfYtfuVYTNiOlyam+YVaO8KaqacgRuxFuP37YtpS6o/jxT6KOl5h+hhqY36s0UavlHWbL+HWJFMcQumIg== -"dexie@^2.0.4 || ^3.0.0 || ^4.0.1-alpha.5", dexie@^3.2.3, "dexie@>=3.1.0-alpha.1 <5.0.0": +dexie@^3.2.3: version "3.2.3" resolved "https://registry.npmmirror.com/dexie/-/dexie-3.2.3.tgz" integrity sha512-iHayBd4UYryDCVUNa3PMsJMEnd8yjyh5p7a+RFeC8i8n476BC9wMhVvqiImq5zJZJf5Tuer+s4SSj+AA3x+ZbQ== @@ -3073,7 +3503,7 @@ eslint-plugin-testing-library@^5.0.1: dependencies: "@typescript-eslint/utils" "^5.58.0" -eslint-scope@^5.1.1: +eslint-scope@5.1.1, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-5.1.1.tgz" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -3089,14 +3519,6 @@ eslint-scope@^7.2.0: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-scope@5.1.1: - version "5.1.1" - resolved "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-5.1.1.tgz" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - eslint-visitor-keys@^2.1.0: version "2.1.0" resolved "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" @@ -3107,7 +3529,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: resolved "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz" integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== -eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.5.0 || ^8.0.0", eslint@^8.0.0, eslint@^8.1.0, eslint@^8.35.0, eslint@>=7.0.0, eslint@>=7.28.0: +eslint@^8.35.0: version "8.41.0" resolved "https://registry.npmmirror.com/eslint/-/eslint-8.41.0.tgz" integrity sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q== @@ -3386,6 +3808,11 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has-proto "^1.0.1" has-symbols "^1.0.3" +get-nonce@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" + integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== + get-stream@^6.0.0, get-stream@^6.0.1: version "6.0.1" resolved "https://registry.npmmirror.com/get-stream/-/get-stream-6.0.1.tgz" @@ -3404,7 +3831,7 @@ git-last-commit@^1.0.1: resolved "https://registry.npmmirror.com/git-last-commit/-/git-last-commit-1.0.1.tgz" integrity sha512-FDSgeMqa7GnJDxt/q0AbrxbfeTyxp4ImxEw1e4nw6NUHA5FMhFUq33dTXI4Xdgcj1VQ1q5QLWF6WxFrJ8KCBOg== -glob-parent@^5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -3418,12 +3845,17 @@ glob-parent@^6.0.1, glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== +glob@7.1.6: + version "7.1.6" + resolved "https://registry.npmmirror.com/glob/-/glob-7.1.6.tgz" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== dependencies: - is-glob "^4.0.1" + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" glob@^7.1.2, glob@^7.1.3, glob@^7.1.6, glob@^7.1.7: version "7.2.3" @@ -3437,18 +3869,6 @@ glob@^7.1.2, glob@^7.1.3, glob@^7.1.6, glob@^7.1.7: once "^1.3.0" path-is-absolute "^1.0.0" -glob@7.1.6: - version "7.1.6" - resolved "https://registry.npmmirror.com/glob/-/glob-7.1.6.tgz" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - globals@^11.1.0: version "11.12.0" resolved "https://registry.npmmirror.com/globals/-/globals-11.12.0.tgz" @@ -3622,7 +4042,7 @@ image-size@~0.5.0: resolved "https://registry.npmmirror.com/image-size/-/image-size-0.5.5.tgz" integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ== -immer@^9.0.21, immer@>=2.0.0: +immer@^9.0.21: version "9.0.21" resolved "https://registry.npmmirror.com/immer/-/immer-9.0.21.tgz" integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA== @@ -3672,6 +4092,13 @@ internal-slot@^1.0.3, internal-slot@^1.0.4, internal-slot@^1.0.5: has "^1.0.3" side-channel "^1.0.4" +invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.1.1.tgz" @@ -4011,7 +4438,7 @@ language-tags@=1.0.5: dependencies: language-subtag-registry "~0.3.2" -less@*, less@^4.1.3: +less@^4.1.3: version "4.1.3" resolved "https://registry.npmmirror.com/less/-/less-4.1.3.tgz" integrity sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA== @@ -4036,7 +4463,7 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -lilconfig@^2.0.5, lilconfig@^2.1.0, lilconfig@2.1.0: +lilconfig@2.1.0, lilconfig@^2.0.5, lilconfig@^2.1.0: version "2.1.0" resolved "https://registry.npmmirror.com/lilconfig/-/lilconfig-2.1.0.tgz" integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== @@ -4126,7 +4553,7 @@ log-update@^4.0.0: slice-ansi "^4.0.0" wrap-ansi "^6.2.0" -loose-envify@^1.1.0, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -4147,6 +4574,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lucide-react@^0.294.0: + version "0.294.0" + resolved "https://registry.npmjs.org/lucide-react/-/lucide-react-0.294.0.tgz#dc406e1e7e2f722cf93218fe5b31cf3c95778817" + integrity sha512-V7o0/VECSGbLHn3/1O67FUgBwWB+hmzshrgDVRJQhMh8uj5D3HBuIvhuAmQTtlupILSplwIZg5FTc4tTKMA2SA== + magic-string@^0.27.0: version "0.27.0" resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.27.0.tgz" @@ -4236,7 +4668,7 @@ modern-normalize@^1.1.0: resolved "https://registry.npmmirror.com/modern-normalize/-/modern-normalize-1.1.0.tgz" integrity sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA== -ms@^2.1.1, ms@2.1.2: +ms@2.1.2, ms@^2.1.1: version "2.1.2" resolved "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== @@ -4400,14 +4832,7 @@ once@^1.3.0: dependencies: wrappy "1" -onetime@^5.1.0: - version "5.1.2" - resolved "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - -onetime@^5.1.2: +onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -4600,14 +5025,7 @@ postcss-js@^2: camelcase-css "^2.0.1" postcss "^7.0.18" -postcss-js@^4: - version "4.0.1" - resolved "https://registry.npmmirror.com/postcss-js/-/postcss-js-4.0.1.tgz" - integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== - dependencies: - camelcase-css "^2.0.1" - -postcss-js@^4.0.1: +postcss-js@^4, postcss-js@^4.0.1: version "4.0.1" resolved "https://registry.npmmirror.com/postcss-js/-/postcss-js-4.0.1.tgz" integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw== @@ -4693,7 +5111,7 @@ postcss@^6.0.9: source-map "^0.6.1" supports-color "^5.4.0" -postcss@^7, postcss@^7.0.32: +postcss@^7, postcss@^7.0.18, postcss@^7.0.32: version "7.0.39" resolved "https://registry.npmmirror.com/postcss/-/postcss-7.0.39.tgz" integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== @@ -4701,15 +5119,7 @@ postcss@^7, postcss@^7.0.32: picocolors "^0.2.1" source-map "^0.6.1" -postcss@^7.0.18: - version "7.0.39" - resolved "https://registry.npmmirror.com/postcss/-/postcss-7.0.39.tgz" - integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== - dependencies: - picocolors "^0.2.1" - source-map "^0.6.1" - -postcss@^8, postcss@^8.0.0, postcss@^8.1.0, postcss@^8.2.14, postcss@^8.3.5, postcss@^8.4.21, postcss@^8.4.23, postcss@>=8.0.9: +postcss@^8, postcss@^8.0.0, postcss@^8.3.5, postcss@^8.4.21, postcss@^8.4.23: version "8.4.23" resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.23.tgz" integrity sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA== @@ -4735,7 +5145,7 @@ prettier-plugin-tailwindcss@^0.2.7: resolved "https://registry.npmmirror.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.2.8.tgz" integrity sha512-KgPcEnJeIijlMjsA6WwYgRs5rh3/q76oInqtMXBA/EMcamrcYJpyhtRhyX1ayT9hnHlHTuO8sIifHF10WuSDKg== -prettier@^2.8.4, prettier@>=2.0.0, prettier@>=2.2.0, prettier@2.x: +prettier@^2.8.4: version "2.8.8" resolved "https://registry.npmmirror.com/prettier/-/prettier-2.8.8.tgz" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== @@ -4819,7 +5229,7 @@ react-app-polyfill@^3.0.0: regenerator-runtime "^0.13.9" whatwg-fetch "^3.6.2" -"react-dom@^16 || ^17 || ^18", "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^17.0.0 || ^18.0.0", react-dom@^18.2.0, react-dom@>=16.14.0, react-dom@>=16.8, react-dom@>=16.8.0, react-dom@>=16.8.1: +react-dom@^18.2.0: version "18.2.0" resolved "https://registry.npmmirror.com/react-dom/-/react-dom-18.2.0.tgz" integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== @@ -4842,6 +5252,25 @@ react-refresh@^0.14.0: resolved "https://registry.npmmirror.com/react-refresh/-/react-refresh-0.14.0.tgz" integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ== +react-remove-scroll-bar@^2.3.3: + version "2.3.4" + resolved "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz#53e272d7a5cb8242990c7f144c44d8bd8ab5afd9" + integrity sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A== + dependencies: + react-style-singleton "^2.2.1" + tslib "^2.0.0" + +react-remove-scroll@2.5.5: + version "2.5.5" + resolved "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz#1e31a1260df08887a8a0e46d09271b52b3a37e77" + integrity sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw== + dependencies: + react-remove-scroll-bar "^2.3.3" + react-style-singleton "^2.2.1" + tslib "^2.1.0" + use-callback-ref "^1.3.0" + use-sidecar "^1.1.2" + react-router-dom@^6.8.2: version "6.11.2" resolved "https://registry.npmmirror.com/react-router-dom/-/react-router-dom-6.11.2.tgz" @@ -4857,6 +5286,15 @@ react-router@6.11.2: dependencies: "@remix-run/router" "1.6.2" +react-style-singleton@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4" + integrity sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g== + dependencies: + get-nonce "^1.0.0" + invariant "^2.2.4" + tslib "^2.0.0" + react-timer-hook@^3.0.5: version "3.0.6" resolved "https://registry.npmmirror.com/react-timer-hook/-/react-timer-hook-3.0.6.tgz" @@ -4870,7 +5308,7 @@ react-tooltip@^5.18.0: "@floating-ui/dom" "^1.0.0" classnames "^2.3.0" -"react@^16 || ^17 || ^18", "react@^16.11.0 || ^17.0.0 || ^18.0.0", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.0 || ^17.0.1 || ^18.0.0", "react@^17.0.0 || ^18.0.0", react@^18.2.0, react@>=16, react@>=16.14.0, react@>=16.8, react@>=16.8.0, react@>=16.8.1, react@>=17.0.0: +react@^18.2.0: version "18.2.0" resolved "https://registry.npmmirror.com/react/-/react-18.2.0.tgz" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== @@ -4916,6 +5354,11 @@ regenerator-runtime@^0.13.11, regenerator-runtime@^0.13.9: resolved "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +regenerator-runtime@^0.14.0: + version "0.14.0" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45" + integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA== + regenerator-transform@^0.15.1: version "0.15.1" resolved "https://registry.npmmirror.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz" @@ -5036,7 +5479,7 @@ rollup-plugin-visualizer@^5.9.0: source-map "^0.7.4" yargs "^17.5.1" -rollup@^3.21.0, "rollup@2.x || 3.x": +rollup@^3.21.0: version "3.23.0" resolved "https://registry.npmmirror.com/rollup/-/rollup-3.23.0.tgz" integrity sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ== @@ -5071,7 +5514,7 @@ safe-regex-test@^1.0.0: resolved "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sass@*, sass@^1.58.3: +sass@^1.58.3: version "1.62.1" resolved "https://registry.npmmirror.com/sass/-/sass-1.62.1.tgz" integrity sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A== @@ -5191,7 +5634,7 @@ source-map-explorer@^2.5.2: temp "^0.9.4" yargs "^16.2.0" -source-map-js@^1.0.2, "source-map-js@>=0.6.2 <2.0.0": +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== @@ -5201,7 +5644,7 @@ source-map@^0.5.0: resolved "https://registry.npmmirror.com/source-map/-/source-map-0.5.7.tgz" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== -source-map@^0.6.1: +source-map@^0.6.1, source-map@~0.6.0: version "0.6.1" resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -5211,11 +5654,6 @@ source-map@^0.7.3, source-map@^0.7.4: resolved "https://registry.npmmirror.com/source-map/-/source-map-0.7.4.tgz" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== -source-map@~0.6.0: - version "0.6.1" - resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - ssf@~0.11.2: version "0.11.2" resolved "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz" @@ -5240,25 +5678,7 @@ string-natural-compare@^3.0.1: resolved "https://registry.npmmirror.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz" integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw== -string-width@^4.1.0: - version "4.2.3" - resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.2.3: +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -5351,7 +5771,7 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: resolved "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -stylus@*, stylus@^0.59.0: +stylus@^0.59.0: version "0.59.0" resolved "https://registry.npmmirror.com/stylus/-/stylus-0.59.0.tgz" integrity sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg== @@ -5411,7 +5831,47 @@ tabbable@^6.0.1: resolved "https://registry.npmmirror.com/tabbable/-/tabbable-6.1.2.tgz" integrity sha512-qCN98uP7i9z0fIS4amQ5zbGBOq+OSigYeGvPy7NDk8Y9yncqDZ9pRPgfsc2PJIVM9RrJj7GIfuRgmjoUU9zTHQ== -tailwindcss@^3, tailwindcss@^3.0, tailwindcss@^3.3.1, "tailwindcss@>=3.0.0 || >= 3.0.0-alpha.1": +tailwind-merge@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.1.0.tgz#541b407e0ec255651e92571d96b685e48f01999c" + integrity sha512-l11VvI4nSwW7MtLSLYT4ldidDEUwQAMWuSHk7l4zcXZDgnCRa0V3OdCwFfM7DCzakVXMNRwAeje9maFFXT71dQ== + dependencies: + "@babel/runtime" "^7.23.5" + +tailwindcss-animate@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz#318b692c4c42676cc9e67b19b78775742388bef4" + integrity sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA== + +tailwindcss@^3: + version "3.3.3" + resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf" + integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w== + dependencies: + "@alloc/quick-lru" "^5.2.0" + arg "^5.0.2" + chokidar "^3.5.3" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.12" + glob-parent "^6.0.2" + is-glob "^4.0.3" + jiti "^1.18.2" + lilconfig "^2.1.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-hash "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.23" + postcss-import "^15.1.0" + postcss-js "^4.0.1" + postcss-load-config "^4.0.1" + postcss-nested "^6.0.1" + postcss-selector-parser "^6.0.11" + resolve "^1.22.2" + sucrase "^3.32.0" + +tailwindcss@^3.3.1: version "3.3.2" resolved "https://registry.npmmirror.com/tailwindcss/-/tailwindcss-3.3.2.tgz" integrity sha512-9jPkMiIBXvPc2KywkraqsUfbfj+dHDb+JPWtSJa9MLFdrPyazI7q6WX2sUrm7R9eVR7qqv3Pas7EvQFzxKnI6w== @@ -5515,6 +5975,11 @@ tsconfig-paths@^4.1.2: minimist "^1.2.6" strip-bom "^3.0.0" +tslib@2.3.0: + version "2.3.0" + resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz" + integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== + tslib@^1.8.1: version "1.14.1" resolved "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz" @@ -5525,11 +5990,6 @@ tslib@^2.0.0, tslib@^2.1.0, tslib@^2.3.0: resolved "https://registry.npmmirror.com/tslib/-/tslib-2.5.2.tgz" integrity sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA== -tslib@2.3.0: - version "2.3.0" - resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz" - integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg== - tsutils@^3.21.0: version "3.21.0" resolved "https://registry.npmmirror.com/tsutils/-/tsutils-3.21.0.tgz" @@ -5585,7 +6045,7 @@ typescript-plugin-css-modules@^5.0.1: stylus "^0.59.0" tsconfig-paths "^4.1.2" -typescript@^4.0.3, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", typescript@>=4.0.0: +typescript@^4.0.3: version "4.9.5" resolved "https://registry.npmmirror.com/typescript/-/typescript-4.9.5.tgz" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== @@ -5666,11 +6126,26 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +use-callback-ref@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.0.tgz#772199899b9c9a50526fedc4993fc7fa1f7e32d5" + integrity sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w== + dependencies: + tslib "^2.0.0" + use-immer@^0.9.0: version "0.9.0" resolved "https://registry.npmmirror.com/use-immer/-/use-immer-0.9.0.tgz" integrity sha512-/L+enLi0nvuZ6j4WlyK0US9/ECUtV5v9RUbtxnn5+WbtaXYUaOBoKHDNL9I5AETdurQ4rIFIj/s+Z5X80ATyKw== +use-sidecar@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2" + integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw== + dependencies: + detect-node-es "^1.1.0" + tslib "^2.0.0" + use-sound@^4.0.1: version "4.0.1" resolved "https://registry.npmmirror.com/use-sound/-/use-sound-4.0.1.tgz" @@ -5688,7 +6163,7 @@ util-deprecate@^1.0.2: resolved "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -vite@^4.1.0-beta.0, vite@^4.1.1: +vite@^4.1.1: version "4.3.8" resolved "https://registry.npmmirror.com/vite/-/vite-4.3.8.tgz" integrity sha512-uYB8PwN7hbMrf4j1xzGDk/lqjsZvCDbt/JC5dyfxc19Pg8kRm14LinK/uq+HSLNswZEoKmweGdtpbnxRtrAXiQ== @@ -5825,12 +6300,7 @@ yallist@^4.0.0: resolved "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yaml@^1.10.0: - version "1.10.2" - resolved "https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - -yaml@^1.10.2: +yaml@^1.10.0, yaml@^1.10.2: version "1.10.2" resolved "https://registry.npmmirror.com/yaml/-/yaml-1.10.2.tgz" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==