diff --git a/lang/en-US.json b/lang/en-US.json index 5265cde..7c79757 100644 --- a/lang/en-US.json +++ b/lang/en-US.json @@ -1,7 +1,5 @@ { "global": { - "login": "Sign in", - "register": "Sign up", "support": "Support", "download": "Download", "themeToggle": "Toggle color scheme", @@ -9,16 +7,47 @@ "docs": "Docs", "blog": "Blog", "discover": "Discover", - "camps": "Camps", + "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", @@ -29,10 +58,88 @@ } }, "home": { - "title": "Gather around the fire", + "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" + "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", diff --git a/sites/app.campground.gg/src/App.scss b/sites/app.campground.gg/src/App.scss deleted file mode 100644 index 513b3b3..0000000 --- a/sites/app.campground.gg/src/App.scss +++ /dev/null @@ -1,19 +0,0 @@ -@use "css/index.scss"; -@import url('https://fonts.googleapis.com/css2?family=Quicksand:wght@300..700&display=swap'); -@import url('https://fonts.googleapis.com/css2?family=Nunito+Sans:ital,opsz,wght@0,6..12,200..1000;1,6..12,200..1000&display=swap'); - -// TODO: Add variables here. -:root[data-mantine-color-scheme='light'] { - -} - -:root[data-mantine-color-scheme='dark'] { - -} - - -* { - font-family: "Nunito Sans", sans-serif; - line-height: 1.6; - font-size: 18px; -} \ No newline at end of file diff --git a/sites/app.campground.gg/src/App.tsx b/sites/app.campground.gg/src/App.tsx deleted file mode 100644 index 9d92e68..0000000 --- a/sites/app.campground.gg/src/App.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { ColorSchemeScript, MantineProvider } from '@mantine/core'; -import { - createBrowserRouter, - RouterProvider, -} from "react-router"; - -import './App.scss' -import '@mantine/core/styles.css'; -import '@mantine/notifications/styles.css'; -import '@mantine/dates/styles.css'; -import '@mantine/code-highlight/styles.css'; -import '@mantine/tiptap/styles.css'; -import '@mantine/dropzone/styles.css'; -import { IntlProvider } from './i18n'; -import { SessionProvider } from './session'; -import Index from './routes/Index'; -import theme from './theme'; - -function App() { - const router = createBrowserRouter([ - { - path: "/", - element: - }, - ]); - - return ( - <> - - - - - - - - - - ) -} - -export default App diff --git a/sites/app.campground.gg/src/components/BrandLogo.tsx b/sites/app.campground.gg/src/components/BrandLogo.tsx deleted file mode 100644 index 1a50c7a..0000000 --- a/sites/app.campground.gg/src/components/BrandLogo.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Group, Image, MantineSize, Text, UnstyledButton } from "@mantine/core"; - -export type Props = { - includeText?: boolean; - size?: MantineSize; -}; - -const sizeToFz: Record = { - "xl": "h1", - "lg": "h2", - "md": "h3", - "sm": "h4", - "xs": "h5" -}; - -export default function BrandLogo({ size, includeText }: Props) { - const fz = sizeToFz[size ?? "md"]; - - return ( - - - - {includeText && - Campground - } - - - ) -} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/IndexFooter.tsx b/sites/app.campground.gg/src/components/IndexFooter.tsx deleted file mode 100644 index c89369e..0000000 --- a/sites/app.campground.gg/src/components/IndexFooter.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React from "react"; -import BrandLogo from "./BrandLogo"; -import IndexFooterItem from "./IndexFooterItem"; -import { SimpleGrid, Stack } from "@mantine/core"; -import IndexFooterSection from "./IndexFooterSection"; -import { FormattedMessage } from "react-intl"; -import { IconBrandBluesky, IconBrandDiscord, IconBrandGithub, IconBrandX } from "@tabler/icons-react"; - -export type Props = { -}; - -export default class IndexFooter extends React.Component { - constructor(props: Props) { - super(props); - } - render() { - return ( - - - - - } href="https://github.com/Project-Campground">GitHub - } href="https://bsky.app/profile/campground.gg">Bluesky - } href="https://discord.com/invite/jasJ97UXDM">Discord - } href="https://x.com/teamcampground">X/Twitter - - - - - - - - - - - - - - - - - - - - - - - - - - ); - } -} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/IndexFooterItem.tsx b/sites/app.campground.gg/src/components/IndexFooterItem.tsx deleted file mode 100644 index 1762506..0000000 --- a/sites/app.campground.gg/src/components/IndexFooterItem.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Group, Text, UnstyledButton } from "@mantine/core"; -import React, { ReactNode } from "react"; - -export type Props = { - children: ReactNode[] | ReactNode; - icon?: ReactNode; - href?: string; -}; - -export default class IndexFooterItem extends React.Component { - constructor(props: Props) { - super(props); - } - render(): React.ReactNode { - const { icon, href, children } = this.props; - - return ( - - - {icon} - - {children} - - - - ); - } -} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/IndexNavbar.tsx b/sites/app.campground.gg/src/components/IndexNavbar.tsx deleted file mode 100644 index 64b8e89..0000000 --- a/sites/app.campground.gg/src/components/IndexNavbar.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from "react"; -import BrandLogo from "./BrandLogo"; -import IndexNavbarItem from "./IndexNavbarItem"; -import { Group } from "@mantine/core"; -import { FormattedMessage } from "react-intl"; - -export type Props = { - page: string; -}; - -export default class IndexNavbar extends React.Component { - constructor(props: Props) { - super(props); - } - render() { - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); - } -} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/IndexPageWrapper.tsx b/sites/app.campground.gg/src/components/IndexPageWrapper.tsx deleted file mode 100644 index 58433de..0000000 --- a/sites/app.campground.gg/src/components/IndexPageWrapper.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React, { ReactNode } from "react"; -import IndexNavbar from "./IndexNavbar"; -import { Flex } from "@mantine/core"; -import IndexFooter from "./IndexFooter"; - -type Props = { - children: ReactNode[] | ReactNode; -}; - -export default class IndexPageWrapper extends React.Component { - constructor(props: Props) { - super(props); - } - - render() { - const { children } = this.props; - - return ( - - - - - {children} - - - - - ); - } -} \ No newline at end of file diff --git a/sites/app.campground.gg/src/css/index.scss b/sites/app.campground.gg/src/css/index.scss deleted file mode 100644 index 6992021..0000000 --- a/sites/app.campground.gg/src/css/index.scss +++ /dev/null @@ -1,67 +0,0 @@ -@use "./functions.scss" as *; - -h1, h2, h3, h4, h5, h6 { - font-family: "Quicksand"; -} - -.landing-side-padding { - @include padding-horizontal(256px); -} -.landing-side-padding-nav { - @include padding-horizontal(256px - 24.75px); -} -.landing-extreme-top { - padding-top: 128px + 64px; -} - -.IndexNavbar { - &.container { - @include padding-vertical(8px); - } - &.menu.center { - flex: 1; - align-items: center; - } - &.spacing { - flex: 1; - } -} - -.IndexFooter.container { - padding-top: 24px; - padding-bottom: 48px; -} - -.BrandLogo.img { - width: 56px; - height: 56px; - &.xs { - width: 36px; - height: 36px; - } - &.sm { - width: 48px; - height: 48px; - } - &.md { - width: 56px; - height: 56px; - } - &.lg { - width: 64px; - height: 64px; - } - &.xl { - width: 96px; - height: 96px; - } -} - -.IndexPage { - &.top { - height: 1080px - 72px; - } - &.top-motto-text { - margin-bottom: 24px; - } -} \ No newline at end of file diff --git a/sites/app.campground.gg/src/routes/Index.tsx b/sites/app.campground.gg/src/routes/Index.tsx deleted file mode 100644 index d6fbaf6..0000000 --- a/sites/app.campground.gg/src/routes/Index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from "react"; -import { FormattedMessage } from "react-intl"; -import IndexPageWrapper from "../components/IndexPageWrapper"; -import { Button, Group, SimpleGrid, Stack, Text } from "@mantine/core"; -import { IconBrandDebian } from "@tabler/icons-react"; - -export type Props = { - -}; - -export default class Index extends React.Component { - constructor(props: Props) { - super(props); - } - render() { - return ( - - - - - - - - - - - - - - - ); - } -} \ No newline at end of file diff --git a/sites/app.campground.gg/src/theme.ts b/sites/app.campground.gg/src/theme.ts deleted file mode 100644 index 7e150aa..0000000 --- a/sites/app.campground.gg/src/theme.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { createTheme } from "@mantine/core" - -const theme = createTheme({ - fontFamily: `Nunito Sans, sans-serif`, - primaryColor: "orange", - colors: { - pink: ["#ff2661", "#ff2661", "#ff2661", "#ff2661", "#ff2661", "#ff2661", "#ff2661", "#ff2661", "#ff2661", "#ff2661", ], - red: ["#ff402b", "#ff402b", "#ff402b", "#ff402b", "#ff402b", "#ff402b", "#ff402b", "#ff402b", "#ff402b", "#ff402b", ], - orange: ["#ff5a26", "#ff5a26", "#ff5a26", "#ff5a26", "#ff5a26", "#ff5a26", "#ff5a26", "#ff5a26", "#ff5a26", "#ff5a26"], - green: ["#20eb53", "#20eb53", "#20eb53", "#20eb53", "#20eb53", "#20eb53", "#20eb53", "#20eb53", "#20eb53", "#20eb53", ], - }, - defaultGradient: { - from: "orange", - to: "pink", - deg: 60 - } -}); - -export default theme; \ No newline at end of file diff --git a/sites/app.campground.gg/.gitignore b/sites/campground.gg/.gitignore similarity index 100% rename from sites/app.campground.gg/.gitignore rename to sites/campground.gg/.gitignore diff --git a/sites/app.campground.gg/README.md b/sites/campground.gg/README.md similarity index 100% rename from sites/app.campground.gg/README.md rename to sites/campground.gg/README.md diff --git a/sites/app.campground.gg/eslint.config.js b/sites/campground.gg/eslint.config.js similarity index 100% rename from sites/app.campground.gg/eslint.config.js rename to sites/campground.gg/eslint.config.js diff --git a/sites/app.campground.gg/index.html b/sites/campground.gg/index.html similarity index 100% rename from sites/app.campground.gg/index.html rename to sites/campground.gg/index.html diff --git a/sites/app.campground.gg/package-lock.json b/sites/campground.gg/package-lock.json similarity index 90% rename from sites/app.campground.gg/package-lock.json rename to sites/campground.gg/package-lock.json index aab0a14..e2eec0d 100644 --- a/sites/app.campground.gg/package-lock.json +++ b/sites/campground.gg/package-lock.json @@ -8,15 +8,12 @@ "name": "react-ts", "version": "0.0.0", "dependencies": { - "@mantine/code-highlight": "^7.17.3", - "@mantine/core": "^7.17.3", - "@mantine/dates": "^7.17.3", - "@mantine/dropzone": "^7.17.3", - "@mantine/form": "^7.17.3", - "@mantine/hooks": "^7.17.3", - "@mantine/modals": "^7.17.3", - "@mantine/notifications": "^7.17.3", - "@mantine/tiptap": "^7.17.3", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@fontsource/nunito-sans": "^5.2.6", + "@fontsource/quicksand": "^5.2.9", + "@mantine/hooks": "^8.3.1", + "@mui/joy": "^5.0.0-beta.52", "@tabler/icons-react": "^3.34.1", "@tiptap/extension-link": "^2.11.5", "@tiptap/pm": "^2.11.5", @@ -72,7 +69,6 @@ "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.25.9", @@ -128,7 +124,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.27.0", @@ -162,7 +157,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.25.9", @@ -204,7 +198,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -214,7 +207,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -248,7 +240,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.27.0" @@ -308,7 +299,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", @@ -323,7 +313,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.26.2", @@ -342,7 +331,6 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -352,7 +340,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.25.9", @@ -362,6 +349,158 @@ "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/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.1", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", @@ -932,21 +1071,6 @@ "@floating-ui/utils": "^0.2.9" } }, - "node_modules/@floating-ui/react": { - "version": "0.26.28", - "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", - "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", - "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.1.2", - "@floating-ui/utils": "^0.2.8", - "tabbable": "^6.0.0" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, "node_modules/@floating-ui/react-dom": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.2.tgz", @@ -966,6 +1090,24 @@ "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", "license": "MIT" }, + "node_modules/@fontsource/nunito-sans": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/@fontsource/nunito-sans/-/nunito-sans-5.2.6.tgz", + "integrity": "sha512-f3qQqoZXtJPqhrh1M/CTeFZnRsZj7fEnILmGmbyNdlx9GrddQ3avQWwsa0cnBkG5UFGWvnzcfuJp1s+PNHjBsg==", + "license": "OFL-1.1", + "funding": { + "url": "https://github.com/sponsors/ayuhito" + } + }, + "node_modules/@fontsource/quicksand": { + "version": "5.2.9", + "resolved": "https://registry.npmjs.org/@fontsource/quicksand/-/quicksand-5.2.9.tgz", + "integrity": "sha512-/oXf8596gz6Looap/9WWr4sFsRaThWGhX979ssU3azqG08mx8Gg4ubO2h8WmeD8IUnq5xJ6tChugZ9qNJO4dVQ==", + "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", @@ -1108,7 +1250,6 @@ "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -1123,7 +1264,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1133,7 +1273,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1143,159 +1282,261 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@mantine/code-highlight": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@mantine/code-highlight/-/code-highlight-7.17.3.tgz", - "integrity": "sha512-O4Dzjlkl/S5bNgxrIue5/iBZEvRYno5u3uE5IwEghvlYdpq6nAKi3/Pho+ON6mndj0lLnyVU1ekzmnoAtEDxSg==", + "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", - "dependencies": { - "clsx": "^2.1.1", - "highlight.js": "^11.10.0" - }, "peerDependencies": { - "@mantine/core": "7.17.3", - "@mantine/hooks": "7.17.3", - "react": "^18.x || ^19.x", - "react-dom": "^18.x || ^19.x" + "react": "^18.x || ^19.x" } }, - "node_modules/@mantine/core": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@mantine/core/-/core-7.17.3.tgz", - "integrity": "sha512-N/AfV5eMnfEMx9WzI7AU5pNFBEzAfT/KtE2XDKS+0ht6RifUmolIxyIvoGMYz2yUEsCBMJZqmBq33Rabf5W7Ug==", + "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": { - "@floating-ui/react": "^0.26.28", - "clsx": "^2.1.1", - "react-number-format": "^5.4.3", - "react-remove-scroll": "^2.6.2", - "react-textarea-autosize": "8.5.6", - "type-fest": "^4.27.0" + "@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": { - "@mantine/hooks": "7.17.3", - "react": "^18.x || ^19.x", - "react-dom": "^18.x || ^19.x" + "@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/@mantine/dates": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@mantine/dates/-/dates-7.17.3.tgz", - "integrity": "sha512-gegLSlK7mi3jAaL/JMLdy6oK9CmY08nXoLvbeO03i+751bmbbbzpoFAaxMzbR6vkP9tPuoapOxJqgDzn2Jm+Dw==", + "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", - "dependencies": { - "clsx": "^2.1.1" - }, - "peerDependencies": { - "@mantine/core": "7.17.3", - "@mantine/hooks": "7.17.3", - "dayjs": ">=1.0.0", - "react": "^18.x || ^19.x", - "react-dom": "^18.x || ^19.x" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" } }, - "node_modules/@mantine/dropzone": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@mantine/dropzone/-/dropzone-7.17.3.tgz", - "integrity": "sha512-dwqmSgBS+fn57h2V2Ko4VN9g3nn/4DYr5poCElYhfYKzGqsDxqe9ZW3rYIg+VtmIAqBpWxX5YuWl4ea5h9xRZA==", + "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": { - "react-dropzone-esm": "15.2.0" + "@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": { - "@mantine/core": "7.17.3", - "@mantine/hooks": "7.17.3", - "react": "^18.x || ^19.x", - "react-dom": "^18.x || ^19.x" + "@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/@mantine/form": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@mantine/form/-/form-7.17.3.tgz", - "integrity": "sha512-ktERldD8f9lrjjz6wIbwMnNbAZq8XEWPx4K5WuFyjXaK0PI8D+gsXIGKMtA5rVrAUFHCWCdbK3yLgtjJNki8ew==", + "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": { - "fast-deep-equal": "^3.1.3", - "klona": "^2.0.6" + "@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": { - "react": "^18.x || ^19.x" - } - }, - "node_modules/@mantine/hooks": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-7.17.3.tgz", - "integrity": "sha512-6o65Rbfl8jd1C1nF9icvungqL0qZViEOmrZgkyKXxBYkC3x91fz4zftwQgNjt1tZHWDNO6Bo4GpRjJyAdwl48g==", - "license": "MIT", - "peerDependencies": { - "react": "^18.x || ^19.x" + "@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/@mantine/modals": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@mantine/modals/-/modals-7.17.3.tgz", - "integrity": "sha512-ZwNDTmfqyVRPUNl+vtBDbgZ9aVeQw6H+KLDSZxEsIYjc8p6u7FgCQ/FaBpsJOf//Oc7gHTLF0al27AqvW8jmOA==", + "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": { - "@mantine/core": "7.17.3", - "@mantine/hooks": "7.17.3", - "react": "^18.x || ^19.x", - "react-dom": "^18.x || ^19.x" + "@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/@mantine/notifications": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@mantine/notifications/-/notifications-7.17.3.tgz", - "integrity": "sha512-MqakDqu/CZzO4arZGpXs3TmGTajqL4xm28vtqW4qWFSU5HZWQ4EosqipqvIJ+swC6YbxNiWvFcfnxxPlHdYk9g==", + "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": { - "@mantine/store": "7.17.3", - "react-transition-group": "4.4.5" + "@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": { - "@mantine/core": "7.17.3", - "@mantine/hooks": "7.17.3", - "react": "^18.x || ^19.x", - "react-dom": "^18.x || ^19.x" + "@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/@mantine/store": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@mantine/store/-/store-7.17.3.tgz", - "integrity": "sha512-wXQXe/Ljv2N6TDRsoVwOHmTGZey7Nt/SS6VeeMujKeNnAybPPXaP1jIbN50MKJoDS4qVPCHJNaHwVKIgMur2aQ==", + "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": { - "react": "^18.x || ^19.x" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@mantine/tiptap": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@mantine/tiptap/-/tiptap-7.17.3.tgz", - "integrity": "sha512-kfMqrHpMq1dcdKsjUjdcHVCGmeRuZq4MclYIIulU5xNaUGyIzspQCeLa8XTH47QDS7ZSNV+8aXR93lPNZdCouA==", + "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": { - "@mantine/core": "7.17.3", - "@mantine/hooks": "7.17.3", - "@tiptap/extension-link": ">=2.1.12", - "@tiptap/react": ">=2.1.12", - "react": "^18.x || ^19.x", - "react-dom": "^18.x || ^19.x" + "@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/utils/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/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2438,6 +2679,18 @@ "undici-types": "~6.20.0" } }, + "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.0.12", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.12.tgz", @@ -2777,6 +3030,21 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "license": "Python-2.0" }, + "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/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2856,7 +3124,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -3002,6 +3269,31 @@ "node": ">=18" } }, + "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/crelt": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz", @@ -3052,7 +3344,6 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -3092,22 +3383,6 @@ "node": ">=0.10" } }, - "node_modules/detect-node-es": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", - "license": "MIT" - }, - "node_modules/dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, "node_modules/electron-to-chromium": { "version": "1.5.128", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.128.tgz", @@ -3127,6 +3402,15 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/esbuild": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", @@ -3449,6 +3733,12 @@ "node": ">=8" } }, + "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", @@ -3515,6 +3805,15 @@ "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", @@ -3525,15 +3824,6 @@ "node": ">=6.9.0" } }, - "node_modules/get-nonce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", - "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -3583,13 +3873,16 @@ "node": ">=8" } }, - "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", + "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": ">=12.0.0" + "node": ">= 0.4" } }, "node_modules/hoist-non-react-statics": { @@ -3622,7 +3915,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -3657,6 +3949,12 @@ "tslib": "^2.8.0" } }, + "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", @@ -3669,6 +3967,21 @@ "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-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3729,7 +4042,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -3745,6 +4057,12 @@ "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", @@ -3794,15 +4112,6 @@ "json-buffer": "3.0.1" } }, - "node_modules/klona": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", - "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -3817,6 +4126,12 @@ "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/linkify-it": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", @@ -3939,7 +4254,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -4071,7 +4385,6 @@ "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==", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -4080,6 +4393,24 @@ "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-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -4100,6 +4431,21 @@ "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-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", @@ -4536,21 +4882,6 @@ "react": "^19.0.0" } }, - "node_modules/react-dropzone-esm": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/react-dropzone-esm/-/react-dropzone-esm-15.2.0.tgz", - "integrity": "sha512-pPwR8xWVL+tFLnbAb8KVH5f6Vtl397tck8dINkZ1cPMxHWH+l9dFmIgRWgbh7V7jbjIcuKXCsVrXbhQz68+dVA==", - "license": "MIT", - "dependencies": { - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">= 10.13" - }, - "peerDependencies": { - "react": ">= 16.8 || 18.0.0" - } - }, "node_modules/react-intl": { "version": "7.1.10", "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-7.1.10.tgz", @@ -4582,16 +4913,6 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "license": "MIT" }, - "node_modules/react-number-format": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/react-number-format/-/react-number-format-5.4.3.tgz", - "integrity": "sha512-VCY5hFg/soBighAoGcdE+GagkJq0230qN6jcS5sp8wQX1qy1fYN/RX7/BXkrs0oyzzwqR8/+eSUrqXbGeywdUQ==", - "license": "MIT", - "peerDependencies": { - "react": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, "node_modules/react-refresh": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", @@ -4602,53 +4923,6 @@ "node": ">=0.10.0" } }, - "node_modules/react-remove-scroll": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz", - "integrity": "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==", - "license": "MIT", - "dependencies": { - "react-remove-scroll-bar": "^2.3.7", - "react-style-singleton": "^2.2.3", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.3", - "use-sidecar": "^1.1.3" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-remove-scroll-bar": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", - "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", - "license": "MIT", - "dependencies": { - "react-style-singleton": "^2.2.2", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/react-router": { "version": "7.4.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.4.0.tgz", @@ -4689,61 +4963,6 @@ "react-dom": ">=18" } }, - "node_modules/react-style-singleton": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", - "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", - "license": "MIT", - "dependencies": { - "get-nonce": "^1.0.0", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/react-textarea-autosize": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.6.tgz", - "integrity": "sha512-aT3ioKXMa8f6zHYGebhbdMD2L00tKeRX1zuVuDx9YQK/JLLRSaSxq3ugECEmUB9z2kvk6bFSIoRHLkkUv0RJiw==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.20.13", - "use-composed-ref": "^1.3.0", - "use-latest": "^1.2.1" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", - "license": "BSD-3-Clause", - "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" - } - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -4762,11 +4981,30 @@ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", "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==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -4952,6 +5190,15 @@ "node": ">=8" } }, + "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", @@ -4974,6 +5221,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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/sugarss": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-4.0.1.tgz", @@ -5004,11 +5257,17 @@ "node": ">=8" } }, - "node_modules/tabbable": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", - "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", - "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/tippy.js": { "version": "6.3.7", @@ -5069,18 +5328,6 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "4.38.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.38.0.tgz", - "integrity": "sha512-2dBz5D5ycHIoliLYLi0Q2V7KRaDlH0uWIvmk7TYlAg5slqwiPv1ezJdZm1QEM0xgk29oYWMCbIG7E6gHpvChlg==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { "version": "5.7.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", @@ -5181,94 +5428,6 @@ "punycode": "^2.1.0" } }, - "node_modules/use-callback-ref": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", - "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-composed-ref": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.4.0.tgz", - "integrity": "sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-isomorphic-layout-effect": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.0.tgz", - "integrity": "sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-latest": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.3.0.tgz", - "integrity": "sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==", - "license": "MIT", - "dependencies": { - "use-isomorphic-layout-effect": "^1.1.1" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-sidecar": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", - "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", - "license": "MIT", - "dependencies": { - "detect-node-es": "^1.1.0", - "tslib": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/use-sync-external-store": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", diff --git a/sites/app.campground.gg/package.json b/sites/campground.gg/package.json similarity index 77% rename from sites/app.campground.gg/package.json rename to sites/campground.gg/package.json index 6f836b8..e430751 100644 --- a/sites/app.campground.gg/package.json +++ b/sites/campground.gg/package.json @@ -1,5 +1,5 @@ { - "name": "react-ts", + "name": "campground-gg", "private": true, "version": "0.0.0", "type": "module", @@ -10,15 +10,12 @@ "preview": "vite preview" }, "dependencies": { - "@mantine/code-highlight": "^7.17.3", - "@mantine/core": "^7.17.3", - "@mantine/dates": "^7.17.3", - "@mantine/dropzone": "^7.17.3", - "@mantine/form": "^7.17.3", - "@mantine/hooks": "^7.17.3", - "@mantine/modals": "^7.17.3", - "@mantine/notifications": "^7.17.3", - "@mantine/tiptap": "^7.17.3", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@fontsource/nunito-sans": "^5.2.6", + "@fontsource/quicksand": "^5.2.9", + "@mantine/hooks": "^8.3.1", + "@mui/joy": "^5.0.0-beta.52", "@tabler/icons-react": "^3.34.1", "@tiptap/extension-link": "^2.11.5", "@tiptap/pm": "^2.11.5", diff --git a/sites/app.campground.gg/postcss.config.cjs b/sites/campground.gg/postcss.config.cjs similarity index 100% rename from sites/app.campground.gg/postcss.config.cjs rename to sites/campground.gg/postcss.config.cjs diff --git a/sites/app.campground.gg/public/campground-logo.svg b/sites/campground.gg/public/campground-logo.svg similarity index 100% rename from sites/app.campground.gg/public/campground-logo.svg rename to sites/campground.gg/public/campground-logo.svg diff --git a/sites/campground.gg/public/example-banner.svg b/sites/campground.gg/public/example-banner.svg new file mode 100644 index 0000000..c7a36f7 --- /dev/null +++ b/sites/campground.gg/public/example-banner.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/sites/app.campground.gg/public/favicon.ico b/sites/campground.gg/public/favicon.ico similarity index 100% rename from sites/app.campground.gg/public/favicon.ico rename to sites/campground.gg/public/favicon.ico diff --git a/sites/app.campground.gg/public/logo.png b/sites/campground.gg/public/logo.png similarity index 100% rename from sites/app.campground.gg/public/logo.png rename to sites/campground.gg/public/logo.png diff --git a/sites/app.campground.gg/public/logo.svg b/sites/campground.gg/public/logo.svg similarity index 100% rename from sites/app.campground.gg/public/logo.svg rename to sites/campground.gg/public/logo.svg diff --git a/sites/app.campground.gg/public/manifest.json b/sites/campground.gg/public/manifest.json similarity index 100% rename from sites/app.campground.gg/public/manifest.json rename to sites/campground.gg/public/manifest.json diff --git a/sites/app.campground.gg/public/mobile.png b/sites/campground.gg/public/mobile.png similarity index 100% rename from sites/app.campground.gg/public/mobile.png rename to sites/campground.gg/public/mobile.png diff --git a/sites/app.campground.gg/public/robots.txt b/sites/campground.gg/public/robots.txt similarity index 100% rename from sites/app.campground.gg/public/robots.txt rename to sites/campground.gg/public/robots.txt diff --git a/sites/app.campground.gg/public/wordmark.svg b/sites/campground.gg/public/wordmark.svg similarity index 100% rename from sites/app.campground.gg/public/wordmark.svg rename to sites/campground.gg/public/wordmark.svg diff --git a/sites/campground.gg/src/App.scss b/sites/campground.gg/src/App.scss new file mode 100644 index 0000000..556cde4 --- /dev/null +++ b/sites/campground.gg/src/App.scss @@ -0,0 +1,33 @@ +@use "css/landing.scss"; + +html, body, #root { + width: 100%; + scroll-behavior: smooth; + height: 100%; +} +html, body { + overflow: hidden; +} +#root { + overflow-y: scroll; + scrollbar-color: rgba(255, 255, 255, 0.2) transparent; + &::-webkit-scrollbar { + background-color: transparent; + width: 8px; + } + &::-webkit-scrollbar-thumb { + border-radius: 8px; + background-color: rgba(255, 255, 255, 0.2); + } +} + +* { + font-family: "Nunito Sans", sans-serif; + line-height: 1.6; + font-size: 18px; +} + +::selection { + background-color: var(--joy-palette-primary-t-500); + color: white; +} \ No newline at end of file diff --git a/sites/campground.gg/src/App.tsx b/sites/campground.gg/src/App.tsx new file mode 100644 index 0000000..4810abd --- /dev/null +++ b/sites/campground.gg/src/App.tsx @@ -0,0 +1,92 @@ +import { + createBrowserRouter, + RouterProvider, +} from "react-router"; + +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 './App.scss' +import { IntlProvider } from './i18n'; +import { SessionProvider } from './session'; +import LandingIndex from './routes/landing/LandingIndex'; +import { CssBaseline, CssVarsProvider, StyledEngineProvider } from '@mui/joy'; +import InitColorSchemeScript from '@mui/joy/InitColorSchemeScript'; +import theme from "./theme"; +import Downloads from "./routes/landing/Downloads"; +import Soon from "./routes/Soon"; +import Features from "./routes/landing/Features"; +import Login from "./routes/Login"; +import Register from "./routes/Register"; +import NotFound from "./routes/NotFound"; +import ResetPassword from "./routes/ResetPassword"; + + +function App() { + const router = createBrowserRouter([ + { + path: "*", + element: + }, + { + path: "/", + element: + }, + { + path: "/downloads", + element: + }, + { + path: "/login", + element: + }, + { + path: "/register", + element: + }, + { + path: "/reset-password", + element: + }, + { + path: "/blog", + element: + }, + { + path: "/docs/features", + element: + }, + { + path: "/docs", + element: + }, + { + path: "/docs/api", + element: + }, + ]); + + return ( + <> + + + + + + + + + + + + + ) +} + +export default App diff --git a/sites/campground.gg/src/components/BrandLogo.tsx b/sites/campground.gg/src/components/BrandLogo.tsx new file mode 100644 index 0000000..8ad5d6f --- /dev/null +++ b/sites/campground.gg/src/components/BrandLogo.tsx @@ -0,0 +1,28 @@ +import { Stack, Typography } from "@mui/joy"; +import { DefaultTypographySystem } from "@mui/joy/styles/types"; + +export type Props = { + includeText?: boolean; + size?: "xl" | "lg" | "md" | "sm" | "xs"; +}; + +const sizeToFz: Record<"xl" | "lg" | "md" | "sm" | "xs", keyof DefaultTypographySystem> = { + "xl": "h1", + "lg": "h2", + "md": "h3", + "sm": "h4", + "xs": "title-sm" +}; + +export default function BrandLogo({ size, includeText }: Props) { + const fz = sizeToFz[size ?? "md"]; + + return ( + + + {includeText && + Campground + } + + ) +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/ObservabilityDisplay.tsx b/sites/campground.gg/src/components/ObservabilityDisplay.tsx new file mode 100644 index 0000000..9d9f197 --- /dev/null +++ b/sites/campground.gg/src/components/ObservabilityDisplay.tsx @@ -0,0 +1,73 @@ +import { keyframes } from "@emotion/react"; +import { Box } from "@mui/joy"; +import React, { ReactNode } from "react"; + +type Element = { + elementId: string; + node: ReactNode; +}; + +type Props = { + threshold?: number; + observeQuery: string; + children: Element[] | Element; +}; +type State = { + displayIds: string[]; +}; + +export default class ObservabilityDisplay extends React.Component { + intersectionObserver?: IntersectionObserver; + items: Element[]; + + static appearAnimation = keyframes` + 0% { + opacity: 0; + } + 100% { + opacity: 100%; + } + `; + + constructor(props: Props) { + super(props); + + this.state = { displayIds: [] }; + this.items = Array.isArray(this.props.children) ? this.props.children : [this.props.children]; + } + + callback(entries: IntersectionObserverEntry[], _: IntersectionObserver) { + console.log(entries.map((x) => ({ targetId: x.target.id, isIntersecting: x.isIntersecting }))); + this.setState({ displayIds: entries.filter(x => x.isIntersecting).map(x => x.target.id) }); + } + + componentDidMount(): void { + const options = { + root: null, + rootMargin: `0px`, + threshold: this.props.threshold, + }; + this.intersectionObserver = new IntersectionObserver(this.callback.bind(this), options); + + for (const item of this.items) + this.intersectionObserver.observe(document.querySelector(`#${item.elementId}`)!); + } + + componentWillUnmount(): void { + + } + + render(): React.ReactNode { + const { displayIds } = this.state; + + return ( + + {this.items.map(({ elementId, node }) => + + {node} + + )} + + ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/PrimaryButton.tsx b/sites/campground.gg/src/components/PrimaryButton.tsx new file mode 100644 index 0000000..01cf5dc --- /dev/null +++ b/sites/campground.gg/src/components/PrimaryButton.tsx @@ -0,0 +1,22 @@ +import { Button, styled } from "@mui/joy"; + +const PrimaryButton = styled(Button)(({ disabled, theme }) => (console.log(theme), { + background: disabled ? `linear-gradient(30deg, ${theme.vars.palette.neutral[300]}, ${theme.vars.palette.neutral[500]})` : `linear-gradient(30deg, ${theme.vars.palette.primary[500]}, ${theme.vars.palette.secondary[500]})`, + boxShadow: disabled ? `0 0 5px ${theme.vars.palette.neutral[400]}` : `0 0 5px ${theme.vars.palette.primary[500]}`, + "::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(--joy-radius-sm))", + }, + ":hover::after": { + backgroundColor: "#FFF3" + } +})); +export default PrimaryButton; \ No newline at end of file diff --git a/sites/campground.gg/src/components/form/AbstractFormField.tsx b/sites/campground.gg/src/components/form/AbstractFormField.tsx new file mode 100644 index 0000000..8d88c9d --- /dev/null +++ b/sites/campground.gg/src/components/form/AbstractFormField.tsx @@ -0,0 +1,17 @@ +import React from "react"; +import { AbstractAnyFormField, FormFieldProps, FormFieldType } from "./forms"; + +export default abstract class AbstractFormField, TState> extends React.Component { + constructor(props: TProps) { + super(props); + } + + public abstract get isValid(): boolean; + + public abstract render(): React.ReactNode; + + protected onChange(value: TValue) { + return this.props.onChange && this.props.onChange(this as unknown as AbstractAnyFormField, value); + } + +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/form/Form.tsx b/sites/campground.gg/src/components/form/Form.tsx new file mode 100644 index 0000000..67b779f --- /dev/null +++ b/sites/campground.gg/src/components/form/Form.tsx @@ -0,0 +1,89 @@ +import React, { FormEvent, ReactNode } from "react"; +import { AnyFormField, FormSectionProps, AnyFormFieldProps } from "./forms"; +import { Stack, Typography } from "@mui/joy"; +import PrimaryButton from "../PrimaryButton"; +import { FormattedMessage } from "react-intl"; +import FormSection from "./FormSection"; + +export type FormProps = { + header?: ReactNode | ReactNode[]; + sections: FormSectionProps[]; + submitText?: string; + children?: ReactNode[] | ReactNode; + onSubmit: (ev: FormEvent, fieldValues: Record) => Promise | void; +}; +type FormState = { + fieldValues: Record; + fieldRequirementFilled: Record; +}; + +export default class Form extends React.Component { + constructor(props: FormProps) { + super(props); + this.state = { + fieldValues: {}, + fieldRequirementFilled: Object.fromEntries( + props + .sections + .flatMap(x => x.fields) + .map(x => [x.id, !x.required || !!x.defaultValue])) + }; + } + + public onButtonSubmit(ev: FormEvent) { + ev.preventDefault(); + return this.props.onSubmit(ev, this.state.fieldValues); + } + + private onFieldChange(props: AnyFormFieldProps, field: AnyFormField, value: any): Promise | void { + this.setState(({ fieldValues, fieldRequirementFilled }) => ({ + fieldValues: { + ...fieldValues, + [props.id]: value + }, + fieldRequirementFilled: { + ...fieldRequirementFilled, + [props.id]: field.isValid + } + })); + + return props.onChange && props.onChange(field, value); + } + + private get isButtonDisabled(): boolean { + return ( + !Object.values(this.state.fieldRequirementFilled).every(x => x) + ); + } + + public render(): ReactNode[] | ReactNode { + const { header, sections, submitText, children } = this.props; + + return ( +
+ + {header && + {header} + } + {/* Sections */} + + {sections.map(section => + + )} + + {/* Form footer */} + + + + + { children } + + +
+ ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/form/FormFieldText.tsx b/sites/campground.gg/src/components/form/FormFieldText.tsx new file mode 100644 index 0000000..05f91f5 --- /dev/null +++ b/sites/campground.gg/src/components/form/FormFieldText.tsx @@ -0,0 +1,58 @@ +import { ChangeEvent, HTMLInputTypeAttribute, ReactNode } from "react"; +import AbstractFormField from "./AbstractFormField"; +import { FormFieldDecoratorProps, FormFieldProps } from "./forms"; +import { Input } from "@mui/joy"; + +export interface FormFieldTextProps extends FormFieldProps<"text", string>, FormFieldDecoratorProps { + inputType?: HTMLInputTypeAttribute; + placeholder?: string; + format?: RegExp; +} + +type State = { + value: string; +}; + +export default class FormFieldText extends AbstractFormField<"text", string, FormFieldTextProps, State> { + constructor(props: FormFieldTextProps) { + super(props); + this.state = { value: "" }; + } + + 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 { + // 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)); + } + + private onInputChange(ev: ChangeEvent) { + const { value } = ev.target; + + this.setState({ value }, () => this.onChange(ev.target.value)); + } + + public override render(): ReactNode { + const { startDecorator, endDecorator, defaultValue, placeholder, inputType } = this.props; + const { isFormatValid, state: { value } } = this; + + return ( + 0 && !isFormatValid} + /> + ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/form/FormFieldWrapper.tsx b/sites/campground.gg/src/components/form/FormFieldWrapper.tsx new file mode 100644 index 0000000..f315f8a --- /dev/null +++ b/sites/campground.gg/src/components/form/FormFieldWrapper.tsx @@ -0,0 +1,23 @@ +import { FormControl, FormLabel } from "@mui/joy"; +import Form from "./Form"; +import { AnyFormField, AnyFormFieldComponent, AnyFormFieldProps } from "./forms"; + +type Props = { + FieldComponent: AnyFormFieldComponent; + onChange: (props: TProps, field: AnyFormField, value: TValue) => Promise | void; + binding: Form; + props: TProps; +}; + +export default function FormFieldWrapper({ FieldComponent, onChange, binding, props }: Props) { + return ( + + {props.header && {props.header}} + + {props.footer} + + ) +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/form/FormSection.tsx b/sites/campground.gg/src/components/form/FormSection.tsx new file mode 100644 index 0000000..fa01c72 --- /dev/null +++ b/sites/campground.gg/src/components/form/FormSection.tsx @@ -0,0 +1,28 @@ +import { Stack, Typography } from "@mui/joy"; +import { AnyFormField, AnyFormFieldProps, fieldTypeToComponent, FormSectionProps } from "./forms"; +import FormFieldWrapper from "./FormFieldWrapper"; +import Form from "./Form"; + +type Props = { + section: FormSectionProps; + fieldBinding: Form; + onFieldChange: (props: AnyFormFieldProps, field: AnyFormField, value: any) => Promise | void; +} + +export default function FormSection({ onFieldChange, fieldBinding, section: { header, fields } }: Props) { + return ( + + {header} + + {fields.map(field => + + )} + + + ) +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/form/forms.tsx b/sites/campground.gg/src/components/form/forms.tsx new file mode 100644 index 0000000..26fd350 --- /dev/null +++ b/sites/campground.gg/src/components/form/forms.tsx @@ -0,0 +1,43 @@ +import { ReactNode } from "react"; +import AbstractFormField from "./AbstractFormField"; +import FormFieldText, { FormFieldTextProps } from "./FormFieldText"; + +export type FormSectionProps = { + header?: ReactNode | ReactNode[]; + fields: AnyFormFieldProps[]; +}; + +export type FormFieldType = "text"; + +export type FormFieldTypeToProps = { + text: FormFieldTextProps; +}; + +export type AnyFormFieldProps = FormFieldTextProps; + +export type AnyFormFieldComponent = new(props: FormFieldProps) => AbstractAnyFormField; + +export type AbstractAnyFormField = AbstractFormField, any>; + +export type AnyFormField = FormFieldText; + +export const fieldTypeToComponent = { + text: FormFieldText, +}; + +export interface FormFieldProps { + type: TType; + id: string; + + header?: ReactNode[] | ReactNode; + footer?: ReactNode[] | ReactNode; + required?: boolean; + defaultValue?: TValue; + + onChange?: (field: AbstractFormField, any>, value: TValue) => Promise | void; +} + +export interface FormFieldDecoratorProps { + startDecorator?: ReactNode[] | ReactNode; + endDecorator?: ReactNode[] | ReactNode; +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/landing/DownloadCard.tsx b/sites/campground.gg/src/components/landing/DownloadCard.tsx new file mode 100644 index 0000000..a4caa4d --- /dev/null +++ b/sites/campground.gg/src/components/landing/DownloadCard.tsx @@ -0,0 +1,37 @@ +import { Button, Card, CardContent, ColorPaletteProp, Stack, Typography } from "@mui/joy"; +import { IconDownload } from "@tabler/icons-react"; +import { ReactNode } from "react"; +import { FormattedMessage } from "react-intl"; + +type Props = { + title: string; + description: string; + icon: ReactNode; + color: ColorPaletteProp; + children?: ReactNode[] | ReactNode; + href?: string; + gridColumn?: string; +}; + + +export default function DownloadCard({ title, description, color, icon, href, gridColumn, children }: Props) { + return ( + + + + + + {title} + + + {description} + + + {children || } + + + + ) +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/landing/FeatureCard.tsx b/sites/campground.gg/src/components/landing/FeatureCard.tsx new file mode 100644 index 0000000..b7a445d --- /dev/null +++ b/sites/campground.gg/src/components/landing/FeatureCard.tsx @@ -0,0 +1,63 @@ +import { AspectRatio, Card, CardContent, CardOverflow, ColorPaletteProp, Link, Stack, Typography } from "@mui/joy"; +import { IconArrowRight } from "@tabler/icons-react"; +import { ReactNode } from "react"; +import { FormattedMessage } from "react-intl"; + +type Props = { + title: string; + description: string; + icon: ReactNode; + href?: string; + imgSrc: string; + color?: ColorPaletteProp; +}; + + +export default function FeatureCard({ title, description, icon, href, imgSrc, color }: Props) { + return ( + + ({ + width: "100%", + height: "100%", + "::before": { + content: "''", + zIndex: 1, + top: 0, + left: 0, + right: 0, + bottom: 0, + border: `solid 2px ${theme.vars.palette[color ?? "primary"][500]}`, + position: "absolute", + borderRadius: theme.vars.radius.md, + maskImage: "linear-gradient(45deg, transparent 0%, black 50%, transparent 100%)", + opacity: 0.5, + } + })} + > + + ({ borderRadius: theme.vars.radius.md })}> + + + + + + + + + + + + + + }> + }} /> + + + + + + ) +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/landing/LandingBareboneWrapper.tsx b/sites/campground.gg/src/components/landing/LandingBareboneWrapper.tsx new file mode 100644 index 0000000..ccec18b --- /dev/null +++ b/sites/campground.gg/src/components/landing/LandingBareboneWrapper.tsx @@ -0,0 +1,29 @@ +import React, { ReactNode } from "react"; +import LandingNavbar from "./LandingNavbar"; +import { Stack } from "@mui/joy"; +import { SxProps } from "@mui/joy/styles/types"; + +type Props = { + sx?: SxProps; + bodySx?: SxProps; + children: ReactNode[] | ReactNode; +}; + +export default class LandingBareboneWrapper extends React.Component { + constructor(props: Props) { + super(props); + } + + render() { + const { sx, bodySx, children } = this.props; + + return ( + + + + {children} + + + ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/landing/LandingFooter.tsx b/sites/campground.gg/src/components/landing/LandingFooter.tsx new file mode 100644 index 0000000..bdcd044 --- /dev/null +++ b/sites/campground.gg/src/components/landing/LandingFooter.tsx @@ -0,0 +1,64 @@ +import React from "react"; +import BrandLogo from "../BrandLogo"; +import LandingFooterItem from "./LandingFooterItem"; +import LandingFooterSection from "./LandingFooterSection"; +import { FormattedMessage } from "react-intl"; +import { IconAffiliateFilled, IconBrandBluesky, IconBrandDiscord, IconBrandGithub, IconBrandX, IconCamper, IconCampfireFilled, IconChristmasTreeFilled, IconUsersGroup } from "@tabler/icons-react"; +import { Grid, Stack } from "@mui/joy"; + +export type Props = { +}; + +export default class LandingFooter extends React.Component { + constructor(props: Props) { + super(props); + } + render() { + return ( + + + + + } href="https://github.com/Project-Campground">GitHub + } href="https://bsky.app/profile/campground.gg">Bluesky + } href="https://discord.com/invite/jasJ97UXDM">Discord + } href="https://x.com/teamcampground">X/Twitter + + + + + + + + + + + + + + + + + }> + + + }> + + + + + }> + + + }> + + + }> + + + + + + ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/landing/LandingFooterItem.tsx b/sites/campground.gg/src/components/landing/LandingFooterItem.tsx new file mode 100644 index 0000000..cd53efc --- /dev/null +++ b/sites/campground.gg/src/components/landing/LandingFooterItem.tsx @@ -0,0 +1,23 @@ +import { Link } from "@mui/joy"; +import React, { ReactNode } from "react"; + +export type Props = { + children: ReactNode[] | ReactNode; + icon?: ReactNode; + href?: string; +}; + +export default class LandingFooterItem extends React.Component { + constructor(props: Props) { + super(props); + } + render(): React.ReactNode { + const { icon, href, children } = this.props; + + return ( + + {children} + + ); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/IndexFooterSection.tsx b/sites/campground.gg/src/components/landing/LandingFooterSection.tsx similarity index 59% rename from sites/app.campground.gg/src/components/IndexFooterSection.tsx rename to sites/campground.gg/src/components/landing/LandingFooterSection.tsx index af0686e..89d6235 100644 --- a/sites/app.campground.gg/src/components/IndexFooterSection.tsx +++ b/sites/campground.gg/src/components/landing/LandingFooterSection.tsx @@ -1,4 +1,4 @@ -import { Stack, Text } from "@mantine/core"; +import { Grid, Stack, Typography } from "@mui/joy"; import React, { ReactNode } from "react"; import { FormattedMessage } from "react-intl"; @@ -7,7 +7,7 @@ export type Props = { children?: ReactNode[]; }; -export default class IndexFooterSection extends React.Component { +export default class LandingFooterSection extends React.Component { constructor(props: Props) { super(props); } @@ -15,14 +15,14 @@ export default class IndexFooterSection extends React.Component { const { header, children } = this.props; return ( - - + + - - + + {children} - + ); } } \ No newline at end of file diff --git a/sites/campground.gg/src/components/landing/LandingNavbar.tsx b/sites/campground.gg/src/components/landing/LandingNavbar.tsx new file mode 100644 index 0000000..b678390 --- /dev/null +++ b/sites/campground.gg/src/components/landing/LandingNavbar.tsx @@ -0,0 +1,49 @@ +import React from "react"; +import BrandLogo from "../BrandLogo"; +import LandingNavbarItem from "./LandingNavbarItem"; +import { FormattedMessage } from "react-intl"; +import { Box, Link, Stack } from "@mui/joy"; +import LandingNavbarPrimary from "./LandingNavbarPrimary"; + +export type Props = { + page: string; +}; + +export default class LandingNavbar extends React.Component { + constructor(props: Props) { + super(props); + } + render() { + return ( + ({ position: "sticky", top: 0, zIndex: 20, backgroundColor: theme.vars.palette.background.transparent })}> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/components/IndexNavbarItem.tsx b/sites/campground.gg/src/components/landing/LandingNavbarItem.tsx similarity index 54% rename from sites/app.campground.gg/src/components/IndexNavbarItem.tsx rename to sites/campground.gg/src/components/landing/LandingNavbarItem.tsx index b9cb17b..5778f27 100644 --- a/sites/app.campground.gg/src/components/IndexNavbarItem.tsx +++ b/sites/campground.gg/src/components/landing/LandingNavbarItem.tsx @@ -1,4 +1,4 @@ -import { Button, ButtonVariant } from "@mantine/core"; +import { Button, ColorPaletteProp, VariantProp } from "@mui/joy"; import React, { ReactNode } from "react"; export type Props = { @@ -6,17 +6,18 @@ export type Props = { href: string; active?: boolean; icon?: ReactNode; - variant?: ButtonVariant; + variant?: VariantProp; + color?: ColorPaletteProp; }; -export default class IndexNavbarItem extends React.Component { +export default class LandingNavbarItem extends React.Component { constructor(props: Props) { super(props); } render(): React.ReactNode { - const { variant, children, href } = this.props; + const { variant, color, children, href } = this.props; return ( - ); diff --git a/sites/campground.gg/src/components/landing/LandingNavbarPrimary.tsx b/sites/campground.gg/src/components/landing/LandingNavbarPrimary.tsx new file mode 100644 index 0000000..a815b82 --- /dev/null +++ b/sites/campground.gg/src/components/landing/LandingNavbarPrimary.tsx @@ -0,0 +1,26 @@ +import { Link } from "@mui/joy"; +import React, { ReactNode } from "react"; +import PrimaryButton from "../PrimaryButton"; + +export type Props = { + children: ReactNode[] | ReactNode; + href: string; + active?: boolean; + icon?: ReactNode; +}; + +export default class LandingNavbarPrimary extends React.Component { + constructor(props: Props) { + super(props); + } + render(): React.ReactNode { + const { children, href } = this.props; + return ( + + + { children } + + + ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/landing/LandingPageWrapper.tsx b/sites/campground.gg/src/components/landing/LandingPageWrapper.tsx new file mode 100644 index 0000000..963960d --- /dev/null +++ b/sites/campground.gg/src/components/landing/LandingPageWrapper.tsx @@ -0,0 +1,27 @@ +import React, { ReactNode } from "react"; +import LandingFooter from "./LandingFooter"; +import { Stack } from "@mui/joy"; +import LandingBareboneWrapper from "./LandingBareboneWrapper"; + +type Props = { + children: ReactNode[] | ReactNode; +}; + +export default class LandingPageWrapper extends React.Component { + constructor(props: Props) { + super(props); + } + + render() { + const { children } = this.props; + + return ( + + + {children} + + + + ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/landing/LandingSection.tsx b/sites/campground.gg/src/components/landing/LandingSection.tsx new file mode 100644 index 0000000..ed22249 --- /dev/null +++ b/sites/campground.gg/src/components/landing/LandingSection.tsx @@ -0,0 +1,53 @@ +import { Grid, Link, Stack, Typography } from "@mui/joy"; +import { IconArrowRight } from "@tabler/icons-react"; +import React, { ReactNode } from "react"; +import { FormattedMessage } from "react-intl"; +import PrimaryButton from "../PrimaryButton"; + +type Props = { + id: string; + subtitle: string; + title: string; + description: string; + icon: ReactNode[] | ReactNode; + learnMore: string; + learnMoreHref: string; +}; + +export default class LandingSection extends React.Component { + constructor(props: Props) { + super(props); + } + + render() { + const { id, subtitle, title, description, learnMore, learnMoreHref, icon } = this.props; + + return ( + + + + + {icon} + + + + + + + + + + + + + + + }> + + + + + + ) + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/landing/sticky/LandingStickyCampfire.tsx b/sites/campground.gg/src/components/landing/sticky/LandingStickyCampfire.tsx new file mode 100644 index 0000000..5e88286 --- /dev/null +++ b/sites/campground.gg/src/components/landing/sticky/LandingStickyCampfire.tsx @@ -0,0 +1,77 @@ +import { Avatar, Box, ColorPaletteProp, Sheet, Stack, Typography } from "@mui/joy"; +import { Theme } from "@mui/joy/styles/types"; +import { IconCaretDown, IconClockFilled, IconFileTextFilled, IconHash, IconMessageFilled, IconMountainFilled } from "@tabler/icons-react"; +import { SystemStyleObject } from "@mui/system/styleFunctionSx/styleFunctionSx"; +import React, { ReactNode } from "react"; +import { floatingAnimation } from "./animations"; + +export default function LandingStickyCampfires() { + return ( + + + + } name="Mod discussions" /> + } name="Suspicious activity" /> + + } name="Mod Schedule" /> + } name="Warnings" /> + + + + } name="Game discussions" /> + } name="Media" /> + + + + } name="Chat" /> + } name="Player Schedule" /> + } name="Suggestions" /> + + } name="Slayer's Profile" /> + } name="Slayer's Gameplay" /> + + + ) +} +function LandingStickyCampfire({ sx, name, description, color, children }: { sx?: SystemStyleObject, name: string, description: string, color: ColorPaletteProp, children: ReactNode[] | ReactNode }) { + return ( + ({ position: "absolute", minWidth: 400, background: theme.vars.palette.background.level2, borderRadius: 16, boxShadow: theme.vars.shadow.xl, ...sx })}> + + + + {name[0]} + + + {name} + {description} + + + + + + {children} + + + + ); +} +function LandingStickyCampfiresChannel({ highlighted, icon, name }: { highlighted?: boolean, icon: React.ReactNode, name: string }) { + return ( + ({ borderRadius: 8, px: 2, py: 1, backgroundColor: highlighted ? theme.vars.palette.background.level4 : theme.vars.palette.background.level2 })}> + + {icon} + {name} + + + ) +} +function LandingStickyCampfiresCategory({ name }: { name: string }) { + return ( + ({ borderRadius: 8, px: 0, py: 1, backgroundColor: theme.vars.palette.background.level2 })}> + + + {name} + + + ) +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/landing/sticky/LandingStickyEncryption.tsx b/sites/campground.gg/src/components/landing/sticky/LandingStickyEncryption.tsx new file mode 100644 index 0000000..9b67093 --- /dev/null +++ b/sites/campground.gg/src/components/landing/sticky/LandingStickyEncryption.tsx @@ -0,0 +1,96 @@ +import { Alert, Avatar, Card, CardContent, ColorPaletteProp, Stack, Typography } from "@mui/joy"; +import { Theme } from "@mui/joy/styles/types"; +import { SystemStyleObject } from "@mui/system/styleFunctionSx/styleFunctionSx"; +import { IconLockFilled } from "@tabler/icons-react"; +import React from "react"; + +const cardWidth = 500; + +export default function LandingStickyEncryption() { + return ( + + ({ + position: "relative", + width: cardWidth + 60, + "::after": { + content: "''", + position: "absolute", + top: 0, + left: 0, + right: 0, + bottom: 0, + zIndex: 10, + background: `linear-gradient(to bottom, transparent, ${theme.vars.palette.background.body})` + } + })}> + + + + + + }> + Chat is protected with encryption + + + ) +} + +type State = { + text: string; +}; +type Props = { + sx?: SystemStyleObject; + color: ColorPaletteProp; + username: string; +}; + +const aCharCode = "A".charCodeAt(0); +const zCharCode = "z".charCodeAt(0); + +function randomizeCharacter() { + return String.fromCharCode(Math.floor(Math.random() * (zCharCode - aCharCode) + aCharCode)); +} +function randomizeText() { + return Array(30).join().split(",").map(randomizeCharacter).join(""); +} + +class LandingStickyEncryptedMessage extends React.Component { + interval?: NodeJS.Timeout; + constructor(props: Props) { + super(props); + + this.state = { + text: randomizeText(), + } + } + componentDidMount(): void { + this.interval = setInterval(() => this.setState({ text: randomizeText() }), 100); + } + componentWillUnmount(): void { + clearInterval(this.interval); + } + render() { + const { sx, color, username } = this.props; + const { text } = this.state; + + return ( + + + + + {username[0]} + + + + {username} + Today at 12:43pm + + {text} + + + + + ); + } +} + diff --git a/sites/campground.gg/src/components/landing/sticky/LandingStickyLists.tsx b/sites/campground.gg/src/components/landing/sticky/LandingStickyLists.tsx new file mode 100644 index 0000000..fdc4620 --- /dev/null +++ b/sites/campground.gg/src/components/landing/sticky/LandingStickyLists.tsx @@ -0,0 +1,89 @@ +import { keyframes } from "@emotion/react"; +import { Avatar, Box, Card, CardContent, Stack, Typography } from "@mui/joy"; +import { Theme } from "@mui/joy/styles/types"; +import { SystemStyleObject } from "@mui/system/styleFunctionSx/styleFunctionSx"; +import { IconCheck, IconX } from "@tabler/icons-react"; +import React from "react"; + +const appearAnimation = keyframes` + 0% { + opacity: 0; + } + 5% { + opacity: 100%; + } + 65% { + opacity: 100%; + } + 70% { + opacity: 0; + } + 100% { + opacity: 0; + } +`; + +export default function LandingStickyLists() { + return ( + + + + + + + + + ) +} + +type Props = { + sx?: SystemStyleObject; + noCompletionAnimation?: boolean; + animationDelay?: string; + title: string; + description: string; +}; + +function LandingStickyListSubItem(props: Props) { + return ( + + ({ mt: -8, ml: 3, height: 112, width: 30, borderBottomLeftRadius: 12, borderBottom: `solid 3px ${theme.vars.palette.neutral[500]}`, borderLeft: `solid 3px ${theme.vars.palette.neutral[500]}` })}> + + + + + ) +} + +class LandingStickyListItem extends React.Component { + constructor(props: Props) { + super(props); + } + render() { + const { sx, noCompletionAnimation, animationDelay, title, description } = this.props; + + return ( + + + + + + + + + + + + + + {title} + {description} + + + + + + ); + } +} + diff --git a/sites/campground.gg/src/components/landing/sticky/LandingStickyProfile.tsx b/sites/campground.gg/src/components/landing/sticky/LandingStickyProfile.tsx new file mode 100644 index 0000000..86cf6e7 --- /dev/null +++ b/sites/campground.gg/src/components/landing/sticky/LandingStickyProfile.tsx @@ -0,0 +1,46 @@ +import { AspectRatio, Avatar, Badge, Box, Card, CardContent, CardOverflow, Stack, Typography } from "@mui/joy"; +import { floatingAnimation } from "./animations"; + +export default function LandingStickyProfile() { + return ( + ({ animation: `${floatingAnimation} 5s infinite`, border: "none", background: `linear-gradient(to bottom right, ${theme.vars.palette.danger[1000]}, ${theme.vars.palette.danger[900]})` })}> + + + ({ background: `linear-gradient(to bottom right, ${theme.vars.palette.danger[500]}, ${theme.vars.palette.danger[400]})` })}> + + + + + ({ width: 96, height: 96, border: `solid 2px ${theme.vars.palette.background.surface}` })}> + + S + + + + + + + + + Susan + @susan.example.com + 1 Mutual Friend • 2 Mutual Campsites + Hello, I am Susan. 👋 I am an avid book reader and an author. + + + + + Blog: Nineteen Eighty-Four — a must-read + Nineteen Eighty-Four is a dystopian novel by the English writer George Orwell. It was published on 8 June 1949 by Secker & Warburg as Orwell's ninth and final completed book. + + + ({ width: "100%", height: 150, background: `linear-gradient(to bottom, transparent 0%, ${theme.vars.palette.danger[900]} 95%)` })}> + + + + + + + + ) +} diff --git a/sites/campground.gg/src/components/landing/sticky/LandingStickySelfHosts.tsx b/sites/campground.gg/src/components/landing/sticky/LandingStickySelfHosts.tsx new file mode 100644 index 0000000..eada85f --- /dev/null +++ b/sites/campground.gg/src/components/landing/sticky/LandingStickySelfHosts.tsx @@ -0,0 +1,50 @@ +import { AspectRatio, Avatar, Box, Card, CardContent, CardOverflow, ColorPaletteProp, Link, Sheet, Stack, Typography } from "@mui/joy"; +import { Theme } from "@mui/joy/styles/types"; +import { SystemStyleObject } from "@mui/system/styleFunctionSx/styleFunctionSx"; +import { floatingAnimation } from "./animations"; + +export default function LandingStickySelfHosts() { + return ( + + + + + ); +} +function LandingStickySelfHost({ name, color, sx }: { name: string; color: ColorPaletteProp; sx?: SystemStyleObject; }) { + return ( + ({ animation: `${floatingAnimation} 5s infinite`, position: "absolute", boxShadow: theme.vars.shadow.xl, minWidth: 600, ...sx })}> + + + ({ background: `linear-gradient(to bottom right, ${theme.vars.palette[color][500]}, ${theme.vars.palette[color][400]})` })}> + + + + + + + + {name[0]} + + + {name} + + + + + ({ backgroundColor: theme.vars.palette.neutral[400], width: 4, height: 16 })} color="neutral" variant="solid"> + + Medium connection + + 127.0.0.1:2025 + + + https://campground.gg + + + + + + + ); +} diff --git a/sites/campground.gg/src/components/landing/sticky/LandingStickyThemes.tsx b/sites/campground.gg/src/components/landing/sticky/LandingStickyThemes.tsx new file mode 100644 index 0000000..394c4b0 --- /dev/null +++ b/sites/campground.gg/src/components/landing/sticky/LandingStickyThemes.tsx @@ -0,0 +1,54 @@ +import { keyframes } from "@emotion/react"; +import { Box, Sheet, Stack, Typography } from "@mui/joy"; +import { IconPaletteFilled } from "@tabler/icons-react"; + +const circularMotion = keyframes` + 0% { + transform: rotate(0deg) translateY(192px) rotate(0deg); + } + 100% { + transform: rotate(360deg) translateY(192px) rotate(-360deg); + } +` +const rainbowBg = keyframes` + 0% { + background-color: #00FFFF; + } + 16.67% { + background-color: #0000FF; + } + 33.33% { + background-color: #FF00FF; + } + 50% { + background-color: #FF0000; + } + 66.67% { + background-color: #FFFF00; + } + 83.33% { + background-color: #00FF00; + } + 100% { + background-color: #00FFFF; + } +` + +export default function LandingStickyThemes() { + return ( + + + + + + + + + + + + + + + ) +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/landing/sticky/animations.ts b/sites/campground.gg/src/components/landing/sticky/animations.ts new file mode 100644 index 0000000..7622176 --- /dev/null +++ b/sites/campground.gg/src/components/landing/sticky/animations.ts @@ -0,0 +1,13 @@ +import { keyframes } from "@emotion/react"; + +export const floatingAnimation = keyframes` + 0% { + transform: translateY(15px); + } + 50% { + transform: translateY(-15px); + } + 100% { + transform: translateY(15px); + } +`; \ No newline at end of file diff --git a/sites/campground.gg/src/components/signin/SigninNavbar.tsx b/sites/campground.gg/src/components/signin/SigninNavbar.tsx new file mode 100644 index 0000000..711a0ec --- /dev/null +++ b/sites/campground.gg/src/components/signin/SigninNavbar.tsx @@ -0,0 +1,26 @@ +import React from "react"; +import BrandLogo from "../BrandLogo"; +import { Box, Link, Stack } from "@mui/joy"; + +export type Props = { + page: string; +}; + +export default class SigninNavbar extends React.Component { + constructor(props: Props) { + super(props); + } + render() { + return ( + + + + + + + + + + ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/components/signin/SigninWrapper.tsx b/sites/campground.gg/src/components/signin/SigninWrapper.tsx new file mode 100644 index 0000000..03566ec --- /dev/null +++ b/sites/campground.gg/src/components/signin/SigninWrapper.tsx @@ -0,0 +1,82 @@ +import React, { ReactNode } from "react"; +import { Box, Sheet, Stack, Typography } from "@mui/joy"; +import { SxProps } from "@mui/joy/styles/types"; +import { FormattedMessage } from "react-intl"; +import SigninNavbar from "./SigninNavbar"; + +type Props = { + header: string; + sx?: SxProps; + bodySx?: SxProps; + children: ReactNode[] | ReactNode; +}; + +export default class SigninWrapper extends React.Component { + constructor(props: Props) { + super(props); + } + + render() { + const { header, sx, bodySx, children } = this.props; + + return ( + + + + ({ + position: "absolute", + top: 0, + left: 0, + right: 0, + bottom: 0, + background: `linear-gradient(to bottom, ${theme.vars.palette.info[950]} 0%, ${theme.vars.palette.info[850]} 25%, ${theme.vars.palette.info[700]} 50%, ${theme.vars.palette.info[300]} 100%)`, + overflow: "hidden", + zIndex: -1, + })}> + ({ + background: `linear-gradient(to left, ${theme.vars.palette.background.body}, ${theme.vars.palette.background.level1})`, + position: "absolute", + content: "''", + zIndex: 2, + top: -1000, + left: -1000, + right: "40%", + bottom: -500, + rotate: "6deg", + // borderRadius: "300% 50%", + mask: [ + `radial-gradient(514.3px at calc(100% - 690px) 50%,#000 100.8%,#0000 101%) 0 calc(50% - 460px)/100% 920px`, + `radial-gradient(519.3px at calc(100% + 470px) 50%,#0000 100.8%,#000 101%) calc(100% - 225px) 50%/100% 920px repeat-y`, + ].join(",") + })}> + + + + + + ({ backgroundColor: theme.vars.palette.background.level1, minWidth: 650, borderRadius: theme.vars.radius.lg, boxShadow: theme.vars.shadow.xl })}> + + + + + + + + {/*
*/} + {children} + {/*
*/} +
+
+
+
+
+ {/* + + + + */} +
+
+ ); + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/css/functions.scss b/sites/campground.gg/src/css/functions.scss similarity index 100% rename from sites/app.campground.gg/src/css/functions.scss rename to sites/campground.gg/src/css/functions.scss diff --git a/sites/campground.gg/src/css/landing.scss b/sites/campground.gg/src/css/landing.scss new file mode 100644 index 0000000..69d22a6 --- /dev/null +++ b/sites/campground.gg/src/css/landing.scss @@ -0,0 +1,36 @@ +@use "./functions.scss" as *; + +$landingSidePadding: 256px; + +.landing-side-padding { + @include padding-horizontal($landingSidePadding); +} +.landing-side-padding-nav { + @include padding-horizontal($landingSidePadding - 24.75px); +} + +.BrandLogo.img { + width: 56px; + height: 56px; + user-select: none; + &.xs { + width: 36px; + height: 36px; + } + &.sm { + width: 48px; + height: 48px; + } + &.md { + width: 56px; + height: 56px; + } + &.lg { + width: 64px; + height: 64px; + } + &.xl { + width: 96px; + height: 96px; + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/i18n/index.ts b/sites/campground.gg/src/i18n/index.ts similarity index 100% rename from sites/app.campground.gg/src/i18n/index.ts rename to sites/campground.gg/src/i18n/index.ts diff --git a/sites/app.campground.gg/src/i18n/provider.tsx b/sites/campground.gg/src/i18n/provider.tsx similarity index 100% rename from sites/app.campground.gg/src/i18n/provider.tsx rename to sites/campground.gg/src/i18n/provider.tsx diff --git a/sites/app.campground.gg/src/i18n/util.ts b/sites/campground.gg/src/i18n/util.ts similarity index 100% rename from sites/app.campground.gg/src/i18n/util.ts rename to sites/campground.gg/src/i18n/util.ts diff --git a/sites/app.campground.gg/src/index.css b/sites/campground.gg/src/index.css similarity index 100% rename from sites/app.campground.gg/src/index.css rename to sites/campground.gg/src/index.css diff --git a/sites/app.campground.gg/src/main.tsx b/sites/campground.gg/src/main.tsx similarity index 100% rename from sites/app.campground.gg/src/main.tsx rename to sites/campground.gg/src/main.tsx diff --git a/sites/campground.gg/src/routes/Login.tsx b/sites/campground.gg/src/routes/Login.tsx new file mode 100644 index 0000000..04009e9 --- /dev/null +++ b/sites/campground.gg/src/routes/Login.tsx @@ -0,0 +1,84 @@ +import React, { FormEvent } from "react"; +import SigninWrapper from "../components/signin/SigninWrapper"; +import { FormattedMessage } from "react-intl"; +import Form from "../components/form/Form"; +import { Link } from "@mui/joy"; + +export type Props = { + +}; + +export default class Login extends React.Component { + constructor(props: Props) { + super(props); + } + onSubmit(event: FormEvent, fieldValues: Record) { + event.preventDefault(); + + const details = { + email: fieldValues.email, + password: fieldValues.password, + } + + console.log(details); + } + render() { + return ( + +
, + format: /^(?:([A-Za-z0-9._%+-]+)@((?:[A-Za-z0-9-]+[.])+[A-Za-z]{2,})|[A-Za-z0-9$_.-]+)$/, + required: true + }, + { + type: "text", + id: "password", + inputType: "password", + placeholder: "Password here", + header: , + footer: + + , + required: true + } + ] + } + ]} + onSubmit={this.onSubmit} + submitText="form.login" + > + + + + + {/* + + + Email + + + + Password + + Forgot your password? + + + + + + + Don't have an account? Sign up + + */} +
+ ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/routes/NotFound.tsx b/sites/campground.gg/src/routes/NotFound.tsx new file mode 100644 index 0000000..c97cf96 --- /dev/null +++ b/sites/campground.gg/src/routes/NotFound.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import { FormattedMessage } from "react-intl"; +import LandingPageWrapper from "../components/landing/LandingPageWrapper"; +import { Link, Stack, Typography } from "@mui/joy"; +import { IconDoorExit, IconMoodAngryFilled } from "@tabler/icons-react"; +import PrimaryButton from "../components/PrimaryButton"; + +export type Props = { + +}; + +export default class NotFound extends React.Component { + constructor(props: Props) { + super(props); + } + render() { + return ( + + + + + + + + + + + + + }> + + + + + + ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/routes/Register.tsx b/sites/campground.gg/src/routes/Register.tsx new file mode 100644 index 0000000..69e3a49 --- /dev/null +++ b/sites/campground.gg/src/routes/Register.tsx @@ -0,0 +1,103 @@ +import React, { ChangeEvent } from "react"; +import { Link, Stack, Typography } from "@mui/joy"; +import { IconAt } from "@tabler/icons-react"; +import SigninWrapper from "../components/signin/SigninWrapper"; +import { FormattedMessage } from "react-intl"; +import Form from "../components/form/Form"; + +export type Props = { + +}; +type PasswordState = { + password: string; + confirmPassword: string; +} +export type State = PasswordState & { + wrongConfirmPassword: boolean; +}; + +export default class Register extends React.Component { + constructor(props: Props) { + super(props); + this.state = { wrongConfirmPassword: false, password: "", confirmPassword: "" }; + } + onSubmit(event: React.FormEvent, fieldValues: Record) { + event.preventDefault(); + + console.log(fieldValues); + } + onPasswordInputChange(property: "password" | "confirmPassword", e: ChangeEvent) { + const { password, confirmPassword } = this.state; + + const newState: Partial = { password, confirmPassword, [property]: e.target.value }; + + this.setState({ ...newState, wrongConfirmPassword: newState.password !== newState.confirmPassword } as State); + } + render() { + return ( + +
, + required: true + }, + { + type: "text", + id: "tagline", + placeholder: "Tag_Here", + header: , + format: /^([A-Za-z0-9$_.-]+)$/, + startDecorator: + + + + + + , + required: true + }, + { + type: "text", + id: "email", + inputType: "email", + placeholder: "example@example.com", + header: , + format: /^([A-Za-z0-9._%+-]+)@((?:[A-Za-z0-9-]+[.])+[A-Za-z]{2,})$/, + required: true + }, + { + type: "text", + id: "password", + inputType: "password", + placeholder: "Password here", + header: , + required: true + }, + { + type: "text", + id: "confirmPassword", + inputType: "password", + placeholder: "Password here", + header: , + required: true + } + ] + } + ]} + onSubmit={this.onSubmit} + submitText="form.register" + > + + + + +
+ ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/routes/ResetPassword.tsx b/sites/campground.gg/src/routes/ResetPassword.tsx new file mode 100644 index 0000000..0aac0a9 --- /dev/null +++ b/sites/campground.gg/src/routes/ResetPassword.tsx @@ -0,0 +1,80 @@ +import React, { ChangeEvent } from "react"; +import { Link } from "@mui/joy"; +import SigninWrapper from "../components/signin/SigninWrapper"; +import { FormattedMessage } from "react-intl"; +import Form from "../components/form/Form"; + +export type Props = { + +}; +type PasswordState = { + password: string; + confirmPassword: string; +} +export type State = PasswordState & { + wrongConfirmPassword: boolean; +}; + +export default class ResetPassword extends React.Component { + constructor(props: Props) { + super(props); + this.state = { wrongConfirmPassword: false, password: "", confirmPassword: "" }; + } + onSubmit(event: React.FormEvent, fieldValues: Record) { + event.preventDefault(); + + console.log(fieldValues); + } + onPasswordInputChange(property: "password" | "confirmPassword", e: ChangeEvent) { + const { password, confirmPassword } = this.state; + + const newState: Partial = { password, confirmPassword, [property]: e.target.value }; + + this.setState({ ...newState, wrongConfirmPassword: newState.password !== newState.confirmPassword } as State); + } + render() { + return ( + +
, + format: /^([A-Za-z0-9._%+-]+)@((?:[A-Za-z0-9-]+[.])+[A-Za-z]{2,})$/, + required: true + }, + { + type: "text", + id: "password", + inputType: "password", + placeholder: "Password here", + header: , + required: true + }, + { + type: "text", + id: "confirmPassword", + inputType: "password", + placeholder: "Password here", + header: , + required: true + } + ] + } + ]} + onSubmit={this.onSubmit} + submitText="form.resetPasswordTitle" + > + + + + +
+ ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/routes/Soon.tsx b/sites/campground.gg/src/routes/Soon.tsx new file mode 100644 index 0000000..94b5501 --- /dev/null +++ b/sites/campground.gg/src/routes/Soon.tsx @@ -0,0 +1,38 @@ +import React from "react"; +import { FormattedMessage } from "react-intl"; +import LandingPageWrapper from "../components/landing/LandingPageWrapper"; +import { Link, Stack, Typography } from "@mui/joy"; +import { IconDoorExit, IconMoodSadFilled } from "@tabler/icons-react"; +import PrimaryButton from "../components/PrimaryButton"; + +export type Props = { + +}; + +export default class Soon extends React.Component { + constructor(props: Props) { + super(props); + } + render() { + return ( + + + + + + + + + + + + + }> + + + + + + ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/routes/landing/Downloads.tsx b/sites/campground.gg/src/routes/landing/Downloads.tsx new file mode 100644 index 0000000..8b0bb9a --- /dev/null +++ b/sites/campground.gg/src/routes/landing/Downloads.tsx @@ -0,0 +1,156 @@ +import React from "react"; +import { FormattedMessage } from "react-intl"; +import LandingPageWrapper from "../../components/landing/LandingPageWrapper"; +import { IconBrandAndroid, IconBrandApple, IconBrandDebian, IconBrandGooglePlay, IconBrandWindows, IconDownload, IconFeather } from "@tabler/icons-react"; +import { Grid, Link, Option, Select, Stack, Typography } from "@mui/joy"; +import PrimaryButton from "../../components/PrimaryButton"; +import DownloadCard from "../../components/landing/DownloadCard"; + +export type Props = { + +}; + +export default class Downloads extends React.Component { + constructor(props: Props) { + super(props); + } + render() { + return ( + + + + + + + + + + + + + + + + + + + + }> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } + href="/downloads" + /> + } + href="/downloads" + /> + } + href="/downloads" + /> + } + href="/downloads" + gridColumn="1 / 4" + > + + + + + + + + + + + + + + + + + + + + + + } + href="/downloads" + /> + } + href="/downloads" + /> + } + href="/downloads" + /> + + + + + + + ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/routes/landing/Features.tsx b/sites/campground.gg/src/routes/landing/Features.tsx new file mode 100644 index 0000000..61021e9 --- /dev/null +++ b/sites/campground.gg/src/routes/landing/Features.tsx @@ -0,0 +1,81 @@ +import React from "react"; +import { FormattedMessage } from "react-intl"; +import LandingPageWrapper from "../../components/landing/LandingPageWrapper"; +import { IconCalendarFilled, IconCampfireFilled, IconCheckbox, IconFileTextFilled, IconLockFilled, IconServer } from "@tabler/icons-react"; +import { Box, Grid, Stack, Typography } from "@mui/joy" +import FeatureCard from "../../components/landing/FeatureCard"; + +export type Props = { + +}; + +export default class Features extends React.Component { + constructor(props: Props) { + super(props); + } + render() { + return ( + + + + + + + + + + + + + } + href="/docs/features/campfires" + imgSrc="/example-banner.svg" + /> + } + href="/docs/features/instances" + imgSrc="/example-banner.svg" + color="warning" + /> + } + href="/docs/features/encryption" + imgSrc="/example-banner.svg" + color="info" + /> + } + href="/docs/features/calendar-tents" + imgSrc="/example-banner.svg" + color="danger" + /> + } + href="/docs/features/list-tents" + imgSrc="/example-banner.svg" + color="success" + /> + } + href="/docs/features/doc-tents" + imgSrc="/example-banner.svg" + color="secondary" + /> + + + ); + } +} \ No newline at end of file diff --git a/sites/campground.gg/src/routes/landing/LandingIndex.tsx b/sites/campground.gg/src/routes/landing/LandingIndex.tsx new file mode 100644 index 0000000..0566915 --- /dev/null +++ b/sites/campground.gg/src/routes/landing/LandingIndex.tsx @@ -0,0 +1,199 @@ +import React from "react"; +import { FormattedMessage } from "react-intl"; +import LandingPageWrapper from "../../components/landing/LandingPageWrapper"; +import { IconBrandDebian, IconCamper, IconCampfire, IconCheckbox, IconLock, IconPalette, IconServer } from "@tabler/icons-react"; +import { Box, Button, Grid, Link, Sheet, Stack, Typography } from "@mui/joy"; +import PrimaryButton from "../../components/PrimaryButton"; +import LandingSection from "../../components/landing/LandingSection"; +import ObservabilityDisplay from "../../components/ObservabilityDisplay"; +import LandingStickyCampfires from "../../components/landing/sticky/LandingStickyCampfire"; +import LandingStickySelfHosts from "../../components/landing/sticky/LandingStickySelfHosts"; +import LandingStickyEncryption from "../../components/landing/sticky/LandingStickyEncryption"; +import LandingStickyProfile from "../../components/landing/sticky/LandingStickyProfile"; +import LandingStickyLists from "../../components/landing/sticky/LandingStickyLists"; +import LandingStickyThemes from "../../components/landing/sticky/LandingStickyThemes"; + +export type Props = { + +}; + +export default class LandingIndex extends React.Component { + constructor(props: Props) { + super(props); + } + render() { + return ( + + {/* Top motto of the Index */} + + + + + + + + + + + + + + + + + + + }> + + + + + + Incorrect operating system? Click here to check out downloads page! + + + + + {/* Features in the Index */} + + } + title="home.campfires.title" + description="home.campfires.description" + learnMore="home.campfires.learnMore" + learnMoreHref="/docs/features/campfires" + /> + } + title="home.selfHost.title" + description="home.selfHost.description" + learnMore="home.selfHost.learnMore" + learnMoreHref="/docs/features/instances" + /> + } + title="home.encryption.title" + description="home.encryption.description" + learnMore="home.encryption.learnMore" + learnMoreHref="/docs/features/encryption" + /> + } + title="home.profiles.title" + description="home.profiles.description" + learnMore="home.profiles.learnMore" + learnMoreHref="/docs/features/profiles" + /> + } + title="home.lists.title" + description="home.lists.description" + learnMore="home.lists.learnMore" + learnMoreHref="/docs/features/list-tents" + /> + } + title="home.themes.title" + description="home.themes.description" + learnMore="home.themes.learnMore" + learnMoreHref="/docs/features/themes" + /> + + + + {{ elementId: "campfires", node: }} + {{ elementId: "selfHost", node: }} + {{ elementId: "encryption", node: }} + {{ elementId: "profiles", node: }} + {{ elementId: "lists", node: }} + {{ elementId: "themes", node: }} + + + + + + + ); + } +} + +class LandingBottomSection extends React.Component { + constructor(props: {}) { + super(props); + } + + render() { + return ( + + ({ + background: `linear-gradient(90deg, ${theme.vars.palette.primary[500]}, ${theme.vars.palette.secondary[500]})`, + position: "absolute", + top: 25, + left: -10, + bottom: 25, + right: -10, + rotate: "1.5deg", + "::before": { + position: "absolute", + content: "''", + top: 0, + bottom: 0, + left: 0, + right: 0, + background: `linear-gradient(0deg, ${theme.vars.palette.info[500]}, transparent, ${theme.vars.palette.warning[500]})`, + opacity: 0.25, + }, + })} + > + + + + + + + + + + + + + + + + + + + + ) + } +} \ No newline at end of file diff --git a/sites/app.campground.gg/src/session/index.ts b/sites/campground.gg/src/session/index.ts similarity index 100% rename from sites/app.campground.gg/src/session/index.ts rename to sites/campground.gg/src/session/index.ts diff --git a/sites/app.campground.gg/src/session/provider.tsx b/sites/campground.gg/src/session/provider.tsx similarity index 100% rename from sites/app.campground.gg/src/session/provider.tsx rename to sites/campground.gg/src/session/provider.tsx diff --git a/sites/app.campground.gg/src/session/types.ts b/sites/campground.gg/src/session/types.ts similarity index 100% rename from sites/app.campground.gg/src/session/types.ts rename to sites/campground.gg/src/session/types.ts diff --git a/sites/app.campground.gg/src/supportedLocales.json b/sites/campground.gg/src/supportedLocales.json similarity index 100% rename from sites/app.campground.gg/src/supportedLocales.json rename to sites/campground.gg/src/supportedLocales.json diff --git a/sites/campground.gg/src/theme/color.ts b/sites/campground.gg/src/theme/color.ts new file mode 100644 index 0000000..0208f66 --- /dev/null +++ b/sites/campground.gg/src/theme/color.ts @@ -0,0 +1,51 @@ +// From Yoki's code +// Copied by PrettyGoodName, but it was also written by PrettyGoodName +// Not exactly a proprietary code +// Could rewrite in-case it's not in Campground's interest + +const getRedChannel = (value: number) => value >> 16; +const getGreenChannel = (value: number) => (value >> 8) % 0x100; +const getBlueChannel = (value: number) => value % 0x100; +const decimalifyColour = (r: number, g: number, b: number) => (Math.floor(r) << 16) | (Math.floor(g) << 8) | Math.floor(b); + +/** + * Mixes two decimal colours by the given opacity. + * @param c1 First colour to mix in + * @param c2 Second colour to mix in + * @param p2 The floating number that represents percentage of second colour to put in the mix. `1` is `100%` + */ +export function mixColors(c1: number, c2: number, p2: number) { + const p1 = 1 - p2; + + return decimalifyColour( + getRedChannel(c1) * p1 + getRedChannel(c2) * p2, + getGreenChannel(c1) * p1 + getGreenChannel(c2) * p2, + getBlueChannel(c1) * p1 + getBlueChannel(c2) * p2 + ); +} + +/** + * Moves colour more towards grey based on the given %. This is similar to `mixColors`. + * @param c Colour to introduce greyness to + * @param p2 The floating number that represents percentage of grey to put in the mix. `1` is `100%` + */ +export function grayscaleColor(c: number, p2: number) { + const p1 = 1 - p2; + + const red = getRedChannel(c); + const green = getGreenChannel(c); + const blue = getBlueChannel(c); + + // Multiply by %, since blue is naturally darker to our eyes and green is the brightest + const brightness = red * 0.4 + green * 0.6 + blue * 0.2; + const greyness = brightness * p2; + + return decimalifyColour(red * p1 + greyness, green * p1 + greyness, blue * p1 + greyness); +} + +export const mixHexColors = (c1: string, c2: string, p1: number) => getHexString(mixColors(getDecimalValue(c1), getDecimalValue(c2), p1)); + +export const greyscaleHexColor = (c: string, p2: number) => getHexString(grayscaleColor(getDecimalValue(c), p2)); + +export const getDecimalValue = (colour: string) => parseInt(colour.slice(1), 16); +export const getHexString = (colour: number) => `#${colour.toString(16).padStart(6, "0")}`; diff --git a/sites/campground.gg/src/theme/dark.ts b/sites/campground.gg/src/theme/dark.ts new file mode 100644 index 0000000..798a9ca --- /dev/null +++ b/sites/campground.gg/src/theme/dark.ts @@ -0,0 +1,53 @@ +import { ColorSystemOptions } from "@mui/joy/styles/extendTheme"; +import { generateColorScheme } from "./gen"; + +const darkest = "#040409", lightest = "#f5f3ff"; + +const shades = { + 950: darkest, + 900: "#0e0b16", + 800: "#151121", + 700: "#181426", + 600: "#1f1b32", + 500: "#231e37", + 400: "#3f405b", + 300: "#78799a", + 200: "#9695b2", + 100: "#dcd8ec", + 50: lightest, +}; + +const darkColorScheme: ColorSystemOptions = { + palette: { + neutral: { + ...shades, + "t-950": `${shades[950]}cc`, + }, + text: { + primary: shades[50], + secondary: shades[100], + tertiary: shades[200], + icon: shades[300], + }, + primary: generateColorScheme("#ff5a26", darkest, lightest), + secondary: generateColorScheme("#ff2661", darkest, lightest), + danger: generateColorScheme("#fe1c56", darkest, lightest), + warning: generateColorScheme("#ff851f", darkest, lightest), + success: generateColorScheme("#2bfa5e", darkest, lightest), + info: generateColorScheme("#6026ff", darkest, lightest), + background: { + transparent: `${shades[950]}dd`, + popup: "#000000", + body: shades[950], + //backdrop: shades[950], + surface: shades[900], + level1: shades[900], + level2: shades[800], + level3: shades[700], + level4: shades[600], + level5: shades[500], + } + } +}; + +export default darkColorScheme; \ No newline at end of file diff --git a/sites/campground.gg/src/theme/font.ts b/sites/campground.gg/src/theme/font.ts new file mode 100644 index 0000000..eb0fc87 --- /dev/null +++ b/sites/campground.gg/src/theme/font.ts @@ -0,0 +1,16 @@ +const fallback = [ + `"Montserrat"`, + `"Public Sans"`, + `var(--labs-fontFamily-fallback, var(--labs--apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"))`, +]; + +export const bodyFontFamily = [ + `"Nunito Sans"`, + ...fallback +].join(", "); + +export const displayFontFamily = [ + `"Quicksand"`, + `"Nunito Sans"`, + ...fallback +].join(", "); \ No newline at end of file diff --git a/sites/campground.gg/src/theme/gen.ts b/sites/campground.gg/src/theme/gen.ts new file mode 100644 index 0000000..fb33074 --- /dev/null +++ b/sites/campground.gg/src/theme/gen.ts @@ -0,0 +1,55 @@ +// From Yoki's code +// Copied by PrettyGoodName, but it was also written by PrettyGoodName +// Not exactly a proprietary code +// Could rewrite in-case it's not in Campground's interest + +import { PaletteOptions } from "@mui/joy/styles/types"; +import { greyscaleHexColor, mixHexColors } from "./color"; + +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), + 700: mixHexColors(typicalColour, background, 0.4), + 600: mixHexColors(typicalColour, background, 0.2), + "t-500": `${typicalColour}cc`, + 500: typicalColour, + 400: mixHexColors(typicalColour, counter, 0.2), + 300: mixHexColors(typicalColour, counter, 0.4), + 200: mixHexColors(typicalColour, counter, 0.6), + 100: mixHexColors(typicalColour, counter, 0.8), + // Solid + solidBg: typicalColour, + solidColor: background, + solidHoverBg: mixHexColors(typicalColour, counter, 0.2), + // Plain + plainHoverBg: mixHexColors(typicalColour, background, 0.9), + plainActiveBg: mixHexColors(typicalColour, background, 0.85), + // 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), + // // Transparency + // "sm-opacity": `${typicalColour}55`, +}); diff --git a/sites/campground.gg/src/theme/index.ts b/sites/campground.gg/src/theme/index.ts new file mode 100644 index 0000000..ee8bad5 --- /dev/null +++ b/sites/campground.gg/src/theme/index.ts @@ -0,0 +1,87 @@ +// import { createTheme } from "@mantine/core" + +import { extendTheme, PaletteVariant } from "@mui/joy"; +import { bodyFontFamily, displayFontFamily } from "./font"; +import lightColorScheme from "./light"; +import darkColorScheme from "./dark"; +import { DefaultPaletteRange } from "@mui/joy/styles/types"; + +declare module "@mui/joy/styles" { + // Add new text levels + interface TypographySystemOverrides { + code: true; + } + interface ListItemButtonPropsVariantOverrides { + indented: true; + } + // Add new text colours + interface PaletteTextOverrides { + code: true; + } + // Add new palette ranges + interface PaletteRangeOverrides { + 1000: true; + 950: true; + 850: true; + ["t-950"]: true; + ["t-500"]: true; + } + // Add new colours + interface PaletteOptions { + secondary: DefaultPaletteRange & PaletteVariant; + } + // Add new backgrounds + interface PaletteBackgroundOverrides { + transparent: true; + // level0: true; + level4: true; + level5: true; + // skeleton0: true; + // skeleton1: true; + } +} + +// Add new colours +declare module "@mui/joy/styles/types/colorSystem" { + interface Palette { + secondary: PaletteRange; + info: PaletteRange; + } + interface ColorPalettePropOverrides { + secondary: true; + info: true; + } +} + +const theme = extendTheme({ + cssVarPrefix: ``, + variants: { + soft: { + info: { + + }, + secondary: { + + } + }, + }, + fontFamily: { + body: bodyFontFamily, + display: displayFontFamily + }, + colorSchemes: { + light: lightColorScheme, + dark: darkColorScheme, + }, + components: { + JoyButton: { + styleOverrides: { + root: { + transition: "background 0.3s", + } + }, + } + } +}); + +export default theme; \ No newline at end of file diff --git a/sites/campground.gg/src/theme/light.ts b/sites/campground.gg/src/theme/light.ts new file mode 100644 index 0000000..dfb8ea2 --- /dev/null +++ b/sites/campground.gg/src/theme/light.ts @@ -0,0 +1,53 @@ +import { ColorSystemOptions } from "@mui/joy/styles/extendTheme"; +import { generateColorScheme } from "./gen"; + +const darkest = "#040409", lightest = "#f5f3ff"; + +const shades = { + 950: lightest, + 900: "#dcd8ec", + 800: "#9695b2", + 700: "#78799a", + 600: "#3f405b", + 500: "#231e37", + 400: "#1f1b32", + 300: "#181426", + 200: "#151121", + 100: "#0e0b16", + 50: darkest, +}; + +const lightColorScheme: ColorSystemOptions = { + palette: { + neutral: { + ...shades, + "t-950": `${lightest}cc`, + }, + text: { + primary: shades[50], + secondary: shades[100], + tertiary: shades[200], + icon: shades[300], + }, + primary: generateColorScheme("#ff5a26", lightest, darkest), + secondary: generateColorScheme("#ff2661", lightest, darkest), + danger: generateColorScheme("#fe1c56", lightest, darkest), + warning: generateColorScheme("#ff851f", lightest, darkest), + success: generateColorScheme("#2bfa5e", lightest, darkest), + info: generateColorScheme("#6026ff", lightest, darkest), + background: { + transparent: `${shades[950]}dd`, + popup: "#000000", + body: shades[950], + //backdrop: shades[950], + surface: shades[900], + level1: shades[900], + level2: shades[800], + level3: shades[700], + level4: shades[600], + level5: shades[500], + } + } +}; + +export default lightColorScheme; \ No newline at end of file diff --git a/sites/app.campground.gg/src/vite-env.d.ts b/sites/campground.gg/src/vite-env.d.ts similarity index 100% rename from sites/app.campground.gg/src/vite-env.d.ts rename to sites/campground.gg/src/vite-env.d.ts diff --git a/sites/app.campground.gg/tsconfig.app.json b/sites/campground.gg/tsconfig.app.json similarity index 100% rename from sites/app.campground.gg/tsconfig.app.json rename to sites/campground.gg/tsconfig.app.json diff --git a/sites/app.campground.gg/tsconfig.json b/sites/campground.gg/tsconfig.json similarity index 100% rename from sites/app.campground.gg/tsconfig.json rename to sites/campground.gg/tsconfig.json diff --git a/sites/app.campground.gg/tsconfig.node.json b/sites/campground.gg/tsconfig.node.json similarity index 100% rename from sites/app.campground.gg/tsconfig.node.json rename to sites/campground.gg/tsconfig.node.json diff --git a/sites/app.campground.gg/vite.config.ts b/sites/campground.gg/vite.config.ts similarity index 100% rename from sites/app.campground.gg/vite.config.ts rename to sites/campground.gg/vite.config.ts