diff --git a/.gitignore b/.gitignore index dbaa84d..5aac315 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,6 @@ firebase-debug.log /test-results/ /playwright-report/ /playwright/.cache/ + +# editors +.idea \ No newline at end of file diff --git a/README.md b/README.md index cb60a50..dafd410 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ pnpm dev # route types will be generated by next.js ## Known issues - Tool search does not set query parameters - - [(Shallow routing) updating search params causes server code to rerun.](https://github.com/vercel/next.js/issues/49668) +- [(Shallow routing) updating search params causes server code to rerun.](https://github.com/vercel/next.js/issues/49668) - [Editor may not resize to fit container size](https://github.com/suren-atoyan/monaco-react/issues/346) - CSS outlines messed up @@ -27,6 +27,8 @@ pnpm dev # route types will be generated by next.js - [x] Formatters - [x] Generators - [ ] Text + - [x] Text Inspector + - [ ] Text Diff - [ ] Graphic - [ ] Settings - [x] Settings menu item diff --git a/app/text/inspector/layout.tsx b/app/text/inspector/layout.tsx new file mode 100644 index 0000000..fdd5631 --- /dev/null +++ b/app/text/inspector/layout.tsx @@ -0,0 +1,17 @@ +import { Metadata } from "next"; + +import { toolGroups } from "@/config/tools"; + +export const metadata: Metadata = { + title: toolGroups.text.tools.inspector_and_case_converter.longTitle, + description: toolGroups.text.tools.inspector_and_case_converter.description, + robots: { + googleBot: { + index: true, + }, + }, +}; + +export default function Layout({ children }: { children: React.ReactNode }) { + return children; +} diff --git a/app/text/inspector/page.tsx b/app/text/inspector/page.tsx new file mode 100644 index 0000000..ed8da03 --- /dev/null +++ b/app/text/inspector/page.tsx @@ -0,0 +1,89 @@ +"use client"; + +import { useCallback, useMemo, useState } from "react"; + +import { toolGroups } from "@/config/tools"; +import { noOp } from "@/lib/base"; +import { + countBytes, + countCharacters, + countLines, + countWords, + modeTitle, + TextTransformMode, + textTransformModes, + transformText, +} from "@/lib/text"; +import { Textarea, TextareaProps } from "@/components/ui/textarea"; +import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"; +import * as Button from "@/components/buttons"; +import { ControlMenu } from "@/components/control-menu"; +import { PageRootSection } from "@/components/page-root-section"; +import { PageSection } from "@/components/page-section"; + +export default function Page() { + const [input, setInput] = useState("ConvertMe"); + const [mode, setMode] = useState(TextTransformMode.original); + + const output = transformText(input, mode); + + const stats = useMemo( + () => ({ + characters: countCharacters(input), + words: countWords(input), + lines: countLines(input), + bytes: countBytes(input), + }), + [input] + ); + + const clearInput = useCallback(() => setInput(""), []); + + const onInputChange: TextareaProps["onChange"] = e => setInput(e.currentTarget.value); + const onModeChange = (value: string) => { + if (value && value in TextTransformMode) { + setMode(value as TextTransformMode); + } + }; + + const inputPasteButton = ; + const inputFileButton = ; + const inputClearButton = ; + + const outputCopyButton = ; + + const inputControl = ; + const outputControl = ; + + return ( + + + + {textTransformModes.map(m => ( + + {modeTitle[m]} + + ))} + + + + + + + + + + + + + + + Characters: {stats.characters} + Words: {stats.words} + Lines: {stats.lines} + Bytes: {stats.bytes} + + + + ); +} diff --git a/app/text/layout.tsx b/app/text/layout.tsx new file mode 100644 index 0000000..c384483 --- /dev/null +++ b/app/text/layout.tsx @@ -0,0 +1,16 @@ +import { Metadata } from "next"; + +import { toolGroups } from "@/config/tools"; + +export const metadata: Metadata = { + title: toolGroups.generators.title, + robots: { + googleBot: { + index: false, + }, + }, +}; + +export default function Layout({ children }: { children: React.ReactNode }) { + return children; +} diff --git a/app/text/page.tsx b/app/text/page.tsx new file mode 100644 index 0000000..aa10303 --- /dev/null +++ b/app/text/page.tsx @@ -0,0 +1,11 @@ +import { toolGroups } from "@/config/tools"; +import { PageRootSection } from "@/components/page-root-section"; +import { ToolCards } from "@/components/tool-cards"; + +export default function Page() { + return ( + + + + ); +} diff --git a/components/icons.tsx b/components/icons.tsx index d26e90a..9677b01 100644 --- a/components/icons.tsx +++ b/components/icons.tsx @@ -28,6 +28,7 @@ export const Settings = memo(icons.Settings, equal); export const Settings2 = memo(icons.Settings2, equal); export const Space = memo(icons.Space, equal); export const Sun = memo(icons.SunMedium, equal); +export const Type = memo(icons.Type, equal); export const Minus = memo(icons.Minus, equal); export const Moon = memo(icons.Moon, equal); export const X = memo(icons.X, equal); diff --git a/components/ui/toggle-group.tsx b/components/ui/toggle-group.tsx new file mode 100644 index 0000000..f62dea2 --- /dev/null +++ b/components/ui/toggle-group.tsx @@ -0,0 +1,39 @@ +"use client"; + +import * as React from "react"; +import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group"; + +import { cn } from "@/lib/style"; + +const ToggleGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName; + +const ToggleGroupItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + {children} + +)); + +ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName; + +export { ToggleGroup, ToggleGroupItem }; diff --git a/config/tools.ts b/config/tools.ts index f4cc38d..92f0be8 100644 --- a/config/tools.ts +++ b/config/tools.ts @@ -124,6 +124,21 @@ export const toolGroups = { }, }, }, + text: { + Icon: icons.Type, + title: "Text", + href: "/text", + tools: { + inspector_and_case_converter: { + Icon: icons.CaseSensitive, + shortTitle: "Inspector & Case Converter", + longTitle: "Text Inspector & Case Converter", + description: "Analyze text and convert it to a different case", + keywords: "case converter convert text inspector inspect", + href: "/text/inspector", + }, + }, + }, } as const satisfies ToolGroups; export const singleTools = { diff --git a/lib/base.ts b/lib/base.ts index 2e13d55..314a77a 100644 --- a/lib/base.ts +++ b/lib/base.ts @@ -20,3 +20,5 @@ export const formatOctal = formatNumber(3, " "); export const formatBinary = formatNumber(4, " "); export const unformatNumber = (x: string) => x.replaceAll(/[ ,]/g, ""); + +export function noOp() {} diff --git a/lib/text.ts b/lib/text.ts new file mode 100644 index 0000000..cfc07d9 --- /dev/null +++ b/lib/text.ts @@ -0,0 +1,96 @@ +import * as changeCase from "change-case"; +import { convert as slugify } from "url-slug"; + +export function countWords(text: string): number { + // Split the text by any whitespace (spaces, newlines, tabs, etc.) + const words = text.split(/\s+/); + // Filter out any empty strings in case there are extra spaces or newlines + const filteredWords = words.filter(word => word.length > 0); + return filteredWords.length; +} + +export function countCharacters(text: string): number { + /** Unicode-proof way to get string length in codepoints (in characters) + For example: + const text = '๐จโ๐ฉโ๐งโ๐ฆ'; + text.length === 11; + [...new Intl.Segmenter().segment(text)].length === 1; + */ + return [...new Intl.Segmenter().segment(text)].length; +} + +export function countLines(text: string): number { + return text.split("\n").length; +} + +export function countBytes(text: string): number { + return new Blob([text]).size; +} + +export enum TextTransformMode { + original = "original", + sentenceCase = "sentenceCase", + lowerCase = "lowerCase", + upperCase = "upperCase", + titleCase = "titleCase", + camelCase = "camelCase", + pascalCase = "pascalCase", + snakeCase = "snakeCase", + kebabCase = "kebabCase", + constantCase = "constantCase", + cobolCase = "cobolCase", + trainCase = "trainCase", + urlSlugify = "urlSlugify", +} + +export const textTransformModes = Object.values(TextTransformMode); + +export const modeTitle = { + [TextTransformMode.original]: "OriginalCase", + [TextTransformMode.upperCase]: "UPPER CASE", + [TextTransformMode.sentenceCase]: "Sentence case", + [TextTransformMode.lowerCase]: "lower case", + [TextTransformMode.titleCase]: "Title Case", + [TextTransformMode.camelCase]: "camelCase", + [TextTransformMode.pascalCase]: "PascalCase", + [TextTransformMode.snakeCase]: "snake_case", + [TextTransformMode.kebabCase]: "kebab-case", + [TextTransformMode.constantCase]: "CONSTANT_CASE", + [TextTransformMode.cobolCase]: "COBOL-CASE", + [TextTransformMode.trainCase]: "Train-Case", + [TextTransformMode.urlSlugify]: "url-slufigy", +}; + +export function transformText(text: string, mode: TextTransformMode) { + switch (mode) { + case TextTransformMode.original: + return text; + case TextTransformMode.upperCase: + return text.toUpperCase(); + case TextTransformMode.sentenceCase: + return changeCase.sentenceCase(text); + case TextTransformMode.lowerCase: + return text.toLowerCase(); + case TextTransformMode.titleCase: + return changeCase.capitalCase(text); + case TextTransformMode.camelCase: + return changeCase.camelCase(text); + case TextTransformMode.pascalCase: + return changeCase.pascalCase(text); + case TextTransformMode.kebabCase: + return changeCase.kebabCase(text); + case TextTransformMode.snakeCase: + return changeCase.snakeCase(text); + case TextTransformMode.cobolCase: + return changeCase.constantCase(text, { delimiter: "-" }); + case TextTransformMode.constantCase: + return changeCase.constantCase(text); + case TextTransformMode.trainCase: + return changeCase.trainCase(text); + case TextTransformMode.urlSlugify: + return slugify(text); + + default: + return text; + } +} diff --git a/package.json b/package.json index bdabebf..9e7d522 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,9 @@ "@radix-ui/react-select": "^1.2.2", "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-switch": "^1.0.3", + "@radix-ui/react-toggle-group": "^1.0.4", "@radix-ui/react-tooltip": "^1.0.6", + "change-case": "^5.4.4", "class-variance-authority": "^0.6.0", "clsx": "^1.2.1", "cmdk": "^0.2.0", @@ -52,6 +54,7 @@ "react-fast-compare": "^3.2.2", "sharp": "^0.32.1", "tailwindcss-animate": "^1.0.5", + "url-slug": "^4.0.1", "uuid": "^9.0.0" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 95701e7..91d3308 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,9 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + dependencies: '@monaco-editor/react': specifier: ^4.5.1 @@ -19,9 +23,15 @@ dependencies: '@radix-ui/react-switch': specifier: ^1.0.3 version: 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-toggle-group': + specifier: ^1.0.4 + version: 1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-tooltip': specifier: ^1.0.6 version: 1.0.6(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) + change-case: + specifier: ^5.4.4 + version: 5.4.4 class-variance-authority: specifier: ^0.6.0 version: 0.6.0(typescript@5.0.4) @@ -82,6 +92,9 @@ dependencies: tailwindcss-animate: specifier: ^1.0.5 version: 1.0.5(tailwindcss@3.3.2) + url-slug: + specifier: ^4.0.1 + version: 4.0.1 uuid: specifier: ^9.0.0 version: 9.0.0 @@ -322,13 +335,13 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.11 + dev: false /@babel/runtime@7.23.2: resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.0 - dev: false /@babel/template@7.21.9: resolution: {integrity: sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ==} @@ -656,19 +669,19 @@ packages: /@radix-ui/number@1.0.1: resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 dev: false /@radix-ui/primitive@1.0.0: resolution: {integrity: sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==} dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 dev: false /@radix-ui/primitive@1.0.1: resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 dev: false /@radix-ui/react-accordion@1.1.2(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0): @@ -713,7 +726,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) '@types/react': 18.2.7 '@types/react-dom': 18.2.4 @@ -734,7 +747,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.7)(react@18.2.0) @@ -762,7 +775,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0) '@radix-ui/react-context': 1.0.1(@types/react@18.2.7)(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) @@ -778,7 +791,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 react: 18.2.0 dev: false @@ -791,7 +804,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@types/react': 18.2.7 react: 18.2.0 dev: false @@ -801,7 +814,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 react: 18.2.0 dev: false @@ -814,7 +827,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@types/react': 18.2.7 react: 18.2.0 dev: false @@ -825,7 +838,7 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/primitive': 1.0.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) '@radix-ui/react-context': 1.0.0(react@18.2.0) @@ -855,7 +868,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@types/react': 18.2.7 react: 18.2.0 dev: false @@ -866,7 +879,7 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/primitive': 1.0.0 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0) @@ -889,7 +902,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) @@ -906,7 +919,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 react: 18.2.0 dev: false @@ -919,7 +932,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@types/react': 18.2.7 react: 18.2.0 dev: false @@ -930,7 +943,7 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0) @@ -951,7 +964,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0) '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.7)(react@18.2.0) @@ -966,7 +979,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0) react: 18.2.0 dev: false @@ -980,7 +993,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.7)(react@18.2.0) '@types/react': 18.2.7 react: 18.2.0 @@ -1020,7 +1033,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@floating-ui/react-dom': 2.0.0(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0) @@ -1043,7 +1056,7 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -1062,7 +1075,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) '@types/react': 18.2.7 '@types/react-dom': 18.2.4 @@ -1076,7 +1089,7 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0) react: 18.2.0 @@ -1096,7 +1109,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0) '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.7)(react@18.2.0) '@types/react': 18.2.7 @@ -1111,7 +1124,7 @@ packages: react: ^16.8 || ^17.0 || ^18.0 react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-slot': 1.0.0(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -1130,7 +1143,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-slot': 1.0.2(@types/react@18.2.7)(react@18.2.0) '@types/react': 18.2.7 '@types/react-dom': 18.2.4 @@ -1138,6 +1151,35 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.7)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.7)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.7)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.7)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.7)(react@18.2.0) + '@types/react': 18.2.7 + '@types/react-dom': 18.2.4 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-select@1.2.2(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==} peerDependencies: @@ -1205,7 +1247,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) react: 18.2.0 dev: false @@ -1219,7 +1261,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0) '@types/react': 18.2.7 react: 18.2.0 @@ -1252,6 +1294,56 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-toggle-group@1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-context': 1.0.1(@types/react@18.2.7)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.7)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-toggle': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.7)(react@18.2.0) + '@types/react': 18.2.7 + '@types/react-dom': 18.2.4 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-toggle@1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.2 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.7)(react@18.2.0) + '@types/react': 18.2.7 + '@types/react-dom': 18.2.4 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-tooltip@1.0.6(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-DmNFOiwEc2UDigsYj6clJENma58OelxD24O4IODoZ+3sQc3Zb+L8w1EP+y9laTuKCLAysPw4fD6/v0j4KNV8rg==} peerDependencies: @@ -1289,7 +1381,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 react: 18.2.0 dev: false @@ -1302,7 +1394,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@types/react': 18.2.7 react: 18.2.0 dev: false @@ -1312,7 +1404,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0) react: 18.2.0 dev: false @@ -1326,7 +1418,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.7)(react@18.2.0) '@types/react': 18.2.7 react: 18.2.0 @@ -1337,7 +1429,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0) react: 18.2.0 dev: false @@ -1351,7 +1443,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.7)(react@18.2.0) '@types/react': 18.2.7 react: 18.2.0 @@ -1362,7 +1454,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 || ^18.0 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 react: 18.2.0 dev: false @@ -1375,7 +1467,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@types/react': 18.2.7 react: 18.2.0 dev: false @@ -1389,7 +1481,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@types/react': 18.2.7 react: 18.2.0 dev: false @@ -1403,7 +1495,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/rect': 1.0.1 '@types/react': 18.2.7 react: 18.2.0 @@ -1418,7 +1510,7 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.7)(react@18.2.0) '@types/react': 18.2.7 react: 18.2.0 @@ -1437,7 +1529,7 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0) '@types/react': 18.2.7 '@types/react-dom': 18.2.4 @@ -1448,7 +1540,7 @@ packages: /@radix-ui/rect@1.0.1: resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 dev: false /@rushstack/eslint-patch@1.3.0: @@ -2058,6 +2150,10 @@ packages: engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} dev: true + /change-case@5.4.4: + resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} + dev: false + /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -2735,6 +2831,35 @@ packages: - supports-color dev: true + /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.59.7)(eslint-import-resolver-node@0.3.9)(eslint@8.41.0): + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 5.59.7(eslint@8.41.0)(typescript@5.0.4) + debug: 3.2.7 + eslint: 8.41.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + dev: true + /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.59.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.41.0): resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} engines: {node: '>=4'} @@ -2787,7 +2912,7 @@ packages: doctrine: 2.1.0 eslint: 8.41.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.7)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.41.0) + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.7)(eslint-import-resolver-node@0.3.9)(eslint@8.41.0) has: 1.0.4 is-core-module: 2.13.0 is-glob: 4.0.3 @@ -2809,7 +2934,7 @@ packages: peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: - '@babel/runtime': 7.22.3 + '@babel/runtime': 7.23.2 aria-query: 5.1.3 array-includes: 3.1.6 array.prototype.flatmap: 1.3.1 @@ -4484,10 +4609,10 @@ packages: /regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + dev: false /regenerator-runtime@0.14.0: resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} - dev: false /regexp.prototype.flags@1.5.0: resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} @@ -5204,6 +5329,11 @@ packages: punycode: 2.3.0 dev: true + /url-slug@4.0.1: + resolution: {integrity: sha512-OkHgffjR6bce7jNTp5BUDBhg2IcnqSAi9DEhLH8Rhxrq84uPBMbHFzvOxniEIRpSSGBcG13LhrtNR5XzUdztfQ==} + engines: {node: '>=18.0.0'} + dev: false + /use-callback-ref@1.3.0(@types/react@18.2.7)(react@18.2.0): resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==} engines: {node: '>=10'}