diff --git a/.gitignore b/.gitignore index 04ee99a9..f499e814 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # custom +.vscode .idea/ # dependencies diff --git a/README.md b/README.md index c112f897..093be0a0 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,7 @@ # Campground + +- To get started, navigate to [Getting Started section](#getting-started). + ## Summary Campground is a free, self-hosted, and open source chat application. This direction will provide users: @@ -23,7 +26,7 @@ A social media platform in which a user can decide to host their own section or One example of a federated platform is Mastodon ### Campsite -An instance of a community that is hosted within our application. This would be similar to a Discord Server/Guild or a Guilded Server. Campsites can contain a Bulletin Board (profile via bluesky), Campers (from a user registry) and Campfires (categories). +An instance of a community that is hosted within our application. This would be similar to a Discord Server/Guild or a Guilded Server. Campsites can contain a Bulletin Board (profile via bluesky), Campers (from a user registry) and Bonfires (similar to groups in Guilded). ### Home The campsite that a camper has registered their user data with. @@ -35,9 +38,9 @@ When a camper is removed from a campsite, their camper data is not deleted from The campsite overview, similar to Guilded's server overview section. This will contain announcements, active tents, and a "getting started" section for the campsite. -### Campfire +### Bonfire A section of tents, most similar to how Guilded “Groups” work. -Campfires will contain An image descriptor, a text descriptor, and tents. +Bonfires will contain An image descriptor, a text descriptor, and tents. ### Tent A communication section that can fall under one of the below types: @@ -67,23 +70,19 @@ Added friends A feature most similar to “server discovery” on Discord and Guilded. A simple directory of Campsites that have opted to be listed in the Community Board. ## Technology Stack -- [Golang](https://go.dev/) - Backend Library +- [Rust](https://rust-lang.org/) - Backend Library An open-source programming language backed by Google. -- [Next.JS](https://nextjs.org/) for [React](https://react.dev/) - Frontend Core Library +- [React Router](https://reactrouter.com/) for [React](https://react.dev/) - Frontend Core Library A React-based framework for building web applications. -Our app is bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). - -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. - -- [Mantine](https://mantine.dev/) for [React](https://react.dev/) - Frontend Components Library +- [MUI JoyUI](https://mui.com/) for [React](https://react.dev/) - Frontend Components Library -A library of components that we can customise and implement within Next.JS. +A library of components that we can customise and implement within React Router. - [React Native](https://reactnative.dev/) - Mobile Frontend @@ -91,9 +90,9 @@ A library of components that we can customise and implement within Next.JS. A framework that allows us to create native Android and iOS apps using React code. -- [SurrealDB](https://surrealdb.com/) - Database +- [PostgreSQL](https://www.postgresql.org/) - Database -A multi-model database system that allows a SQL-based language to be used +A database system that allows a SQL-based language to be used - [SeaweedFS](https://github.com/seaweedfs/seaweedfs) - File Server @@ -115,10 +114,6 @@ The protocol that Signal uses for communication between users directly. An open-source software that makes it easier for translators to contribute without requiring them to have technical knowledge and also making it easier to collaborate. - -## Design System -We will be utilizing Material 3 for our design system. - ## Branching Strategy / Testing Flow We will be utilising the preferred branching strategy for Git repositories: - Main - The public / production code that builds into what standard users will see @@ -218,8 +213,24 @@ The moment this is ever removed from our motto, we don't deserve any user base. When given the choice between losing support of deprecated systems or holding back the advancement of alternative or newer systems, we will choose the latter. For example, if support for Windows 7 ends on a dependency, but the update also enables better Linux support, we would opt to end Windows 7 support. ## Getting Started -How to run the development server on [http://localhost:3000](http://localhost:3000): + +### Front-end Webapp + +**Prerequisites:** +- Running [back-end](https://github.com/project-campground/backend/tree/2026/campsites#getting-started) +- Running [PDS](https://github.com/project-campground/backend/tree/2026/campsites#getting-started) + ```bash +cd ./sites/campground.gg + +# Create config file +cp config.example.json config.json + +# Optional: Edit the config using any editor +nano ./config.json +# or +code ./config.json + npm run dev # or yarn dev @@ -228,16 +239,18 @@ pnpm dev # or bun dev ``` -Entry page: `app/page.tsx` - -## Learn More -To learn more about Next.js, take a look at the following resources: -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! - -## Deploy on Vercel -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +### Landing page +How to run the development server on [http://localhost:3000](http://localhost:3000): +```bash +cd ./sites/campground.gg -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` +Entry page: `app/page.tsx` \ No newline at end of file diff --git a/lang/en-US.json b/lang/en-US.json index 7c797578..ac6eaf8d 100644 --- a/lang/en-US.json +++ b/lang/en-US.json @@ -1,240 +1,632 @@ { - "global": { - "support": "Support", - "download": "Download", - "themeToggle": "Toggle color scheme", - "api": "API", - "docs": "Docs", - "blog": "Blog", - "discover": "Discover", - "campsites": "Campsites", - "campers": "Campers", - "instances": "Instances", - "socialMedia": "Social media", - "resources": "Resources", - "openBrowser": "Open in Browser" - }, - "info": { - "username": "Username", - "tagline": "Tag", - "taglineOrEmail": "Tag or Email", - "email": "Email", - "password": "Password", - "confirmPassword": "Confirm password" - }, - "form": { - "login": "Sign in", - "register": "Sign up", - "noAccount": "Don't have an account? Register", - "hasAccount": "Already have an account? Login", - "resetPasswordTitle": "Reset password", - "resetPassword": "Forgot your password? Change it", - "submit": "Submit" - }, - "placeholder": { - "underConstruction": { - "title": "Under Construction", - "description": "Sorry, this section is still under construction. Come back later!" - }, - "notFound": { - "title": "404 Not Found", - "description": "This page could not be found." - }, - "goBackToHome": "Go back to home page" - }, - "landing": { - "home": "Home", - "about": "About", - "features": "Features", - "team": "The team", - "brandkit": "Brand kit", - "download": { - "win": "Download for Windows", - "osx": "Download for OSX", - "linux": "Download for Linux", - "debian": "Download for Debian", - "android": "Download for Android", - "ios": "Download for iOS" - } - }, - "home": { - "title": "Gather around the fire, friends", - "description": "Campground is the best place for you and your friends to hang out, create communities, and have fun without any hassle!", - "download": "Download Campground", - "open": "Open Campground", - "bottom": { - "title": "What are you waiting for?", - "description": "Try Campground now, anywhere!" - }, - "campfires": { - "subtitle": "Campfires", - "title": "Organize channels with campfires", - "description": "May also be known as groups or sub-servers, campfires are server-like group of tents/channels with their own icons, banners and roles.", - "learnMore": "Learn more about Campfires" - }, - "profiles": { - "subtitle": "Profiles", - "title": "Highly customizable profiles", - "description": "Create posts and media, discover others, link game and more with Campground's highly customizable profiles.", - "learnMore": "Learn more about Profiles" - }, - "lists": { - "subtitle": "Lists", - "title": "To-do list tents", - "description": "Create list tents (channels) and set up tasks to complete. Organize the tasks, mark them, add notes, create threads and more.", - "learnMore": "Learn more about Lists" - }, - "encryption": { - "subtitle": "Encryption", - "title": "E2EE Private messaging", - "description": "Secure your messages with end-to-end encryption for direct messages. Feel safe with Campground.", - "learnMore": "Learn more about Encryption" - }, - "selfHost": { - "subtitle": "Self-hosting", - "title": "Self-host your campsites", - "description": "Create your own instance and manage YOUR OWN content. No one else, just you and your communities.", - "learnMore": "Learn more about Self-hosting" - }, - "themes": { - "subtitle": "Themes", - "title": "Customize the looks", - "description": "Change the way application looks with highly customizable themes with CSS. Do not like how app looks? Change it!", - "learnMore": "Learn more about Themes" - } - }, - "features": { - "title": "See all of Campgrounds features", - "description": "Campfires? List tents? Calendar tents? Profiles? All here for you to check out and learn!", - "learnMore": "Learn more about {feature}", - "instances": { - "title": "Instances", - "description": "Host your own Campground instances and create campsites on them" - }, - "campfires": { - "title": "Campfires", - "description": "Organize your campsites with campfires." - }, - "encryption": { - "title": "E2E Encryption", - "description": "Learn about direct messages encryption." - }, - "calendarTents": { - "title": "Calendar tents", - "description": "Keep track of events with calendar tents." - }, - "listTents": { - "title": "List tents", - "description": "Create and complete tasks in tents." - }, - "docTents": { - "title": "Document tents", - "description": "Create documents in your tents." - } - }, - "downloads": { - "title": "Get Campground", - "description": "Download Campground on your current device. Everywhere, anywhere; on your phone, on your desktop.", - "wrongDevice": "Wrong device? Scroll down to other downloads.", - "desktop": "Different desktop device?", - "desktopDescription": "Get Campground on any desktop device.", - "mobile": "Or maybe on your phone?", - "mobileDescription": "Make sure everyone can reach you no matter where you are!" - }, - "languages": { - "af-ZA": "Afrikaans", - "ar-SA": "Arabic", - "ca-ES": "Catalan", - "cs-CZ": "Czech", - "da-DK": "Danish", - "de-DE": "German", - "el-GR": "Greek", - "fi-FI": "Finnish", - "fr-FR": "French", - "en-US": "English (US)", - "es-ES": "Spanish", - "he-IL": "Hebrew", - "hu-HU": "Hungarian", - "it-IT": "Italian", - "ja-JP": "Japanese", - "ko-KR": "Korean", - "nl-NL": "Dutch", - "no-NO": "Norwegian", - "pl-PL": "Polish", - "pt-BR": "Portuguese (Brazil)", - "pt-PT": "Portuguese (Portugal)", - "ro-RO": "Romanian", - "ru-RU": "Russian", - "sr-SP": "Serbian", - "sv-SE": "Swedish", - "tr-TR": "Turkish", - "uk-UA": "Ukrainian", - "vi-VN": "Vietnamese", - "zh-CN": "Simplified Chinese (China)", - "zh-TW": "Simplified Chinese (Taiwan)" - }, - "client": { - "common": { - "yes": "Yes", - "no": "No", - "cancel": "Cancel", - "retry": "Retry", - "abort": "Abort", - "ok": "OK", - "delete": "Delete", - "remove": "Remove" - }, - "login": { - "handle": "Handle", - "password": "Password", - "signinButton": "Sign in", - "resetPassword": "Reset password", - "reactivateUserHandle": "Activate handle", - "errors": { - "connectionFailed": "Login failed due to network connection problems.", - "incorrectCredentials": "The handle or password provided is incorrect.", - "passwordResetDisabled": "The administrator had disabled password reset functionality. Contact them on %s to ask for a new password.", - "handleDisabled": "Your handle was disabled. You can enable it by clicking 'Activate handle' button.", - "handleDisabledWithReason": "Your handle was disabled by administrator. Reason: %s", - "handleBanned": "Your handle was banned.", - "handleBannedWithReason": "Your handle was banned. Reason: %s", - "handleTempBannedWithReason": "Your handle was banned till %s. Reason: %s" - } - }, - "profileView": { - "avatar": "Avatar", - "status": "Status" - }, - "settingsView": { - "title": "Manage profile", - "common": { - "title": "Common", - "changePassword": "Change password", - "changeDName": "Change display name", - "removeAvatar": "Remove avatar", - "uploadAvatar": "Upload new avatar" - }, - "connections": { - "title": "Connections", - "description": "Manage social media connections", - "add": "Add connection", - "label": "Connection label", - "content": "Content" - } - }, - "presence": { - "offline": "Offline", - "invisible": "Invisible", - "away": "Away", - "dnd": "Do Not Disturb", - "online": "Online" - }, - "activityPresence": { - "game": "Playing %s", - "listening": "Listening to %s", - "streaming": "Streaming %s", - "streamingDesktop": "Sharing their screen", - "streamingDetailed": "Streaming %s on %s" - } - } + "app.actors.addFriend": { + "description": "Menu button for adding user as a friend", + "message": "Add friend" + }, + "app.actors.block": { + "description": "Menu button for blocking the user", + "message": "Block" + }, + "app.actors.example": { + "description": "Username of an example user in roles settings page", + "message": "Example user" + }, + "app.actors.viewProfile": { + "description": "Menu button for viewing user's profile", + "message": "View profile" + }, + "app.bans.actor": { + "description": "Who was banned in the ban list", + "message": "Banned user" + }, + "app.bans.at": { + "description": "Banned when in the ban list", + "message": "Banned at" + }, + "app.bans.by": { + "description": "Banned by who in the ban list", + "message": "Banned by" + }, + "app.bans.plural": { + "description": "The campsite user bans in plural form", + "message": "Bans" + }, + "app.bans.reason": { + "description": "Reason for the ban in the ban list", + "message": "Reason" + }, + "app.bans.reason.example": { + "description": "Example of a ban reason when banning user", + "message": "Have been spamming" + }, + "app.bans.unban": { + "description": "Unban multiple or one user button in the ban list", + "message": "Unban users" + }, + "app.bonfires.bannerClick": { + "description": "Hint that you can press on tent list banner to open bonfire list", + "message": "Click to see bonfire list" + }, + "app.bonfires.create": { + "description": "The menu button for creating bonfires", + "message": "Create bonfire" + }, + "app.bonfires.delete": { + "description": "The menu button for deleting bonfires", + "message": "Delete bonfire" + }, + "app.bonfires.delete.inputName": { + "description": "The header of the input that requires typing out bonfire's name to allow deleting it.", + "message": "The name of the bonfire" + }, + "app.bonfires.noTents": { + "description": "Note telling user that the bonfire contains no visible tents for them", + "message": "This bonfire has no visible tents" + }, + "app.bonfires.settings": { + "description": "The menu button for opening bonfire settings and the title of bonfire settings", + "message": "Campsite settings" + }, + "app.bonfires.settings.bannerNote": { + "description": "Notifying that bonfire's banner shows up at the top of tent list", + "message": "The banner shows up at the top of the tent list" + }, + "app.bonfires.settings.delete.warning": { + "description": "The warning about the consequences of deleting bonfire", + "message": "Deleting this bonfire will result in permanent deletion of all of its messages, tents and content. If you are sure you want to delete this bonfire, type the name of the bonfire and press ''{buttonText}''." + }, + "app.bonfires.settings.name": { + "description": "The header of the bonfire name field in settings", + "message": "Bonfire name" + }, + "app.bonfires.settings.profile": { + "description": "The bonfire profile settings tab", + "message": "Bonfire profile" + }, + "app.bulletin.campsiteInfo": { + "description": "The title of the campsite info field at the right side of Bulletin Board", + "message": "Campsite info" + }, + "app.campsites.Create": { + "description": "The campsite creation page title", + "message": "Create a Campsite" + }, + "app.campsites.delete": { + "description": "The settings page for deleting campsite", + "message": "Delete campsite" + }, + "app.campsites.delete.warning": { + "description": "The warning about the consequences of deleting campsite", + "message": "Deleting this campsite will result in permanent deletion of all of its messages, tents, bonfires, content and will force all members to leave. If you are sure you want to delete this campsite, type the name of the campsite and press ''{buttonText}''." + }, + "app.campsites.members": { + "description": "Displays the amount of members campsite has", + "message": "{count, number} {count, plural, one { member } other { members }}" + }, + "app.campsites.name": { + "description": "The header of the campsite name field in settings", + "message": "Campsite name" + }, + "app.campsites.notFound": { + "description": "User cannot view the campsite", + "message": "Campsite not found" + }, + "app.campsites.notFound.description": { + "description": "User cannot view the campsite", + "message": "It seems that this campsite does not exist." + }, + "app.campsites.settings": { + "description": "The menu button for opening campsite settings and the title of campsite settings", + "message": "Campsite settings" + }, + "app.campsites.settings.bannerNote": { + "description": "Notifying that campsite's banner shows up in the bulletin board", + "message": "The banner shows up in Bulletin Board" + }, + "app.campsites.settings.delete.inputName": { + "description": "The header of the input that requires typing out campsite's name to allow deleting it.", + "message": "The name of the campsite" + }, + "app.campsites.settings.profile": { + "description": "The campsite profile settings tab", + "message": "Campsite profile" + }, + "app.common.createdAt": { + "description": "Member joined sometime ago", + "message": "Joined at" + }, + "app.common.createdBy": { + "description": "Content created by who", + "message": "Created by" + }, + "app.common.expiresAt": { + "description": "Content expires", + "message": "Expires" + }, + "app.createdAt": { + "description": "Specific date that something was created/sent at", + "message": "Created {time}" + }, + "app.invites.accept": { + "description": "Button for accepting an invite", + "message": "Accept invite" + }, + "app.invites.allowedAmount": { + "description": "The amount of times the invite can be used", + "message": "Allowed times of use" + }, + "app.invites.code": { + "description": "The placeholder for yet uncreated invite code or invite code in the invite list", + "message": "Invite code" + }, + "app.invites.confirm": { + "description": "Asks user whether they want to accept the invite", + "message": "Do you want to accept invite to this campsite?" + }, + "app.invites.create": { + "description": "Menu item for creating campsite invites", + "message": "Create invite" + }, + "app.invites.create.description": { + "description": "The description of invite creation modal", + "message": "Create invite links to this campsite" + }, + "app.invites.delete": { + "description": "Menu button for deleting multiple invites in the invite list", + "message": "Delete invites" + }, + "app.invites.deny": { + "description": "Button for denying an invite", + "message": "Deny invite" + }, + "app.invites.plural": { + "description": "The campsite invites in plural form", + "message": "Invites" + }, + "app.invites.used": { + "description": "The amount of times invite has been used in invite list", + "message": "Times used" + }, + "app.members": { + "description": "Members pseudo-tent name, members tab in the right sidebar", + "message": "Members" + }, + "app.members.ban": { + }, + "app.members.ban.description": { + "description": "Note about what the user ban will imply when banning a user", + "message": "The member will lose all their roles, be kicked from the campsite and be unable to join back until their ban is lifted." + }, + "app.members.kick": { + }, + "app.members.nickname": { + "description": "The title of nickname change field", + "message": "Member nickname" + }, + "app.members.nickname.change": { + }, + "app.members.nickname.change.description": { + "description": "Note about the nickname change in change nickname modal", + "message": "The nickname will be displayed only on this campsite for every member to see" + }, + "app.members.singular": { + "description": "Singular form of campsite member", + "message": "Member" + }, + "app.messages.delete": { + "description": "Message deletion button", + "message": "Delete message" + }, + "app.messages.edited": { + "description": "Hint at the top of the message that the message was edited", + "message": "({icon} edited)" + }, + "app.messages.end": { + "description": "The very top of the tent that gives user a note that there are no more messages", + "message": "This is the beginning of this tent. There are no more messages in this tent." + }, + "app.messages.example": { + "description": "An example message text in roles settings page", + "message": "This is an example text." + }, + "app.messages.noPermission": { + "description": "Tells user they lack permission to write in the text tent", + "message": "You do not have the permission to type in this tent." + }, + "app.permissions.plural": { + "description": "Permissions in settings as plural", + "message": "Permissions" + }, + "app.roles": { + "description": "Roles header in settings and whatnot in plural form", + "message": "Roles" + }, + "app.roles.colors": { + "description": "The animation field in role settings page", + "message": "Select the type of gradient color animation" + }, + "app.roles.display": { + "description": "Display tab in role settings", + "message": "Display" + }, + "app.roles.manage": { + "description": "Manage role tab in role settings", + "message": "Manage" + }, + "app.roles.mentionable": { + "description": "Mentionable by anyone setting in role settings", + "message": "Mentionable by anyone" + }, + "app.roles.mentionable.description": { + "description": "Mentionable by anyone setting's description in role settings", + "message": "Allows any member with permission to create content to mention other members that have this role" + }, + "app.roles.motion.linear": { + "description": "Linear animation option for roles gradient color animation", + "message": "Linear" + }, + "app.roles.motion.none": { + "description": "Unanimated option for roles gradient color animation", + "message": "Unanimated" + }, + "app.roles.motion.radial": { + "description": "Radial animation option for roles gradient color animation", + "message": "Radial" + }, + "app.roles.motion.wave": { + "description": "Wave animation option for roles gradient color animation", + "message": "Wave" + }, + "app.roles.name": { + "description": "The name field of the roles settings page", + "message": "Role name" + }, + "app.roles.separately": { + "description": "Display separately setting in role settings", + "message": "Display separately" + }, + "app.roles.separately.description": { + "description": "Display separately setting's description in role settings", + "message": "Displays the members that have this role separately from the rest of the members in the member list" + }, + "app.roles.unknown": { + "description": "The title of the role when the role has not been found in role mention", + "message": "Unknown role" + }, + "app.settings": { + "description": "Menu button for settings, as well as settings title", + "message": "Settings" + }, + "app.settings.other": { + "description": "Other settings pages and content", + "message": "Other" + }, + "app.settings.save": { + "description": "Button for saving changes in settings", + "message": "Save changes" + }, + "app.settings.unsavedChanges": { + "description": "The text that appears in the pop up when you change values in settings", + "message": "You have unsaved changes" + }, + "app.system.tentCreated": { + "description": "Member has created the currently viewed tent", + "message": "{member} has created this tent." + }, + "app.system.tentNameUpdated": { + "description": "Member has modified the name of the currently viewed tent", + "message": "{member} has changed the name of this tent from {oldName} to {newName}." + }, + "app.tentCategories.create": { + "description": "The menu button for creating tent categories", + "message": "Create category" + }, + "app.tentCategories.delete": { + "description": "The menu button for deleting tent categories", + "message": "Delete category" + }, + "app.tentCategories.settings": { + "description": "The menu button for opening tent category settings and the title of category settings", + "message": "Category settings" + }, + "app.tentCategories.settings.deleteInputName": { + "description": "The header of the input that requires typing out tent category's name to allow deleting it.", + "message": "The name of the category" + }, + "app.tentCategories.settings.deleteWarning": { + "description": "The warning about the consequences of deleting tent category", + "message": "Deleting this tent category will result in permanent deletion of all of its messages, tents and content. If you are sure you want to delete this tent category, type the name of the category and press ''{buttonText}''." + }, + "app.tentCategories.settings.name": { + "description": "The header of the category name field in settings", + "message": "Category name" + }, + "app.tentCategories.settings.profile": { + "description": "The category profile settings tab", + "message": "Category profile" + }, + "app.tentCategories.singular": { + "description": "Tent category in singular form for tent creation modal", + "message": "Category" + }, + "app.tents.bulletin": { + "description": "Bulletin Board pseudo-tent name", + "message": "Bulletin Board" + }, + "app.tents.create": { + "description": "Create tent button at the bottom of tent list, as well as the title of tent creation modal", + "message": "Create tent" + }, + "app.tents.create.description": { + "description": "Tent creation modal description", + "message": "Create a new tent or tent category in this bonfire" + }, + "app.tents.create.type": { + "description": "Header for tent type selection", + "message": "Select the type of tent's content" + }, + "app.tents.create.what": { + "description": "What to create: tent or tent category", + "message": "What to create" + }, + "app.tents.delete": { + "description": "The menu button for deleting tent", + "message": "Delete tent" + }, + "app.tents.delete.inputName": { + "description": "The header of the input that requires typing out tent's name to allow deleting it.", + "message": "The name of the tent" + }, + "app.tents.delete.warning": { + "description": "The warning about the consequences of deleting tent", + "message": "Deleting this tent will result in permanent deletion of all of its permissions, messages and content. If you are sure you want to delete this tent, type the name of the tent and press ''{buttonText}''." + }, + "app.tents.leaveCampsite": { + "description": "Menu item for leaving a campsite", + "message": "Leave campsite" + }, + "app.tents.open": { + "description": "The menu button for opening tents", + "message": "Open tent" + }, + "app.tents.settings": { + "description": "The menu button for opening tent settings and the title of tent settings", + "message": "Tent settings" + }, + "app.tents.settings.name": { + "description": "The header of the tent name field in settings", + "message": "Tent name" + }, + "app.tents.settings.profile": { + "description": "The tent profile settings tab", + "message": "Tent profile" + }, + "app.tents.singular": { + "description": "Tent in singular form for tent creation modal", + "message": "Tent" + }, + "app.tents.text": { + "description": "Text tent type", + "message": "Text" + }, + "app.tents.unknown": { + "description": "The name of the tent in tent mentions when the tent could not be found", + "message": "Unknown tent" + }, + "app.threads": { + "description": "Message threads tab in the right sidebar", + "message": "Threads" + }, + "app.time.ago": { + "description": "When something happened 'ago'", + "message": "{time} ago" + }, + "app.time.in": { + "description": "When something will happen in specific time", + "message": "In {time}" + }, + "app.time.invalid": { + "description": "The provided date to timestamp component is invalid in some way", + "message": "Invalid date" + }, + "app.time.never": { + "description": "The provided date to timestamp component is empty and is usually used to indicate that something never happened", + "message": "Never" + }, + "app.time.none": { + "description": "Unformatted timestamp", + "message": "{time}" + }, + "app.time.now": { + "description": "When something happened just now (less than a minute ago)", + "message": "Just now" + }, + "common.cancel": { + "description": "Cancelling an action in settings, modals and content", + "message": "Cancel" + }, + "common.copy": { + "description": "Text of button for copying text", + "message": "Copy" + }, + "common.copy.successful": { + "description": "User has successfully copied a value", + "message": "Successfully copied!" + }, + "common.delete": { + "description": "Delete content", + "message": "Delete" + }, + "common.infinite": { + "description": "Infinite amount of something. Used in invite creation placeholder when assigning the amount of times invite can be used", + "message": "Infinite" + }, + "downloads.description": { + }, + "downloads.desktop": { + }, + "downloads.desktopDescription": { + }, + "downloads.mobile": { + }, + "downloads.mobileDescription": { + }, + "downloads.title": { + }, + "downloads.wrongDevice": { + }, + "features.description": { + }, + "features.learnMore": { + }, + "features.title": { + }, + "form.confirmDelete": { + "description": "Button for confirming deletion of content", + "message": "Confirm deletion" + }, + "form.hasAccount": { + "description": "Link to login page in registration page", + "message": "Already have an account? Try logging in" + }, + "form.login": { + "description": "Login button and page title", + "message": "Login" + }, + "form.logout": { + "description": "Menu button for logging out of the account", + "message": "Logout" + }, + "form.noAccount": { + "description": "Link for navigating to registration page in login page", + "message": "No account? Create one" + }, + "form.resetPassword": { + "description": "Reset password link in login page", + "message": "Forgot password? Change it" + }, + "form.submit": { + "description": "Submit button for submitting form values", + "message": "Submit" + }, + "form.tagPlaceholder": { + "description": "Placeholder used for adding tags in forms", + "message": "Add tag" + }, + "form.uploadImage": { + "description": "Hint or button for uploading images", + "message": "Upload image" + }, + "form.uploadImage.description": { + "description": "Description of modal instructing to upload an image or submit its URL", + "message": "Upload an image or paste the URL of it" + }, + "form.uploadImage.title": { + "description": "Prompt for the title of the image in image uploading modal", + "message": "Image title" + }, + "form.uploadImage.url": { + "description": "Prompt for the URL of the image in image uploading modal", + "message": "Image URL" + }, + "global.api": { + }, + "global.banner": { + "description": "The banner of campsites, bonfires and users", + "message": "Banner" + }, + "global.blog": { + }, + "global.campers": { + }, + "global.campsites": { + }, + "global.docs": { + }, + "global.download": { + }, + "global.instances": { + }, + "global.openBrowser": { + }, + "global.support": { + }, + "home.bottom.description": { + }, + "home.bottom.title": { + }, + "home.description": { + }, + "home.title": { + }, + "info.description": { + "description": "Description in campsites, bonfires and elsewhere", + "message": "Description" + }, + "info.handle": { + "description": "User handles", + "message": "Handle" + }, + "info.handleOrEmail": { + "description": "User handles or email as login detail", + "message": "Handle or Email" + }, + "info.name": { + "description": "The name of the content, objects, tents, etc.", + "message": "Name" + }, + "info.password": { + "description": "Password as a login detail", + "message": "Password" + }, + "info.password.confirm": { + "description": "Confirm a password when registering or changing password", + "message": "Confirm password" + }, + "info.password.placeholder": { + "description": "Placeholder in the password field when registering", + "message": "Password here" + }, + "info.tags.plural": { + "description": "Plural form of campsite tags or other content tags", + "message": "Tags" + }, + "info.title": { + "description": "The title of the content, objects, tents, etc.", + "message": "Title" + }, + "info.topic": { + "description": "Topic header in settings and tents", + "message": "Topic" + }, + "info.username": { + "description": "Display name of the user", + "message": "Username" + }, + "landing.brandKit": { + }, + "landing.download.debian": { + }, + "landing.features": { + }, + "landing.team": { + }, + "placeholder.goBackToHome": { + }, + "placeholder.notFound.description": { + }, + "placeholder.notFound.title": { + }, + "placeholder.underConstruction.description": { + }, + "placeholder.underConstruction.title": { + }, + "tent.bonfires.create": { + "description": "Bonfire creation button in the bonfire list", + "message": "Create bonfire" + }, + "tent.bonfires.create.description": { + "description": "Description for bonfire creation modal", + "message": "Create a new bonfire in this campsite" + } } diff --git a/lang/en-US_old.json b/lang/en-US_old.json new file mode 100644 index 00000000..fa2356f9 --- /dev/null +++ b/lang/en-US_old.json @@ -0,0 +1,274 @@ +{ + "languages": { + "af-ZA": "Afrikaans", + "ar-SA": "Arabic", + "ca-ES": "Catalan", + "cs-CZ": "Czech", + "da-DK": "Danish", + "de-DE": "German", + "el-GR": "Greek", + "fi-FI": "Finnish", + "fr-FR": "French", + "en-US": "English (US)", + "es-ES": "Spanish", + "he-IL": "Hebrew", + "hu-HU": "Hungarian", + "it-IT": "Italian", + "ja-JP": "Japanese", + "ko-KR": "Korean", + "nl-NL": "Dutch", + "no-NO": "Norwegian", + "pl-PL": "Polish", + "pt-BR": "Portuguese (Brazil)", + "pt-PT": "Portuguese (Portugal)", + "ro-RO": "Romanian", + "ru-RU": "Russian", + "sr-SP": "Serbian", + "sv-SE": "Swedish", + "tr-TR": "Turkish", + "uk-UA": "Ukrainian", + "vi-VN": "Vietnamese", + "zh-CN": "Simplified Chinese (China)", + "zh-TW": "Simplified Chinese (Taiwan)" + }, + + "info": { + "username": "Username", + "title": "Title", + "uniqueTitle": "Name", + "handle": "Handle", + "about": "About me", + "avatar": "Avatar", + "tags": { + "add": "Add a tag", + "singular": "Tag", + "plural": "Tags" + }, + "banner": "Banner", + "description": "Description", + "information": "Information", + "tagline": "Tag", + "handleOrEmail": "Handle or Email", + "email": "Email", + "password": "Password", + "confirmPassword": "Confirm password" + }, + + "common": { + "yes": "Yes", + "no": "No", + "add": "Add", + "cancel": "Cancel", + "retry": "Retry", + "abort": "Abort", + "ok": "Okay", + "delete": "Delete", + "remove": "Remove", + "edit": "Edit", + "submit": "Submit", + "download": "Download", + "copy": "Copy", + "infinite": "Infinite" + }, + + "login": { + "login": "Sign in", + "register": "Sign up", + "noAccount": "Don't have an account? Register", + "hasAccount": "Already have an account? Login", + "resetPasswordTitle": "Reset password", + "resetPassword": "Forgot your password? Change it", + + "reactivateUserHandle": "Activate handle", + + "errors": { + "connectionFailed": "Login failed due to network connection problems.", + "incorrectCredentials": "The handle or password provided is incorrect.", + "passwordResetDisabled": "The administrator had disabled password reset functionality. Contact them on %s to ask for a new password.", + "handleDisabled": "Your handle was disabled. You can enable it by clicking 'Activate handle' button.", + "handleDisabledWithReason": "Your handle was disabled by administrator. Reason: %s", + "handleBanned": "Your handle was banned.", + "handleBannedWithReason": "Your handle was banned. Reason: %s", + "handleTempBannedWithReason": "Your handle was banned till %s. Reason: %s" + } + }, + + "global": { + "support": "Support", + "changeTheme": "Change theme", + "api": "API", + "docs": "Docs", + "blog": "Blog", + "discover": "Discover", + "discovery": "Discovery", + "campsites": "Campsites", + "campers": "Campers", + "instances": "Instances", + "socialMedia": "Social media", + "resources": "Resources", + "openBrowser": "Open in Browser" + }, + + "placeholder": { + "underConstruction": { + "title": "Under Construction", + "description": "Sorry, this section is still under construction. Come back later!" + }, + "notFound": { + "title": "404 Not Found", + "description": "This page could not be found." + }, + "goBackToHome": "Go back to home page" + }, + + "landing": { + "nav": { + "home": "Home", + "about": "About", + "features": "Features", + "team": "The team", + "brandKit": "Brand kit" + }, + "home": { + "title": "Gather around the fire, friends", + "description": "Campground is the best place for you and your friends to hang out, create communities, and have fun without any hassle!", + "download": "Download Campground", + "open": "Open Campground", + "bottom": { + "title": "What are you waiting for?", + "description": "Try Campground now, anywhere!" + }, + "bonfires": { + "subtitle": "Bonfires", + "title": "Organize channels with bonfires", + "description": "May also be known as groups or sub-servers, bonfires are server-like group of tents/channels with their own icons, banners and roles.", + "learnMore": "Learn more about Bonfires" + }, + "profiles": { + "subtitle": "Profiles", + "title": "Highly customizable profiles", + "description": "Create posts and media, discover others, link game and more with Campground's highly customizable profiles.", + "learnMore": "Learn more about Profiles" + }, + "lists": { + "subtitle": "Lists", + "title": "To-do list tents", + "description": "Create list tents (channels) and set up tasks to complete. Organize the tasks, mark them, add notes, create threads and more.", + "learnMore": "Learn more about Lists" + }, + "encryption": { + "subtitle": "Encryption", + "title": "E2EE Private messaging", + "description": "Secure your messages with end-to-end encryption for direct messages. Feel safe with Campground.", + "learnMore": "Learn more about Encryption" + }, + "selfHost": { + "subtitle": "Self-hosting", + "title": "Self-host your campsites", + "description": "Create your own instance and manage YOUR OWN content. No one else, just you and your communities.", + "learnMore": "Learn more about Self-hosting" + }, + "themes": { + "subtitle": "Themes", + "title": "Customize the looks", + "description": "Change the way application looks with highly customizable themes with CSS. Do not like how app looks? Change it!", + "learnMore": "Learn more about Themes" + } + }, + "features": { + "title": "See all of Campgrounds features", + "description": "Campfires? List tents? Calendar tents? Profiles? All here for you to check out and learn!", + "learnMore": "Learn more about {feature}", + "instances": { + "title": "Instances", + "description": "Host your own Campground instances and create campsites on them" + }, + "bonfires": { + "title": "Bonfires", + "description": "Organize your campsites with bonfires." + }, + "encryption": { + "title": "E2E Encryption", + "description": "Learn about direct messages encryption." + }, + "calendarTents": { + "title": "Calendar tents", + "description": "Keep track of events with calendar tents." + }, + "listTents": { + "title": "List tents", + "description": "Create and complete tasks in tents." + }, + "docTents": { + "title": "Document tents", + "description": "Create documents in your tents." + } + }, + "downloads": { + "title": "Get Campground", + "description": "Download Campground on your current device. Everywhere, anywhere; on your phone, on your desktop.", + "wrongDevice": "Wrong device? Scroll down to other downloads.", + "desktop": "Different desktop device?", + "desktopDescription": "Get Campground on any desktop device.", + "mobile": "Or maybe on your phone?", + "mobileDescription": "Make sure everyone can reach you no matter where you are!", + "platform": { + "win": "Download for Windows", + "osx": "Download for OSX", + "linux": "Download for Linux", + "debian": "Download for Debian", + "android": "Download for Android", + "ios": "Download for iOS" + } + } + }, + + "client": { + "createdAt": "Created at {at}", + "datestamp": { + "now": "Just now", + "invalidDate": "The provided date is invalid", + "ago": "{time} ago" + }, + "campsites": { + "members": "{count} members", + "settings": { + "members": "Campsite members", + "name": "Campsite name", + "other": "Other", + "profile": "Campsite profile", + "roles": "Roles", + "invites": "Invites", + "bans": "User bans", + "delete": "Delete campsite" + } + }, + "tents": { + "createInvite": "Create invites", + "campsiteSettings": "Campsite settings", + "bonfireSettings": "Bonfire settings", + "leaveCampsite": "Leave campsite", + "bulletin": "Bulletin Board", + "members": "Members", + "create": "Create tent" + }, + "bulletin": { + "campsiteInfo": "Campsite Information" + }, + "members": { + "changeNickname": "Change nickname", + "mute": "Timeout member", + "kick": "Kick member", + "ban": "Ban member", + "unban": "Remove ban" + }, + "settings": { + "save": "Save changes", + "unsavedChanges": "You have unsaved changes" + }, + "system": { + "tentNameUpdated": "{member} updated the name of this tent from {oldName} to {newName}.", + "tentCreated": "{member} created this tent." + } + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..57999c5e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,54 @@ +{ + "name": "frontend", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "@formatjs/cli": "^6.14.1" + } + }, + "node_modules/@formatjs/cli": { + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/@formatjs/cli/-/cli-6.14.1.tgz", + "integrity": "sha512-afBgzduP4lrOEm1FxMAVMXKi2FNE7KDOWJ7SyhvEI7zRbHhA7qVkb2DbxpPUhtDg0BrdHjdp8ppVyVVNYaFaaA==", + "dev": true, + "license": "MIT", + "bin": { + "formatjs": "bin/formatjs" + }, + "engines": { + "node": ">= 20.12.0" + }, + "peerDependencies": { + "@glimmer/syntax": "^0.84.3 || ^0.95.0", + "@vue/compiler-core": "^3.5.0", + "content-tag": "^4.1.0", + "vue": "^3.5.0" + }, + "peerDependenciesMeta": { + "@glimmer/env": { + "optional": true + }, + "@glimmer/reference": { + "optional": true + }, + "@glimmer/syntax": { + "optional": true + }, + "@glimmer/validator": { + "optional": true + }, + "@vue/compiler-core": { + "optional": true + }, + "content-tag": { + "optional": true + }, + "vue": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..6cba40e8 --- /dev/null +++ b/package.json @@ -0,0 +1,8 @@ +{ + "scripts": { + "extract": "formatjs extract 'sites/*campground.gg/src/**/*.ts*' --ignore='**/*.d.ts' --out-file lang/en-US.json --format='crowdin' --id-interpolation-pattern '[sha512:contenthash:base64:6]'" + }, + "devDependencies": { + "@formatjs/cli": "^6.14.1" + } +} diff --git a/packages/components/.gitignore b/packages/components/.gitignore new file mode 100644 index 00000000..b512c09d --- /dev/null +++ b/packages/components/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/packages/components/BrandLogo.tsx b/packages/components/BrandLogo.tsx new file mode 100644 index 00000000..ca458e7c --- /dev/null +++ b/packages/components/BrandLogo.tsx @@ -0,0 +1,92 @@ +import { Stack, Typography, styled } from "@mui/joy"; +import type { DefaultTypographySystem } from "@mui/joy/styles/types"; +import SvgLogo from "./svg/SvgLogo"; +import SvgUse from "./svg/SvgUse"; +import { jsx } from "react/jsx-runtime"; + +type Size = "xl" | "lg" | "md" | "sm" | "xs"; + +type Props = { + includeText?: boolean; + size?: Size; +}; + +const sizeToFz: Record = { + "xl": "h1", + "lg": "h2", + "md": "h3", + "sm": "h4", + "xs": "title-sm" +}; + +const sizeToPx: Record = { + xs: 36, + sm: 48, + md: 56, + lg: 64, + xl: 96, +}; + +const BrandIconContainer = styled("span", { + name: "BrandIconContainer", +})(() => ({ + "& > svg": { + width: sizeToPx.md, + height: sizeToPx.md, + userSelect: "none", + }, + "&.BrandIconContainer-sizeMd > svg": { + width: sizeToPx.md, + height: sizeToPx.md, + }, + "&.BrandIconContainer-sizeSm > svg": { + width: sizeToPx.sm, + height: sizeToPx.sm, + }, + "&.BrandIconContainer-sizeXs > svg": { + width: sizeToPx.xs, + height: sizeToPx.xs, + }, + "&.BrandIconContainer-sizeLg > svg": { + width: sizeToPx.lg, + height: sizeToPx.lg, + }, + "&.BrandIconContainer-sizeXl > svg": { + width: sizeToPx.xl, + height: sizeToPx.xl, + }, +})); + +const Svg = styled("svg", { + name: "BrandLogoSvg", + slot: "svg", +})(({ theme }) => ({ + color: theme.vars.palette.primary[500], +})); + +const normalizeName = (size: Size) => size[0].toUpperCase() + size.slice(1); + + +export default function BrandLogo({ size, includeText }: Props) { + const sizeName = size ? normalizeName(size) : "Md"; + const fz = sizeToFz[size ?? "md"]; + const px = sizeToPx[size ?? "md"]; + + return ( + jsx(Stack, { + direction: "row", + alignItems: "center", + gap: 1, + className: `BrandLogo container BrandIconContainer-size${sizeName}`, + children: [ + jsx(BrandIconContainer, { sx: { height: px, }, className: `BrandIconContainer-size${sizeName}`, children: + jsx(Svg, { width: px, height: px, children: [ + jsx(SvgLogo, {}, "logo"), + jsx(SvgUse, { id: "cg-logo" }, "use"), + ]}), + }, "icon"), + includeText && jsx(Typography, { level: fz, textColor: "primary.500", children: "Campground" }, "logo"), + ] + }) + ) +} \ No newline at end of file diff --git a/packages/components/FlexCenter.tsx b/packages/components/FlexCenter.tsx new file mode 100644 index 00000000..6f458e91 --- /dev/null +++ b/packages/components/FlexCenter.tsx @@ -0,0 +1,33 @@ +import type { PropsWithChildren } from "react"; +import { styled } from "@mui/joy"; +import { jsx } from "react/jsx-runtime"; + +type Props = PropsWithChildren; + +const FlexCenterVertical = styled("div", { + name: "FlexCenter", + slot: "root", +})(() => ({ + display: "flex", + alignItems: "center", + flexDirection: "row", + height: "100%", + width: "100%", +})); +const FlexCenterHorizontal = styled("div", { + name: "FlexCenter", + slot: "sub", +})(() => ({ + display: "flex", + alignItems: "center", + flexDirection: "column", + width: "100%", +})); + +export default function FlexCenter({ children }: Props) { + return ( + jsx(FlexCenterVertical, { + children: jsx(FlexCenterHorizontal, { children }) + }) + ); +} \ No newline at end of file diff --git a/packages/components/GradientTypography.tsx b/packages/components/GradientTypography.tsx new file mode 100644 index 00000000..f753a529 --- /dev/null +++ b/packages/components/GradientTypography.tsx @@ -0,0 +1,139 @@ +import { Typography, styled } from "@mui/joy"; +import { keyframes } from "@emotion/react"; +import { forwardRef } from "react"; +import { jsx } from "react/jsx-runtime"; +import type { TypographyProps } from "@mui/joy"; + +export const animatedLinearGradient = keyframes` + 0% { + background-position-x: 0%; + } + 100% { + background-position-x: 100%; + } +`; + +export const animatedWaveGradient = keyframes` + 0% { + background-position-x: 0%; + } + 100% { + background-position-x: 100%; + } +`; + +export const animatedRadialGradient = keyframes` + 0% { + background-position-y: 0%; + background-position-x: 0%; + } + 12.5% { + background-position-y: 50%; + } + 37.5% { + background-position-y: 110%; + } + 37.501% { + background-position-y: 0%; + } + 50% { + background-position-y: 50%; + background-position-x: 100%; + } + 62.5% { + background-position-y: 110%; + } + 62.501% { + background-position-y: 0%; + } + 75% { + background-position-y: 50%; + } + 100% { + background-position-y: 110%; + background-position-x: 0%; + } +`; + +export type GradientAnimation = "none" | "wave" | "linear" | "radial"; +export interface GradientTypographyProps extends TypographyProps { + motion?: GradientAnimation; + colors?: string[] | undefined | null; +}; + +const GradientTypographyRoot = styled(Typography, { + name: "GradientTypography", + slot: "root", +})<{ ownerState: GradientTypographyProps; }>(({ ownerState: { colors } }) => ({ + "&.GradientTypography-withColors": { + WebkitTextFillColor: "transparent", + color: "transparent", + backgroundClip: "text", + width: "max-content", + background: `linear-gradient(to right in oklch, var(--GradientTypography-gradient)) text`, + animationDuration: `var(--GradientTypography-time)`, + animationIterationCount: "infinite", + animationTimingFunction: "linear", + }, + "&.GradientTypography-withColors.GradientTypography-motionNone": { + // oklch just has the best colour interpolation for most colours and might be expected by users + }, + "&.GradientTypography-withColors.GradientTypography-motionLinear": { + backgroundClip: "text", + backgroundSize: `8000%`, + }, + "&.GradientTypography-withColors.GradientTypography-motionWave": { + backgroundClip: "text", + backgroundSize: `200%`, + }, + "&.GradientTypography-withColors.GradientTypography-motionRadial": { + backgroundClip: "text", + background: `radial-gradient(circle at center in oklch, var(--GradientTypography-gradient)) text`, + backgroundSize: "200% 1000%", + }, +})); + +const GradientTypography = forwardRef(function GradientTypography(props, ref) { + const { motion, colors, sx, ...other } = props; + const ownerState = other; + const percentageOfColor = 50 / (colors?.length ?? 1); + const defaultedMotion = motion ?? "none"; + + return ( + jsx(GradientTypographyRoot, { + ref, + ownerState, + className: [ + `motion${defaultedMotion[0].toUpperCase() + defaultedMotion.slice(1)}`, + colors?.length && `withColors` + ].filter((x) => x).map((x) => `GradientTypography-${x}`).join(" "), + sx: Object.assign({}, ...[ + // !colors?.length && { + // background: "transparent", + // }, + colors?.length && (!motion || motion === "none") && { + "--GradientTypography-gradient": colors.join(", "), + }, + colors?.length && motion === "linear" && { + "--GradientTypography-gradient": colors.concat(colors[0]).join(", "), + "--GradientTypography-time": `${2.5 * colors.length}s`, + animationName: `${animatedLinearGradient}`, + }, + colors?.length && motion === "wave" && { + "--GradientTypography-gradient": colors.concat(colors).concat(colors[0]).map((x, i) => `${x} ${percentageOfColor * i}%`).join(", "), + "--GradientTypography-time": `${2.5 * colors.length}s`, + animationName: `${animatedWaveGradient}`, + }, + colors?.length && motion === "radial" && { + "--GradientTypography-gradient": colors.concat(colors).join(", "), + "--GradientTypography-time": `${10 * colors.length}s`, + animationName: `${animatedRadialGradient}`, + }, + sx, + ].filter((x) => x)), + ...other + }) + ) +}); + +export default GradientTypography; \ No newline at end of file diff --git a/packages/components/Group.tsx b/packages/components/Group.tsx new file mode 100644 index 00000000..32930615 --- /dev/null +++ b/packages/components/Group.tsx @@ -0,0 +1,56 @@ +import { Stack, styled } from "@mui/joy"; +import { forwardRef } from "react"; +import { jsx } from "react/jsx-runtime"; +import type { StackProps } from "@mui/joy"; + +export interface GroupProps extends StackProps { + wrap?: boolean; + withMobile?: boolean; + withMobileReversed?: boolean; + className?: string; +} + +const GroupRoot = styled(Stack, { + name: "CampgroundGroup", + slot: "root", +})<{ ownerState: GroupProps }>(({ theme }) => ({ + flexDirection: "row", + "&.CampgroundGroup-wrap": { + flexWrap: "wrap", + }, + "&.CampgroundGroup-mobile": { + flexWrap: "wrap", + [theme.breakpoints.down("sm")]: { + flexDirection: "column", + } + }, + "&.CampgroundGroup-mobile.CampgroundGroup-mobile-reverse": { + flexWrap: "wrap-reverse", + [theme.breakpoints.down("sm")]: { + flexDirection: "column-reverse", + } + }, +})); + + +const Group = forwardRef(function Group(props, ref) { + const { wrap, withMobile, withMobileReversed, className, ...other } = props; + const ownerState = other; + + return ( + jsx(GroupRoot, { + ref, + ownerState, + className: [ + `CampgroundGroup-root`, + wrap && `CampgroundGroup-wrap`, + (withMobile || withMobileReversed) && `CampgroundGroup-mobile`, + withMobileReversed && `CampgroundGroup-mobile-reverse`, + className, + ].filter(Boolean).join(" "), + ...other + }) + ) +}); + +export default Group; \ No newline at end of file diff --git a/packages/components/Image.tsx b/packages/components/Image.tsx new file mode 100644 index 00000000..0f5562b1 --- /dev/null +++ b/packages/components/Image.tsx @@ -0,0 +1,13 @@ +import { styled, type Radius } from "@mui/joy"; + +const Image = styled("img", { + name: "Image", + slot: "root", +})<{ mh?: number; mw?: number; radius?: keyof Radius; noRadius?: boolean; }>(({ theme, mh, mw, radius, noRadius }) => ({ + maxHeight: mh, + maxWidth: mw, + width: "min-content", + height: "min-content", + borderRadius: noRadius ? "none" : theme.vars.radius[radius ?? "sm"], +})); +export default Image; \ No newline at end of file diff --git a/packages/components/SmoothTabList.tsx b/packages/components/SmoothTabList.tsx new file mode 100644 index 00000000..26634d1d --- /dev/null +++ b/packages/components/SmoothTabList.tsx @@ -0,0 +1,63 @@ +import { styled, Tab, TabList, type TabListProps } from "@mui/joy"; +import { useRef, type ReactNode } from "react"; +import { useTabsList } from "@mui/base"; +import { jsx, Fragment } from "react/jsx-runtime"; + +const SmoothTabListRoot = styled(TabList, { + name: "SmoothTabList", + slot: "root", +})(() => ({ + position: "relative", + overflow: "hidden", +})); +const SmoothTabListBackground = styled("div", { + name: "SmoothTabList", + slot: "background", +})(({ theme }) => ({ + position: "absolute", + transition: "left ease-out 0.2s", + height: "100%", + backgroundColor: theme.vars.palette.background.level2, +})); +const SmoothTab = styled(Tab, { + name: "SmoothTab", + slot: "root", +})(({ theme }) => ({ + transition: "color 0.2s", + "&.Mui-selected": { + backgroundColor: "transparent", + }, + "&:hover, &:not(&.Mui-selected, [aria-selected=\"true\"]):hover": { + backgroundColor: "transparent", + color: theme.vars.palette.text.secondary, + } +})); + +type SmoothTabListProps = Omit & { + tabs: Array<{ + id: string | number | boolean; + name: ReactNode[] | ReactNode; + startDecorator?: ReactNode[] | ReactNode; + endDecorator?: ReactNode[] | ReactNode; + }>; +} + +export default function SmoothTabList({ tabs, onChange, ...props }: SmoothTabListProps) { + const ref = useRef(null); + const { selectedValue } = useTabsList({ rootRef: ref }); + const currentTabIndex = tabs.findIndex((x) => x.id === selectedValue); + const tabWidth = 100 / tabs.length; + + return ( + jsx(SmoothTabListRoot, {...props, ref, children: [ + jsx(SmoothTabListBackground, { sx: { left: `${currentTabIndex * tabWidth}%`, width: `${tabWidth}%` } }, "background"), + ...tabs.map((x) => + jsx(SmoothTab, {children: [ + jsx(Fragment, { children: x.startDecorator }, "start"), + jsx(Fragment, { children: x.name }, "name"), + jsx(Fragment, { children: x.endDecorator }, "end"), + ]}, x.id.toString()) + ) + ]}) + ); +} \ No newline at end of file diff --git a/packages/components/TextBlock.tsx b/packages/components/TextBlock.tsx new file mode 100644 index 00000000..6a8964f5 --- /dev/null +++ b/packages/components/TextBlock.tsx @@ -0,0 +1,67 @@ +import { styled } from "@mui/joy"; +import { forwardRef } from "react"; +import { jsx } from "react/jsx-runtime"; + +export interface TextBlockProps extends React.PropsWithChildren { + weight?: 500 | 600 | 700 | 800 | 900; + align?: "top" | "center" | "bottom"; + hideOnMobile?: boolean; + className?: string; +} + +const TextBlockRoot = styled("span", { + name: "TextBlock", + slot: "root", +})<{ ownerState: TextBlockProps }>(({ theme }) => ({ + display: "inline-block", + verticalAlign: "center", + "&.TextBlock-weight500": { + fontWeight: 500, + }, + "&.TextBlock-alignTop": { + verticalAlign: "top", + }, + "&.TextBlock-alignBottom": { + verticalAlign: "bottom", + }, + "&.TextBlock-weight600": { + fontWeight: 500, + }, + "&.TextBlock-weight700": { + fontWeight: 500, + }, + "&.TextBlock-weight800": { + fontWeight: 500, + }, + "&.TextBlock-weight900": { + fontWeight: 500, + }, + "&.TextBlock-hideOnMobile": { + [theme.breakpoints.down("md")]: { + display: "none", + }, + } +})); + + +const TextBlock = forwardRef(function TextBlockTypography(props, ref) { + const { hideOnMobile, weight, className, align, ...other } = props; + const ownerState = props; + + return ( + jsx(TextBlockRoot, { + ref, + ownerState, + className: [ + `TextBlock-root`, + hideOnMobile && "TextBlock-hideOnMobile", + weight && `TextBlock-weight${weight}`, + align && `TextBlock-align${align[0].toUpperCase()}${align.slice(1)}`, + className, + ].filter(Boolean).join(" "), + ...other + }) + ) +}); + +export default TextBlock; \ No newline at end of file diff --git a/packages/components/index.ts b/packages/components/index.ts index e69de29b..66f41aec 100644 --- a/packages/components/index.ts +++ b/packages/components/index.ts @@ -0,0 +1,13 @@ +import "./types"; + +export { default as theme } from "./theme"; +export { default as SvgDefs } from "./svg/SvgDefs"; +export { default as SvgUse } from "./svg/SvgUse"; +export { default as BrandLogo } from "./BrandLogo"; +export { default as Group } from "./Group"; +export { default as FlexCenter } from "./FlexCenter"; +export { default as Image } from "./Image"; +export { default as SmoothTabList } from "./SmoothTabList"; +export { default as TextBlock } from "./TextBlock"; +export { default as GradientTypography } from "./GradientTypography"; +export { loremIpsum } from "./util"; \ No newline at end of file diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json new file mode 100644 index 00000000..bdcdd227 --- /dev/null +++ b/packages/components/package-lock.json @@ -0,0 +1,1043 @@ +{ + "name": "components", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "components", + "version": "1.0.0", + "license": "AGPL-3.0-or-later", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mui/joy": "^5.0.0-beta.52", + "react": "^19.1.1" + }, + "devDependencies": { + "@types/react": "^19.1.13" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.40-1", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40-1.tgz", + "integrity": "sha512-agKXuNNy0bHUmeU7pNmoZwNFr7Hiyhojkb9+2PVyDG5+6RafYuyMgbrav8CndsB7KUc/U51JAw9vKNDLYBzaUA==", + "deprecated": "This package has been replaced by @base-ui-components/react", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@floating-ui/react-dom": "^2.0.8", + "@mui/types": "~7.2.15", + "@mui/utils": "^5.17.1", + "@popperjs/core": "^2.11.8", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.18.0.tgz", + "integrity": "sha512-jbhwoQ1AY200PSSOrNXmrFCaSDSJWP7qk6urkTmIirvRXDROkqe+QwcLlUiw/PrREwsIF/vm3/dAXvjlMHF0RA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/joy": { + "version": "5.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@mui/joy/-/joy-5.0.0-beta.52.tgz", + "integrity": "sha512-e8jQanA5M1f/X52mJrw0UIW8Er7EAHuLuigmGFw7yIsAgIluhIP4rZ7JcbVrUi6z5Gk0weC9QWUUtjLejAbO8g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.40-1", + "@mui/core-downloads-tracker": "^5.17.1", + "@mui/system": "^5.17.1", + "@mui/types": "~7.2.15", + "@mui/utils": "^5.17.1", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.17.1.tgz", + "integrity": "sha512-XMxU0NTYcKqdsG8LRmSoxERPXwMbp16sIXPcLVgLGII/bVNagX0xaheWAwFv8+zDK7tI3ajllkuD3GZZE++ICQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.17.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.18.0.tgz", + "integrity": "sha512-BN/vKV/O6uaQh2z5rXV+MBlVrEkwoS/TK75rFQ2mjxA7+NBo8qtTAOA4UaM0XeJfn7kh2wZ+xQw2HAx0u+TiBg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.18.0.tgz", + "integrity": "sha512-ojZGVcRWqWhu557cdO3pWHloIGJdzVtxs3rk0F9L+x55LsUjcMUVkEhiF7E4TMxZoF9MmIHGGs0ZX3FDLAf0Xw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/private-theming": "^5.17.1", + "@mui/styled-engine": "^5.18.0", + "@mui/types": "~7.2.15", + "@mui/utils": "^5.17.1", + "clsx": "^2.1.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.24", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz", + "integrity": "sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.17.1.tgz", + "integrity": "sha512-jEZ8FTqInt2WzxDV8bhImWBqeQRD99c/id/fq83H0ER9tFl+sfZlaAoCdznGvbSQQ9ividMxqSV2c7cC1vBcQg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/types": "~7.2.15", + "@types/prop-types": "^15.7.12", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.1.13", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz", + "integrity": "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", + "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", + "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.1" + } + }, + "node_modules/react-is": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz", + "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT", + "peer": true + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + } + } +} diff --git a/packages/components/package.json b/packages/components/package.json index 4c61680e..6c3d299f 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -10,5 +10,14 @@ "campground" ], "author": "Team Campground", - "license": "AGPL-3.0-or-later" + "license": "AGPL-3.0-or-later", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mui/joy": "^5.0.0-beta.52", + "react": "^19.1.1" + }, + "devDependencies": { + "@types/react": "^19.1.13" + } } diff --git a/packages/components/svg/SvgDefs.tsx b/packages/components/svg/SvgDefs.tsx new file mode 100644 index 00000000..20b2ae8b --- /dev/null +++ b/packages/components/svg/SvgDefs.tsx @@ -0,0 +1,12 @@ +import SvgLogo from "./SvgLogo"; +import { jsx } from "react/jsx-runtime"; + +export default function SvgDefs() { + return ( + jsx("svg", { style: { display: "none" }, children: + jsx("defs", { children: + jsx(SvgLogo, {}) + }) + }) + ) +} \ No newline at end of file diff --git a/packages/components/svg/SvgLogo.tsx b/packages/components/svg/SvgLogo.tsx new file mode 100644 index 00000000..b26f8a4b --- /dev/null +++ b/packages/components/svg/SvgLogo.tsx @@ -0,0 +1,13 @@ +import { jsx } from "react/jsx-runtime" + +export default function SvgLogo() { + return ( + jsx("symbol", { id: "cg-logo", viewBox: "0 0 128 128", fill: "none", children: + jsx("path", { + fill: "currentColor", + d: "M 60.8311,69.74142 49.623213,91.571274 a 1.2996556,1.2996556 58.588438 0 0 1.156175,1.893259 h 3.819337 a 2.7316262,2.7316262 142.07782 0 0 2.64868,-2.063589 l 4.035548,-16.000411 a 0.53675239,0.53675239 3.8004694e-4 0 1 1.040909,7e-6 l 4.035318,16.000397 a 2.7315888,2.7315888 37.922562 0 0 2.648653,2.063596 h 17.060503 a 7.0290828,7.0290828 16.844861 0 1 3.898998,1.180509 l 12.261906,8.174498 a 1.1389927,1.1389927 151.84486 0 0 1.77079,-0.9477 l 0,-6.279095 a 2.1282119,2.1282119 135 0 1 2.12821,-2.128212 h 1.77158 a 1.2996506,1.2996506 121.41146 0 0 1.15617,-1.893256 L 100.15584,74.236409 C 99.618996,73.190792 98.763878,72.345622 98.245868,72.345953 82.77247,72.209028 70.681956,70.792781 63.802346,68.576087 62.683925,68.215718 61.367941,68.695802 60.8311,69.74142 Z", + transform: "matrix(1.8247901,0,0,2.1860492,-80.778157,-116.31827)" + }) + }) + ); +} diff --git a/packages/components/svg/SvgUse.tsx b/packages/components/svg/SvgUse.tsx new file mode 100644 index 00000000..688de383 --- /dev/null +++ b/packages/components/svg/SvgUse.tsx @@ -0,0 +1,9 @@ +import { jsx } from "react/jsx-runtime"; + +export default function SvgUse({ id, className, width, height }: { id: string; className?: string; width?: string; height?: string; }) { + return ( + jsx("svg", { version: "2.0", className, width, height, children: + jsx("use", { href: `#${id}` }) + }) + ) +} \ No newline at end of file diff --git a/sites/campground.gg/src/theme/color.ts b/packages/components/theme/color.ts similarity index 100% rename from sites/campground.gg/src/theme/color.ts rename to packages/components/theme/color.ts diff --git a/packages/components/theme/common.ts b/packages/components/theme/common.ts new file mode 100644 index 00000000..2f940455 --- /dev/null +++ b/packages/components/theme/common.ts @@ -0,0 +1,25 @@ +import { mixHexColors } from "./color"; + +const _lightestToDarkest = { + 50: "#f5f3ff", + 100: "#e7e4f4", + 150: "#dcd8ec", + 200: "#c6c3d9", + 250: "#b7b4cd", + 300: "#9695b2", + 400: "#78799a", + + 500: mixHexColors("#78799a", "#373754", 0.5), + + 600: "#373754", + 700: "#2a2640", + 750: "#1f1b32", + 800: "#1a162a", + 850: "#151121", + 900: "#0e0b16", + 950: "#040409", +} as const; +export type ShadePaletteKeys = keyof typeof _lightestToDarkest; +export type ShadePalette = Record; +export const lightestToDarkest = _lightestToDarkest as ShadePalette; +export const darkestToLightest = Object.fromEntries(Object.entries(_lightestToDarkest).map(([key, value]) => [1000 - parseInt(key), value])) as ShadePalette; \ No newline at end of file diff --git a/packages/components/theme/dark.ts b/packages/components/theme/dark.ts new file mode 100644 index 00000000..fa0ca47d --- /dev/null +++ b/packages/components/theme/dark.ts @@ -0,0 +1,25 @@ +import type { ColorSystemOptions } from "@mui/joy/styles/extendTheme"; +import { generateColorScheme, generateNeutralColorScheme } from "./gen"; +import { lightestToDarkest } from "./common"; + +const shades = lightestToDarkest; + +const {background, neutral, text} = generateNeutralColorScheme(shades, false); +const darkColorScheme: ColorSystemOptions = { + shadowOpacity: "0.30", + palette: { + neutral, + text, + primary: generateColorScheme("#ff5a26", shades[950], shades[50]), + secondary: generateColorScheme("#ff2661", shades[950], shades[50]), + danger: generateColorScheme("#fe1c56", shades[950], shades[50]), + warning: generateColorScheme("#fea01c", shades[950], shades[50]), + success: generateColorScheme("#0cef43", shades[950], shades[50]), + info: generateColorScheme("#6026ff", shades[950], shades[50]), + // debug: generateColorScheme("#26f2ff", shades[950], shades[50]), + // note: generateColorScheme("#ca1cfe", shades[950], shades[50]), + background, + } +}; + +export default darkColorScheme; \ No newline at end of file diff --git a/sites/campground.gg/src/theme/font.ts b/packages/components/theme/font.ts similarity index 100% rename from sites/campground.gg/src/theme/font.ts rename to packages/components/theme/font.ts diff --git a/packages/components/theme/gen.ts b/packages/components/theme/gen.ts new file mode 100644 index 00000000..c18e42a1 --- /dev/null +++ b/packages/components/theme/gen.ts @@ -0,0 +1,151 @@ +import type { PaletteOptions, PaletteText } from "@mui/joy/styles/types"; +import { greyscaleHexColor, mixHexColors } from "./color"; +import type { lightestToDarkest } from "./common"; + +export const generateColorScheme = (typicalColour: string, background: string, counter: string): Partial => ({ + 1000: mixHexColors(typicalColour, background, 0.95), + 950: mixHexColors(typicalColour, background, 0.88), + 900: mixHexColors(typicalColour, background, 0.8), + 850: mixHexColors(typicalColour, background, 0.7), + 800: mixHexColors(typicalColour, background, 0.6), + 750: mixHexColors(typicalColour, background, 0.5), + 700: mixHexColors(typicalColour, background, 0.4), + 600: mixHexColors(typicalColour, background, 0.2), + 500: typicalColour, + 400: mixHexColors(typicalColour, counter, 0.2), + 300: mixHexColors(typicalColour, counter, 0.4), + 250: mixHexColors(typicalColour, counter, 0.5), + 200: mixHexColors(typicalColour, counter, 0.6), + 150: mixHexColors(typicalColour, counter, 0.7), + 100: mixHexColors(typicalColour, counter, 0.8), + 50: mixHexColors(typicalColour, counter, 0.88), + // Extra + "t-500": `${typicalColour}cc`, + border: `${typicalColour}0B`, + // Solid + solidBg: typicalColour, + solidColor: background, + solidHoverBg: mixHexColors(typicalColour, counter, 0.2), + // Plain + plainHoverBg: mixHexColors(typicalColour, background, 0.85), + plainActiveBg: mixHexColors(typicalColour, background, 0.9), + // Outlined + outlinedColor: mixHexColors(typicalColour, counter, 0.5), + outlinedBorder: mixHexColors(typicalColour, background, 0.55), + + outlinedHoverBg: mixHexColors(typicalColour, background, 0.9), + outlinedHoverColor: mixHexColors(typicalColour, counter, 0.6), + outlinedHoverBorder: mixHexColors(typicalColour, background, 0.45), + + outlinedActiveBg: mixHexColors(typicalColour, background, 0.8), + outlinedActiveColor: mixHexColors(typicalColour, counter, 0.7), + outlinedActiveBorder: mixHexColors(typicalColour, background, 0.35), + + outlinedDisabledColor: mixHexColors(greyscaleHexColor(typicalColour, 0.7), background, 0.5), + outlinedDisabledBorder: mixHexColors(typicalColour, background, 0.85), + // Soft + softBg: mixHexColors(typicalColour, background, 0.8), + softColor: mixHexColors(typicalColour, counter, 0.5), + + softHoverBg: mixHexColors(typicalColour, background, 0.7), + softHoverColor: mixHexColors(typicalColour, counter, 0.7), + + softActiveBg: mixHexColors(typicalColour, background, 0.6), + softActiveColor: mixHexColors(typicalColour, counter, 0.8), +}); + +type PickedPaletteOptions = "background" | "neutral" | "text"; +export const generateNeutralColorScheme = (shades: typeof lightestToDarkest, lightMode: boolean): { [k in PickedPaletteOptions]: Partial } => { + const modeTotalSubtraction = lightMode ? 50 * 2 : 0; + const modeAddition = -50; + const text: Pick = { + primary: shades[100], + secondary: shades[200], + tertiary: shades[400], + quartary: shades[500], + }; + + return { + text: { + ...text, + mid: shades[300], + icon: shades[300], + code: "#fe603f", + "code-keyword": "#fe603f", + "code-string": "#ff538b", + "code-number": "#c998f9", + "code-template": "#ea16b0", + "code-class": "#74a6f8", + "code-function": "#ffb95e", + "code-attribute": "#bcec6a", + }, + background: { + body: shades[(950 - modeTotalSubtraction) as 950], + surface: shades[900], + level1: shades[900], + level2: shades[lightMode ? 950 : 850], + level3: shades[(950 + (modeAddition * 1)) as 900], + level4: shades[(950 + (modeAddition * 2)) as 900], + level5: shades[(950 + (modeAddition * 3)) as 900], + + skeleton: shades[850], + skeletonPulse: shades[800], + + backdrop: `${shades[800]}aa`, + backdrop950: `${shades[950]}aa`, + transparent0: `${shades[950]}dd`, + transparent1: `${shades[950]}99`, + transparent2: `${shades[950]}55`, + popup: `#${shades[950]}`, + }, + neutral: { + ...shades, + // Extra + border: `${shades[50]}${(lightMode ? 0x2b : 0x0b).toString(16).padStart(2, "0")}`, + "t-950": `${shades[950]}cc`, + // Plain + plainColor: text.tertiary, + plainHoverColor: text.secondary, + plainActiveColor: text.tertiary, + plainDisabledColor: text.quartary, + + plainHoverBg: shades[850], + plainActiveBg: shades[950], + // Solid + solidBg: shades[750], + solidHoverBg: shades[700], + solidActiveBg: shades[800], + solidDisabledBg: shades[800], + + solidColor: text.primary, + solidHoverColor: text.primary, + solidActiveColor: text.primary, + solidDisabledColor: text.tertiary, + + // Outlined + outlinedColor: text.tertiary, + outlinedHoverColor: text.secondary, + outlinedActiveColor: text.tertiary, + outlinedDisabledColor: text.quartary, + + outlinedBorder: `${shades[400]}${(lightMode ? 0x40 : 0x20).toString(16).padStart(2, "0")}`, + outlinedDisabledBorder: `${shades[400]}${(lightMode ? 0x30 : 0x10).toString(16).padStart(2, "0")}`, + + outlinedBg: shades[900], + outlinedHoverBg: shades[850], + outlinedActiveBg: shades[950], + outlinedDisabledBg: shades[900], + + // Soft + softColor: text.tertiary, + softHoverColor: text.secondary, + softActiveColor: text.tertiary, + softDisabledColor: text.quartary, + + softBg: shades[850], + softHoverBg: shades[800], + softActiveBg: shades[750], + softDisabledBg: shades[850], + } + }; +} \ No newline at end of file diff --git a/packages/components/theme/index.ts b/packages/components/theme/index.ts new file mode 100644 index 00000000..a476b71f --- /dev/null +++ b/packages/components/theme/index.ts @@ -0,0 +1,294 @@ +import { extendTheme, type ColorPaletteProp, type ButtonOwnerState, type IconButtonOwnerState, type MenuButtonOwnerState, type ListItemButtonOwnerState, type Theme, type Palette } from "@mui/joy"; +import { bodyFontFamily, displayFontFamily } from "./font"; +import lightColorScheme from "./light"; +import darkColorScheme from "./dark"; +import "../types"; + +const complementaryPalettes: Record, keyof Palette> = { + primary: "secondary", + secondary: "primary", + success: "success", + warning: "danger", + danger: "danger", + info: "info", + // note: "debug", + // debug: "info", + neutral: "neutral", +}; + +const buttonAnimations = { + transitionDuration: "0.2s", + transitionProperty: "background, background-color, color, box-shadow, transform", + ":active": { + transform: "scale(0.925) translateY(2px)", + }, + ":hover": { + transform: "scale(1.0125)", + }, + // To not be ignored in modified buttons + "&:active:hover": { + transform: "scale(0.925) translateY(2px)", + } +}; +const ButtonStyling: (props: { ownerState: ButtonOwnerState | IconButtonOwnerState | MenuButtonOwnerState | ListItemButtonOwnerState, theme: Theme }) => any = ({ theme, ownerState: { variant, disabled, color, } }) => ({ + ...buttonAnimations, + ...(variant === "glow" ? { + background: disabled ? `linear-gradient(30deg, ${theme.vars.palette.neutral[500]}, ${theme.vars.palette.neutral[600]})` : `linear-gradient(30deg, ${theme.vars.palette[(color ?? "primary") as ColorPaletteProp][500]} ${!color || color === "primary" ? 0 : 20}%, ${theme.vars.palette[complementaryPalettes[color ?? "primary" as keyof typeof complementaryPalettes] as ColorPaletteProp][500]} ${!color || color === "primary" ? 100 : 130}%)`, + boxShadow: disabled ? theme.vars.shadow.md : `0px 0px 8px ${theme.vars.palette[(color ?? "primary") as ColorPaletteProp][500]}`, + color: theme.vars.palette.common.black, + ":not([disabled]):hover": { + boxShadow: `0 0 15px ${theme.vars.palette[(color ?? "primary") as ColorPaletteProp][400]}`, + }, + "::after": { + content: '""', + zIndex: 1, + top: 0, + left: 0, + right: 0, + bottom: 0, + backgroundColor: "transparent", + position: "absolute", + transition: "background 0.3s", + borderRadius: "var(--Button-radius, var(--radius-sm))", + }, + ":not([disabled]):hover::after": { + backgroundColor: "#FFF3" + } + } : {}) +}); + +const theme = extendTheme({ + zIndex: { + badge: 1100, + table: 1200, + modal: 1300, + tooltip: 1400, + popup: 1500, + snackbar: 1600, + }, + cssVarPrefix: ``, + typography: { + h1: { + letterSpacing: "0.05em", + }, + h2: { + letterSpacing: "0.025em", + }, + h3: { + letterSpacing: "0.025em", + }, + "title-lg": { + letterSpacing: "0.025em", + }, + "title-md": { + letterSpacing: "0.0125em", + }, + code: { + padding: `2px 4px`, + borderRadius: `var(--radius-md)`, + backgroundColor: `var(--palette-background-body)`, + color: `var(--palette-primary-300)`, + fontFamily: `var(--fontFamily-code)`, + display: "inline", + } + }, + fontFamily: { + body: bodyFontFamily, + display: displayFontFamily + }, + colorSchemes: { + light: lightColorScheme, + dark: darkColorScheme, + }, + shadow: { + insetSm: "inset 0 0 2px rgba(var(--shadowChannel) / var(--shadowOpacity))", + insetMd: "inset 0 0 4px rgba(var(--shadowChannel) / var(--shadowOpacity))", + insetLg: "inset 0 0 8px rgba(var(--shadowChannel) / var(--shadowOpacity))", + menu: "0 0 12px rgba(var(--shadowChannel) / calc(var(--shadowOpacity) * 2))", + }, + components: { + JoySkeleton: { + styleOverrides: { + root: ({ theme }) => ({ + "--unstable_pulse-bg": theme.vars.palette.background.skeletonPulse, + "::after": { + backgroundColor: theme.vars.palette.background.skeleton, + }, + "::before": { + backgroundColor: theme.vars.palette.background.skeleton, + }, + }), + }, + }, + JoySwitch: { + styleOverrides: { + track: { + transition: "background 0.3s", + }, + thumb: { + transitionProperty: "left, background", + transitionDuration: "0.3s", + }, + }, + }, + JoyRadio: { + styleOverrides: { + action: { + transition: "background 0.2s", + }, + }, + }, + JoyAvatar: { + styleOverrides: { + root: ({ theme, ownerState: { size } }) => { + const sizeXAmount = (size?.split("x").length ?? 1) - 1; + return { + fontFamily: "var(--fontFamily-display)", + fontWeight: 700, + ...(size?.includes("x") ? { + fontSize: `${sizeXAmount / 2 + 1}rem`, + width: theme.spacing(7 + (sizeXAmount * 2)), + height: theme.spacing(7 + (sizeXAmount * 2)), + } : {}) + } + } + } + }, + JoyModal: { + defaultProps: { + container: () => document.getElementById("root"), + }, + styleOverrides: { + root: { + display: "grid", + gridTemplateColumns: "1fr", + gridTemplateRows: "1fr", + alignItems: "center", + justifyItems: "center", + }, + backdrop: () => ({ + backdropFilter: "none", + }), + } + }, + JoyModalDialog: { + styleOverrides: { + root: ({ theme }) => ({ + animation: "appear-animation ease-out 0.125s", + transform: "none", + top: 0, + left: 0, + gridColumn: "1 / 2", + gridRow: "1 / 2", + position: "relative", + overflow: "hidden", + [theme.breakpoints.up("md")]: { + "&.MuiModalDialog-layoutFullscreen": { + borderRadius: theme.vars.radius.xl, + } + }, + [theme.breakpoints.only("md")]: { + "&.MuiModalDialog-layoutFullscreen": { + width: `calc(100% - 64px)`, + height: `calc(100% - 32px)`, + } + }, + [theme.breakpoints.up("lg")]: { + "&.MuiModalDialog-layoutFullscreen": { + width: `calc(100% - 96px)`, + height: `calc(100% - 48px)`, + } + } + }), + } + }, + JoyMenu: { + defaultProps: { + container: () => document.getElementById("root"), + }, + styleOverrides: { + root: ({ theme }) => ({ + "--List-padding": "var(--ListDivider-gap)", + border: `solid 1px var(--palette-neutral-border)`, + animation: "appear-animation-opacity ease-out 0.125s", + boxShadow: "var(--shadow-menu)", + }) + } + }, + JoyMenuItem: { + styleOverrides: { + root: ({ theme }) => ({ + ...buttonAnimations, + borderRadius: theme.vars.radius.md, + }), + }, + }, + JoyMenuButton: { + styleOverrides: { + root: ButtonStyling, + }, + }, + JoyListItem: { + styleOverrides: { + root: { + "&.MuiListItem-variantSoft": { + ...buttonAnimations, + }, + }, + }, + }, + JoyListItemButton: { + styleOverrides: { + root: ButtonStyling, + }, + }, + JoyButton: { + styleOverrides: { + root: ButtonStyling, + }, + }, + JoyIconButton: { + styleOverrides: { + root: ButtonStyling, + }, + }, + JoyCard: { + styleOverrides: { + root: ({ theme }) => ({ + boxShadow: theme.vars.shadow.sm, + }), + } + }, + JoyTabList: { + styleOverrides: { + root: ({ theme }) => ({ + backgroundColor: theme.vars.palette.background.body, + borderRadius: theme.vars.radius.md, + borderBottom: "none", + boxShadow: "none", + }) + } + }, + JoyTab: { + styleOverrides: { + root: ({ theme }) => ({ + borderRadius: theme.vars.radius.md, + borderBottom: "none", + flex: 1, + "::after": { + display: "none", + } + }) + } + }, + JoyTabPanel: { + styleOverrides: { + root: () => ({ + flex: 1, + }) + } + }, + } +}); + +export default theme; \ No newline at end of file diff --git a/packages/components/theme/light.ts b/packages/components/theme/light.ts new file mode 100644 index 00000000..cf1278a8 --- /dev/null +++ b/packages/components/theme/light.ts @@ -0,0 +1,25 @@ +import type { ColorSystemOptions } from "@mui/joy/styles/extendTheme"; +import { generateColorScheme, generateNeutralColorScheme } from "./gen"; +import { darkestToLightest } from "./common"; + +const shades = darkestToLightest; + +const {background, neutral, text} = generateNeutralColorScheme(shades, true); +const lightColorScheme: ColorSystemOptions = { + shadowOpacity: "0.10", + palette: { + neutral, + text, + primary: generateColorScheme("#ff5a26", shades[950], shades[50]), + secondary: generateColorScheme("#ff2661", shades[950], shades[50]), + danger: generateColorScheme("#fe1c56", shades[950], shades[50]), + warning: generateColorScheme("#ff851f", shades[950], shades[50]), + success: generateColorScheme("#2bfa5e", shades[950], shades[50]), + info: generateColorScheme("#6026ff", shades[950], shades[50]), + // debug: generateColorScheme("#26f2ff", shades[950], shades[50]), + // note: generateColorScheme("#ca1cfe", shades[950], shades[50]), + background, + } +}; + +export default lightColorScheme; \ No newline at end of file diff --git a/packages/components/types/colorSystem.ts b/packages/components/types/colorSystem.ts new file mode 100644 index 00000000..baf29303 --- /dev/null +++ b/packages/components/types/colorSystem.ts @@ -0,0 +1,55 @@ + +import type { PaletteRange } from "@mui/joy/styles/types"; + +export interface Palette { + secondary: PaletteRange; + info: PaletteRange; + // debug: PaletteRange; + // note: PaletteRange; +} +export interface ColorPalettePropOverrides { + secondary: true; + info: true; + // debug: true; + // note: true; +} +// Add new text colours +export interface PaletteTextOverrides { + code: true; + mid: true; + quartary: true; + ["code-keyword"]: true; + ["code-string"]: true; + ["code-number"]: true; + ["code-template"]: true; + ["code-function"]: true; + ["code-class"]: true; + ["code-attribute"]: true; +} +// Add new palette ranges +export interface PaletteRangeOverrides { + 1000: true; + 950: true; + 850: true; + 750: true; + 250: true; + 150: true; + 50: true; + border: true; + ["t-950"]: true; + ["t-500"]: true; +} +// Add new backgrounds +export interface PaletteBackgroundOverrides { + backdrop950: true; + + transparent0: true; + transparent1: true; + transparent2: true; + + level4: true; + level5: true; + + skeleton: true; + skeletonPulse: true; +} diff --git a/packages/components/types/components.ts b/packages/components/types/components.ts new file mode 100644 index 00000000..d9aa6666 --- /dev/null +++ b/packages/components/types/components.ts @@ -0,0 +1,8 @@ +export interface ButtonPropsVariantOverrides { + glow: true; +} +export interface AvatarPropsSizeOverrides { + xl: true; + xxl: true; + xxxl: true; +} \ No newline at end of file diff --git a/packages/components/types/index.ts b/packages/components/types/index.ts new file mode 100644 index 00000000..45c9d004 --- /dev/null +++ b/packages/components/types/index.ts @@ -0,0 +1,25 @@ +import type { TypographySystemOverrides as TextSystemOverrides } from "./typography"; +import type { ShadowOverrides as CustomShadowOverrides } from "./shadow"; +import type { Palette as ColorPalette, ColorPalettePropOverrides as ColorPropOverrides, PaletteTextOverrides as ColorTextOverrides, PaletteRangeOverrides as ColorRangeOverrides, PaletteBackgroundOverrides as ColorBackgroundOverrides } from "./colorSystem"; +import type { ButtonPropsVariantOverrides as ComponentButtonPropsVariantOverrides } from "./components"; + +declare module "@mui/joy/styles/types/shadow" { + interface ShadowOverrides extends CustomShadowOverrides { } +} + +declare module "@mui/joy" { + interface ButtonPropsVariantOverrides extends ComponentButtonPropsVariantOverrides { } +} + +declare module "@mui/joy/styles/types/typography" { + interface TypographySystemOverrides extends TextSystemOverrides { } +} + +// Add new colours +declare module "@mui/joy/styles/types/colorSystem" { + interface Palette extends ColorPalette { } + interface ColorPalettePropOverrides extends ColorPropOverrides { } + interface PaletteTextOverrides extends ColorTextOverrides { } + interface PaletteRangeOverrides extends ColorRangeOverrides { } + interface PaletteBackgroundOverrides extends ColorBackgroundOverrides {} +} \ No newline at end of file diff --git a/packages/components/types/shadow.ts b/packages/components/types/shadow.ts new file mode 100644 index 00000000..49e42e53 --- /dev/null +++ b/packages/components/types/shadow.ts @@ -0,0 +1,6 @@ +export interface ShadowOverrides { + insetSm: true; + insetMd: true; + insetLg: true; + menu: true; +} \ No newline at end of file diff --git a/packages/components/types/typography.ts b/packages/components/types/typography.ts new file mode 100644 index 00000000..82c4ddda --- /dev/null +++ b/packages/components/types/typography.ts @@ -0,0 +1,14 @@ + +import { } from "@mui/joy"; + +// Add new text levels +export interface TypographySystemOverrides { + code: true; + ["code-keyword"]: true; + ["code-string"]: true; + ["code-number"]: true; + ["code-template"]: true; + ["code-function"]: true; + ["code-class"]: true; + ["code-attribute"]: true; +} diff --git a/packages/components/util.ts b/packages/components/util.ts new file mode 100644 index 00000000..cbb8defc --- /dev/null +++ b/packages/components/util.ts @@ -0,0 +1,6 @@ +export const loremIpsum = { + sm: `Lorem ipsum dolor sit amet`, + md: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.`, + lg: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.`, + xl: `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.` +}; \ No newline at end of file diff --git a/sites/app.campground.gg/.gitignore b/sites/app.campground.gg/.gitignore new file mode 100644 index 00000000..9321f0a1 --- /dev/null +++ b/sites/app.campground.gg/.gitignore @@ -0,0 +1,30 @@ +# campground +config.json + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +.react-router +build + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/sites/app.campground.gg/README.md b/sites/app.campground.gg/README.md new file mode 100644 index 00000000..6a5edae8 --- /dev/null +++ b/sites/app.campground.gg/README.md @@ -0,0 +1,11 @@ +# App.Campground.GG + +This contains the source code for `app.campground.gg` web-app client, the interface you interact with to use the Campground platform on the web and likely Electron or Electron-like frameworks. + +## API + +This web-app interacts with Campground back-end API and requires proper configuration. To configure it, it is recommended to copy `config.example.json` as `config.json` and likely change the values in the configuration. + +## CSS + +You can also change the CSS of the Campground web-app client by editing `src/custom.css`. It is recommended to use MUI variables instead of directly using colours, as it may not result in appearance that works with both light and dark themes. \ No newline at end of file diff --git a/sites/app.campground.gg/api.config.ts b/sites/app.campground.gg/api.config.ts new file mode 100644 index 00000000..86785398 --- /dev/null +++ b/sites/app.campground.gg/api.config.ts @@ -0,0 +1,6 @@ +import config from "./config.json"; + +export const defaultAppApiUrl = config.pdsUrl; +export const defaultAppBackendUrl = config.backendUrl; +export const defaultBackendDomain = config.backendDomain; +export const defaultXrpcPrefix = `/xrpc/`; \ No newline at end of file diff --git a/sites/app.campground.gg/config.example.json b/sites/app.campground.gg/config.example.json new file mode 100644 index 00000000..6002b519 --- /dev/null +++ b/sites/app.campground.gg/config.example.json @@ -0,0 +1,5 @@ +{ + "pdsUrl": "http://localhost:2583", + "backendUrl": "http://localhost:8080", + "backendDomain": "localhost:8080" +} \ No newline at end of file diff --git a/sites/app.campground.gg/eslint.config.js b/sites/app.campground.gg/eslint.config.js new file mode 100644 index 00000000..ca07660a --- /dev/null +++ b/sites/app.campground.gg/eslint.config.js @@ -0,0 +1,28 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + { ignores: ['dist'] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}', '.react-router/types/**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + }, +) diff --git a/sites/app.campground.gg/index.html b/sites/app.campground.gg/index.html new file mode 100644 index 00000000..865f8eba --- /dev/null +++ b/sites/app.campground.gg/index.html @@ -0,0 +1,13 @@ + + + + + + + app-campground-gg + + +
+ + + diff --git a/sites/app.campground.gg/package-lock.json b/sites/app.campground.gg/package-lock.json new file mode 100644 index 00000000..3d82f0fe --- /dev/null +++ b/sites/app.campground.gg/package-lock.json @@ -0,0 +1,8469 @@ +{ + "name": "app-campground-gg", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "app-campground-gg", + "version": "0.0.0", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@fontsource/nunito-sans": "^5.2.7", + "@fontsource/quicksand": "^5.2.10", + "@mantine/hooks": "^8.3.1", + "@mui/joy": "^5.0.0-beta.52", + "@react-router/fs-routes": "^7.9.1", + "@react-router/node": "^7.7.1", + "@react-router/serve": "^7.7.1", + "@tabler/icons-react": "^3.35.0", + "@types/mdast": "^4.0.4", + "cbor2": "^2.0.1", + "components": "file:../../packages/components", + "highlight.js": "^11.11.1", + "isbot": "^5", + "mdast-util-find-and-replace": "^3.0.2", + "mdast-util-from-markdown": "^2.0.2", + "mdast-util-gfm": "^3.1.0", + "mdast-util-to-markdown": "^2.1.2", + "micromark-extension-gfm": "^3.0.0", + "ms": "^2.1.3", + "react": "^19.1.1", + "react-colorful": "^5.6.1", + "react-dom": "^19.1.1", + "react-intl": "^7.1.11", + "react-markdown": "^10.1.0", + "react-router": "^7.7.1", + "react-router-dom": "^7.9.3", + "remark-breaks": "^4.0.0", + "remark-gfm": "^4.0.1", + "slate": "^0.118.1", + "slate-history": "^0.113.1", + "slate-react": "^0.118.2", + "uuid": "^13.0.0", + "vite-plugin-static-copy": "^2.3.0" + }, + "devDependencies": { + "@eslint/js": "^9.36.0", + "@react-router/dev": "^7.7.1", + "@types/ms": "^2.1.0", + "@types/react": "^19.1.13", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.3", + "babel-plugin-react-compiler": "^19.1.0-rc.3", + "eslint": "^9.36.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.4.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.44.0", + "vite": "^6.2.0", + "vite-tsconfig-paths": "^5.1.4" + } + }, + "../../packages/components": { + "version": "1.0.0", + "license": "AGPL-3.0-or-later", + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mui/joy": "^5.0.0-beta.52", + "react": "^19.1.1" + }, + "devDependencies": { + "@types/react": "^19.1.13" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", + "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz", + "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz", + "integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==", + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.27.1.tgz", + "integrity": "sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.3", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.4", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cto.af/wtf8": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@cto.af/wtf8/-/wtf8-0.0.2.tgz", + "integrity": "sha512-ATm4UQiKrdm5GnU6BvIwUDN+LDEtt23zuzKFpnfDT59ULAd0aMYm/nSFzbSO02garLcXumRC13PzNfa7BsfvSg==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.4.0.tgz", + "integrity": "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz", + "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz", + "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz", + "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz", + "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", + "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz", + "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz", + "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz", + "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz", + "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz", + "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz", + "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz", + "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz", + "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz", + "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz", + "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz", + "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz", + "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz", + "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz", + "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz", + "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz", + "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz", + "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz", + "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz", + "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz", + "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz", + "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.1.tgz", + "integrity": "sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", + "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.4.tgz", + "integrity": "sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.6.tgz", + "integrity": "sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.4" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, + "node_modules/@fontsource/nunito-sans": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@fontsource/nunito-sans/-/nunito-sans-5.2.7.tgz", + "integrity": "sha512-Vh+xhMsrH1eA9Q83Va82su3rDmNilYg+ur/TfHAOyr5kTpCOWMB8B1tDoJvSe+yJPpZ2jEWtnBHGqI2LUPVxUA==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/quicksand": { + "version": "5.2.10", + "resolved": "https://registry.npmjs.org/@fontsource/quicksand/-/quicksand-5.2.10.tgz", + "integrity": "sha512-rck0ccT6vJF9RnbSW2ON1grq5qFZvjVOGvYIUixATXF8mNh4KglD+8Sn8QpRgKQBSBJF5yOR3SBYBWPg/Y8YbQ==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@formatjs/ecma402-abstract": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz", + "integrity": "sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA==", + "license": "MIT", + "dependencies": { + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/intl-localematcher": "0.6.1", + "decimal.js": "^10.4.3", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/fast-memoize": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz", + "integrity": "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-messageformat-parser": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.2.tgz", + "integrity": "sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.4", + "@formatjs/icu-skeleton-parser": "1.8.14", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/icu-skeleton-parser": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.14.tgz", + "integrity": "sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.4", + "tslib": "^2.8.0" + } + }, + "node_modules/@formatjs/intl": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-3.1.6.tgz", + "integrity": "sha512-tDkXnA4qpIFcDWac8CyVJq6oW8DR7W44QDUBsfXWIIJD/FYYen0QoH46W7XsVMFfPOVKkvbufjboZrrWbEfmww==", + "license": "MIT", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.4", + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/icu-messageformat-parser": "2.11.2", + "intl-messageformat": "10.7.16", + "tslib": "^2.8.0" + }, + "peerDependencies": { + "typescript": "^5.6.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@formatjs/intl-localematcher": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.6.1.tgz", + "integrity": "sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@juggle/resize-observer": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz", + "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==", + "license": "Apache-2.0" + }, + "node_modules/@mantine/hooks": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-8.3.1.tgz", + "integrity": "sha512-lQutBS+Q0iz/cNFvdrsYassPWo3RtWcmDGJeOtKfHigLzFOhxUuLOkQgepDbMf3WcVMB/tist6Px1PQOv57JTw==", + "license": "MIT", + "peerDependencies": { + "react": "^18.x || ^19.x" + } + }, + "node_modules/@mjackson/node-fetch-server": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@mjackson/node-fetch-server/-/node-fetch-server-0.2.0.tgz", + "integrity": "sha512-EMlH1e30yzmTpGLQjlFmaDAjyOeZhng1/XCd7DExR8PNAnG/G1tyruZxEoUe11ClnwGhGrtsdnyyUx1frSzjng==", + "license": "MIT" + }, + "node_modules/@mui/base": { + "version": "5.0.0-beta.40-1", + "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40-1.tgz", + "integrity": "sha512-agKXuNNy0bHUmeU7pNmoZwNFr7Hiyhojkb9+2PVyDG5+6RafYuyMgbrav8CndsB7KUc/U51JAw9vKNDLYBzaUA==", + "deprecated": "This package has been replaced by @base-ui-components/react", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@floating-ui/react-dom": "^2.0.8", + "@mui/types": "~7.2.15", + "@mui/utils": "^5.17.1", + "@popperjs/core": "^2.11.8", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/core-downloads-tracker": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.18.0.tgz", + "integrity": "sha512-jbhwoQ1AY200PSSOrNXmrFCaSDSJWP7qk6urkTmIirvRXDROkqe+QwcLlUiw/PrREwsIF/vm3/dAXvjlMHF0RA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/joy": { + "version": "5.0.0-beta.52", + "resolved": "https://registry.npmjs.org/@mui/joy/-/joy-5.0.0-beta.52.tgz", + "integrity": "sha512-e8jQanA5M1f/X52mJrw0UIW8Er7EAHuLuigmGFw7yIsAgIluhIP4rZ7JcbVrUi6z5Gk0weC9QWUUtjLejAbO8g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/base": "5.0.0-beta.40-1", + "@mui/core-downloads-tracker": "^5.17.1", + "@mui/system": "^5.17.1", + "@mui/types": "~7.2.15", + "@mui/utils": "^5.17.1", + "clsx": "^2.1.0", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/private-theming": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.17.1.tgz", + "integrity": "sha512-XMxU0NTYcKqdsG8LRmSoxERPXwMbp16sIXPcLVgLGII/bVNagX0xaheWAwFv8+zDK7tI3ajllkuD3GZZE++ICQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/utils": "^5.17.1", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.18.0.tgz", + "integrity": "sha512-BN/vKV/O6uaQh2z5rXV+MBlVrEkwoS/TK75rFQ2mjxA7+NBo8qtTAOA4UaM0XeJfn7kh2wZ+xQw2HAx0u+TiBg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@emotion/cache": "^11.13.5", + "@emotion/serialize": "^1.3.3", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.18.0.tgz", + "integrity": "sha512-ojZGVcRWqWhu557cdO3pWHloIGJdzVtxs3rk0F9L+x55LsUjcMUVkEhiF7E4TMxZoF9MmIHGGs0ZX3FDLAf0Xw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/private-theming": "^5.17.1", + "@mui/styled-engine": "^5.18.0", + "@mui/types": "~7.2.15", + "@mui/utils": "^5.17.1", + "clsx": "^2.1.0", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.24", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.24.tgz", + "integrity": "sha512-3c8tRt/CbWZ+pEg7QpSwbdxOk36EfmhbKf6AGZsD1EcLDLTSZoxxJ86FVtcjxvjuhdyBiWKSTGZFaXCnidO2kw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.17.1.tgz", + "integrity": "sha512-jEZ8FTqInt2WzxDV8bhImWBqeQRD99c/id/fq83H0ER9tFl+sfZlaAoCdznGvbSQQ9ividMxqSV2c7cC1vBcQg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.23.9", + "@mui/types": "~7.2.15", + "@types/prop-types": "^15.7.12", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^19.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/git": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", + "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@npmcli/git/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-4.0.1.tgz", + "integrity": "sha512-lRCEGdHZomFsURroh522YvA/2cVb9oPIJrjHanCJZkiasz1BzcnLr3tBJhlV7S86MBJBuAQ33is2D60YitZL2Q==", + "license": "ISC", + "dependencies": { + "@npmcli/git": "^4.1.0", + "glob": "^10.2.2", + "hosted-git-info": "^6.1.1", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/json-parse-even-better-errors": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.2.tgz", + "integrity": "sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==", + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", + "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", + "license": "ISC", + "dependencies": { + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@react-router/dev": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@react-router/dev/-/dev-7.9.1.tgz", + "integrity": "sha512-fW/qubsdHq1nsufHPLpXa6hiNvXXV9JBtWqRlJ02OOhFeaWERZw4rGoHjG1DCg8/QTTadgbzplmP97ZnzWPkcA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.7", + "@babel/generator": "^7.27.5", + "@babel/parser": "^7.27.7", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/preset-typescript": "^7.27.1", + "@babel/traverse": "^7.27.7", + "@babel/types": "^7.27.7", + "@npmcli/package-json": "^4.0.1", + "@react-router/node": "7.9.1", + "arg": "^5.0.1", + "babel-dead-code-elimination": "^1.0.6", + "chokidar": "^4.0.0", + "dedent": "^1.5.3", + "es-module-lexer": "^1.3.1", + "exit-hook": "2.2.1", + "isbot": "^5.1.11", + "jsesc": "3.0.2", + "lodash": "^4.17.21", + "pathe": "^1.1.2", + "picocolors": "^1.1.1", + "prettier": "^3.6.2", + "react-refresh": "^0.14.0", + "semver": "^7.3.7", + "set-cookie-parser": "^2.6.0", + "tinyglobby": "^0.2.14", + "valibot": "^0.41.0", + "vite-node": "^3.2.2" + }, + "bin": { + "react-router": "bin.js" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@react-router/serve": "^7.9.1", + "@vitejs/plugin-rsc": "*", + "react-router": "^7.9.1", + "typescript": "^5.1.0", + "vite": "^5.1.0 || ^6.0.0 || ^7.0.0", + "wrangler": "^3.28.2 || ^4.0.0" + }, + "peerDependenciesMeta": { + "@react-router/serve": { + "optional": true + }, + "@vitejs/plugin-rsc": { + "optional": true + }, + "typescript": { + "optional": true + }, + "wrangler": { + "optional": true + } + } + }, + "node_modules/@react-router/dev/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@react-router/dev/node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@react-router/dev/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-router/express": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@react-router/express/-/express-7.9.1.tgz", + "integrity": "sha512-d1sfsD3AJXZj+C5k3jAmxAD3vJXGfoh3lNmtSwxp0NdZFHI54zPC5S9o80cy3P8p6Gc7XzSEQJYk9k7fAM/AIw==", + "license": "MIT", + "dependencies": { + "@react-router/node": "7.9.1" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "express": "^4.17.1 || ^5", + "react-router": "7.9.1", + "typescript": "^5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@react-router/fs-routes": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@react-router/fs-routes/-/fs-routes-7.9.1.tgz", + "integrity": "sha512-K97pQ7PIUJnmYPzoC5lrJxr3XKDn5ZLBMkp403usQJlucpP2NUfRw7I5N3NdqQ5XDbPEyROOJr6wsZnWGPPC7g==", + "license": "MIT", + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@react-router/dev": "^7.9.1", + "typescript": "^5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@react-router/fs-routes/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@react-router/fs-routes/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@react-router/node": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@react-router/node/-/node-7.9.1.tgz", + "integrity": "sha512-XfyVLM+sDUDB1frGNr7iqaKNglrPwBiUp8+sFdL4///bngy49pUb2RuEtn2J2Cy5yjL+IlKbjJFrsmfimLBmeg==", + "license": "MIT", + "dependencies": { + "@mjackson/node-fetch-server": "^0.2.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react-router": "7.9.1", + "typescript": "^5.1.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@react-router/serve": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@react-router/serve/-/serve-7.9.1.tgz", + "integrity": "sha512-yVBSb5KsNCdkSoOk186/M5GJtcIvKE32Ax9LhXySVpM+suCSjucI+p2TXDOJIYsBqr2aKcBl/bNBm5sIJxG/HA==", + "license": "MIT", + "dependencies": { + "@react-router/express": "7.9.1", + "@react-router/node": "7.9.1", + "compression": "^1.7.4", + "express": "^4.19.2", + "get-port": "5.1.1", + "morgan": "^1.10.0", + "source-map-support": "^0.5.21" + }, + "bin": { + "react-router-serve": "bin.js" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react-router": "7.9.1" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.35", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.35.tgz", + "integrity": "sha512-slYrCpoxJUqzFDDNlvrOYRazQUNRvWPjXA17dAOISY3rDMxX6k8K4cj2H+hEYMHF81HO3uNd5rHVigAWRM5dSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.2.tgz", + "integrity": "sha512-o3pcKzJgSGt4d74lSZ+OCnHwkKBeAbFDmbEm5gg70eA8VkyCuC/zV9TwBnmw6VjDlRdF4Pshfb+WE9E6XY1PoQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.2.tgz", + "integrity": "sha512-cqFSWO5tX2vhC9hJTK8WAiPIm4Q8q/cU8j2HQA0L3E1uXvBYbOZMhE2oFL8n2pKB5sOCHY6bBuHaRwG7TkfJyw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.2.tgz", + "integrity": "sha512-vngduywkkv8Fkh3wIZf5nFPXzWsNsVu1kvtLETWxTFf/5opZmflgVSeLgdHR56RQh71xhPhWoOkEBvbehwTlVA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.2.tgz", + "integrity": "sha512-h11KikYrUCYTrDj6h939hhMNlqU2fo/X4NB0OZcys3fya49o1hmFaczAiJWVAFgrM1NCP6RrO7lQKeVYSKBPSQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.2.tgz", + "integrity": "sha512-/eg4CI61ZUkLXxMHyVlmlGrSQZ34xqWlZNW43IAU4RmdzWEx0mQJ2mN/Cx4IHLVZFL6UBGAh+/GXhgvGb+nVxw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.2.tgz", + "integrity": "sha512-QOWgFH5X9+p+S1NAfOqc0z8qEpJIoUHf7OWjNUGOeW18Mx22lAUOiA9b6r2/vpzLdfxi/f+VWsYjUOMCcYh0Ng==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.2.tgz", + "integrity": "sha512-kDWSPafToDd8LcBYd1t5jw7bD5Ojcu12S3uT372e5HKPzQt532vW+rGFFOaiR0opxePyUkHrwz8iWYEyH1IIQA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.2.tgz", + "integrity": "sha512-gKm7Mk9wCv6/rkzwCiUC4KnevYhlf8ztBrDRT9g/u//1fZLapSRc+eDZj2Eu2wpJ+0RzUKgtNijnVIB4ZxyL+w==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.2.tgz", + "integrity": "sha512-66lA8vnj5mB/rtDNwPgrrKUOtCLVQypkyDa2gMfOefXK6rcZAxKLO9Fy3GkW8VkPnENv9hBkNOFfGLf6rNKGUg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.2.tgz", + "integrity": "sha512-s+OPucLNdJHvuZHuIz2WwncJ+SfWHFEmlC5nKMUgAelUeBUnlB4wt7rXWiyG4Zn07uY2Dd+SGyVa9oyLkVGOjA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.2.tgz", + "integrity": "sha512-8wTRM3+gVMDLLDdaT6tKmOE3lJyRy9NpJUS/ZRWmLCmOPIJhVyXwjBo+XbrrwtV33Em1/eCTd5TuGJm4+DmYjw==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.2.tgz", + "integrity": "sha512-6yqEfgJ1anIeuP2P/zhtfBlDpXUb80t8DpbYwXQ3bQd95JMvUaqiX+fKqYqUwZXqdJDd8xdilNtsHM2N0cFm6A==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.2.tgz", + "integrity": "sha512-sshYUiYVSEI2B6dp4jMncwxbrUqRdNApF2c3bhtLAU0qA8Lrri0p0NauOsTWh3yCCCDyBOjESHMExonp7Nzc0w==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.2.tgz", + "integrity": "sha512-duBLgd+3pqC4MMwBrKkFxaZerUxZcYApQVC5SdbF5/e/589GwVvlRUnyqMFbM8iUSb1BaoX/3fRL7hB9m2Pj8Q==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.2.tgz", + "integrity": "sha512-tzhYJJidDUVGMgVyE+PmxENPHlvvqm1KILjjZhB8/xHYqAGeizh3GBGf9u6WdJpZrz1aCpIIHG0LgJgH9rVjHQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.2.tgz", + "integrity": "sha512-opH8GSUuVcCSSyHHcl5hELrmnk4waZoVpgn/4FDao9iyE4WpQhyWJ5ryl5M3ocp4qkRuHfyXnGqg8M9oKCEKRA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.2.tgz", + "integrity": "sha512-LSeBHnGli1pPKVJ79ZVJgeZWWZXkEe/5o8kcn23M8eMKCUANejchJbF/JqzM4RRjOJfNRhKJk8FuqL1GKjF5oQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.2.tgz", + "integrity": "sha512-uPj7MQ6/s+/GOpolavm6BPo+6CbhbKYyZHUDvZ/SmJM7pfDBgdGisFX3bY/CBDMg2ZO4utfhlApkSfZ92yXw7Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.2.tgz", + "integrity": "sha512-Z9MUCrSgIaUeeHAiNkm3cQyst2UhzjPraR3gYYfOjAuZI7tcFRTOD+4cHLPoS/3qinchth+V56vtqz1Tv+6KPA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.2.tgz", + "integrity": "sha512-+GnYBmpjldD3XQd+HMejo+0gJGwYIOfFeoBQv32xF/RUIvccUz20/V6Otdv+57NE70D5pa8W/jVGDoGq0oON4A==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.2.tgz", + "integrity": "sha512-ApXFKluSB6kDQkAqZOKXBjiaqdF1BlKi+/eqnYe9Ee7U2K3pUDKsIyr8EYm/QDHTJIM+4X+lI0gJc3TTRhd+dA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.2.tgz", + "integrity": "sha512-ARz+Bs8kY6FtitYM96PqPEVvPXqEZmPZsSkXvyX19YzDqkCaIlhCieLLMI5hxO9SRZ2XtCtm8wxhy0iJ2jxNfw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tabler/icons": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.35.0.tgz", + "integrity": "sha512-yYXe+gJ56xlZFiXwV9zVoe3FWCGuZ/D7/G4ZIlDtGxSx5CGQK110wrnT29gUj52kEZoxqF7oURTk97GQxELOFQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-react": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.35.0.tgz", + "integrity": "sha512-XG7t2DYf3DyHT5jxFNp5xyLVbL4hMJYJhiSdHADzAjLRYfL7AnjlRfiHDHeXxkb2N103rEIvTsBRazxXtAUz2g==", + "license": "MIT", + "dependencies": { + "@tabler/icons": "3.35.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "react": ">= 16" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/estree-jsx": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz", + "integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==", + "license": "MIT", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz", + "integrity": "sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==", + "license": "MIT", + "dependencies": { + "hoist-non-react-statics": "^3.3.0" + }, + "peerDependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.1.13", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.13.tgz", + "integrity": "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ==", + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.9.tgz", + "integrity": "sha512-qXRuZaOsAdXKFyOhRBg6Lqqc0yay13vN7KrIg4L7N4aaHN68ma9OK3NE1BoDFgFOTfM7zg+3/8+2n8rLUH3OKQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.44.1.tgz", + "integrity": "sha512-molgphGqOBT7t4YKCSkbasmu1tb1MgrZ2szGzHbclF7PNmOkSTQVHy+2jXOSnxvR3+Xe1yySHFZoqMpz3TfQsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.44.1", + "@typescript-eslint/type-utils": "8.44.1", + "@typescript-eslint/utils": "8.44.1", + "@typescript-eslint/visitor-keys": "8.44.1", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.44.1", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.44.1.tgz", + "integrity": "sha512-EHrrEsyhOhxYt8MTg4zTF+DJMuNBzWwgvvOYNj/zm1vnaD/IC5zCXFehZv94Piqa2cRFfXrTFxIvO95L7Qc/cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.44.1", + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/typescript-estree": "8.44.1", + "@typescript-eslint/visitor-keys": "8.44.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.44.1.tgz", + "integrity": "sha512-ycSa60eGg8GWAkVsKV4E6Nz33h+HjTXbsDT4FILyL8Obk5/mx4tbvCNsLf9zret3ipSumAOG89UcCs/KRaKYrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.44.1", + "@typescript-eslint/types": "^8.44.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.44.1.tgz", + "integrity": "sha512-NdhWHgmynpSvyhchGLXh+w12OMT308Gm25JoRIyTZqEbApiBiQHD/8xgb6LqCWCFcxFtWwaVdFsLPQI3jvhywg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/visitor-keys": "8.44.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.44.1.tgz", + "integrity": "sha512-B5OyACouEjuIvof3o86lRMvyDsFwZm+4fBOqFHccIctYgBjqR3qT39FBYGN87khcgf0ExpdCBeGKpKRhSFTjKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.44.1.tgz", + "integrity": "sha512-KdEerZqHWXsRNKjF9NYswNISnFzXfXNDfPxoTh7tqohU/PRIbwTmsjGK6V9/RTYWau7NZvfo52lgVk+sJh0K3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/typescript-estree": "8.44.1", + "@typescript-eslint/utils": "8.44.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.44.1.tgz", + "integrity": "sha512-Lk7uj7y9uQUOEguiDIDLYLJOrYHQa7oBiURYVFqIpGxclAFQ78f6VUOM8lI2XEuNOKNB7XuvM2+2cMXAoq4ALQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.44.1.tgz", + "integrity": "sha512-qnQJ+mVa7szevdEyvfItbO5Vo+GfZ4/GZWWDRRLjrxYPkhM+6zYB2vRYwCsoJLzqFCdZT4mEqyJoyzkunsZ96A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.44.1", + "@typescript-eslint/tsconfig-utils": "8.44.1", + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/visitor-keys": "8.44.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.44.1.tgz", + "integrity": "sha512-DpX5Fp6edTlocMCwA+mHY8Mra+pPjRZ0TfHkXI8QFelIKcbADQz1LUPNtzOFUriBB2UYqw4Pi9+xV4w9ZczHFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.44.1", + "@typescript-eslint/types": "8.44.1", + "@typescript-eslint/typescript-estree": "8.44.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.44.1.tgz", + "integrity": "sha512-576+u0QD+Jp3tZzvfRfxon0EA2lzcDt3lhUbsC6Lgzy9x2VR4E+JUiNyGHi5T8vk0TV+fpJ5GLG1JsJuWCaKhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.44.1", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "license": "ISC" + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.0.3.tgz", + "integrity": "sha512-PFVHhosKkofGH0Yzrw1BipSedTH68BFF8ZWy1kfUpCtJcouXXY0+racG8sExw7hw0HoX36813ga5o3LTWZ4FUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.4", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.35", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/babel-dead-code-elimination": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.10.tgz", + "integrity": "sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" + } + }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-react-compiler": { + "version": "19.1.0-rc.3", + "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.1.0-rc.3.tgz", + "integrity": "sha512-mjRn69WuTz4adL0bXGx8Rsyk1086zFJeKmes6aK0xPuK3aaXmDJdLHqwKKMrpm6KAI1MCoUK72d2VeqQbu8YIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.0" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.6.tgz", + "integrity": "sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.26.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz", + "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.8.3", + "caniuse-lite": "^1.0.30001741", + "electron-to-chromium": "^1.5.218", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001743", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001743.tgz", + "integrity": "sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/cbor2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cbor2/-/cbor2-2.0.1.tgz", + "integrity": "sha512-9bE8+tueGxONyxpttNKkAKKcGVtAPeoSJ64AjVTTjEuBOuRaeeP76EN9BbmQqkz1ZeTP0QPvksNBKwvEutIUzQ==", + "license": "MIT", + "dependencies": { + "@cto.af/wtf8": "0.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-reference-invalid": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz", + "integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/components": { + "resolved": "../../packages/components", + "link": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/compute-scroll-into-view": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz", + "integrity": "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "license": "MIT" + }, + "node_modules/decode-named-character-reference": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dedent": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", + "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/direction": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/direction/-/direction-1.0.4.tgz", + "integrity": "sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==", + "license": "MIT", + "bin": { + "direction": "cli.js" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.222", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.222.tgz", + "integrity": "sha512-gA7psSwSwQRE60CEoLz6JBCQPIxNeuzB2nL8vE03GK/OHxlvykbLyeiumQy1iH5C2f3YbRAZpGCMT12a/9ih9w==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", + "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.10", + "@esbuild/android-arm": "0.25.10", + "@esbuild/android-arm64": "0.25.10", + "@esbuild/android-x64": "0.25.10", + "@esbuild/darwin-arm64": "0.25.10", + "@esbuild/darwin-x64": "0.25.10", + "@esbuild/freebsd-arm64": "0.25.10", + "@esbuild/freebsd-x64": "0.25.10", + "@esbuild/linux-arm": "0.25.10", + "@esbuild/linux-arm64": "0.25.10", + "@esbuild/linux-ia32": "0.25.10", + "@esbuild/linux-loong64": "0.25.10", + "@esbuild/linux-mips64el": "0.25.10", + "@esbuild/linux-ppc64": "0.25.10", + "@esbuild/linux-riscv64": "0.25.10", + "@esbuild/linux-s390x": "0.25.10", + "@esbuild/linux-x64": "0.25.10", + "@esbuild/netbsd-arm64": "0.25.10", + "@esbuild/netbsd-x64": "0.25.10", + "@esbuild/openbsd-arm64": "0.25.10", + "@esbuild/openbsd-x64": "0.25.10", + "@esbuild/openharmony-arm64": "0.25.10", + "@esbuild/sunos-x64": "0.25.10", + "@esbuild/win32-arm64": "0.25.10", + "@esbuild/win32-ia32": "0.25.10", + "@esbuild/win32-x64": "0.25.10" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.36.0.tgz", + "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.1", + "@eslint/core": "^0.15.2", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.36.0", + "@eslint/plugin-kit": "^0.3.5", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.21.tgz", + "integrity": "sha512-MWDWTtNC4voTcWDxXbdmBNe8b/TxfxRFUL6hXgKWJjN9c1AagYEmpiFWBWzDw+5H3SulWUe1pJKTnoSdmk88UA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-util-is-identifier-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz", + "integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/exit-hook": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", + "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "11.3.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", + "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "16.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.4.0.tgz", + "integrity": "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-to-jsx-runtime": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz", + "integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "comma-separated-tokens": "^2.0.0", + "devlop": "^1.0.0", + "estree-util-is-identifier-name": "^3.0.0", + "hast-util-whitespace": "^3.0.0", + "mdast-util-mdx-expression": "^2.0.0", + "mdast-util-mdx-jsx": "^3.0.0", + "mdast-util-mdxjs-esm": "^2.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-js": "^1.0.0", + "unist-util-position": "^5.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/hosted-git-info": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.3.tgz", + "integrity": "sha512-HVJyzUrLIL1c0QmviVh5E8VGyUS7xCFPS6yydaVd1UegW+ibV/CohqTH9MkOLDp5o+rb82DMo77PTuc9F/8GKw==", + "license": "ISC", + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/html-url-attributes": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", + "integrity": "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.3.tgz", + "integrity": "sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "license": "MIT" + }, + "node_modules/intl-messageformat": { + "version": "10.7.16", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.16.tgz", + "integrity": "sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug==", + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.4", + "@formatjs/fast-memoize": "2.2.7", + "@formatjs/icu-messageformat-parser": "2.11.2", + "tslib": "^2.8.0" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-alphabetical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz", + "integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-alphanumerical": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz", + "integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==", + "license": "MIT", + "dependencies": { + "is-alphabetical": "^2.0.0", + "is-decimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-decimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz", + "integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hexadecimal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", + "integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/is-hotkey": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-hotkey/-/is-hotkey-0.2.0.tgz", + "integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw==", + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isbot": { + "version": "5.1.31", + "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.1.31.tgz", + "integrity": "sha512-DPgQshehErHAqSCKDb3rNW03pa2wS/v5evvUqtxt6TTnHRqAG8FdzcSSJs9656pK6Y+NT7K9R4acEYXLHYfpUQ==", + "license": "Unlicense", + "engines": { + "node": ">=18" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-expression": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.1.tgz", + "integrity": "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdx-jsx": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.2.0.tgz", + "integrity": "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "parse-entities": "^4.0.0", + "stringify-entities": "^4.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-mdxjs-esm": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz", + "integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==", + "license": "MIT", + "dependencies": { + "@types/estree-jsx": "^1.0.0", + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-newline-to-break": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-newline-to-break/-/mdast-util-newline-to-break-2.0.0.tgz", + "integrity": "sha512-MbgeFca0hLYIEx/2zGsszCSEJJ1JSCdiY5xQxRcLDDGa8EPvlLPupJ4DSajbMPAnC0je8jfb9TiUATnxxrHUog==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-find-and-replace": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/morgan": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", + "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", + "license": "MIT", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.1.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/morgan/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-releases": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz", + "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==", + "license": "MIT" + }, + "node_modules/normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-install-checks/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "license": "ISC", + "dependencies": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-pick-manifest": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.2.tgz", + "integrity": "sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg==", + "license": "ISC", + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", + "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-entities": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.2.tgz", + "integrity": "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "character-entities-legacy": "^3.0.0", + "character-reference-invalid": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "is-alphanumerical": "^2.0.0", + "is-decimal": "^2.0.0", + "is-hexadecimal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/parse-entities/node_modules/@types/unist": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", + "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "license": "ISC" + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", + "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-colorful": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/react-colorful/-/react-colorful-5.6.1.tgz", + "integrity": "sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/react-dom": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", + "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.1" + } + }, + "node_modules/react-intl": { + "version": "7.1.11", + "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-7.1.11.tgz", + "integrity": "sha512-tnVoRCWvW5Ie2ikYSdPF7z3+880yCe/9xPmitFeRPw3RYDcCfR4m8ZYa4MBq19W4adt9Z+PQA4FaMBCJ7E+HCQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@formatjs/ecma402-abstract": "2.3.4", + "@formatjs/icu-messageformat-parser": "2.11.2", + "@formatjs/intl": "3.1.6", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/react": "16 || 17 || 18 || 19", + "hoist-non-react-statics": "^3.3.2", + "intl-messageformat": "10.7.16", + "tslib": "^2.8.0" + }, + "peerDependencies": { + "react": "16 || 17 || 18 || 19", + "typescript": "^5.6.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/react-is": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.1.1.tgz", + "integrity": "sha512-tr41fA15Vn8p4X9ntI+yCyeGSf1TlYaY5vlTZfQmeLBrFo3psOPX6HhTDnFNL9uj3EhP0KAQ80cugCl4b4BERA==", + "license": "MIT" + }, + "node_modules/react-markdown": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz", + "integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "hast-util-to-jsx-runtime": "^2.0.0", + "html-url-attributes": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "remark-parse": "^11.0.0", + "remark-rehype": "^11.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=18", + "react": ">=18" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.1.tgz", + "integrity": "sha512-pfAByjcTpX55mqSDGwGnY9vDCpxqBLASg0BMNAuMmpSGESo/TaOUG6BllhAtAkCGx8Rnohik/XtaqiYUJtgW2g==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-router-dom": { + "version": "7.9.3", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.3.tgz", + "integrity": "sha512-1QSbA0TGGFKTAc/aWjpfW/zoEukYfU4dc1dLkT/vvf54JoGMkW+fNA+3oyo2gWVW1GM7BxjJVHz5GnPJv40rvg==", + "license": "MIT", + "dependencies": { + "react-router": "7.9.3" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/react-router-dom/node_modules/react-router": { + "version": "7.9.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.3.tgz", + "integrity": "sha512-4o2iWCFIwhI/eYAIL43+cjORXYn/aRQPgtFRRZb3VzoyQ5Uej0Bmqj7437L97N9NJW4wnicSwLOLS+yCXfAPgg==", + "license": "MIT", + "dependencies": { + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/remark-breaks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-breaks/-/remark-breaks-4.0.0.tgz", + "integrity": "sha512-IjEjJOkH4FuJvHZVIW0QCDWxcG96kCq7An/KVH2NfJe6rKZU2AsHeB3OEjPNRxi4QC34Xdx7I2KGYn6IpT7gxQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-newline-to-break": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz", + "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-rehype": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-11.1.2.tgz", + "integrity": "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "mdast-util-to-hast": "^13.0.0", + "unified": "^11.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.52.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.2.tgz", + "integrity": "sha512-I25/2QgoROE1vYV+NQ1En9T9UFB9Cmfm2CJ83zZOlaDpvz29wGQSZXWKw7MiNXau7wYgB/T9fVIdIuEQ+KbiiA==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.52.2", + "@rollup/rollup-android-arm64": "4.52.2", + "@rollup/rollup-darwin-arm64": "4.52.2", + "@rollup/rollup-darwin-x64": "4.52.2", + "@rollup/rollup-freebsd-arm64": "4.52.2", + "@rollup/rollup-freebsd-x64": "4.52.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.52.2", + "@rollup/rollup-linux-arm-musleabihf": "4.52.2", + "@rollup/rollup-linux-arm64-gnu": "4.52.2", + "@rollup/rollup-linux-arm64-musl": "4.52.2", + "@rollup/rollup-linux-loong64-gnu": "4.52.2", + "@rollup/rollup-linux-ppc64-gnu": "4.52.2", + "@rollup/rollup-linux-riscv64-gnu": "4.52.2", + "@rollup/rollup-linux-riscv64-musl": "4.52.2", + "@rollup/rollup-linux-s390x-gnu": "4.52.2", + "@rollup/rollup-linux-x64-gnu": "4.52.2", + "@rollup/rollup-linux-x64-musl": "4.52.2", + "@rollup/rollup-openharmony-arm64": "4.52.2", + "@rollup/rollup-win32-arm64-msvc": "4.52.2", + "@rollup/rollup-win32-ia32-msvc": "4.52.2", + "@rollup/rollup-win32-x64-gnu": "4.52.2", + "@rollup/rollup-win32-x64-msvc": "4.52.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" + }, + "node_modules/scroll-into-view-if-needed": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz", + "integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==", + "license": "MIT", + "dependencies": { + "compute-scroll-into-view": "^3.0.2" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slate": { + "version": "0.118.1", + "resolved": "https://registry.npmjs.org/slate/-/slate-0.118.1.tgz", + "integrity": "sha512-6H1DNgnSwAFhq/pIgf+tLvjNzH912M5XrKKhP9Frmbds2zFXdSJ6L/uFNyVKxQIkPzGWPD0m+wdDfmEuGFH5Tg==", + "license": "MIT", + "dependencies": { + "immer": "^10.0.3", + "tiny-warning": "^1.0.3" + } + }, + "node_modules/slate-dom": { + "version": "0.118.1", + "resolved": "https://registry.npmjs.org/slate-dom/-/slate-dom-0.118.1.tgz", + "integrity": "sha512-D6J0DF9qdJrXnRDVhYZfHzzpVxzqKRKFfS0Wcin2q0UC+OnQZ0lbCGJobatVbisOlbSe7dYFHBp9OZ6v1lEcbQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@juggle/resize-observer": "^3.4.0", + "direction": "^1.0.4", + "is-hotkey": "^0.2.0", + "is-plain-object": "^5.0.0", + "lodash": "^4.17.21", + "scroll-into-view-if-needed": "^3.1.0", + "tiny-invariant": "1.3.1" + }, + "peerDependencies": { + "slate": ">=0.99.0" + } + }, + "node_modules/slate-history": { + "version": "0.113.1", + "resolved": "https://registry.npmjs.org/slate-history/-/slate-history-0.113.1.tgz", + "integrity": "sha512-J9NSJ+UG2GxoW0lw5mloaKcN0JI0x2IA5M5FxyGiInpn+QEutxT1WK7S/JneZCMFJBoHs1uu7S7e6pxQjubHmQ==", + "license": "MIT", + "dependencies": { + "is-plain-object": "^5.0.0" + }, + "peerDependencies": { + "slate": ">=0.65.3" + } + }, + "node_modules/slate-react": { + "version": "0.118.2", + "resolved": "https://registry.npmjs.org/slate-react/-/slate-react-0.118.2.tgz", + "integrity": "sha512-D7eQVZGgiqV36mooozu8sNWuCkzJqcHQWERQn9FxqmugnbEOKaPBj5OX1x5WGAVexfrxAT5dTAHUaRb0lGqFDw==", + "license": "MIT", + "dependencies": { + "@juggle/resize-observer": "^3.4.0", + "direction": "^1.0.4", + "is-hotkey": "^0.2.0", + "lodash": "^4.17.21", + "scroll-into-view-if-needed": "^3.1.0", + "tiny-invariant": "1.3.1" + }, + "peerDependencies": { + "react": ">=18.2.0", + "react-dom": ">=18.2.0", + "slate": ">=0.114.0", + "slate-dom": ">=0.116.0" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "license": "CC0-1.0" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "license": "MIT", + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/style-to-js": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.17.tgz", + "integrity": "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.9" + } + }, + "node_modules/style-to-object": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.9.tgz", + "integrity": "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.1.tgz", + "integrity": "sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw==", + "license": "MIT" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.44.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.44.1.tgz", + "integrity": "sha512-0ws8uWGrUVTjEeN2OM4K1pLKHK/4NiNP/vz6ns+LjT/6sqpaYzIVFajZb1fj/IDwpsrrHb3Jy0Qm5u9CPcKaeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.44.1", + "@typescript-eslint/parser": "8.44.1", + "@typescript-eslint/typescript-estree": "8.44.1", + "@typescript-eslint/utils": "8.44.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/unified": { + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", + "integrity": "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz", + "integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, + "node_modules/valibot": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.41.0.tgz", + "integrity": "sha512-igDBb8CTYr8YTQlOKgaN9nSS0Be7z+WRuaeYqGf3Cjz3aKmSnqEmYnkfVjzIuumGqfHpa3fLIvMEAfhrpqN8ng==", + "license": "MIT", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "6.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.6.tgz", + "integrity": "sha512-0msEVHJEScQbhkbVTb/4iHZdJ6SXp/AvxL2sjwYQFfBqleHtnCqv1J3sa9zbWz/6kW1m9Tfzn92vW+kZ1WV6QA==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-node/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/vite-plugin-static-copy": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-2.3.2.tgz", + "integrity": "sha512-iwrrf+JupY4b9stBttRWzGHzZbeMjAHBhkrn67MNACXJVjEMRpCI10Q3AkxdBkl45IHaTfw/CNVevzQhP7yTwg==", + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.3", + "fast-glob": "^3.2.11", + "fs-extra": "^11.1.0", + "p-map": "^7.0.3", + "picocolors": "^1.0.0" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0" + } + }, + "node_modules/vite-plugin-static-copy/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/vite-plugin-static-copy/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/vite-plugin-static-copy/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/vite-tsconfig-paths": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.1.4.tgz", + "integrity": "sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/sites/app.campground.gg/package.json b/sites/app.campground.gg/package.json new file mode 100644 index 00000000..2a76ca52 --- /dev/null +++ b/sites/app.campground.gg/package.json @@ -0,0 +1,66 @@ +{ + "name": "app-campground-gg", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "build": "react-router build", + "dev": "react-router dev", + "start": "react-router-serve ./build/server/index.js", + "typecheck": "react-router typegen && tsc" + }, + "dependencies": { + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@fontsource/nunito-sans": "^5.2.7", + "@fontsource/quicksand": "^5.2.10", + "@mantine/hooks": "^8.3.1", + "@mui/joy": "^5.0.0-beta.52", + "@react-router/fs-routes": "^7.9.1", + "@react-router/node": "^7.7.1", + "@react-router/serve": "^7.7.1", + "@tabler/icons-react": "^3.35.0", + "@types/mdast": "^4.0.4", + "cbor2": "^2.0.1", + "components": "file:../../packages/components", + "highlight.js": "^11.11.1", + "isbot": "^5", + "mdast-util-find-and-replace": "^3.0.2", + "mdast-util-from-markdown": "^2.0.2", + "mdast-util-gfm": "^3.1.0", + "mdast-util-to-markdown": "^2.1.2", + "micromark-extension-gfm": "^3.0.0", + "ms": "^2.1.3", + "react": "^19.1.1", + "react-colorful": "^5.6.1", + "react-dom": "^19.1.1", + "react-intl": "^7.1.11", + "react-markdown": "^10.1.0", + "react-router": "^7.7.1", + "react-router-dom": "^7.9.3", + "remark-breaks": "^4.0.0", + "remark-gfm": "^4.0.1", + "slate": "^0.118.1", + "slate-history": "^0.113.1", + "slate-react": "^0.118.2", + "uuid": "^13.0.0", + "vite-plugin-static-copy": "^2.3.0" + }, + "devDependencies": { + "@eslint/js": "^9.36.0", + "@react-router/dev": "^7.7.1", + "@types/ms": "^2.1.0", + "@types/react": "^19.1.13", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.3", + "babel-plugin-react-compiler": "^19.1.0-rc.3", + "eslint": "^9.36.0", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "globals": "^16.4.0", + "typescript": "~5.8.3", + "typescript-eslint": "^8.44.0", + "vite": "^6.2.0", + "vite-tsconfig-paths": "^5.1.4" + } +} diff --git a/sites/app.campground.gg/public/Campground.svg b/sites/app.campground.gg/public/Campground.svg new file mode 100644 index 00000000..a3679acc --- /dev/null +++ b/sites/app.campground.gg/public/Campground.svg @@ -0,0 +1,193 @@ + + + + + Campground logo + + + + + + + + + + + + + + + 03/10/2026 (US date format) + + + PrettyGoodName + + + Campground logo + + + PrettyGoodName + + + + + Campground + + + campground-logo + + + logomark logo brand branding icon favicon + + + Campground is federated chatting platform for the people. + + + + + + + + + + + + + diff --git a/sites/app.campground.gg/public/DefaultAvatar0.png b/sites/app.campground.gg/public/DefaultAvatar0.png new file mode 100644 index 00000000..b0fa755c Binary files /dev/null and b/sites/app.campground.gg/public/DefaultAvatar0.png differ diff --git a/sites/app.campground.gg/public/favicon.ico b/sites/app.campground.gg/public/favicon.ico new file mode 100644 index 00000000..800254e0 Binary files /dev/null and b/sites/app.campground.gg/public/favicon.ico differ diff --git a/sites/app.campground.gg/public/icon.png b/sites/app.campground.gg/public/icon.png new file mode 100644 index 00000000..56622329 Binary files /dev/null and b/sites/app.campground.gg/public/icon.png differ diff --git a/sites/app.campground.gg/react-router.config.ts b/sites/app.campground.gg/react-router.config.ts new file mode 100644 index 00000000..a0329ab9 --- /dev/null +++ b/sites/app.campground.gg/react-router.config.ts @@ -0,0 +1,9 @@ +import { type Config } from "@react-router/dev/config"; + +export default { + ssr: false, + appDirectory: "src", + future: { + v8_middleware: true, + } +} satisfies Config; diff --git a/sites/app.campground.gg/src/api/HTTPClient.ts b/sites/app.campground.gg/src/api/HTTPClient.ts new file mode 100644 index 00000000..4805fd33 --- /dev/null +++ b/sites/app.campground.gg/src/api/HTTPClient.ts @@ -0,0 +1,230 @@ +import { defaultXrpcPrefix, defaultAppApiUrl, defaultBackendDomain } from "api.config"; +import type { HttpResponseError, HttpResponseOkWithContent, HttpResponseWithContent } from "./HTTPResponse"; +import type { ProfileView } from "types/user"; +import type { HTTPRefreshLogin } from "./HTTPErrorHandler"; +import type { SessionAuthRefresh } from "~/context/session/types"; +import type { AtprotoRecord, AtprotoValueBase, GetRecordListResponse, PutRecordResponse } from "types/record"; +import type { Me } from "types/me"; +import HTTPClientTentManager from "./tent"; +import HTTPClientCampsiteManager from "./campsite"; +import HTTPClientBonfireManager from "./bonfire"; +import HTTPClientMessageManager from "./message"; +import HTTPClientPermissionManager from "./permission"; +import HTTPClientProfilePostManager from "./profilePost"; +import HTTPClientRoleManager from "./role"; +import HTTPClientCategoryManager from "./category"; +import HTTPClientInviteManager from "./invite"; +import HTTPClientMemberManager from "./member"; +import HTTPClientMemberBanManager from "./memberBan"; + +type HTTPMethodXRPC = "GET" | "POST"; +type HTTPMethod = HTTPMethodXRPC | "DELETE" | "OPTION" | "HEAD" | "PUT" | "PATCH"; + +export interface RequestPrefixed { + url: string; + routePrefix: string; +} +export interface HTTPClientConfig extends RequestPrefixed { + atprotoProxy: string; + auth?: string; + refreshAuth?: string; + userDid?: string; +}; + +type QueryType = string | number | boolean | undefined | null; + +export interface RequestConfig { + method: HTTPMethod; + route: string; + body?: any; + request?: RequestInit; + queries?: Record; +} + +export default class HTTPClient { + private static _default: HTTPClientConfig = { + url: defaultAppApiUrl, + routePrefix: defaultXrpcPrefix, + // auth: `...`, + // refreshAuth: `...`, + // userDid: `...`, + atprotoProxy: `did:web:${defaultBackendDomain.replace(":", "%3A")}#campground_appview` + }; + + private _config: HTTPClientConfig; + private _onRefreshLogin?: HTTPRefreshLogin; + public profilePosts = new HTTPClientProfilePostManager(this); + + public campsites = new HTTPClientCampsiteManager(this); + + public members = new HTTPClientMemberManager(this); + public roles = new HTTPClientRoleManager(this); + public memberBans = new HTTPClientMemberBanManager(this); + public invites = new HTTPClientInviteManager(this); + + public bonfires = new HTTPClientBonfireManager(this); + public categories = new HTTPClientCategoryManager(this); + public tents = new HTTPClientTentManager(this); + + public permissions = new HTTPClientPermissionManager(this); + public messages = new HTTPClientMessageManager(this); + + constructor(config: Partial, onRefreshLogin?: HTTPRefreshLogin) { + this._config = { ...HTTPClient._default, ...config }; + this._onRefreshLogin = onRefreshLogin; + } + + public get authExpired(): boolean | null { + try { + return this._config.auth ? JSON.parse(atob(this._config.auth?.split(".")[1]!)).exp * 1000 < new Date().getTime() : null; + } catch(err) { + console.warn(err); + return null; + } + } + + public get actorDid() { + return this._config.userDid; + } + + public static login(auth: { identifier: string; password: string; }, requestConfig: Partial = {}) { + return HTTPClient.atprotoFetch({ + method: "POST", + route: "com.atproto.server.createSession", + body: { ...auth, allowTakenDown: true }, + ...requestConfig, + }); + } + + public async refreshLogin(requestConfig: Partial = {}) { + const resp = await HTTPClient.atprotoFetch({ + method: "POST", + route: "com.atproto.server.refreshSession", + headers: { + "Authorization": `Bearer ${this._config.refreshAuth}`, + }, + ...requestConfig, + }); + if (!resp.ok) + return resp; + this._onRefreshLogin?.(resp.content!); + // Change in HTTP as well + this._config.auth = resp.content?.accessJwt ?? this._config.auth; + this._config.refreshAuth = resp.content?.refreshJwt ?? this._config.refreshAuth; + return resp; + } + + private static convertValueToArray([key, value]: [string, any]) { + return Array.isArray(value) + ? value.filter((y) => typeof y !== "undefined" && y !== null).map((y) => [key, y.toString()]) + : [[key, value.toString()]]; + } + + public static convertObjectToQuery(value: Record): URLSearchParams { + const newValue = ( + Object + .entries(value) + .filter(([_, key]) => typeof key !== "undefined" && key !== null) + .flatMap(this.convertValueToArray) + ); + return new URLSearchParams(newValue); + } + + public static async atprotoFetch(config: Partial & RequestConfig & { headers?: HeadersInit; }): Promise> { + const { url, queries, routePrefix, route, method, body, request, headers } = { ...this._default, ...config }; + + const queriesString = queries ? `?${this.convertObjectToQuery(queries)}` : ``; + + const resolvedUrl = `${url}${routePrefix}${route}${queriesString}`; + + const response = await fetch(resolvedUrl, { + method, + body: body ? JSON.stringify(body) : null, + headers: { + "Content-Type": "application/json", + ...headers, + }, + ...request, + }); + const responseBody = response.body ? await response.json() : null; + if (!response.ok) + return { ok: false, url: response.url, status: response.status, content: undefined, errorHeader: responseBody?.message ? responseBody.error : null, errorDescription: responseBody?.message ?? responseBody?.error ?? "Unknown error" } satisfies HttpResponseError; + + else + return { ok: true, url: response.url, status: response.status, content: responseBody as T, errorHeader: undefined, errorDescription: undefined, } satisfies HttpResponseOkWithContent; + } + + async fetch({ method, body, queries, route, request }: RequestConfig) { + const doFetch = (auth: string | undefined) => HTTPClient.atprotoFetch({ + url: this._config.url, + routePrefix: this._config.routePrefix, + body, + queries, + route, + ...request, + + method, + headers:{ + "atproto-proxy": this._config.atprotoProxy, + ...request?.headers, + ...(this._config.auth ? { "Authorization": `Bearer ${auth}` } : {}) + }, + }); + + if (!this._config.auth) + return doFetch(undefined); + + console.log("Expired", this.authExpired); + const token = this.authExpired + ? await this.refreshLogin().then((refresh) => refresh.ok ? refresh.content!.accessJwt : this._config.auth) + : this._config.auth; + + const resp = await doFetch(token); + if (!resp.ok && resp.errorHeader === "ExpiredToken") { + console.log("Expired token", this.authExpired); + return this.refreshLogin() + .then((refresh) => refresh.ok ? doFetch(refresh.content!.accessJwt) : refresh); + } + return resp; + } + public get(config: Omit) { + return this.fetch({ method: "GET", ...config }); + } + public post(config: Omit) { + return this.fetch({ method: "POST", ...config }); + } + + public fetchPDS(method: HTTPMethodXRPC, nsid: string, request: Omit) { + return this.fetch({ route: nsid, method, request: { headers: { "atproto-proxy": "" } }, ...request }); + } + public getRecord(config: { repo: string; rkey: string; collection: string; }) { + return this.fetchPDS>("GET", "com.atproto.repo.getRecord", { queries: config }); + } + public getRecordList(config: { repo: string; collection: string; }) { + return this.fetchPDS>("GET", "com.atproto.repo.listRecords", { queries: config }); + } + public putRecord(config: { repo: string; rkey: string; collection: string; record: T; }) { + return this.fetchPDS("POST", "com.atproto.repo.putRecord", { body: config, }); + } + public deleteRecord(config: { repo: string; rkey: string; collection: string; }) { + return this.fetchPDS("POST", "com.atproto.repo.deleteRecord", { body: config, }); + } + public getServiceAuth(config: { exp?: number; lxm?: string; }) { + return this.fetchPDS<{ token: string; }>("GET", "com.atproto.server.getServiceAuth", { queries: { aud: this._config.atprotoProxy.split("#", 1)[0], ...config } }); + } + + public getMe() { + return this.get({ + route: `gg.campground.actor.getMe`, + }); + } + + public fetchProfile(actor: string) { + return this.get({ + route: `gg.campground.actor.getProfile`, + queries: { + actor, + }, + }); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/HTTPErrorHandler.ts b/sites/app.campground.gg/src/api/HTTPErrorHandler.ts new file mode 100644 index 00000000..dcfbfaaf --- /dev/null +++ b/sites/app.campground.gg/src/api/HTTPErrorHandler.ts @@ -0,0 +1,3 @@ +import type { SessionAuthRefresh } from "~/context/session/types"; + +export type HTTPRefreshLogin = (refresh: SessionAuthRefresh) => void; \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/HTTPResponse.ts b/sites/app.campground.gg/src/api/HTTPResponse.ts new file mode 100644 index 00000000..c9706595 --- /dev/null +++ b/sites/app.campground.gg/src/api/HTTPResponse.ts @@ -0,0 +1,20 @@ +export type HttpResponse = HttpResponseOk | HttpResponseError; +export type HttpResponseWithContent = HttpResponseOkWithContent | HttpResponseError; + +interface HttpResponseBase { + ok: TOk; + status: number; + url: string; +} +export interface HttpResponseError extends HttpResponseBase { + errorHeader?: string; + errorDescription: string; + content: undefined; +} +export interface HttpResponseOk extends HttpResponseOkWithContent { +} +export interface HttpResponseOkWithContent extends HttpResponseBase { + errorHeader: undefined; + errorDescription: undefined; + content: T; +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/WSClient.ts b/sites/app.campground.gg/src/api/WSClient.ts new file mode 100644 index 00000000..578a58b5 --- /dev/null +++ b/sites/app.campground.gg/src/api/WSClient.ts @@ -0,0 +1,149 @@ +import { decodeSequence, encode } from "cbor2"; +import type { KeyValueEncoded } from "cbor2/sorts"; +import { stringify } from "uuid"; +import type HTTPClient from "./HTTPClient"; +import type { TypeToPayload } from "types/ws"; + +type Config = { + url: string; +}; + +interface WSFrameHeader { + op: TOp; +} +interface WSFrameHeaderTyped extends WSFrameHeader { + t: TType; +} +interface WSFrame { + payload: TData; +} +interface WSErrorFrame extends WSFrameHeader<-1>, WSFrame<{ error: string; message?: string; }> {} +interface WSDataFrame extends WSFrameHeaderTyped<1, TType>, WSFrame< TData> { + t: TType; +} + +type WSMessage = WSErrorFrame | WSDataFrame; + +export type WSSubscriptionCallback = (message: WSMessage) => unknown; + +const mapObjectValue = (value: any): any => + value instanceof Uint8Array + ? stringify(value as Uint8Array) + : Array.isArray(value) + ? (value as any[]).map(mapObjectValue) + : value; + +const createObject = (kve: KeyValueEncoded[]) => + Object.fromEntries(kve.map(([key, value]) => [key as string, mapObjectValue(value)])); + +export interface WSSubscription { + callback: WSSubscriptionCallback; +}; + +export default class WSClient { + private _config: Config; + private _subscriptions: WSSubscription[]; + private _client: WebSocket; + private _onOpen: Array<() => unknown> = []; + constructor(config: Config) { + this._config = config; + this._subscriptions = []; + this._client = new WebSocket(this._config.url); + this._client.onmessage = this._onMessage.bind(this); + } + public subscribe(callback: WSSubscriptionCallback) { + const subscription = { + callback, + }; + this._subscriptions.push(subscription); + return subscription; + } + public unsubscribe(subscription: WSSubscription) { + this._subscriptions = this._subscriptions.filter((x) => x !== subscription); + } + public initWithAuth(restClient: HTTPClient) { + this._client.onopen = async () => { + console.log("WebSocket Open"); + const serviceAuth = await restClient.getServiceAuth({ lxm: "gg.campground.websocket.subscribe" }); + this._client.send( + encode({ + op: 0, + payload: serviceAuth.ok ? { + serviceAuth: serviceAuth.content.token, + } : undefined, + }) + ); + console.log("Sent WebSocket auth frame"); + setTimeout(() => { + this._internalInitOnOpen(); + }, 300); + }; + } + public initWithoutAuth() { + this._client.onopen = () => { + this._client.send( + encode({ + op: 0, + }) + ); + this._internalInitOnOpen(); + } + } + private _internalInitOnOpen() { + console.log("Fully initializing WebSocket"); + for (const onOpen of this._onOpen) + onOpen(); + } + public setCampsite(campsiteId: string | null) { + if (this._client.readyState !== this._client.OPEN) + return this._onOpen.push(this._internalSetCampsite.bind(this, campsiteId)); + + console.log("Setting campsite in WS", campsiteId); + setTimeout(() => { + this._internalSetCampsite(campsiteId); + }, 100); + } + private _internalSetCampsite(campsiteId: string | null) { + console.log("Set campsite in WS", campsiteId); + this._client.send( + encode({ + op: 1, + payload: { + t: "View", + campsite: campsiteId || "", + } + }) + ); + } + public switchCampsite(campsiteId: string) { + this._client.send( + encode({ + op: 1, + payload: { + t: "View", + campsiteId, + }, + }) + ); + } + public fetchPermissions() { + this._client.send( + encode({ + op: 1, + payload: { + t: "ViewPermissions", + }, + }) + ); + } + private async _onMessage(msg: MessageEvent) { + const [header, payload] = [...decodeSequence(await (msg.data as Blob).bytes(), { createObject })] as [WSFrameHeader<-1> | WSFrameHeaderTyped<1, string>, any]; + const message: WSMessage = {...header, payload } as WSMessage; + console.log("Message", message); + return await Promise.allSettled( + this._subscriptions.map((x) => + x.callback(message) + ) + ); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/base.ts b/sites/app.campground.gg/src/api/base.ts new file mode 100644 index 00000000..92ad9549 --- /dev/null +++ b/sites/app.campground.gg/src/api/base.ts @@ -0,0 +1,8 @@ +import type HTTPClient from "./HTTPClient"; + +export default class HTTPClientObjectManager { + protected client: HTTPClient; + constructor(client: HTTPClient) { + this.client = client; + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/bonfire.ts b/sites/app.campground.gg/src/api/bonfire.ts new file mode 100644 index 00000000..f8c7f85a --- /dev/null +++ b/sites/app.campground.gg/src/api/bonfire.ts @@ -0,0 +1,43 @@ +import type { BonfireViewDetailed } from "types/bonfires"; +import type { BonfireViewBasic } from "types/bonfires"; +import HTTPClientObjectManager from "./base"; + +export default class HTTPClientBonfireManager extends HTTPClientObjectManager { + public get(campsite_id: string, bonfire_id: string) { + return this.client.get({ + route: "gg.campground.bonfire.getBonfire", + queries: { campsite_id, bonfire_id, }, + }); + } + + public create(campsite_id: string, body: { name: string, description: string; position: number; }) { + return this.client.post({ + route: "gg.campground.bonfire.createBonfire", + queries: { campsite_id }, + body, + }); + } + + public update(campsite_id: string, bonfire_id: string, body: { name?: string, description?: string; avatarUri?: string; bannerUri?: string; }) { + return this.client.post({ + route: "gg.campground.bonfire.updateBonfire", + queries: { campsite_id, bonfire_id }, + body, + }); + } + + public move(bonfire_id: string, body: { position?: number; }) { + return this.client.post({ + route: "gg.campground.bonfire.moveBonfire", + queries: { bonfire_id }, + body, + }); + } + + public delete(campsite_id: string, bonfire_id: string) { + return this.client.post({ + route: "gg.campground.bonfire.deleteBonfire", + queries: { campsite_id, bonfire_id }, + }); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/campsite.ts b/sites/app.campground.gg/src/api/campsite.ts new file mode 100644 index 00000000..3af27779 --- /dev/null +++ b/sites/app.campground.gg/src/api/campsite.ts @@ -0,0 +1,33 @@ +import type { CampsiteViewBasic, CampsiteViewDetailed, CreateCampsiteOutput } from "types/campsites"; +import HTTPClientObjectManager from "./base"; + +export default class HTTPClientCampsiteManager extends HTTPClientObjectManager { + public get(campsite_id: string) { + return this.client.get({ + route: "gg.campground.campsite.getCampsite", + queries: { campsite_id }, + }); + } + + public create(body: { avatar?: string; name: string; description: string; tags: string[]; vanityUrl?: string | null; }) { + return this.client.post({ + route: "gg.campground.campsite.createCampsite", + body, + }); + } + + public update(campsite_id: string, body: { avatarUri?: string; bannerUri?: string; name?: string; description?: string; tags?: string[]; vanityUrl?: string | null; }) { + return this.client.post({ + route: "gg.campground.campsite.updateCampsite", + queries: { campsite_id, }, + body, + }); + } + + public delete(campsite_id: string) { + return this.client.post({ + route: "gg.campground.campsite.deleteCampsite", + queries: { campsite_id, }, + }); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/category.ts b/sites/app.campground.gg/src/api/category.ts new file mode 100644 index 00000000..04a812ac --- /dev/null +++ b/sites/app.campground.gg/src/api/category.ts @@ -0,0 +1,35 @@ +import HTTPClientObjectManager from "./base"; +import type { TentCategoryView } from "types/tent"; + +export default class HTTPClientCategoryManager extends HTTPClientObjectManager { + create(campsite_id: string, bonfire_id: string, body: { name: string; description: string; position: number; }) { + return this.client.post({ + route: "gg.campground.tent.createCategory", + queries: { campsite_id, bonfire_id, }, + body, + }); + } + + update(category_id: string, body: { name?: string; description?: string; }) { + return this.client.post({ + route: "gg.campground.tent.updateCategory", + queries: { category_id, }, + body, + }); + } + + move(category_id: string, body: { bonfireId?: string; position?: number; }) { + return this.client.post({ + route: "gg.campground.tent.moveCategory", + queries: { category_id, }, + body, + }); + } + + delete(category_id: string) { + return this.client.post({ + route: "gg.campground.tent.deleteCategory", + queries: { category_id, }, + }); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/invite.ts b/sites/app.campground.gg/src/api/invite.ts new file mode 100644 index 00000000..d8681af1 --- /dev/null +++ b/sites/app.campground.gg/src/api/invite.ts @@ -0,0 +1,55 @@ +import HTTPClientObjectManager from "./base"; +import type { GetInvitesOutput } from "types/invites"; +import type { CampsiteInviteViewDetailed } from "types/invites"; +import type { CampsiteInviteViewBasic } from "types/invites"; + +export default class HTTPClientInviteManager extends HTTPClientObjectManager { + get(invite_id: string) { + return this.client.get({ + route: "gg.campground.invite.getInvite", + queries: { + invite_id, + }, + }); + } + + getMany(campsite_id: string, offset: number = 0, limit: number = 50) { + return this.client.get({ + route: "gg.campground.invite.getInvites", + queries: { + campsite_id, + offset, + limit, + }, + }); + } + + use(invite_id: string) { + return this.client.post({ + route: "gg.campground.invite.useInvite", + queries: { + invite_id, + }, + }); + } + + create(campsite_id: string, body: Pick) { + return this.client.post({ + route: "gg.campground.invite.createInvite", + queries: { + campsite_id, + }, + body, + }); + } + + delete(campsite_id: string, invite_id: string) { + return this.client.post({ + route: "gg.campground.invite.deleteInvite", + queries: { + campsite_id, + invite_id, + }, + }); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/member.ts b/sites/app.campground.gg/src/api/member.ts new file mode 100644 index 00000000..918f2477 --- /dev/null +++ b/sites/app.campground.gg/src/api/member.ts @@ -0,0 +1,75 @@ +import type { MemberViewDetailed } from "types/membership"; +import type { GetMembersDetailedOutput } from "types/membership"; +import type { GetMembersOutput } from "types/membership"; +import HTTPClientObjectManager from "./base"; + +export default class HTTPClientMemberManager extends HTTPClientObjectManager { + getMany(campsite_id: string, offsetOrIds: string[] | number) { + return this.client.get({ + route: "gg.campground.membership.getMembers", + queries: { + campsite_id, + offset: typeof offsetOrIds === "number" + ? offsetOrIds.toString() + : null, + actors: Array.isArray(offsetOrIds) + ? offsetOrIds + : null + }, + }); + } + + getManyDetailed(campsite_id: string, offset: number) { + return this.client.get({ + route: "gg.campground.membership.getMembersDetailed", + queries: { + campsite_id, + offset, + }, + }); + } + + get(campsite_id: string, actor: string) { + return this.client.get({ + route: "gg.campground.membership.getMember", + queries: { + campsite_id, + actor, + }, + }); + } + + update(campsite_id: string, actor: string, body: { nickname: string | undefined; }) { + return this.client.post({ + route: "gg.campground.membership.updateMember", + queries: { campsite_id, actor }, + body, + }); + } + + remove(campsite_id: string, actor: string) { + return this.client.post({ + route: "gg.campground.membership.removeMember", + queries: { + campsite_id, + actor, + }, + }); + } + + addRole(campsite_id: string, role_id: string, body: { memberIds: string[]; }) { + return this.client.post({ + route: "gg.campground.role.addMemberRoles", + queries: { campsite_id, role_id }, + body, + }); + } + + removeRole(campsite_id: string, role_id: string, body: { memberIds: string[]; }) { + return this.client.post({ + route: "gg.campground.role.removeMemberRoles", + queries: { campsite_id, role_id }, + body, + }); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/memberBan.ts b/sites/app.campground.gg/src/api/memberBan.ts new file mode 100644 index 00000000..0ba0aaeb --- /dev/null +++ b/sites/app.campground.gg/src/api/memberBan.ts @@ -0,0 +1,37 @@ +import HTTPClientObjectManager from "./base"; +import type { MemberBanView, GetBansOutput } from "types/membership"; + +export default class HTTPClientMemberBanManager extends HTTPClientObjectManager { + getMany(campsite_id: string, offset: number = 0, limit: number = 50) { + return this.client.get({ + route: "gg.campground.membership.getMemberBans", + queries: { + campsite_id, + offset, + limit, + }, + }); + } + + create(campsite_id: string, actor: string, body: { reason: string; }) { + console.log({ campsite_id, actor }); + return this.client.post({ + route: "gg.campground.membership.banMember", + queries: { + campsite_id, + actor, + }, + body, + }); + } + + delete(campsite_id: string, actor: string) { + return this.client.post({ + route: "gg.campground.membership.deleteMemberBan", + queries: { + campsite_id, + actor, + }, + }); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/message.ts b/sites/app.campground.gg/src/api/message.ts new file mode 100644 index 00000000..909a65ee --- /dev/null +++ b/sites/app.campground.gg/src/api/message.ts @@ -0,0 +1,34 @@ +import HTTPClientObjectManager from "./base"; +import type { TentMessagesOutput, MessageViewBasic } from "types/content"; + +export default class HTTPClientMessageManager extends HTTPClientObjectManager { + getMany(tent_id: string, offset: number = 0, limit: number = 50) { + return this.client.get({ + route: "gg.campground.message.getMessages", + queries: { tent_id, offset, limit, }, + }); + } + + create(tent_id: string, body: { content: string; replies?: string[]; }) { + return this.client.post({ + route: "gg.campground.message.createMessage", + queries: { tent_id, }, + body, + }); + } + + update(tent_id: string, message_id: string, body: { content: string; }) { + return this.client.post({ + route: "gg.campground.message.updateMessage", + queries: { tent_id, message_id, }, + body, + }); + } + + delete(tent_id: string, message_id: string) { + return this.client.post({ + route: "gg.campground.message.deleteMessage", + queries: { tent_id, message_id, }, + }); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/permission.ts b/sites/app.campground.gg/src/api/permission.ts new file mode 100644 index 00000000..1e361273 --- /dev/null +++ b/sites/app.campground.gg/src/api/permission.ts @@ -0,0 +1,20 @@ +import type { GetPermissionsOutput } from "types/permissions"; +import type { CampsitePermissionView } from "types/permissions"; +import HTTPClientObjectManager from "./base"; + +export default class HTTPClientPermissionManager extends HTTPClientObjectManager { + get(queries: ({ tent_id: string; } | { category_id: string; } | { bonfire_id: string; }) & { non_self?: boolean }) { + return this.client.get({ + route: "gg.campground.permission.getPermissions", + queries, + }); + } + + update(queries: ({ tent_id: string; } | { category_id: string; } | { bonfire_id: string; }) & ({ role_id: string; } | { actor: string; }), body: Pick) { + return this.client.post({ + route: "gg.campground.permission.updatePermission", + queries, + body, + }); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/profilePost.ts b/sites/app.campground.gg/src/api/profilePost.ts new file mode 100644 index 00000000..f2537863 --- /dev/null +++ b/sites/app.campground.gg/src/api/profilePost.ts @@ -0,0 +1,90 @@ +import type { ProfilePostViewBasic, ProfilePostViewDetailed, ProfilePostViewParented } from "types/user"; +import HTTPClientObjectManager from "./base"; + +export default class HTTPClientProfilePostManager extends HTTPClientObjectManager { + getMany(actor: string, replies: boolean = false, offset: number = 0, limit: number = 50) { + return this.client.get<{ posts: ProfilePostViewParented[] }>({ + route: `gg.campground.profile.getPosts`, + queries: { + actor: actor, + limit, + offset, + replies, + }, + }); + } + + getReplies(actor: string, post_tid: string, offset: number = 0) { + return this.client.get<{ posts: ProfilePostViewBasic[] }>({ + route: `gg.campground.profile.getReplies`, + queries: { + uri: `at://${actor}/gg.campground.profile.post/${post_tid}`, + limit: "50", + offset: offset.toString(), + }, + }); + } + + get(actor: string, post_tid: string) { + return this.client.get({ + route: `gg.campground.profile.getPost`, + queries: { + uri: `at://${actor}/gg.campground.profile.post/${post_tid}`, + }, + }); + } + + unindex(uri: string) { + return this.client.post({ + route: `gg.campground.profile.unindexPost`, + queries: { + uri, + }, + }); + } + + create(record: { parentUri?: string | undefined; content: string; tags: string[]; createdAt: string; updatedAt: string; }) { + if (!this.client.actorDid) + throw new Error("Operation not allowed while unauthenticated"); + + return this.client.putRecord({ + repo: this.client.actorDid, + collection: "gg.campground.profile.post", + rkey: "", + record: { + ...record, + "$type": "gg.campground.profile.post", + }, + }); + } + + update(uri: string, record: { content?: string; tags?: string[]; }) { + if (!this.client.actorDid) + throw new Error("Operation not allowed while unauthenticated"); + + return this.client.putRecord({ + repo: this.client.actorDid, + collection: "gg.campground.profile.post", + rkey: uri.split("/")[4], + record: { + ...record, + "updatedAt": new Date().toISOString(), + "$type": "gg.campground.profile.post", + }, + }); + } + + async delete(uri: string) { + if (!this.client.actorDid) + throw new Error("Operation not allowed while unauthenticated"); + + const a = await this.client.deleteRecord({ + repo: this.client.actorDid, + collection: "gg.campground.profile.post", + // at://did:.../gg.campground.profile.post/... + rkey: uri.split("/")[4], + }); + await this.unindex(uri); + return a; + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/role.ts b/sites/app.campground.gg/src/api/role.ts new file mode 100644 index 00000000..1d063592 --- /dev/null +++ b/sites/app.campground.gg/src/api/role.ts @@ -0,0 +1,43 @@ +import type { GetRolesOutput } from "types/roles"; +import type { RoleView } from "types/roles"; +import HTTPClientObjectManager from "./base"; + +export default class HTTPClientRoleManager extends HTTPClientObjectManager { + getMany(campsite_id: string) { + return this.client.post({ + route: "gg.campground.role.getRoles", + queries: { campsite_id }, + }); + } + + create(campsite_id: string, body: Pick) { + return this.client.post({ + route: "gg.campground.role.createRole", + queries: { campsite_id }, + body, + }); + } + + update(campsite_id: string, role_id: string, body: Partial>) { + return this.client.post({ + route: "gg.campground.role.updateRole", + queries: { campsite_id, role_id }, + body, + }); + } + + moveMany(campsite_id: string, body: { rolesByPosition: Record; }) { + return this.client.post({ + route: "gg.campground.role.moveRoles", + queries: { campsite_id, }, + body, + }); + } + + delete(campsite_id: string, role_id: string) { + return this.client.post({ + route: "gg.campground.role.deleteRole", + queries: { campsite_id, role_id }, + }); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/api/tent.ts b/sites/app.campground.gg/src/api/tent.ts new file mode 100644 index 00000000..c96dce33 --- /dev/null +++ b/sites/app.campground.gg/src/api/tent.ts @@ -0,0 +1,50 @@ +import HTTPClientObjectManager from "./base"; +import type { GetTentsOutput, TentViewDetailed } from "types/tent"; +import type { MessageViewBasic } from "types/content"; + +export default class HTTPClientTentManager extends HTTPClientObjectManager { + getMany(campsite_id: string, bonfire_id: string) { + return this.client.get({ + route: "gg.campground.tent.getTents", + queries: { campsite_id, bonfire_id, }, + }); + } + + get(tent_id: string) { + return this.client.get({ + route: "gg.campground.tent.getTent", + queries: { tent_id, }, + }); + } + + create(campsite_id: string, bonfire_id: string, body: { type: number; name: string; description: string; position: number; }) { + return this.client.post({ + route: "gg.campground.tent.createTent", + queries: { campsite_id, bonfire_id, }, + body: { viewType: 0, ...body }, + }); + } + + update(tent_id: string, body: { name?: string; description?: string; viewType?: number; }) { + return this.client.post({ + route: "gg.campground.tent.updateTent", + queries: { tent_id, }, + body, + }); + } + + move(tent_id: string, body: { bonfireId?: string | null; categoryId?: string | null; position?: number; }) { + return this.client.post({ + route: "gg.campground.tent.moveTent", + queries: { tent_id, }, + body, + }); + } + + delete(tent_id: string) { + return this.client.post({ + route: "gg.campground.tent.deleteTent", + queries: { tent_id, }, + }); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/app.css b/sites/app.campground.gg/src/app.css new file mode 100644 index 00000000..213c41db --- /dev/null +++ b/sites/app.campground.gg/src/app.css @@ -0,0 +1,109 @@ +@import "@fontsource/nunito-sans/500.css"; +@import "@fontsource/nunito-sans/500-italic.css"; +@import "@fontsource/nunito-sans/700.css"; +@import "@fontsource/nunito-sans/700-italic.css"; +@import "@fontsource/nunito-sans/900.css"; +@import "@fontsource/nunito-sans/900-italic.css"; +@import "@fontsource/quicksand/400.css"; +@import "@fontsource/quicksand/500.css"; +@import "@fontsource/quicksand/700.css"; +@import "./custom.css"; + +html, body, #root { + width: 100%; + height: 100%; + overflow: hidden; +} +::selection { + background-color: var(--palette-primary-t-500); + color: var(--palette-primary-100); +} + +* { + scrollbar-color: var(--palette-neutral-400) transparent; +} +*::-webkit-scrollbar { + background-color: transparent; + width: 8px; +} +*::-webkit-scrollbar-thumb { + border-radius: 8px; + background-color: var(--palette-neutral-400); +} + +.svg-primary { + stroke: var(--palette-text-primary); +} + +.svg-secondary { + stroke: var(--palette-text-secondary); +} + +.svg-tertiary { + stroke: var(--palette-text-tertiary); +} + +.svg-neutral-50 { + stroke: var(--palette-neutral-50); +} + +.svg-neutral-100 { + stroke: var(--palette-neutral-100); +} + +.svg-neutral-200 { + stroke: var(--palette-neutral-200); +} + +.svg-neutral-300 { + stroke: var(--palette-neutral-300); +} + +.svg-neutral-400 { + stroke: var(--palette-neutral-400); +} + +.svg-neutral-500 { + stroke: var(--palette-neutral-500); +} + +.svg-neutral-600 { + stroke: var(--palette-neutral-600); +} + +.stroke-3 { + stroke-width: 3px; +} + +.stroke-4 { + stroke-width: 3px; +} + +.stroke-5 { + stroke-width: 3px; +} + +@keyframes appear-animation { + 0% { + opacity: 0%; + transform: scale(75%); + } + 80% { + transform: scale(100%); + } + 90% { + transform: scale(97.5%); + } + 100% { + opacity: 100%; + transform: scale(100%); + } +} +@keyframes appear-animation-opacity { + 0% { + opacity: 0%; + } + 100% { + opacity: 100%; + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/CopyInput.tsx b/sites/app.campground.gg/src/components/CopyInput.tsx new file mode 100644 index 00000000..b7a05d4d --- /dev/null +++ b/sites/app.campground.gg/src/components/CopyInput.tsx @@ -0,0 +1,44 @@ +import { Button, Input } from "@mui/joy"; +import { useState } from "react"; +import { useIntl } from "react-intl"; +import { useSnackbars } from "~/context/snackbar"; +import { FormattedMessageGlobal } from "~/i18n"; + +type Props = { + text?: string; + placeholder?: string; + onCopy?: () => string | Promise; +}; + +export default function CopyInput({ text: copyText, placeholder, onCopy }: Props) { + if (!(copyText || onCopy)) + throw new Error("Expected text or onCopy in the props"); + + const floating = useSnackbars(); + const [text, setText] = useState(copyText || placeholder); + const intl = useIntl(); + + const onClick = async () => { + const fetched = copyText ?? await onCopy!(); + navigator.clipboard.writeText(fetched); + setText(fetched); + floating.notifySuccess( + intl.formatMessage({ + id: "common.copy.successful", + defaultMessage: "Successfully copied!", + description: "User has successfully copied a value", + }) + ); + } + + return ( + + + + } + /> + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/Datestamp.tsx b/sites/app.campground.gg/src/components/Datestamp.tsx new file mode 100644 index 00000000..be8d2bfa --- /dev/null +++ b/sites/app.campground.gg/src/components/Datestamp.tsx @@ -0,0 +1,103 @@ +import { Tooltip, styled } from "@mui/joy"; +import ms from "ms"; +import { FormattedMessage, defineMessage } from "react-intl"; + +type DatestampType = "ago" | "now" | "in" | "none"; +type Props = { + date: Date | undefined | null; + long?: boolean; + when?: boolean; + prefix?: string; + displayDate?: boolean; + dateOptions?: Intl.DateTimeFormatOptions; +}; + +export const defaultDateOptions: Intl.DateTimeFormatOptions = { + weekday: "long", + year: "numeric", + month: "long", + day: "numeric", + hour: "2-digit", + minute: "2-digit", +}; + +const DatestampRoot = styled("span", { + name: "Datestamp", + slot: "root", +})(() => ({ + display: "inline-block", + verticalAlign: "center", +})); + +const datestampFormatByType: Record> = { + ago: defineMessage({ + id: "app.time.ago", + defaultMessage: "{time} ago", + description: "When something happened 'ago'", + }), + now: defineMessage({ + id: "app.time.now", + defaultMessage: "Just now", + description: "When something happened just now (less than a minute ago)", + }), + in: defineMessage({ + id: "app.time.in", + defaultMessage: "In {time}", + description: "When something will happen in specific time", + }), + none: defineMessage({ + id: "app.time.none", + defaultMessage: "{time}", + description: "Unformatted timestamp", + }), +}; + +export default function Datestamp({ prefix, dateOptions, when, displayDate, date, long }: Props) { + if (!date) + return ( + + + + ) + + const isInvalid = !date || Number.isNaN(date.getSeconds()); + + if (isInvalid) + return ( + + + + ); + + const timespan = Date.now() - date.getTime(); + const type: DatestampType = when + ? timespan < -1000 + ? "in" + : timespan < 60000 + ? "now" + : "ago" + : "none"; + + // Anything below a minute (seconds ago) should be displayed as "Just now" + const time = ; + const dateFormat = date.toLocaleString("en-US", dateOptions ?? defaultDateOptions); + + return ( + + + {prefix}{displayDate ? dateFormat : time} + + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/ErrorBoundary.tsx b/sites/app.campground.gg/src/components/ErrorBoundary.tsx new file mode 100644 index 00000000..e620422a --- /dev/null +++ b/sites/app.campground.gg/src/components/ErrorBoundary.tsx @@ -0,0 +1,78 @@ +import React, { PropsWithChildren } from "react"; +import HTTPError from "~/util/HTTPError"; +import PagePlaceholder, { PagePlaceholderIcon } from "./pages/PagePlaceholder"; +import { Typography } from "@mui/joy"; +import { TextBlock } from "components"; + +interface ErrorBoundaryError { + message: string; + header: string; + status: number | null; +} +type State = { + error: ErrorBoundaryError | null; +}; + +export default class ErrorBoundary extends React.Component { + constructor(props: PropsWithChildren) { + super(props); + this.state = { error: null }; + } + componentDidCatch(error: Error, _errorInfo: React.ErrorInfo): void { + return this.setState(ErrorBoundary.getDerivedStateFromError(error)); + } + render() { + const { error } = this.state; + + if (error) + return ( + + {error.status + ? + {error.status} + + : null + } + + {error.header} + + + }> + {error.message} + + ); + + const { children } = this.props; + + const Renderer = () => { + return children; + } + + try { + return ( + + ); + } catch(e) { + console.error("Error not caught by error boundary", e); + } + } + static getDerivedStateFromError(error: Error): { error: ErrorBoundaryError } { + if (error instanceof HTTPError) + return { + error: { + message: error.message, + header: error.header, + status: error.status, + } + }; + + return { + error: { + message: error.message, + header: error.name, + status: null, + } + }; + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/ImageEditBadge.tsx b/sites/app.campground.gg/src/components/ImageEditBadge.tsx new file mode 100644 index 00000000..b2c0df9c --- /dev/null +++ b/sites/app.campground.gg/src/components/ImageEditBadge.tsx @@ -0,0 +1,18 @@ +import { Badge, styled } from "@mui/joy"; + +const ImageEditBadge = styled(Badge)(({ theme }) => ({ + cursor: "pointer", + color: theme.vars.palette.text.tertiary, + width: "min-content", + "& > .MuiBadge-badge": { + backgroundColor: theme.vars.palette.background.level3, + padding: 0, + transitionProperty: "background, color", + transitionDuration: "0.3s", + }, + "&:hover > .MuiBadge-badge": { + backgroundColor: theme.vars.palette.background.level4, + color: theme.vars.palette.text.secondary, + }, +})); +export default ImageEditBadge; \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/ItemBottomMover.tsx b/sites/app.campground.gg/src/components/ItemBottomMover.tsx new file mode 100644 index 00000000..181f1ebc --- /dev/null +++ b/sites/app.campground.gg/src/components/ItemBottomMover.tsx @@ -0,0 +1,41 @@ +import { Box, styled } from "@mui/joy"; +import { useDroppable } from "~/draggable"; + +const ItemBottomMoverBox = styled(Box, { + name: "ItemBottomMoverBox", + slot: "root", +})(({ theme }) => ({ + height: 12, + position: "relative", + backgroundColor: "transparent", + "&::before": { + content: "''", + position: "absolute", + top: 0, + left: 0, + right: 0, + height: 2, + borderRadius: theme.vars.radius.md, + backgroundColor: "transparent", + transition: "background 0.3s", + }, + "&.ItemBottomMover-over::before": { + backgroundColor: theme.vars.palette.primary[500], + }, +})); + +export default function ItemBottomMover({ disabled, group, categoryId, bottomItemId }: { disabled?: boolean; group?: "bonfire" | "tent" | "category"; categoryId: string; bottomItemId?: string | undefined; }) { + const { attributes: droppableAttributes, isOver } = useDroppable({ + id: `b:${categoryId}`, + disabled, + ignoreIds: bottomItemId ? [bottomItemId] : undefined, + group: group ?? "tent", + }); + + return ( + + ) +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/Link.tsx b/sites/app.campground.gg/src/components/Link.tsx new file mode 100644 index 00000000..8d3ff588 --- /dev/null +++ b/sites/app.campground.gg/src/components/Link.tsx @@ -0,0 +1,20 @@ +import { CircularProgress, Link as JoyLink, type LinkProps, styled } from "@mui/joy"; +import { useState } from "react"; +import { useNavigate } from "react-router"; + +const LinkRoot = styled(JoyLink, { + slot: "root" +})(() => ({ + +})); + +export default function Link({ children, href, ...props }: LinkProps) { + const navigate = useNavigate(); + const [loading, setLoading] = useState(false); + + return ( + : props.startDecorator} onClick={href ? () => (setLoading(true), navigate(href)) : undefined}> + {children} + + ) +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/SimpleNotification.tsx b/sites/app.campground.gg/src/components/SimpleNotification.tsx new file mode 100644 index 00000000..40b06d3c --- /dev/null +++ b/sites/app.campground.gg/src/components/SimpleNotification.tsx @@ -0,0 +1,28 @@ +import { Badge } from "@mui/joy"; +import { ReactNode } from "react"; + +type Props = { + children: ReactNode[] | ReactNode; + regular?: boolean; + pingCount?: number; + size?: "sm" | "md" | "lg"; + badgeInset?: number; +}; + +const notificationWidth: Record<"sm" | "md" | "lg", number> = { + sm: 12, + md: 16, + lg: 24, +} + +export default function SimpleNotification({ children, pingCount, regular, size, badgeInset }: Props) { + const inset = badgeInset ?? 4; + + return ( + + + {children} + + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/ThreadLine.tsx b/sites/app.campground.gg/src/components/ThreadLine.tsx new file mode 100644 index 00000000..fe86f078 --- /dev/null +++ b/sites/app.campground.gg/src/components/ThreadLine.tsx @@ -0,0 +1,83 @@ +import { Box, Stack, styled } from "@mui/joy"; +import type { SxProps } from "@mui/joy/styles/types"; +import { Group } from "components"; +import React from "react"; + +const ThreadItemHook = styled(`div`, { + name: "ThreadLineItem", + slot: "hook", +})(({ theme }) => ({ + position: "absolute", + border: `solid 3px ${theme.vars.palette.neutral[700]}`, + height: "50%", + width: 30, + left: 20, + "&:not(.reverse)": { + borderTop: 0, + borderRight: 0, + borderBottomLeftRadius: theme.vars.radius.md, + bottom: "50%", + }, + "&.reverse": { + borderBottom: 0, + borderRight: 0, + borderTopLeftRadius: theme.vars.radius.md, + top: "50%", + } +})); +const ThreadItemLine = styled(`div`, { + name: "ThreadLineItem", + slot: "line", +})(({ theme }) => ({ + position: "absolute", + border: `solid 3px ${theme.vars.palette.neutral[700]}`, + borderTop: 0, + borderRight: 0, + height: `calc(50% + ${theme.vars.radius.md})`, + width: 3, + left: 20, + "&:not(.reverse)": { + bottom: 0, + }, + "&.reverse": { + top: 0, + }, +})); + +const ThreadLineItemWrapper = styled(Group, { + name: "ThreadLineItem", + slot: "root", +})(() => ({ + position: "relative", + width: "100%", + "&:not(.reverse):last-of-type .line": { + opacity: 0, + }, + "&.reverse:first-of-type .line": { + opacity: 0, + }, +})); + +export function ThreadLineItem({ children, reverse, hookSx }: React.PropsWithChildren & { reverse?: boolean; hookSx?: SxProps }) { + return ( + + + + + {children} + + + ) +} +export function ThreadLineWrapper({ children, }: { children: React.ReactElement[] }) { + return ( + + + {children[0]} + + + {children.slice(1)} + + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/Tristate.tsx b/sites/app.campground.gg/src/components/Tristate.tsx new file mode 100644 index 00000000..54d08b36 --- /dev/null +++ b/sites/app.campground.gg/src/components/Tristate.tsx @@ -0,0 +1,119 @@ +import { Box, ButtonGroup, IconButton, Stack, styled, type VariantProp } from "@mui/joy"; +import { IconCheck, IconSlash, IconX } from "@tabler/icons-react"; +import React, { useState, type ReactNode } from "react"; + +const TristateRoot = styled(Stack, { + name: "Tristate", + slot: "root", +})<{ ownerState: TristateOwnerState; }>(({ ownerState }) => ({ + display: "inline-flex", + flexDirection: ownerState.left ? "row-reverse" : "row", + gap: "var(--Tristate-gap, 0.625rem)", +})); + +const TristateLabel = styled(Box, { + name: "Tristate", + slot: "label", +})<{ ownerState: TristateOwnerState; }>(() => ({ + flex: 1, +})); + +const TristateBox = styled(ButtonGroup, { + name: "Tristate", + slot: "box", +})<{ ownerState: TristateOwnerState; }>(({ theme }) => ({ + position: "relative", + overflow: "hidden", + "--ButtonGroup-separatorColor": "transparent", + border: `solid 1px ${theme.vars.palette.neutral[800]}`, + boxShadow: theme.vars.shadow.sm, +})); + +const TristateBoxBackground = styled(Box, { + name: "Tristate", + slot: "box-background", +})<{ ownerState: TristateOwnerState; }>(({ theme }) => ({ + position: "absolute", + height: "100%", + width: "33.33%", + top: 0, + bottom: 0, + left: 0, + transitionDuration: "0.3s", + transitionProperty: "background, left", + backgroundColor: theme.vars.palette.neutral[800], + "&.on": { + left: "66.66%", + backgroundColor: theme.vars.palette.success[900], + }, + "&.pass": { + left: "33.33%", + backgroundColor: theme.vars.palette.warning[900], + }, + "&.off": { + left: "0%", + backgroundColor: theme.vars.palette.danger[900], + } +})); + +export type TristateValue = "on" | "pass" | "off"; +export interface TristateProps { + value?: TristateValue; + defaultValue?: TristateValue; + variant?: VariantProp; + label?: ReactNode | ReactNode[]; + left?: boolean; + onChange?: (value: TristateValue) => unknown; +}; +interface TristateOwnerState extends TristateProps { + +} +const TristateButton = styled(IconButton)(({ theme, color }) => ({ + color: theme.vars.palette.text.quartary, + backgroundColor: "transparent", + transitionProperty: "color, background", + transitionDuration: "0.3s", + "&:hover": { + backgroundColor: "rgba(255, 255, 255, 0.05)", + color: theme.vars.palette.text.tertiary, + }, + "&.checked": { + color: theme.vars.palette[color as "neutral"][500], + }, + "&.checked:hover": { + backgroundColor: "rgba(255, 255, 255, 0.05)", + color: theme.vars.palette[color as "neutral"][400], + } +})); + +const Tristate = React.forwardRef(function Tristate(props, ref) { + const { value, defaultValue, variant, label, onChange } = props; + + const ownerState = { ...props, variant }; + const [triValue, setTriValue] = value ? [value] : useState(value ?? defaultValue ?? "pass"); + const onValueChange = (newValue: TristateValue) => { + setTriValue?.(newValue); + onChange?.(newValue); + }; + + return ( + + + + + + + + + + + + + + {label && + {label} + } + + ); +}); +export default Tristate; \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/UnstyledLink.tsx b/sites/app.campground.gg/src/components/UnstyledLink.tsx new file mode 100644 index 00000000..fc24eb8f --- /dev/null +++ b/sites/app.campground.gg/src/components/UnstyledLink.tsx @@ -0,0 +1,7 @@ +import { styled } from "@mui/joy"; +import { Link } from "react-router"; + +const UnstyledLink = styled(Link)(() => ({ + textDecoration: "none", +})); +export default UnstyledLink; \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/UserAvatar.tsx b/sites/app.campground.gg/src/components/UserAvatar.tsx new file mode 100644 index 00000000..92218fc0 --- /dev/null +++ b/sites/app.campground.gg/src/components/UserAvatar.tsx @@ -0,0 +1,88 @@ +import { Avatar, Badge, Skeleton, styled } from "@mui/joy"; +import type { SxProps } from "@mui/joy/styles/types"; + +const availableBadgeSizes = ["sm", "md", "lg"]; + +type Size = "sm" | "md" | "lg" | "xl" | "xxl" | "xxxl"; +type Props = { + did: string; + withStatus?: boolean; + avatar?: string | null; + status?: string | null; + size?: Size; + sx?: SxProps; + badgeSx?: SxProps; +}; +const sizeToPx: Record = { + sm: 24, + md: 32, + lg: 48, + xl: 56, + xxl: 80, + xxxl: 128, +}; + +const StyledAvatar = styled(Avatar)<{ size?: Size }>(({ theme, size }) => ({ + width: sizeToPx[size ?? "md"], + height: sizeToPx[size ?? "md"], + borderRadius: theme.vars.radius[(size as Size) === "xxl" || (size as Size) === "xxxl" ? "xl" : size as "md" ?? "md"], + // zIndex: 7, +})); + +export default function UserAvatar({ withStatus, avatar, size, badgeSx, sx }: Props) { + const sizePx = sizeToPx[size ?? "md"]; + const badgeSize = sizePx * 0.25; + + return ( + + + + + ); +} + +export function UserAvatarSkeleton({ size, withStatus, sx }: Pick) { + const sizePx = sizeToPx[size ?? "md"]; + const badgeSize = sizePx * 0.25; + + return ( + + + + + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/UserDisplay.tsx b/sites/app.campground.gg/src/components/UserDisplay.tsx new file mode 100644 index 00000000..5bfe1c09 --- /dev/null +++ b/sites/app.campground.gg/src/components/UserDisplay.tsx @@ -0,0 +1,112 @@ +import { Dropdown, Menu, MenuButton, Skeleton, Typography, styled } from "@mui/joy"; +import UserAvatar, { UserAvatarSkeleton } from "./UserAvatar"; +import type { ProfileView } from "types/user"; +import UserProfileCard from "../layout/UserProfileCard"; +import { GradientTypography, Group, TextBlock } from "components"; +import type { MemberView } from "types/membership"; +import type { RoleMotion } from "types/roles"; +import type { RoleView } from "types/roles"; +import type { MouseEvent } from "react"; + +type Size = "sm" | "md" | "lg"; + +type Props = { + user: T; + member?: MemberView | null; + noAvatar?: boolean; + motion?: RoleMotion; + colors?: string[]; + size?: Size; + avatarSize?: Size | "xl"; + showHandle?: boolean; + align?: "top" | "center" | "bottom"; + noHoverBackground?: boolean; + withStatus?: boolean; + campsiteRoles?: RoleView[]; +}; + +const sizeToGap: Record = { + sm: 1, + md: 1.5, + lg: 2, +}; + +const GapSpan = styled("span", { + name: "UserDisplay", + slot: "gap", +})(() => ({ + display: "inline-block", +})); + +export function UserDisplayNoModal({ onClick, withStatus, noAvatar, colors, motion, user, size, avatarSize, align, showHandle, member, }: Props & { onClick?: (ev: MouseEvent) => unknown; }) { + const actualSize = size ?? "md"; + return ( + + {!noAvatar && + <> + + + + + + } + + + {member?.nickname ?? user.displayName} + + + { + showHandle && <> + + + @{user.handle.split("/")[2]} + + + } + + ); +} + +export default function UserDisplay(props: Props) { + return ( + <> + + + + + + + + + + ); +} + +export function UserDisplaySkeleton({ showHandle, withStatus, noAvatar, size, alignItems, avatarSize }: Pick, "showHandle" | "withStatus" | "noAvatar" | "size" | "alignItems" | "avatarSize">) { + const actualSize = size ?? "md"; + + return ( + + {!noAvatar && } + + + Example user + + + { + showHandle && <> + + + @example + + + + } + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/VerifiedIcon.tsx b/sites/app.campground.gg/src/components/VerifiedIcon.tsx new file mode 100644 index 00000000..fafd4632 --- /dev/null +++ b/sites/app.campground.gg/src/components/VerifiedIcon.tsx @@ -0,0 +1,23 @@ +import { Avatar } from "@mui/joy"; +import { IconCheck } from "@tabler/icons-react"; + +type Props = { + size?: "xs" | "sm" | "md" | "lg"; +}; + +const pxToSize: Record<"xs" | "sm" | "md" | "lg", number> = { + xs: 12, + sm: 16, + md: 20, + lg: 24, +}; + +export default function VerifiedIcon({ size }: Props) { + const sizePx = pxToSize[size ?? "md"]; + + return ( + + + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/campsite/RoleDisplay.tsx b/sites/app.campground.gg/src/components/campsite/RoleDisplay.tsx new file mode 100644 index 00000000..04e4afa1 --- /dev/null +++ b/sites/app.campground.gg/src/components/campsite/RoleDisplay.tsx @@ -0,0 +1,99 @@ +import { styled, type ButtonProps, type Radius } from "@mui/joy"; +import { IconX, type ReactNode } from "@tabler/icons-react"; +import type { RoleView } from "types/roles"; +import { colorToDecimal } from "~/util/color"; + +const RoleDisplayBadge = styled("span", { + name: "RoleDisplay", + slot: "root" +})<{ colors?: string[] | undefined; }>(({ colors, theme }) => ({ + display: "flex", + // color: colors?.length ?? theme.vars.palette.text.secondary, + WebkitTextFillColor: "transparent", + background: colors?.length ? colors.length > 1 ? `linear-gradient(to right, ${colors.join(", ")}) text` : `${colors[0]} text` : `${theme.vars.palette.text.secondary} text`, + // border: color ? "none" : `dashed 1px ${theme.vars.palette.neutral[400]}`, + fontWeight: 700, + padding: `2px 8px`, + width: "max-content", + flexDirection: "row", + alignItems: "center", + gap: 6, + overflow: "hidden", + position: "relative", + borderRadius: theme.vars.radius.lg, + "::after": { + content: "''", + position: "absolute", + opacity: 0.20, + top: 0, + left: 0, + border: `solid 1px transparent`, + right: 0, + bottom: 0, + zIndex: 0, + background: colors?.length ? colors.length > 1 ? `linear-gradient(to right, ${colors.join(", ")})` : colors[0] : `transparent`, + }, + "&.uncolored::after": { + opacity: 1, + border: colors?.length ? `solid 1px transparent` : `dashed 1px ${theme.vars.palette.neutral[400]}`, + }, +})); +const RoleDisplayCircle = styled("div", { + name: "RoleDisplay", + slot: "circle" +})<{ colors?: string[] | undefined; }>(({ colors, theme }) => ({ + display: "block", + width: 16, + height: 16, + minWidth: 16, + borderRadius: "100%", + background: colors?.length ? colors.length > 1 ? `linear-gradient(to right, ${colors.join(", ")})` : `${colors[0]}` : theme.vars.palette.neutral[400], +})); +const RoleDisplayDecorator = styled("span", { + name: "RoleDisplay", + slot: "remove" +})(() => ({ + zIndex: 4, + lineHeight: 0, + cursor: "pointer", + padding: 2, +})); +const RoleDisplayName = styled("span", { + name: "RoleDisplay", + slot: "name", +})(() => ({ + width: "max-content", +})); + +type Props = { + role: RoleView; + radius?: keyof Radius; + size?: ButtonProps["size"]; + startDecorator?: ReactNode[] | ReactNode; + endDecorator?: ReactNode[] | ReactNode; + onClick?: (role: RoleView) => unknown; + onRemove?: (role: RoleView) => unknown; +}; +const sizeToPadding = { + "sm": "0px 6px", + "md": "2px 8px", +}; + +export default function RoleDisplay({ radius, role, size, startDecorator, endDecorator, onClick, onRemove }: Props) { + const colors = colorToDecimal(role.colors); + const padding = sizeToPadding[size as "md" ?? "md"]; + return ( + onClick(role) : undefined} sx={{ p: padding, borderRadius: radius, cursor: onClick ? "pointer" : undefined }}> + {startDecorator || } + + {role.name} + + {endDecorator && + {endDecorator} + } + {onRemove && !(role.flags & 1) && onRemove(role)}> + + } + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/content/ContentCategory.tsx b/sites/app.campground.gg/src/components/content/ContentCategory.tsx new file mode 100644 index 00000000..bb385bda --- /dev/null +++ b/sites/app.campground.gg/src/components/content/ContentCategory.tsx @@ -0,0 +1,49 @@ +import { Box, IconButton, Stack, styled } from "@mui/joy"; +import { Group } from "components"; +import React, { useState, type HTMLAttributes } from "react"; +import { RotatingCaret } from "./RotatingCaret"; + +const CategoryContainer = styled(Stack, { + name: "CategoryContainer", + slot: "root", +})(({ theme }) => ({ + position: "relative", + "&::after": { + content: "''", + position: "absolute", + top: -2, + left: 0, + right: 0, + height: 2, + borderRadius: theme.vars.radius.md, + backgroundColor: "transparent", + transition: "background 0.3s", + }, + "&.CategoryContainer-over::after": { + backgroundColor: theme.vars.palette.primary[500], + }, +})); + +type Props = React.PropsWithChildren & HTMLAttributes & { + header: React.ReactNode | React.ReactNode[]; + isDraggingOver?: boolean; +}; + +export default function ContentCategory({ header, children, isDraggingOver, ...attributes }: Props) { + const [open, setOpen] = useState(true); + const className = [open && "CategoryContainer-open", isDraggingOver && "CategoryContainer-over"].filter((x) => x).join(" "); + + return ( + + + setOpen(!open)}> + x).join(" ")} /> + + {header} + + + {children} + + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/content/ContentOverflow.tsx b/sites/app.campground.gg/src/components/content/ContentOverflow.tsx new file mode 100644 index 00000000..3f0d8713 --- /dev/null +++ b/sites/app.campground.gg/src/components/content/ContentOverflow.tsx @@ -0,0 +1,31 @@ +import { CardOverflow, Dropdown, Menu, MenuButton, styled } from "@mui/joy"; +import { IconDotsVertical } from "@tabler/icons-react"; + +const OverflowButtonWrapper = styled(CardOverflow, { + name: "CampgroundOverflow", +})(() => ({ + position: "absolute", + top: 5, + right: 5, + zIndex: 10, + transition: "opacity 0.5s", + opacity: 0, + ".MuiCard-root:hover &, .CampgroundOverflow-parent:hover &": { + opacity: 1, + } +})); + +export default function ContentOverflow({ children }: React.PropsWithChildren) { + return ( + + + + + + + { children } + + + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/content/RotatingCaret.tsx b/sites/app.campground.gg/src/components/content/RotatingCaret.tsx new file mode 100644 index 00000000..549433a5 --- /dev/null +++ b/sites/app.campground.gg/src/components/content/RotatingCaret.tsx @@ -0,0 +1,13 @@ +import { styled } from "@mui/joy"; +import { IconCaretRightFilled } from "@tabler/icons-react"; + +export const RotatingCaret = styled(IconCaretRightFilled, { + name: "RotatingCaret", + slot: "root" +})(() => ({ + transform: "rotate(0deg)", + transition: "transform 0.5s", + "&.RotatingCaret-open": { + transform: "rotate(90deg)", + } +})); \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/BasicPostEditor.tsx b/sites/app.campground.gg/src/components/editor/BasicPostEditor.tsx new file mode 100644 index 00000000..c363044b --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/BasicPostEditor.tsx @@ -0,0 +1,50 @@ +import { Button, Divider, Link, Stack } from "@mui/joy"; +import type { SxProps } from "@mui/joy/styles/types"; +import { useState } from "react"; +import { Group } from "components"; +import BlockTextSlate from "./BlockTextSlate"; +import withCgMarkdown from "~/editor/withCgMarkdown"; +import { withHistory } from "slate-history"; +import { withReact } from "slate-react"; +import { createEditor } from "slate"; +import type { RichEditor } from "~/editor/editor"; +import { IconArrowRight } from "@tabler/icons-react"; +import { mdastifyEditor } from "~/editor/mdast"; +import { serializeMarkdown } from "~/editor/mdast/markdown"; +import TextEditor from "./TextEditor"; +import RichEditorToolbar, { RichEditorToolbarBlockFormatting, RichEditorToolbarHeading, RichEditorToolbarInlineFormatting, RichEditorToolbarTableFormatting } from "./RichEditorToolbar"; + +type Props = { + content?: string; + placeholder?: string; + sx?: SxProps; + confirmButton?: string; + onConfirm: (content: string) => void | Promise; + onCancel?: () => void | Promise; +}; + +export default function BasicPostEditor({ placeholder, onConfirm, onCancel, content, confirmButton, sx }: Props) { + const [editor] = useState(() => withCgMarkdown(withHistory(withReact(createEditor()))) as RichEditor); + + return ( + + ({ color: theme.vars.palette.text.secondary })}> + + + + + + + + + + + + + + + {onCancel && Cancel} + + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/BlockNodeInsert.tsx b/sites/app.campground.gg/src/components/editor/BlockNodeInsert.tsx new file mode 100644 index 00000000..06ccacff --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/BlockNodeInsert.tsx @@ -0,0 +1,32 @@ +import { IconButton } from "@mui/joy"; +import { ReactNode } from "react"; +import { useSlate } from "slate-react"; +import type { EditorBlockElementType, EditorItemElementType } from "../../editor/editor"; + +type Props = { + format: EditorBlockElementType | EditorItemElementType; + children: ReactNode[] | ReactNode; +}; + +export default function BlockNodeInsert({ children, format: formatting, }: Props) { + const editor = useSlate(); + + const addFormatting = (ev: React.MouseEvent) => { + ev.preventDefault(); + + editor.insertNode( + { + type: formatting, + children: [], + }, + { + at: editor.selection?.focus ?? [editor.children.length], + } + ); + }; + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/BlockNodeMenuItem.tsx b/sites/app.campground.gg/src/components/editor/BlockNodeMenuItem.tsx new file mode 100644 index 00000000..eb28ebed --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/BlockNodeMenuItem.tsx @@ -0,0 +1,28 @@ +import { MenuItem } from "@mui/joy"; +import { ReactNode } from "react"; +import { useSlate } from "slate-react"; +import type { EditorBlockElementType } from "../../editor/editor"; +import CampgroundEditor from "./CampgroundEditor"; + +type Props = { + format: EditorBlockElementType; + additionalProps?: any; + children: ReactNode[] | ReactNode; + onClick?: () => void; +}; + +export default function BlockNodeMenuItem({ children, format: formatting, additionalProps, onClick }: Props) { + const editor = useSlate(); + + const setFormatting = (ev: React.MouseEvent) => { + ev.preventDefault(); + CampgroundEditor.setBlockFormatting(editor, formatting, additionalProps); + onClick?.(); + }; + + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/BlockNodeToggle.tsx b/sites/app.campground.gg/src/components/editor/BlockNodeToggle.tsx new file mode 100644 index 00000000..2cba810f --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/BlockNodeToggle.tsx @@ -0,0 +1,30 @@ +import { IconButton } from "@mui/joy"; +import { ReactNode } from "react"; +import { useSlate } from "slate-react"; +import type { RichEditor, EditorBlockElementType } from "../../editor/editor"; +import CampgroundEditor from "./CampgroundEditor"; + +type Props = { + format: T; + children: ReactNode[] | ReactNode; + onClick?: (editor: RichEditor, format: T) => void; +}; + +export default function BlockNodeToggle({ children, format: formatting, onClick }: Props) { + const editor = useSlate(); + + const active = CampgroundEditor.isNodeFormatted(editor, formatting); + + const toggleFormattingFn = onClick ?? CampgroundEditor.toggleBlockFormatting; + + const toggleFormatting = (ev: React.MouseEvent) => { + ev.preventDefault(); + toggleFormattingFn(editor, formatting); + }; + + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/BlockTextSlate.tsx b/sites/app.campground.gg/src/components/editor/BlockTextSlate.tsx new file mode 100644 index 00000000..76b04543 --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/BlockTextSlate.tsx @@ -0,0 +1,41 @@ +import { Slate } from "slate-react"; +import type { SxProps } from "@mui/joy/styles/types"; +import { styled } from "@mui/joy"; +import type { RichEditor } from "../../editor/editor"; +import { paragraph } from "~/editor/utils"; +import { deserializeMarkdown } from "~/editor/mdast/markdown"; +import { slatefyRoot } from "~/editor/mdast/editor"; +import ErrorBoundary from "../ErrorBoundary"; + +type Props = React.PropsWithChildren & { + ref?: React.RefObject; + editor: RichEditor; + sx: SxProps; + defaultValue?: string; + enableToolbar?: boolean; +}; + +const StyledContainer = styled("div", { + name: "MarkdownEditorContainer", + slot: "root", +})(({ theme }) => ({ + position: "relative", + border: `solid 1px ${theme.vars.palette.neutral[600]}`, + borderRadius: theme.vars.radius.md, + // position: "relative", + // overflow: "hidden", + color: theme.vars.palette.text.secondary, +})); + +export default function BlockTextSlate({ ref, defaultValue, editor, sx, children }: Props) { + + return ( + + + + {children} + + + + ) +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/CampgroundEditor.tsx b/sites/app.campground.gg/src/components/editor/CampgroundEditor.tsx new file mode 100644 index 00000000..84937452 --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/CampgroundEditor.tsx @@ -0,0 +1,332 @@ +import { type Ancestor, Editor, Element, Node, type NodeEntry, type Path, Text, Transforms } from "slate"; +import { EditorInlineElementType, type RichEditor, type EditorElementType, type EditorBlockElementType, type EditorItemElementType } from "../../editor/editor"; +import type { EditorTextFormatting } from "~/editor/text"; +import { EditorItemParents, EditorListElementType } from "~/editor/element"; +import { paragraph } from "~/editor/utils"; + +export default class CampgroundEditor { + static clearEditor(editor: RichEditor) { + editor.delete({ + at: { + anchor: editor.start([]), + focus: editor.end([]), + } + }); + editor.unwrapNodes({ mode: "all", match: (node) => !Editor.isEditor(node) }); + + editor.insertNode(paragraph()); + } + static isNodeFormatted(editor: RichEditor, type: EditorElementType) { + const { selection } = editor; + + // Can't detect nodes; out of focus of editor + if (!selection) + return false; + + const [match] = Array.from( + Editor.nodes(editor, { + at: Editor.unhangRange(editor, selection), + match: n => { + if (!Editor.isEditor(n) && Element.isElement(n)) + return n.type === type; + + return false; + } + }) + ); + + // Returned at least one element, which means it is formatted + return Boolean(match); + } + static getSelectedNodes(editor: RichEditor, type?: EditorElementType): NodeEntry[] | null { + const { selection } = editor; + + // Can't detect nodes; out of focus of editor + if (!selection) + return null; + + return Array.from( + Editor.nodes(editor, { + at: Editor.unhangRange(editor, selection), + match: n => !Editor.isEditor(n) && Element.isElement(n) && (!type || n.type === type), + }) + ); + } + static getNearestAncestor(editor: RichEditor, type?: EditorElementType): NodeEntry | undefined | null { + const { selection } = editor; + + // Can't detect nodes; out of focus of editor + if (!selection) + return null; + + return Editor.above(editor, { + at: Editor.unhangRange(editor, selection), + match: n => !Editor.isEditor(n) && Element.isElement(n) && (!type || n.type === type), + }); + } + static isTextFormatted(editor: RichEditor, type: keyof EditorTextFormatting) { + const marks = Editor.marks(editor); + return (marks?.[type] as boolean | null) ?? false; + } + static toggleTextFormatting(editor: RichEditor, type: keyof EditorTextFormatting) { + const isMarked = this.isTextFormatted(editor, type); + + return isMarked ? Editor.removeMark(editor, type) : Editor.addMark(editor, type, true); + } + static isListElement(element: any) { + return Element.isElement(element) && EditorItemParents["list-item"].includes(element.type as EditorBlockElementType); + } + static toggleBlockFormatting(editor: RichEditor, type: EditorBlockElementType, additionalProps?: any) { + const active = CampgroundEditor.isNodeFormatted(editor, type); + + // Simple type change + const props = active ? additionalProps && Object.keys(additionalProps).reduce((obj, prop) => (obj[prop] = null, obj), {} as Record) : additionalProps; + + Transforms.setNodes(editor, { + type: active ? `paragraph` : type, + ...props, + }); + } + static insertTableRow(editor: RichEditor, columns: number, tablePath: Path, row: number) { + const rowPath = [...tablePath, row]; + console.log({ tablePath }); + editor.insertNode( + { + type: "table-row", + children: Array(columns) + .fill(null) + .map(() => ({ + type: "table-cell", + children: [ + { text: "" } + ] + })) + }, + { + at: rowPath, + } + ); + editor.select({ path: [...rowPath, 0, 0], offset: 1 }); + } + static insertTableColumn(editor: RichEditor, rows: number, tablePath: Path, column: number) { + for (let row = 0; row < rows; row++) { + const columnPath = [...tablePath, row, column]; + + editor.insertNode( + { + type: "table-cell", + children: [ + { text: "" } + ] + }, + { + at: columnPath, + } + ); + } + // editor.select({ path: [...insertedPath, 0, 0], offset: 1 }); + } + static removeTableColumn(editor: RichEditor, tablePath: Path, column: number) { + editor.removeNodes( + { + at: tablePath, + match: (node, path) => Element.isElement(node) && node.type === "table-cell" && path.slice(-1)[0] === column, + }, + ); + } + static setBlockFormatting(editor: RichEditor, type: EditorBlockElementType, additionalProps?: any) { + // Simple type change + Transforms.setNodes(editor, { + type: type, + ...additionalProps, + }); + } + static toggleInlineFormatting(editor: RichEditor, type: EditorInlineElementType) { + const active = CampgroundEditor.isNodeFormatted(editor, type); + + if (active) + return Transforms.unwrapNodes(editor, { + match: (n) => + !Editor.isEditor(n) && + Element.isElement(n) && + (EditorInlineElementType as readonly string[]).includes(n.type) + }); + + Transforms.wrapNodes( + editor, + { + type: "link", + url: "#", + children: [] + }, + { + match: (n) => + !Editor.isEditor(n) && + ((Element.isElement(n) && (EditorInlineElementType as readonly string[]).includes(n.type)) || Text.isText(n)) + } + ); + } + static toggleListFormatting(editor: RichEditor, type: EditorBlockElementType) { + if (!editor.selection) + return; + + const nearestList = Editor.above(editor, { + match: (node) => + Element.isElement(node) && + EditorListElementType.includes(node.type as EditorListElementType) + }); + + // Wrap into a list + if (!nearestList) + { + Transforms.wrapNodes( + editor, + { + type: "list-item", + children: [], + }, + { + at: editor.selection, + match: n => Element.isElement(n) + } + ); + Transforms.wrapNodes( + editor, + { + type, + children: [], + }, + { + match: n => Element.isElement(n) && n.type === "list-item" + } + ); + + return; + } + // Change list type + else if (Element.isElement(nearestList[0]) && nearestList[0].type !== type) + return Transforms.setNodes( + editor, + { + type, + }, + { + at: nearestList[1], + } + ); + + // unwrap all the lists + Transforms.unwrapNodes( + editor, + { + match: n => Element.isElement(n) && n.type === "list-item", + at: editor.selection, + split: true, + }, + ); + Transforms.unwrapNodes( + editor, + { + match: n => Element.isElement(n) && n.type === type, + split: true, + at: editor.selection, + mode: "all", + } + ); + } + static toggleCodeFormatting(editor: RichEditor, type: EditorBlockElementType, itemType: EditorItemElementType) { + const active = CampgroundEditor.isNodeFormatted(editor, type); + + // Simple type change + Transforms.setNodes( + editor, + { + type: active ? `paragraph` : itemType, + }, + { + match: n => Element.isElement(n), + split: true, + } + ); + + if (active) + Transforms.unwrapNodes( + editor, + { + match: n => Element.isElement(n) && n.type === type + } + ) + else + Transforms.wrapNodes( + editor, + { + type, + children: [], + lang: "js", + }, + { + match: n => Element.isElement(n) && n.type === itemType + } + ); + } + static insertTableFormatting(editor: RichEditor) { + editor.insertNode({ + type: "table", + children: [ + { + type: "table-row", + children: [ + { + type: "table-cell", + children: [ + { text: "Cell #1" } + ] + }, + { + type: "table-cell", + children: [ + { text: "Cell #2" } + ] + } + ] + }, + { + type: "table-row", + children: [ + { + type: "table-cell", + children: [ + { text: "Cell #3" } + ] + }, + { + type: "table-cell", + children: [ + { text: "Cell #4" } + ] + } + ] + } + ] + }); + } + static insertImageFormatting(editor: RichEditor, url: string, title?: string | null | undefined) { + editor.insertNode({ + type: "paragraph", + children: [ + { + type: "image", + url, + title, + children: [ + { + text: "" + }, + ], + } + ] + }, { + at: editor.selection?.focus, + }); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/CodeBlockEditorHeader.tsx b/sites/app.campground.gg/src/components/editor/CodeBlockEditorHeader.tsx new file mode 100644 index 00000000..5bce0ea7 --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/CodeBlockEditorHeader.tsx @@ -0,0 +1,45 @@ +import { Option, Select } from "@mui/joy"; +import type { EditorCodeBlock } from "../../editor/editor"; +import hljs from "highlight.js"; +import { useSlateStatic } from "slate-react"; +import { Element, Transforms } from "slate"; +import { Group } from "components"; + +type Props = { + element: EditorCodeBlock; +}; + +export default function CodeBlockEditorHeader({ element }: Props) { + const editor = useSlateStatic(); + + const onValueSelected = (_: unknown, language: string | null) => { + Transforms.setNodes( + editor, + { + lang: language, + }, + { + match: m => + Element.isElement(m) && m === element, + } + ); + }; + + const languages = + hljs + .listLanguages() + .map((x) => [x, hljs.getLanguage(x)?.name ?? x]); + + return ( + + + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/CodeNodeToggle.tsx b/sites/app.campground.gg/src/components/editor/CodeNodeToggle.tsx new file mode 100644 index 00000000..ea4e3acc --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/CodeNodeToggle.tsx @@ -0,0 +1,27 @@ +import { IconButton } from "@mui/joy"; +import { ReactNode } from "react"; +import { useSlate } from "slate-react"; +import type { EditorBlockElementType, EditorItemElementType } from "../../editor/editor"; +import CampgroundEditor from "./CampgroundEditor"; + +type Props = { + format: EditorBlockElementType; + itemFormat: EditorItemElementType; + children: ReactNode[] | ReactNode; +}; + +export default function CodeNodeToggle({ children, format: formatting, itemFormat }: Props) { + const editor = useSlate(); + + const active = CampgroundEditor.isNodeFormatted(editor, itemFormat); + + const toggleFormatting = (ev: React.MouseEvent) => { + ev.preventDefault(); + CampgroundEditor.toggleCodeFormatting(editor, formatting, itemFormat); + }; + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/EditorElement.tsx b/sites/app.campground.gg/src/components/editor/EditorElement.tsx new file mode 100644 index 00000000..570e50b6 --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/EditorElement.tsx @@ -0,0 +1,200 @@ +import { useSelected, useSlate, type RenderElementProps } from "slate-react"; +import type { EditorElementType, EditorCodeBlock, EditorCodeLine, EditorHeading } from "../../editor/editor"; +import React, { ReactNode } from "react"; +import { CodeContainer, CodeGrid, CodeHeader, CodeLine, CodeLineNumber, CodePre } from "../markdown/CodeBlock"; +import CodeBlockEditorHeader from "./CodeBlockEditorHeader"; +import { CodeEditorContextProvider, useCodeEditorContext } from "./codeEditorContext"; +import Link from "../Link"; +import { TableColumnContextProvider, TableContextProvider, TableRowContextProvider, useTableColumnContext, useTableRowContext } from "./tableHeadContext"; +import type { EditorImage, EditorOrderedList, EditorTable } from "~/editor/element"; +import Divider from "../markdown/Divider"; +import EditorImageDisplay, { EditorImageDisplayRoot, EditorImageAlt, EditorImageWrapperRoot, EditorImageHeaderRoot } from "./EditorImageDisplay"; +import EditorTableDisplay, { EditorColumnAdder, EditorRowAdder, EditorTableColumnAdderRow } from "./EditorTableDisplay"; +import { Typography } from "@mui/joy"; +import { IconFileFilled } from "@tabler/icons-react"; + +const typeToRenderer: Record (ReactNode[] | ReactNode)> = { + paragraph({ attributes, children }) { + return

{children}

+ }, + divider({ attributes }) { + const selected = useSelected(); + + return ; + }, + heading({ attributes, children, element }) { + const Tag = `h${(element as EditorHeading).depth ?? 1}` as "h1"; + return ( + + {children} + + ); + }, + link({ children, attributes }) { + return ( + + {children} + + ); + }, + image({ element, children }) { + const selected = useSelected(); + const image = element as EditorImage; + + return ( + + + {image.title && + + {image.title} + } + + + + {children} + + + ); + }, + ["block-quote"]({ attributes, children }) { + return
{children}
+ }, + ["code-block"]({ attributes, children, element }) { + return ( + + + + + + + + {children} + + + + + ); + }, + ["code-line"]({ element, attributes, children }) { + // Since no index is given + const context = useCodeEditorContext(); + const index = context?.findIndex((x) => x === element) ?? -1; + + return ( + <> + + {index + 1} + + + {children} + + + ); + }, + ["unordered-list"]({ attributes, children }) { + return ( +
    + {children} +
+ ); + }, + ["ordered-list"]({ element, attributes, children }) { + const ordered = element as EditorOrderedList; + return ( +
    + {children} +
+ ); + }, + ["list-item"]({ attributes, children }) { + return ( +
  • + {children} +
  • + ); + }, + ["table"]({ attributes, children, element }) { + const editor = useSlate(); + const table = element as EditorTable; + const headRow = children[0]; + const thisTable = [...editor.nodes({ + match: (node) => node === table, + })]; + + return ( + + + + + + {table.children.map((_, i) => + + + + )} + + + + {headRow} + + + + {(children as React.ReactElement[]).slice(1).map((x, i) => + + {x} + + )} + + + + + ); + }, + ["table-row"]({ attributes, children }) { + const row = useTableRowContext(); + const tableAlign = useTableColumnContext(); + + return ( + <> + + {(children as React.ReactElement[]).map((x, i) => + + {x} + + )} + + + + ); + }, + ["table-cell"]({ attributes, children }) { + const tableRow = useTableRowContext(); + const tableAlign = useTableColumnContext(); + // First row is a head + const Component = tableRow ? "td" : "th"; + + return ( + + {children} + + ); + }, + // ["inline-quote"]({ attributes, children }) { + // return ( + // + // {children} + // + // ); + // }, +} + +export default function EditorElement({ attributes, children, element }: RenderElementProps) { + const nodeType = element.type; + const Renderer = typeToRenderer[nodeType]; + + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/EditorImageDisplay.tsx b/sites/app.campground.gg/src/components/editor/EditorImageDisplay.tsx new file mode 100644 index 00000000..532efc22 --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/EditorImageDisplay.tsx @@ -0,0 +1,67 @@ +import { styled } from "@mui/joy"; +import { Image } from "components"; + +export const EditorImageDisplayRoot = styled(`div`, { + name: "EditorImage", + slot: "root", +})(() => ({ + position: "relative", + width: "min-content", + height: "min-content", +})); +export const EditorImageWrapperRoot = styled(`div`, { + name: "EditorImage", + slot: "wrapper", +})(({ theme }) => ({ + position: "relative", + display: "flex", + flexDirection: "column", + overflow: "hidden", + backgroundColor: theme.vars.palette.background.body, + borderRadius: theme.vars.radius.sm, +})); +export const EditorImageHeaderRoot = styled(`div`, { + name: "EditorImage", + slot: "header", +})(({ theme }) => ({ + overflow: "hidden", + whiteSpace: "break-spaces", + padding: "6px 8px", + display: "flex", + flexDirection: "row", + alignItems: "center", + color: theme.vars.palette.text.quartary, + gap: 4, +})); +export const EditorImageAlt = styled(`div`, { + name: "EditorImageAlt", + slot: "root", +})(({ theme }) => ({ + backgroundColor: theme.vars.palette.background.body, + color: theme.vars.palette.text.secondary, + borderRadius: theme.vars.radius.sm, + whiteSpace: "break-spaces", + marginTop: 2, + padding: "2px 4px", + "::before": { + content: "'Alt: '", + }, +})); +const EditorImageDisplay = styled(Image, { + name: "EditorImageDisplay", + slot: "image", +})(({ theme }) => ({ + border: "solid 1px transparent", + "&.selected": { + border: `solid 1px ${theme.vars.palette.primary[500]}` + } +})); +export default EditorImageDisplay; + +// export default function EditorImageDisplay({ element }: Props) { +// return ( +// +// +// +// ); +// } \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/EditorLeaf.tsx b/sites/app.campground.gg/src/components/editor/EditorLeaf.tsx new file mode 100644 index 00000000..816c24af --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/EditorLeaf.tsx @@ -0,0 +1,64 @@ +import { styled, Typography } from "@mui/joy"; +import type { RenderLeafProps } from "slate-react"; + +const Leaf = styled(Typography, { + name: "Leaf", +})<{ component: string; }>(({ theme }) => ({ + display: "inline", + fontSize: "inherit", + "h1, h2, h3, h4, h5, h6 &": { + fontSize: "inherit", + fontWeight: "bolder", + }, + "&.bold, &.strong": { + fontWeight: "bolder", + }, + "&.italic, &.emphasis": { + fontStyle: "italic", + }, + "&.strikethrough": { + textDecorationLine: "line-through", + }, + "&.underline": { + textDecorationLine: "underline", + }, + "&.underline.strikethrough": { + textDecorationLine: "line-through underline", + }, + "&.keyword, &.built_in": { + color: theme.vars.palette.text["code-keyword"], + }, + "&.function": { + color: theme.vars.palette.text["code-function"], + }, + "&.class": { + color: theme.vars.palette.text["code-class"], + }, + "&.attribute": { + color: theme.vars.palette.text["code-attribute"], + }, + "&.string": { + color: theme.vars.palette.text["code-string"], + }, + "&.number": { + color: theme.vars.palette.text["code-number"], + }, + "&.template": { + color: theme.vars.palette.text["code-template"], + }, +})); + +export default function EditorLeaf({ children, leaf, attributes }: RenderLeafProps) { + const { text: _, scope, ...rest } = leaf; + const classes = Object.keys(rest); + const { code } = rest; + + if (scope) + classes.push(scope); + + return ( + + {children} + + ) +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/EditorTableDisplay.tsx b/sites/app.campground.gg/src/components/editor/EditorTableDisplay.tsx new file mode 100644 index 00000000..7200e0c5 --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/EditorTableDisplay.tsx @@ -0,0 +1,135 @@ +import { styled } from "@mui/joy"; +import { useSlate } from "slate-react"; +import { useTableContext } from "./tableHeadContext"; +import CampgroundEditor from "./CampgroundEditor"; + +const EditorTableDisplay = styled("table", { + name: "EditorTableDisplay", + slot: "root" +})(() => ({ + position: "relative", +})); +export const EditorTableColumnAdderRow = styled("tr", { + name: "EditorTableDisplay", + slot: "column-adder-row" +})(() => ({ + position: "initial !important" as "initial", + height: 0, + "& > td": { + padding: 0, + height: 0, + } +})); + +const EditorRowAdderWrapper = styled("div", { + name: "EditorRowAdder", + slot: "root" +})(() => ({ + position: "absolute", + width: "100%", + height: 6, + opacity: 0, + transition: "opacity 0.3s", + cursor: "pointer", + zIndex: 10, + ":hover": { + opacity: 0.7, + } +})); +const EditorRowAdderDisplay = styled("div", { + name: "EditorRowAdder", + slot: "display" +})(({ theme }) => ({ + position: "relative", + height: 3, + width: "100%", + borderRadius: "2px", + backgroundColor: theme.vars.palette.primary[500], + "&::after": { + position: "absolute", + color: theme.vars.palette.common.black, + content: "'+'", + padding: "2px 6px", + borderRadius: theme.vars.radius.sm, + top: "-0.9em", + backgroundColor: theme.vars.palette.primary[500], + left: "-0.5em", + }, +})); + +export function EditorRowAdder({ nth }: { nth: number }) { + const table = useTableContext(); + const editor = useSlate(); + const onClick = () => + CampgroundEditor.insertTableRow( + editor, + table.columns, + table.tablePosition, + nth + ); + + return ( + + + + ); +} + +const EditorColumnAdderWrapper = styled("div", { + name: "EditorColumnAdder", + slot: "root" +})(() => ({ + position: "absolute", + height: "100%", + width: 6, + opacity: 0, + top: 0, + bottom: 0, + transition: "opacity 0.3s", + cursor: "pointer", + zIndex: 10, + ":hover": { + opacity: 0.7, + } +})); +const EditorColumnAdderDisplay = styled("div", { + name: "EditorColumnAdder", + slot: "display" +})(({ theme }) => ({ + position: "relative", + width: 3, + height: "100%", + borderRadius: "2px", + backgroundColor: theme.vars.palette.primary[500], + "&::after": { + position: "absolute", + color: theme.vars.palette.common.black, + content: "'+'", + padding: "2px 6px", + borderRadius: theme.vars.radius.sm, + left: "-0.6em", + backgroundColor: theme.vars.palette.primary[500], + top: "-0.5em", + }, +})); + +export function EditorColumnAdder({ nth }: { nth: number }) { + const table = useTableContext(); + const editor = useSlate(); + const onClick = () => + CampgroundEditor.insertTableColumn( + editor, + table.rows, + table.tablePosition, + nth, + ); + + return ( + + + + ); +} + + +export default EditorTableDisplay; \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/InlineNodeToggle.tsx b/sites/app.campground.gg/src/components/editor/InlineNodeToggle.tsx new file mode 100644 index 00000000..7e7fc3dc --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/InlineNodeToggle.tsx @@ -0,0 +1,26 @@ +import { IconButton } from "@mui/joy"; +import { ReactNode } from "react"; +import { useSlate } from "slate-react"; +import type { EditorInlineElementType } from "../../editor/editor"; +import CampgroundEditor from "./CampgroundEditor"; + +type Props = { + format: EditorInlineElementType; + children: ReactNode[] | ReactNode; +}; + +export default function InlineNodeToggle({ children, format: formatting }: Props) { + const editor = useSlate(); + + const active = CampgroundEditor.isNodeFormatted(editor, formatting); + + const toggleFormatting = (ev: React.MouseEvent) => { + ev.preventDefault(); + CampgroundEditor.toggleInlineFormatting(editor, formatting); + }; + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/ListNodeToggle.tsx b/sites/app.campground.gg/src/components/editor/ListNodeToggle.tsx new file mode 100644 index 00000000..bcc20757 --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/ListNodeToggle.tsx @@ -0,0 +1,27 @@ +import { IconButton } from "@mui/joy"; +import { ReactNode } from "react"; +import { useSlate } from "slate-react"; +import type { EditorBlockElementType, EditorItemElementType } from "../../editor/editor"; +import CampgroundEditor from "./CampgroundEditor"; + +type Props = { + format: EditorBlockElementType; + itemFormat: EditorItemElementType; + children: ReactNode[] | ReactNode; +}; + +export default function ListNodeToggle({ children, format: formatting }: Props) { + const editor = useSlate(); + + const active = CampgroundEditor.isNodeFormatted(editor, formatting); + + const toggleFormatting = (ev: React.MouseEvent) => { + ev.preventDefault(); + CampgroundEditor.toggleListFormatting(editor, formatting); + }; + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/MarkNodeToggle.tsx b/sites/app.campground.gg/src/components/editor/MarkNodeToggle.tsx new file mode 100644 index 00000000..070bf3ec --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/MarkNodeToggle.tsx @@ -0,0 +1,27 @@ +import { IconButton } from "@mui/joy"; +import { ReactNode } from "react"; +import { useSlate } from "slate-react"; +import type { EditorTextFormatting } from "../../editor/editor"; +import CampgroundEditor from "./CampgroundEditor"; + +type Props = { + format: keyof EditorTextFormatting; + children: ReactNode[] | ReactNode; +}; + +export default function MarkNodeToggle({ children, format: formatting }: Props) { + const editor = useSlate(); + + const active = CampgroundEditor.isTextFormatted(editor, formatting); + + const toggleFormatting = (ev: React.MouseEvent) => { + ev.preventDefault(); + CampgroundEditor.toggleTextFormatting(editor, formatting); + }; + + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/MessageEditor.tsx b/sites/app.campground.gg/src/components/editor/MessageEditor.tsx new file mode 100644 index 00000000..b53a427d --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/MessageEditor.tsx @@ -0,0 +1,115 @@ +import { Box, Button, Divider, Dropdown, IconButton, Link, MenuButton, Sheet, Stack, styled } from "@mui/joy"; +import type { SxProps } from "@mui/joy/styles/types"; +import { useRef, useState } from "react"; +import { Group } from "components"; +import BlockTextSlate from "./BlockTextSlate"; +import withCgMarkdown from "~/editor/withCgMarkdown"; +import { withHistory } from "slate-history"; +import { withReact } from "slate-react"; +import { createEditor, Node } from "slate"; +import type { RichEditor } from "~/editor/editor"; +import { IconArrowRight, IconMoodHappyFilled, IconPlus, IconSend2 } from "@tabler/icons-react"; +import MessageEditorMenu from "./MessageEditorMenu"; +import { serializeMarkdown } from "~/editor/mdast/markdown"; +import { mdastifyEditor } from "~/editor/mdast"; +import CampgroundEditor from "./CampgroundEditor"; +import type { EditorElement } from "~/editor/element"; +import TextEditor from "./TextEditor"; +import RichEditorFloater from "./RichEditorFloater"; + +type Props = { + content?: string; + placeholder?: string; + confirmButton?: string; + sx?: SxProps; + onCancel?: () => unknown; + onConfirm: (content: string) => unknown; + onClearReplies?: () => unknown; +}; + +export const MessageEditorContainer = styled(Sheet)(({ theme }) => ({ + backgroundColor: theme.vars.palette.background.level2, + width: "100%", + // 200 + border 1 + padding 8 + maxHeight: 218, + padding: "8px 8px", + boxShadow: theme.vars.shadow.sm, + border: `solid 1px ${theme.vars.palette.neutral.border}`, + borderRadius: theme.vars.radius.md, +})); +export const MessageEditorButton = styled(IconButton)(({ theme }) => ({ + backgroundColor: theme.vars.palette.background.level2, + color: theme.vars.palette.text.tertiary, + "&:hover": { + backgroundColor: theme.vars.palette.background.level3, + color: theme.vars.palette.text.secondary, + } +})); + +const MessageEditorGroup = styled(Group)(() => ({ + height: "100%", +})); + +export default function MessageEditor({ placeholder, content, onConfirm, onCancel, confirmButton, onClearReplies, sx }: Props) { + const [editor] = useState(() => withCgMarkdown(withHistory(withReact(createEditor()))) as RichEditor); + const relativeRef = useRef(null); + + const onDone = async () => { + if (editor.children.length === 1 && (editor.children[0] as EditorElement).type === "paragraph" && !Node.string(editor.children[0]).trim()) + return; + + const serialized = serializeMarkdown(mdastifyEditor(editor)); + + CampgroundEditor.clearEditor(editor); + + return onConfirm(serialized); + }; + + return ( + + + + + + + + + + + + + + + + + + + + + + + {!confirmButton && + + } + + + + + {confirmButton && + + {onCancel && Cancel} + } + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/MessageEditorMenu.tsx b/sites/app.campground.gg/src/components/editor/MessageEditorMenu.tsx new file mode 100644 index 00000000..ab8d597c --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/MessageEditorMenu.tsx @@ -0,0 +1,40 @@ +import { ListItemContent, ListItemDecorator, Menu, MenuItem, Modal } from "@mui/joy"; +import { IconMountainFilled, IconTable } from "@tabler/icons-react"; +import { useSlate } from "slate-react"; +import ImageInputModal from "../../layout/ImageInputModal"; +import { useState } from "react"; +import CampgroundEditor from "./CampgroundEditor"; + +export default function MessageEditorMenu() { + const editor = useSlate(); + const [imageModal, setImageModal] = useState(false); + const closeImageModal = () => setImageModal(false); + const onSubmitImage = (url: string, title: string | null | undefined) => + CampgroundEditor.insertImageFormatting(editor, url, title); + + return ( + <> + + CampgroundEditor.insertTableFormatting(editor)}> + + + + + Add a table + + + setImageModal(true)}> + + + + + Add image + + + + + + + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/RichEditorFloater.tsx b/sites/app.campground.gg/src/components/editor/RichEditorFloater.tsx new file mode 100644 index 00000000..fb1f071e --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/RichEditorFloater.tsx @@ -0,0 +1,46 @@ +import { styled, Tooltip } from "@mui/joy"; +import { useEffect, useRef, type RefObject } from "react"; +import { useFocused, useSlate } from "slate-react"; +import RichEditorToolbar, { RichEditorToolbarInlineFormatting } from "./RichEditorToolbar"; +import { Editor, Range } from "slate"; + +const TooltipAnchor = styled("div", { + name: "TooltipAnchor", + slot: "root" +})(() => ({ + position: "absolute", + width: 0, + height: 2, +})) + +export default function RichEditorFloater({ useRelativeRef }: { useRelativeRef: RefObject }) { + const ref = useRef(null); + const editor = useSlate(); + const focused = useFocused(); + + useEffect(() => { + if (!ref.current || !useRelativeRef.current) + return; + else if (!focused || !editor.selection || Range.isCollapsed(editor.selection) || Editor.string(editor, editor.selection) === "") + return ref.current.removeAttribute("style"); + + const refElement = ref.current; + const rect = window.getSelection()!.getRangeAt(0).getBoundingClientRect(); + const relativeRect = useRelativeRef.current.getBoundingClientRect(); + Object.assign(ref.current.style, { + display: "block", + top: `${rect.top + window.pageYOffset - refElement.offsetHeight - relativeRect.y}px`, + left: `${rect.left + window.pageXOffset - (refElement.offsetWidth / 2) + (rect.width / 2) - relativeRect.x}px`, + }); + }); + + return ( + + + + } sx={{ transform: "none" }} placement="top" disablePortal> + + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/RichEditorToolbar.tsx b/sites/app.campground.gg/src/components/editor/RichEditorToolbar.tsx new file mode 100644 index 00000000..fce391ff --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/RichEditorToolbar.tsx @@ -0,0 +1,157 @@ +import { ButtonGroup, Dropdown, IconButton, ListItemContent, ListItemDecorator, Menu, MenuButton } from "@mui/joy"; +import { Group } from "components"; +import { ReactNode } from "react" +import MarkNodeToggle from "./MarkNodeToggle"; +import { IconBlockquote, IconBold, IconBraces, IconCaretDownFilled, IconCode, IconH1, IconH2, IconH3, IconH4, IconH6, IconItalic, IconList, IconListNumbers, IconSeparatorHorizontal, IconStrikethrough, IconTable, IconTableColumn, IconTableRow, IconUnderline } from "@tabler/icons-react"; +import BlockNodeToggle from "./BlockNodeToggle"; +import ListNodeToggle from "./ListNodeToggle"; +import CodeNodeToggle from "./CodeNodeToggle"; +import BlockNodeInsert from "./BlockNodeInsert"; +import BlockNodeMenuItem from "./BlockNodeMenuItem"; +import TableNodeInsert from "./TableNodeInsert"; +import { useSlate } from "slate-react"; +import CampgroundEditor from "./CampgroundEditor"; +import type { EditorTable } from "~/editor/element"; + +type Props = { + children: ReactNode[] | ReactNode; +} + +export function RichEditorToolbarInlineFormatting() { + return ( + + + + + + + + + + + + + + + + + {/* + + */} + + ); +} + +export function RichEditorToolbarBlockFormatting() { + return ( + + + + + + + + + + + + + + + + + + + + + ); +} + +export function RichEditorToolbarTableFormatting() { + const editor = useSlate(); + + const activeTable = CampgroundEditor.getSelectedNodes(editor, "table"); + + if (!activeTable?.length) + return <>; + const table = activeTable[0]; + const insertRow = () => + CampgroundEditor.insertTableRow(editor, (table[0] as EditorTable).children[0]?.children.length ?? 0, table[1], editor.selection!.focus.path.slice(-3)[0]! + 1); + const insertColumn = () => + CampgroundEditor.insertTableColumn(editor, (table[0] as EditorTable).children.length, table[1], editor.selection!.focus.path.slice(-2)[0]! + 1); + + return ( + + + + + + + + + ); +} +export function RichEditorToolbarHeading() { + return ( + + + + + + + + + + + + + + + + Heading 2 + + + + + + + + Heading 3 + + + + + + + + Heading 4 + + + + + + + + Heading 5 + + + + + + + + Heading 6 + + + + + ); +} + +export default function RichEditorToolbar({ children }: Props) { + return ( + ({ p: 1, backgroundColor: theme.vars.palette.background.level1 })}> + {children} + + ) +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/TableNodeInsert.tsx b/sites/app.campground.gg/src/components/editor/TableNodeInsert.tsx new file mode 100644 index 00000000..c3187482 --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/TableNodeInsert.tsx @@ -0,0 +1,24 @@ +import { IconButton } from "@mui/joy"; +import { ReactNode } from "react"; +import { useSlate } from "slate-react"; +import CampgroundEditor from "./CampgroundEditor"; + +type Props = { + children: ReactNode[] | ReactNode; +}; + +export default function TableNodeInsert({ children }: Props) { + const editor = useSlate(); + + const active = CampgroundEditor.isNodeFormatted(editor, "table-cell"); + + const toggleFormatting = (ev: React.MouseEvent) => { + ev.preventDefault(); + CampgroundEditor.insertTableFormatting(editor); + }; + return ( + + {children} + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/TextEditor.tsx b/sites/app.campground.gg/src/components/editor/TextEditor.tsx new file mode 100644 index 00000000..5e04d2e4 --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/TextEditor.tsx @@ -0,0 +1,90 @@ +import useBlockDecorate from "~/editor/block-decorate"; +import EditorElement from "./EditorElement"; +import EditorLeaf from "./EditorLeaf"; +import { editorKeyboardLogic, type KeyboardSettings } from "~/editor/keyboard-logic"; +import { styled } from "@mui/joy"; +import { Editable, useSlate } from "slate-react"; +import MarkdownWrapper from "../markdown/MarkdownWrapper"; +import ErrorBoundary from "../ErrorBoundary"; +import type { RichEditor } from "~/editor/editor"; +import CampgroundEditor from "./CampgroundEditor"; + +type Props = React.PropsWithChildren & { + placeholder?: string; + keyboardSettings?: KeyboardSettings; +}; + +export const StyledEditor = styled(Editable, { + name: "MarkdownEditor", + slot: "editor", +})(() => ({ + ":focus": { + outline: "none", + }, + "> .tiptap > *:first-of-type": { + marginTop: 0, + }, + "> .tiptap > *:last-of-type": { + marginBottom: 0, + }, +})); +const StyledWrapper = styled(MarkdownWrapper, { + name: "MarkdownEditor", + slot: "root", +})(() => ({ + padding: `6px 12px`, + position: "relative", + overflowY: "auto", + overflowX: "hidden", + width: "100%", + height: "100%", +})); + +const controlKeybinds: Record, settings: KeyboardSettings) => unknown> = { + "b": (editor) => { + CampgroundEditor.toggleTextFormatting(editor, "bold"); + }, + "i": (editor) => { + CampgroundEditor.toggleTextFormatting(editor, "italic"); + }, + "s": (editor) => { + CampgroundEditor.toggleTextFormatting(editor, "strikethrough"); + }, + "l": (editor) => { + CampgroundEditor.toggleTextFormatting(editor, "underline"); + }, + "e": (editor) => { + CampgroundEditor.toggleTextFormatting(editor, "code"); + } +}; + +export default function TextEditor({ keyboardSettings, placeholder }: Props) { + const editor = useSlate(); + const blockDecorate = useBlockDecorate(); + const keyboardSettingsDefaulted = keyboardSettings ?? {}; + + return ( + + + { + const keybind = event.ctrlKey && controlKeybinds[event.key]; + const logic = editorKeyboardLogic[event.key]; + + if (!(logic || keybind)) + return; + + event.preventDefault(); + (logic ?? keybind)(editor, event, keyboardSettingsDefaulted); + }} + /> + + + ) +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/codeEditorContext.tsx b/sites/app.campground.gg/src/components/editor/codeEditorContext.tsx new file mode 100644 index 00000000..cf0c34eb --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/codeEditorContext.tsx @@ -0,0 +1,13 @@ +import { createContext, useContext } from "react"; +import type { EditorCodeLine } from "../../editor/editor"; + +export const CodeEditorContext = createContext([]); +export const useCodeEditorContext = () => useContext(CodeEditorContext); + +export function CodeEditorContextProvider({ codeLines, children }: React.PropsWithChildren & { codeLines: EditorCodeLine[] }) { + return ( + + {children} + + ) +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/editor/tableHeadContext.tsx b/sites/app.campground.gg/src/components/editor/tableHeadContext.tsx new file mode 100644 index 00000000..729fe123 --- /dev/null +++ b/sites/app.campground.gg/src/components/editor/tableHeadContext.tsx @@ -0,0 +1,41 @@ +import { createContext, useContext } from "react"; +import type { Path } from "slate"; +import type { BlockAlignment } from "~/editor/element"; + +export const TableContext = createContext<{ tablePosition: Path; rows: number; columns: number; }>({ tablePosition: [], rows: 0, columns: 0 }); +export const useTableContext = () => useContext(TableContext); + +export function TableContextProvider({ tablePosition, rows, columns, children }: React.PropsWithChildren & { tablePosition: Path; rows: number; columns: number; }) { + return ( + + {children} + + ) +} + +export const TableRowContext = createContext(0); +export const useTableRowContext = () => useContext(TableRowContext); + +export function TableRowContextProvider({ nth, children }: React.PropsWithChildren & { nth: number; }) { + return ( + + {children} + + ) +} + +export type TableAlign = { + column: number; + allAligns: BlockAlignment[] | undefined | null; +}; + +export const TableColumnContext = createContext({ column: 0, allAligns: [] }); +export const useTableColumnContext = () => useContext(TableColumnContext); + +export function TableColumnContextProvider({ value, children }: React.PropsWithChildren & { value: TableAlign; }) { + return ( + + {children} + + ) +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/form/AbstractFormField.tsx b/sites/app.campground.gg/src/components/form/AbstractFormField.tsx new file mode 100644 index 00000000..5d55a2dc --- /dev/null +++ b/sites/app.campground.gg/src/components/form/AbstractFormField.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import type { FieldTypeToInstance, FormFieldProps, FormFieldType } from "./forms"; + +interface AbstractFormFieldState { + value: T; +} + +export default abstract class AbstractFormField, TState extends AbstractFormFieldState = AbstractFormFieldState> extends React.Component { + private valueFallback: TValue; + + constructor(props: TProps, valueFallback: TValue, state: Omit = {} as Omit, context?: any) { + super(props, context); + + this.valueFallback = valueFallback; + (this.state as any) = { + value: props.defaultValue ?? valueFallback, + ...state + } + } + + public abstract get isValid(): boolean; + + public abstract render(): React.ReactNode; + + public override componentDidUpdate(prevProps: Readonly, _prevState: Readonly, _snapshot?: any): void { + if (prevProps.defaultValue !== this.props.defaultValue) + this.setState({ value: this.props.defaultValue ?? this.valueFallback }); + } + + protected onChange(value: TValue) { + return this.props.onChange && this.props.onChange(this as unknown as FieldTypeToInstance[TType], value); + } + + public resetValue() { + this.setState({ value: this.props.defaultValue ?? this.valueFallback }); + } + +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/form/Form.tsx b/sites/app.campground.gg/src/components/form/Form.tsx new file mode 100644 index 00000000..fabdf497 --- /dev/null +++ b/sites/app.campground.gg/src/components/form/Form.tsx @@ -0,0 +1,188 @@ +import React, { ReactNode, type MouseEvent } from "react"; +import type { FormSectionProps, AnyFormFieldProps, FieldTypeToInstance, FormFieldType, AbstractAnyFormField } from "./forms"; +import { Button, Stack, styled, Typography, type ColorPaletteProp } from "@mui/joy"; + +import { FormattedMessage } from "react-intl"; +import FormSection from "./FormSection"; +import { Group } from "components"; +import { FormattedMessageGlobal } from "~/i18n"; + +export type FormProps = { + sections: FormSectionProps[]; + gap?: number; + + header?: ReactNode | ReactNode[]; + description?: ReactNode | ReactNode[]; + children?: ReactNode[] | ReactNode; + + onChange?: (isValid: boolean, fieldValues: Record) => Promise | unknown; + ReactiveComponent?: (values: Record) => (ReactNode[] | ReactNode); + inlineReactiveComponent?: boolean; + + submitText?: ReactNode[] | ReactNode; + cancelText?: ReactNode[] | ReactNode; + submitColor?: ColorPaletteProp; + onSubmit?: (ev: MouseEvent, fieldValues: Record) => Promise | unknown; + onCancel?: (ev: MouseEvent) => unknown; + +}; +type FormState = { + fieldValues: Record; + fieldRequirementFilled: Record; +}; + +const getFieldValuesAndRequirements = (props: FormProps) => ({ + fieldValues: + Object.fromEntries( + props + .sections + .flatMap(x => x.fields) + .map(x => [x.id, x.defaultValue]) + .filter((x) => typeof x[1] !== "undefined" && x[1] !== null) + ), + fieldRequirementFilled: + Object.fromEntries( + props + .sections + .flatMap(x => x.fields) + .map(x => [x.id, !x.required || (typeof x.defaultValue !== "undefined" && x.defaultValue !== null)])) +}); + +const FormRoot = styled("form", { + name: "Form", + slot: "root", +})(({ theme }) => ({ + display: "flex", + flexDirection: "column", + gap: theme.spacing(3), + "&.Form-with-sidebar": { + flexDirection: "row", + flexWrap: "wrap", + [theme.breakpoints.down("md")]: { + flexDirection: "column", + }, + }, +})); +const FormContent = styled(Stack, { + name: "Form", + slot: "content", +})(({ theme }) => ({ + gap: theme.spacing(3), + flex: 1, +})); + +export default class Form extends React.Component { + private _fieldRefs: Record = {}; + + constructor(props: FormProps) { + super(props); + + this.state = getFieldValuesAndRequirements(props); + } + + private static getFieldDefaultValueEntries(sections: FormSectionProps[]): [string, any][] { + return sections.flatMap((x) => x.fields).map((x) => [x.id, x.defaultValue]); + } + + private static getFieldDefaultValues(sections: FormSectionProps[]): Record { + return Object.fromEntries(this.getFieldDefaultValueEntries(sections)); + } + + componentDidUpdate(prevProps: Readonly, _prevState: Readonly, _snapshot?: any): void { + if (prevProps.sections === this.props.sections) + return; + + const newEntries = Form.getFieldDefaultValueEntries(this.props.sections); + const oldDefaults = Form.getFieldDefaultValues(prevProps.sections); + + // Nothing to update + if (newEntries.every(([key, defaultValue]) => oldDefaults[key] === defaultValue)) + return; + + this.resetValues(); + } + + public resetValues() { + this.setState(getFieldValuesAndRequirements(this.props)); + for (const fieldKey in this._fieldRefs) { + this._fieldRefs[fieldKey].resetValue(); + } + } + + private addFieldRef(field: AbstractAnyFormField) { + this._fieldRefs[field.props.id] = field; + } + + public onButtonSubmit(ev: MouseEvent) { + ev.preventDefault(); + return this.props.onSubmit?.(ev, this.state.fieldValues); + } + + private onFieldChange(props: AnyFormFieldProps, field: FieldTypeToInstance[FormFieldType], value: any): Promise | void { + return this.setState(({ fieldValues, fieldRequirementFilled }) => ({ + fieldValues: { + ...fieldValues, + [props.id]: value + }, + fieldRequirementFilled: { + ...fieldRequirementFilled, + [props.id]: field.isValid + } + }), () => this.props.onChange?.(this.allValid, this.state.fieldValues)); + } + + private get allValid(): boolean { + return Object.values(this.state.fieldRequirementFilled).every(x => x); + } + + public render(): ReactNode[] | ReactNode { + const { header, sections, submitText, cancelText, children, ReactiveComponent, gap, submitColor, description, inlineReactiveComponent } = this.props; + const { fieldValues } = this.state; + + return ( + + + + {header && + {header} + } + {description && + {description} + } + + {/* Sections */} + + {sections.map(section => + + )} + + {/* Form footer */} + + + {this.props.onCancel && } + {this.props.onSubmit && } + + { children } + + + {ReactiveComponent && } + + ); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/form/FormFieldArray.tsx b/sites/app.campground.gg/src/components/form/FormFieldArray.tsx new file mode 100644 index 00000000..77bc03ff --- /dev/null +++ b/sites/app.campground.gg/src/components/form/FormFieldArray.tsx @@ -0,0 +1,151 @@ +import type { ReactNode } from "react"; +import AbstractFormField from "./AbstractFormField"; +import { fieldTypeToComponent, type AbstractAnyFormField, type FieldTypeToComponent, type FieldTypeToInstance, type FormFieldDecoratorProps, type FormFieldProps, type FormFieldType, type FormFieldTypeToProps } from "./forms"; +import { Card, Stack, Button, IconButton, styled } from "@mui/joy"; +import { IconGripVertical, IconPlus, IconX } from "@tabler/icons-react"; +import FormFieldWrapper from "./FormFieldWrapper"; +import { Group } from "components"; +import { DragDropProvider, useDraggable, useDroppable } from "~/draggable"; +import { moveIndexes } from "~/util/array"; + +export interface FormFieldArrayProps extends FormFieldProps<"array", any[]>, FormFieldDecoratorProps { + field: FormFieldTypeToProps[FormFieldType], + max?: number; + min?: number; +} + +type State = { + value: any[]; + valid: boolean[]; +}; + +export default class FormFieldArray extends AbstractFormField<"array", any[], FormFieldArrayProps, State> { + private _fieldRefs: AbstractAnyFormField[] = []; + + constructor(props: FormFieldArrayProps) { + super(props, [], { valid: Array(props.defaultValue?.length ?? 0).fill(FormFieldArray.isDefaultValid(props.field)) }); + } + + private static isDefaultValid(field: FormFieldTypeToProps[FormFieldType]) { + return !field.required || (typeof field.defaultValue !== "undefined" && field.defaultValue !== null); + } + + public override get isValid(): boolean { + return this.state.valid.slice(0, this.state.value.length).every((x) => x) + && ((this.props.max && this.state.value.length <= this.props.max) || !this.props.max) + && ((this.props.min && this.state.value.length >= this.props.min) || !this.props.min); + } + + public override resetValue(): void { + for (const fieldRef of this._fieldRefs) + fieldRef.resetValue(); + + super.resetValue(); + } + + private onSubFieldChange(index: number, field: FieldTypeToInstance[FormFieldType], value: any) { + return this.setState({ + value: [...this.state.value.slice(0, index), value, ...this.state.value.slice(index + 1)], + valid: [...this.state.valid.slice(0, index), field.isValid, ...this.state.valid.slice(index + 1)], + }, () => this.onChange(this.state.value)); + } + + private addField() { + this.setState({ + value: [...this.state.value, this.props.field.defaultValue], + valid: [...this.state.valid, FormFieldArray.isDefaultValid(this.props.field)], + }); + } + + private onValueMove(draggedIndex: number, droppedAtIndex: number) { + if (draggedIndex === droppedAtIndex) + return; + + this.setState({ + value: moveIndexes(this.state.value, draggedIndex, droppedAtIndex), + valid: moveIndexes(this.state.valid, draggedIndex, droppedAtIndex), + }, () => this.onChange(this.state.value)); + } + + private onRemoveField(index: number) { + this.setState({ + value: [...this.state.value.slice(0, index), ...this.state.value.slice(index + 1)], + valid: [...this.state.valid.slice(0, index), ...this.state.valid.slice(index + 1)], + }, () => this.onChange(this.state.value)); + + } + + public override render(): ReactNode { + const { field } = this.props; + const { state: { value } } = this; + const FieldComponent = fieldTypeToComponent[field.type]; + + this._fieldRefs = []; + return ( + + +
    + this.onValueMove(Number(draggedId), Number(droppedId))}> + {value.map((x, i) => + this._fieldRefs[i] = field} + /> + )} + +
    + +
    + ); + } +} + +const FormFieldArrayItemCard = styled(Card)(({ theme }) => ({ + position: "relative", + "::after": { + content: "''", + position: "absolute", + top: -4, + left: 0, + right: 0, + height: 3, + borderRadius: theme.vars.radius.md, + backgroundColor: "transparent", + transition: "background 0.3s", + }, + "&.over::after": { + backgroundColor: theme.vars.palette.primary[500], + } +})) + +function FormFieldArrayItem({ onRemove, index, FieldComponent, field, defaultValue, onSubFieldChange, addFieldRef }: { addFieldRef: (field: AbstractAnyFormField) => void, onRemove: () => unknown, index: number, onSubFieldChange: (field: FieldTypeToInstance[FormFieldType], value: any) => void, defaultValue: any, FieldComponent: FieldTypeToComponent[keyof FieldTypeToComponent], field: FormFieldArrayProps["field"] }) { + const { attributes: draggableAttributes } = useDraggable({ + id: index.toString(), + }); + const { attributes: droppableAttributes, isOver } = useDroppable({ + id: index.toString(), + }); + + return ( + + + + + + + + + + ); +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/form/FormFieldAvatar.tsx b/sites/app.campground.gg/src/components/form/FormFieldAvatar.tsx new file mode 100644 index 00000000..b13503c8 --- /dev/null +++ b/sites/app.campground.gg/src/components/form/FormFieldAvatar.tsx @@ -0,0 +1,63 @@ +import type { ReactNode } from "react"; +import AbstractFormField from "./AbstractFormField"; +import type { FormFieldProps } from "./forms"; +import { Avatar, Modal, type ColorPaletteProp, type Radius, type VariantProp, } from "@mui/joy"; +import ImageInputModal from "../../layout/ImageInputModal"; +import { IconPencil, IconPhotoPlus } from "@tabler/icons-react"; +import ImageEditBadge from "../ImageEditBadge"; + +export interface FormFieldAvatarProps extends FormFieldProps<"avatar", string | null> { + borderRadius?: keyof Radius; + color?: ColorPaletteProp; + variant?: VariantProp; + placeholder?: ReactNode | ReactNode[]; + size?: "sm" | "md" | "lg"; +} + +type State = { + value: string | null; + open: boolean; +}; + +export default class FormFieldAvatar extends AbstractFormField<"avatar", string | null, FormFieldAvatarProps, State> { + constructor(props: FormFieldAvatarProps) { + super(props, ""); + this.state = { open: false, value: props.defaultValue ?? null }; + } + + private onInputChange(value: string | null) { + console.log({ value }); + this.setState({ value }, () => value && this.onChange(value)); + } + + public override get isValid(): boolean { + return this.isNotEmptyOrRequired; + } + + private get isNotEmptyOrRequired(): boolean { + return !this.props.required || this.state.value !== null; + } + + onCloseModal() { + return this.setState({ open: false }); + } + + public override render(): ReactNode { + const { variant, color, borderRadius, size } = this.props; + const { open, value } = this.state; + const onCloseModal = this.onCloseModal.bind(this); + + return ( + <> + this.setState({ open: true })} badgeContent={} variant="soft" anchorOrigin={{ vertical: "bottom", horizontal: "right" }} color="neutral"> + + + + + + this.onInputChange(null)} /> + + + ); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/form/FormFieldCheckbox.tsx b/sites/app.campground.gg/src/components/form/FormFieldCheckbox.tsx new file mode 100644 index 00000000..8e772252 --- /dev/null +++ b/sites/app.campground.gg/src/components/form/FormFieldCheckbox.tsx @@ -0,0 +1,82 @@ +import type { ReactNode } from "react"; +import AbstractFormField from "./AbstractFormField"; +import type { FormFieldDecoratorProps, FormFieldProps } from "./forms"; +import { Checkbox, Sheet, Stack, Typography, } from "@mui/joy"; +import type React from "react"; +import { Group } from "components"; + +type CheckboxType = "default" | "button"; +export interface FormFieldCheckboxProps extends FormFieldProps<"checkbox", boolean>, FormFieldDecoratorProps { + label?: ReactNode[] | ReactNode; + description?: ReactNode[] | ReactNode; + design?: CheckboxType; +} + +type State = { + value: boolean; +}; + +export default class FormFieldCheckbox extends AbstractFormField<"checkbox", boolean, FormFieldCheckboxProps, State> { + constructor(props: FormFieldCheckboxProps) { + super(props, false); + this.state = { value: props.defaultValue ?? false }; + } + + public override get isValid(): boolean { + return this.isNotEmptyOrRequired; + } + + private get isNotEmptyOrRequired(): boolean { + return !this.props.required || this.state.value !== null; + } + + private onInputChange(ev: React.ChangeEvent) { + const value = ev.target.checked; + this.setState({ value }, () => this.onChange(value)); + } + + private FieldText() { + const { label, description, startDecorator, endDecorator } = this.props; + + return ( + (label || description) && + + {startDecorator} + + {label} + {description} + + {endDecorator} + + ) + } + + public override render(): ReactNode { + const { defaultValue, design } = this.props; + const { state: { value } } = this; + const onChange = this.onInputChange.bind(this); + const FieldText = this.FieldText.bind(this); + + return ( + design === "button" + ? + } + defaultChecked={defaultValue} + checked={value} + onChange={onChange} + /> + + : } + defaultChecked={defaultValue} + checked={value} + onChange={onChange} + /> + ); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/form/FormFieldColor.tsx b/sites/app.campground.gg/src/components/form/FormFieldColor.tsx new file mode 100644 index 00000000..be6ab5a6 --- /dev/null +++ b/sites/app.campground.gg/src/components/form/FormFieldColor.tsx @@ -0,0 +1,84 @@ +import type { ReactNode } from "react"; +import AbstractFormField from "./AbstractFormField"; +import type { FormFieldProps } from "./forms"; +import { Box, Dropdown, MenuButton, Stack, styled } from "@mui/joy"; +import { Group } from "components"; +import ColorPickerMenu from "../../layout/ColorPickerMenu"; +import { mixColors } from "components/theme/color"; + +export interface FormFieldColorProps extends FormFieldProps<"color", number> { + allowAlpha?: boolean; +} + +type State = { + value: number; +}; + +const ColorPick = styled(Box, { + name: "ColorPick", + slot: "root", +})(({ theme }) => ({ + width: 24, + height: 24, + backgroundColor: theme.vars.palette.primary[500], + borderRadius: theme.vars.radius.md, + cursor: "pointer", + boxShadow: theme.vars.shadow.sm, +})); + +const preselectedColors = [ + 0xfe1c56, + 0xff5a26, + 0xfea01c, + 0x0cef43, + 0x26f2ff, + 0x6026ff, + 0xca1cfe, +]; +const dark = 0x0e0b16; +const preselectedColorsDarker = preselectedColors.map((x) => mixColors(x, dark, 0.5)); + +export default class FormFieldColor extends AbstractFormField<"color", number, FormFieldColorProps, State> { + constructor(props: FormFieldColorProps) { + super(props, 0); + } + + private onInputChange(value: number) { + this.setState({ value }, () => value && this.onChange(value)); + } + + public override get isValid(): boolean { + return true; + } + + public override render(): ReactNode { + const { allowAlpha } = this.props; + const { value } = this.state; + const hexColor = `#${value.toString(16).padStart(6, "0")}`; + + return ( + + + + ({ boxShadow: theme.vars.shadow.sm, fontFamily: theme.fontFamily.code })} color="neutral" variant="outlined" startDecorator={}> + {hexColor} + + + + + + {preselectedColors.map((color) => + this.onInputChange(color)} sx={{ backgroundColor: `#${color.toString(16).padStart(6, "0")}` }} /> + )} + + + {preselectedColorsDarker.map((color) => + this.onInputChange(color)} sx={{ backgroundColor: `#${color.toString(16).padStart(6, "0")}` }} /> + )} + + + + + ); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/form/FormFieldImage.tsx b/sites/app.campground.gg/src/components/form/FormFieldImage.tsx new file mode 100644 index 00000000..49d43a4a --- /dev/null +++ b/sites/app.campground.gg/src/components/form/FormFieldImage.tsx @@ -0,0 +1,105 @@ +import type { ReactNode } from "react"; +import AbstractFormField from "./AbstractFormField"; +import type { FormFieldProps } from "./forms"; +import { AspectRatio, Modal, Sheet, styled, Typography, type Radius, } from "@mui/joy"; +import ImageInputModal from "../../layout/ImageInputModal"; +import { IconPencil } from "@tabler/icons-react"; +import ImageEditBadge from "../ImageEditBadge"; +import { FlexCenter, Image } from "components"; +import { FormattedMessage } from "react-intl"; + +export interface FormFieldImageProps extends FormFieldProps<"image", string | null> { + borderRadius?: keyof Radius; + sizeRatio: number; + width: number; +} + +interface State { + value: string | null; + open: boolean; +}; + +const ImagePlaceholder = styled(Sheet)(({ theme }) => ({ + backgroundColor: theme.vars.palette.neutral.solidBg, + transition: "background, color", + transitionDuration: "0.3s", + color: theme.vars.palette.neutral.solidColor, + "&:hover": { + backgroundColor: theme.vars.palette.neutral.solidHoverBg, + } +})); +const FieldImage = styled(Image)<{ radius: keyof Radius; }>(({ radius, theme }) => ({ + backgroundColor: theme.vars.palette.background.level4, + transition: "background 0.3s", + position: "relative", + borderRadius: theme.vars.radius[radius], + "&::after": { + position: "absolute", + content: "''", + top: 0, + left: 0, + right: 0, + bottom: 0, + zIndex: 2, + borderRadius: theme.vars.radius[radius], + backgroundColor: "transparent", + }, + "&:hover::after": { + backgroundColor: "rgba(255, 255, 255, 0.2)", + } +})); + +export default class FormFieldImage extends AbstractFormField<"image", string | null, FormFieldImageProps, State> { + constructor(props: FormFieldImageProps) { + super(props, ""); + this.state = { open: false, value: props.defaultValue ?? null }; + } + + private onInputChange(value: string | null) { + console.log({ value }); + this.setState({ value }, () => value && this.onChange(value)); + } + + public override get isValid(): boolean { + return this.isNotEmptyOrRequired; + } + + private get isNotEmptyOrRequired(): boolean { + return !this.props.required || this.state.value !== null; + } + + onCloseModal() { + return this.setState({ open: false }); + } + + public override render(): ReactNode { + const { borderRadius, sizeRatio, width } = this.props; + const { open, value } = this.state; + const onCloseModal = this.onCloseModal.bind(this); + + return ( + <> + this.setState({ open: true })} badgeContent={} variant="soft" anchorOrigin={{ vertical: "bottom", horizontal: "right" }} color="neutral"> + + {value + ? + : + + + + + + } + + + + this.onInputChange(null)} /> + + + ); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/form/FormFieldNumber.tsx b/sites/app.campground.gg/src/components/form/FormFieldNumber.tsx new file mode 100644 index 00000000..f57c3811 --- /dev/null +++ b/sites/app.campground.gg/src/components/form/FormFieldNumber.tsx @@ -0,0 +1,91 @@ +import type { ChangeEvent, ReactNode } from "react"; +import AbstractFormField from "./AbstractFormField"; +import type { FormFieldDecoratorProps, FormFieldProps } from "./forms"; +import { Button, ButtonGroup, Input } from "@mui/joy"; +import { Group } from "components"; +import { IconCaretDownFilled, IconCaretUpFilled } from "@tabler/icons-react"; + +export interface FormFieldNumberProps extends FormFieldProps<"number", number | null>, FormFieldDecoratorProps { + placeholder?: string; + min?: number; + max?: number; + incrementBy?: number; + allowFloating?: boolean; +} + +type State = { + textValue: string; + value: number | null; +}; + +export default class FormFieldNumber extends AbstractFormField<"number", number | null, FormFieldNumberProps, State> { + constructor(props: FormFieldNumberProps) { + super(props, null); + } + + public override get isValid(): boolean { + return this.isNotEmptyOrRequired && this.hasAllowedValue; + } + + private get isNotEmptyOrRequired(): boolean { + return !this.props.required || this.state.value !== null; + } + + private get hasAllowedValue(): boolean { + return !( + this.state.value !== null && + ((typeof this.props.max !== "undefined" && (this.state.value ?? 0) > this.props.max) || + (typeof this.props.min !== "undefined" && (this.state.value ?? 0) < this.props.min) || + (this.props.allowFloating && Math.floor(this.state.value ?? 0) !== (this.state.value ?? 0))) + ); + } + + private onInputChange(ev: ChangeEvent) { + const { value } = ev.target; + const numValue = value.length < 1 ? null : parseFloat(value); + + this.setState({ textValue: value, value: numValue }, () => this.onChange(numValue)); + } + + + private _increment = this.increaseValue.bind(this, 1); + private _decrement = this.increaseValue.bind(this, -1); + private increaseValue(increasedBy: number) { + const increasedByFinal = increasedBy * (this.props.incrementBy ?? 1); + + if (this.state.value === null) + return this.setState({ textValue: increasedByFinal.toString(), value: increasedByFinal }); + + const increased = this.state.value + increasedByFinal; + this.setState({ textValue: increased.toString(), value: increased }); + } + + public override render(): ReactNode { + const { startDecorator, endDecorator, placeholder, disabled } = this.props; + const { state: { textValue, value } } = this; + + return ( + + {endDecorator} + + + + + + } + onChange={this.onInputChange.bind(this)} + error={Number.isNaN(value) || !this.isValid} + disabled={disabled} + /> + ); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/form/FormFieldRadio.tsx b/sites/app.campground.gg/src/components/form/FormFieldRadio.tsx new file mode 100644 index 00000000..2475504d --- /dev/null +++ b/sites/app.campground.gg/src/components/form/FormFieldRadio.tsx @@ -0,0 +1,152 @@ +import type { ReactNode } from "react"; +import AbstractFormField from "./AbstractFormField"; +import type { FormFieldDecoratorProps, FormFieldProps } from "./forms"; +import { List, ListItem, Radio, RadioGroup, Stack, styled, Typography, } from "@mui/joy"; + +export interface FormFieldRadioItem { + value: string | boolean | number; + text: ReactNode[] | ReactNode; + startDecorator?: React.ReactNode; + endDecorator?: React.ReactNode; +} +type RadioType = "default" | "button" | "grid"; +export interface FormFieldRadioProps extends FormFieldProps<"radio", string | boolean | number | null>, FormFieldDecoratorProps { + options: FormFieldRadioItem[]; + design?: RadioType; +} + +const RadioList = styled(List)(() => ({ + "--List-gap": "8px", + "--ListItem-paddingY": "16px", + "--ListItem-radius": "8px", +})); + +const RadioGrid = styled(List)(({ theme }) => ({ + "--List-gap": 0, + "--ListItem-paddingY": "16px", + "--ListItem-radius": "8px", + display: "grid", + gridTemplateColumns: "1fr 1fr 1fr", + gap: theme.spacing(1), +})); +const RadioLabel = styled(Stack, { + name: "RadioLabel", + slot: "root", +})(({ theme }) => ({ + gap: theme.spacing(2), + flexDirection: "column", + alignItems: "center", +})) + +export default class FormFieldRadio extends AbstractFormField<"radio", number | boolean | string | null, FormFieldRadioProps> { + constructor(props: FormFieldRadioProps) { + super(props, null); + } + + public override get isValid(): boolean { + return this.isNotEmptyOrRequired; + } + + private get isNotEmptyOrRequired(): boolean { + return !this.props.required || this.state.value !== null; + } + + private onInputChange(value: string | number | boolean | null) { + this.setState({ value }, () => value && this.onChange(value)); + } + + private RadioOption(option: FormFieldRadioItem) { + return ( + + ); + } + + private RadioOptionButtoned(option: FormFieldRadioItem) { + return ( + + + {option.startDecorator} + + {option.text} + + {option.endDecorator} + + } + sx={{ flexGrow: 1, flexDirection: "row-reverse" }} + /> + + ); + } + + private RadioOptionGridButtoned(option: FormFieldRadioItem) { + return ( + + + {option.startDecorator} + + {option.text} + + {option.endDecorator} + + } + sx={{ flexGrow: 1, flexDirection: "row" }} + disableIcon + /> + + ); + } + + public override render(): ReactNode { + const { options, defaultValue } = this.props; + const { state: { value } } = this; + const RadioOptionButtoned = this.RadioOptionButtoned.bind(this); + const RadioOptionGridButtoned = this.RadioOptionGridButtoned.bind(this); + const RadioOption = this.RadioOption.bind(this); + + return ( + this.onInputChange(e.target.value)}> + {this.props.design === "button" + ? + {options.map((x, i) => + + )} + + : this.props.design === "grid" + ? + {options.map((x, i) => + + )} + + : options.map((x, i) => + + )} + + ); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/form/FormFieldSelect.tsx b/sites/app.campground.gg/src/components/form/FormFieldSelect.tsx new file mode 100644 index 00000000..2f356f21 --- /dev/null +++ b/sites/app.campground.gg/src/components/form/FormFieldSelect.tsx @@ -0,0 +1,89 @@ +import type { ReactNode } from "react"; +import AbstractFormField from "./AbstractFormField"; +import type { FormFieldDecoratorProps, FormFieldProps } from "./forms"; +import { ListItemDecorator, Option, Select, type SelectOption } from "@mui/joy"; + +export interface FormFieldSelectItem { + value: string | boolean | number | null; + text: ReactNode[] | ReactNode; + startDecorator?: ReactNode[] | ReactNode; + endDecorator?: ReactNode[] | ReactNode; +} +export interface FormFieldSelectProps extends FormFieldProps<"select", string | boolean | number | null>, FormFieldDecoratorProps { + options: FormFieldSelectItem[]; + placeholder?: string; +} + +type State = { + value: string | number | boolean | null; +}; + +export default class FormFieldSelect extends AbstractFormField<"select", number | boolean | string | null, FormFieldSelectProps, State> { + constructor(props: FormFieldSelectProps) { + super(props, null); + } + + public override get isValid(): boolean { + return this.isNotEmptyOrRequired; + } + + private get isNotEmptyOrRequired(): boolean { + return !this.props.required || !!this.state.value; + } + + private onInputChange(value: string | number | boolean | null) { + this.setState({ value }, () => value && this.onChange(value)); + } + + private renderValue(option: SelectOption | null) { + const optionRecord = this.props.options.find((x) => x.value === option?.value); + console.log({ option, optionRecord }); + + return this.renderOption(option?.value, optionRecord); + } + + private renderOption(value: string | number | boolean | undefined | null, option: FormFieldSelectItem | undefined) { + // console.log({ value, option }); + return ( + <> + {option?.startDecorator && + + {option?.startDecorator} + + } + {option?.text ?? value} + {option?.endDecorator && + + {option?.startDecorator} + + } + + ); + } + + public override render(): ReactNode { + const { startDecorator, endDecorator, defaultValue, placeholder, options } = this.props; + const { state: { value } } = this; + + console.log({ defaultValue, options }); + return ( + + ); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/form/FormFieldSwitch.tsx b/sites/app.campground.gg/src/components/form/FormFieldSwitch.tsx new file mode 100644 index 00000000..6a4fa53c --- /dev/null +++ b/sites/app.campground.gg/src/components/form/FormFieldSwitch.tsx @@ -0,0 +1,84 @@ +import type { ReactNode } from "react"; +import AbstractFormField from "./AbstractFormField"; +import type { FormFieldDecoratorProps, FormFieldProps } from "./forms"; +import { Switch, FormControl, Sheet, Stack, Typography, } from "@mui/joy"; +import type React from "react"; +import { Group } from "components"; + +type SwitchType = "default" | "button"; +export interface FormFieldSwitchProps extends FormFieldProps<"switch", boolean | number>, FormFieldDecoratorProps { + label?: ReactNode[] | ReactNode; + description?: ReactNode[] | ReactNode; + design?: SwitchType; + checkedValue?: number; +} + +type State = { + value: boolean | number; +}; + +export default class FormFieldSwitch extends AbstractFormField<"switch", boolean | number, FormFieldSwitchProps, State> { + constructor(props: FormFieldSwitchProps) { + super(props, props.checkedValue ? 0 : false); + } + + public override get isValid(): boolean { + return this.isNotEmptyOrRequired; + } + + private get isNotEmptyOrRequired(): boolean { + return !this.props.required || this.state.value !== null && this.state.value !== 0; + } + + private onInputChange(ev: React.ChangeEvent) { + const value = ev.target.checked; + const checkedValue = this.props.checkedValue ? (Number(value) as 1 | 0) * this.props.checkedValue : value; + this.setState({ value: checkedValue }, () => this.onChange(checkedValue)); + } + + private FieldText() { + const { label, description, startDecorator, endDecorator } = this.props; + + return ( + (label || description) && + + {startDecorator} + + {label} + {description} + + {endDecorator} + + ) + } + + public override render(): ReactNode { + const { design } = this.props; + const { state: { value } } = this; + const onChange = this.onInputChange.bind(this); + const FieldText = this.FieldText.bind(this); + + return ( + + + {design === "button" + ? + + + : } + + ); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/form/FormFieldTags.tsx b/sites/app.campground.gg/src/components/form/FormFieldTags.tsx new file mode 100644 index 00000000..0e75bc58 --- /dev/null +++ b/sites/app.campground.gg/src/components/form/FormFieldTags.tsx @@ -0,0 +1,81 @@ +import type { ReactNode } from "react"; +import AbstractFormField from "./AbstractFormField"; +import type { FormFieldProps } from "./forms"; +import { Chip, Input, Stack, type ColorPaletteProp, type VariantProp, } from "@mui/joy"; +import { Group } from "components"; +import { IconPlus, IconX } from "@tabler/icons-react"; +import { IntlContext } from "react-intl"; +import type React from "react"; + +export interface FormFieldTagsProps extends FormFieldProps<"tags", string[]> { + color?: ColorPaletteProp; + variant?: VariantProp; +} + +type State = { + value: string[]; +}; + +export default class FormFieldTags extends AbstractFormField<"tags", string[], FormFieldTagsProps, State> { + constructor(props: FormFieldTagsProps, context: React.ContextType) { + super(props, [], {}, context); + } + + private onInputChange(value: string[]) { + this.setState({ value }, () => value && this.onChange(value)); + } + + public override get isValid(): boolean { + return this.isNotEmptyOrRequired; + } + + private get isNotEmptyOrRequired(): boolean { + return !this.props.required || Boolean(this.state.value.length); + } + + removeValue(value: string) { + return this.onInputChange(this.state.value.filter((x) => x !== value)); + } + + addValue(value: string) { + if (this.state.value.includes(value)) + return; + + return this.onInputChange([...this.state.value, value]); + } + + public override render(): ReactNode { + const { value } = this.state; + const { variant, color } = this.props; + const variantOrDefault = variant ?? "solid"; + const colorOrDefault = color ?? "neutral"; + + return ( + + + {value.map((x) => + {x} + )} + + {(intl) => + } + placeholder={ + intl.formatMessage({ + id: "form.tagPlaceholder", + defaultMessage: "Add tag", + description: "Placeholder used for adding tags in forms" + }) + } + variant={variantOrDefault} + color={colorOrDefault} + sx={{ width: 150, borderRadius: "1.5rem" }} + onKeyUp={(ev) => ev.key === "Enter" && (ev.target as HTMLInputElement).value && (this.addValue((ev.target as HTMLInputElement).value), (ev.target as HTMLInputElement).value = "")} + /> + } + + + + ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/form/FormFieldText.tsx b/sites/app.campground.gg/src/components/form/FormFieldText.tsx similarity index 59% rename from sites/campground.gg/src/components/form/FormFieldText.tsx rename to sites/app.campground.gg/src/components/form/FormFieldText.tsx index 05f91f5c..36795e85 100644 --- a/sites/campground.gg/src/components/form/FormFieldText.tsx +++ b/sites/app.campground.gg/src/components/form/FormFieldText.tsx @@ -1,12 +1,15 @@ -import { ChangeEvent, HTMLInputTypeAttribute, ReactNode } from "react"; +import type { ChangeEvent, HTMLInputTypeAttribute, ReactNode } from "react"; import AbstractFormField from "./AbstractFormField"; -import { FormFieldDecoratorProps, FormFieldProps } from "./forms"; +import type { FormFieldDecoratorProps, FormFieldProps } from "./forms"; import { Input } from "@mui/joy"; export interface FormFieldTextProps extends FormFieldProps<"text", string>, FormFieldDecoratorProps { inputType?: HTMLInputTypeAttribute; placeholder?: string; format?: RegExp; + allowedValue?: string | null; + max?: number; + min?: number; } type State = { @@ -15,12 +18,11 @@ type State = { export default class FormFieldText extends AbstractFormField<"text", string, FormFieldTextProps, State> { constructor(props: FormFieldTextProps) { - super(props); - this.state = { value: "" }; + super(props, ""); } public override get isValid(): boolean { - return this.isNotEmptyOrRequired && this.isFormatValid; + return this.isNotEmptyOrRequired && this.isFormatValid && this.hasAllowedValue; } private get isNotEmptyOrRequired(): boolean { @@ -28,31 +30,40 @@ export default class FormFieldText extends AbstractFormField<"text", string, For } private get isFormatValid(): boolean { - // Special thanks to De Morgan for solving this mess - // !this.props.format || !!this.props.format!.exec(this.state.value) - return !(this.props.format && !this.props.format!.exec(this.state.value)); + return !( + (this.props.min && this.state.value.length < this.props.min) || + (this.props.format && !this.props.format!.exec(this.state.value)) + ); + } + + private get hasAllowedValue(): boolean { + return !this.props.allowedValue || this.props.allowedValue === this.state.value; } private onInputChange(ev: ChangeEvent) { const { value } = ev.target; + if (this.props.max && value.length > this.props.max) + return; + this.setState({ value }, () => this.onChange(ev.target.value)); } public override render(): ReactNode { - const { startDecorator, endDecorator, defaultValue, placeholder, inputType } = this.props; + const { startDecorator, endDecorator, placeholder, inputType, disabled } = this.props; const { isFormatValid, state: { value } } = this; return ( 0 && !isFormatValid} - /> + disabled={disabled} + /> ); } } \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/form/FormFieldTextArea.tsx b/sites/app.campground.gg/src/components/form/FormFieldTextArea.tsx new file mode 100644 index 00000000..0b6d4b74 --- /dev/null +++ b/sites/app.campground.gg/src/components/form/FormFieldTextArea.tsx @@ -0,0 +1,62 @@ +import type { ChangeEvent, ReactNode } from "react"; +import AbstractFormField from "./AbstractFormField"; +import type { FormFieldDecoratorProps, FormFieldProps } from "./forms"; +import { Textarea } from "@mui/joy"; + +export interface FormFieldTextAreaProps extends FormFieldProps<"textarea", string>, FormFieldDecoratorProps { + placeholder?: string; + format?: RegExp; + max?: number; + min?: number; +} + +type State = { + value: string; +}; + +export default class FormFieldTextArea extends AbstractFormField<"textarea", string, FormFieldTextAreaProps, State> { + constructor(props: FormFieldTextAreaProps) { + super(props, ""); + } + + public override get isValid(): boolean { + return this.isNotEmptyOrRequired && this.isFormatValid; + } + + private get isNotEmptyOrRequired(): boolean { + return !this.props.required || this.state.value.length > 0; + } + + private get isFormatValid(): boolean { + return !( + (this.props.min && this.state.value.length < this.props.min) || + (this.props.format && !this.props.format!.exec(this.state.value)) + ); + } + + private onInputChange(ev: ChangeEvent) { + const { value } = ev.target; + + if (this.props.max && value.length > this.props.max) + return; + + this.setState({ value }, () => this.onChange(ev.target.value)); + } + + public override render(): ReactNode { + const { startDecorator, endDecorator, placeholder } = this.props; + const { isFormatValid, state: { value } } = this; + + return ( +