diff --git a/package-lock.json b/package-lock.json index 5b75a87..db13c31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,10 +8,13 @@ "name": "basic-frontend", "version": "0.1.0", "dependencies": { + "@babel/core": "^7.16.0", "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", "@mui/icons-material": "^5.11.16", "@mui/material": "^5.13.6", + "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", + "@svgr/webpack": "^5.5.0", "@testing-library/jest-dom": "^5.16.5", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", @@ -19,12 +22,63 @@ "@types/node": "^16.18.36", "@types/react": "^18.2.14", "@types/react-dom": "^18.2.6", + "@types/react-google-recaptcha": "^2.1.5", + "babel-jest": "^27.4.2", + "babel-loader": "^8.2.3", + "babel-plugin-named-asset-import": "^0.3.8", + "babel-preset-react-app": "^10.0.1", + "bfj": "^7.0.2", + "browserslist": "^4.18.1", + "camelcase": "^6.2.1", + "case-sensitive-paths-webpack-plugin": "^2.4.0", + "css-loader": "^6.5.1", + "css-minimizer-webpack-plugin": "^3.2.0", + "dotenv": "^10.0.0", + "dotenv-expand": "^5.1.0", + "eslint": "^8.3.0", + "eslint-config-react-app": "^7.0.1", + "eslint-webpack-plugin": "^3.1.1", + "file-loader": "^6.2.0", + "fs-extra": "^10.0.0", + "html-webpack-plugin": "^5.5.0", + "identity-obj-proxy": "^3.0.0", + "jest": "^27.4.3", + "jest-resolve": "^27.4.2", + "jest-watch-typeahead": "^1.0.0", + "mini-css-extract-plugin": "^2.4.5", + "postcss": "^8.4.4", + "postcss-flexbugs-fixes": "^5.0.2", + "postcss-loader": "^6.2.1", + "postcss-normalize": "^10.0.1", + "postcss-preset-env": "^7.0.1", + "prompts": "^2.4.2", + "query-string": "^8.1.0", "react": "^18.2.0", + "react-app-polyfill": "^3.0.0", + "react-dev-utils": "^12.0.1", "react-dom": "^18.2.0", + "react-google-recaptcha": "^3.1.0", + "react-refresh": "^0.11.0", "react-router-dom": "^6.14.0", - "react-scripts": "5.0.1", + "resolve": "^1.20.0", + "resolve-url-loader": "^4.0.0", + "sass-loader": "^12.3.0", + "semver": "^7.3.5", + "source-map-loader": "^3.0.0", + "string-replace-loader": "^3.1.0", + "style-loader": "^3.3.1", + "tailwindcss": "^3.0.2", + "terser-webpack-plugin": "^5.2.5", "typescript": "^4.9.5", - "web-vitals": "^2.1.4" + "web-vitals": "^2.1.4", + "webpack": "^5.64.4", + "webpack-dev-server": "^4.6.0", + "webpack-manifest-plugin": "^4.0.2", + "workbox-webpack-plugin": "^6.4.1" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "dotenv-webpack": "^8.0.1" } }, "node_modules/@adobe/css-tools": { @@ -640,9 +694,17 @@ } }, "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "version": "7.21.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz", + "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-property-in-object instead.", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.21.0", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, "engines": { "node": ">=6.9.0" }, @@ -1900,6 +1962,17 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/preset-env/node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -4560,6 +4633,14 @@ "@types/react": "*" } }, + "node_modules/@types/react-google-recaptcha": { + "version": "2.1.9", + "resolved": "https://registry.npmjs.org/@types/react-google-recaptcha/-/react-google-recaptcha-2.1.9.tgz", + "integrity": "sha512-nT31LrBDuoSZJN4QuwtQSF3O89FVHC4jLhM+NtKEmVF5R1e8OY0Jo4//x2Yapn2aNHguwgX5doAq8Zo+Ehd0ug==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-is": { "version": "18.2.1", "resolved": "https://registry.npmjs.org/@types/react-is/-/react-is-18.2.1.tgz", @@ -6862,6 +6943,14 @@ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" }, + "node_modules/decode-uri-component": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.4.1.tgz", + "integrity": "sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==", + "engines": { + "node": ">=14.16" + } + }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -7182,11 +7271,44 @@ "node": ">=10" } }, + "node_modules/dotenv-defaults": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz", + "integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==", + "dev": true, + "dependencies": { + "dotenv": "^8.2.0" + } + }, + "node_modules/dotenv-defaults/node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/dotenv-expand": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" }, + "node_modules/dotenv-webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-8.1.0.tgz", + "integrity": "sha512-owK1JcsPkIobeqjVrk6h7jPED/W6ZpdFsMPR+5ursB7/SdgDyO+VzAU+szK8C8u3qUhtENyYnj8eyXMR5kkGag==", + "dev": true, + "dependencies": { + "dotenv-defaults": "^2.0.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "webpack": "^4 || ^5" + } + }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -8428,6 +8550,17 @@ "node": ">=8" } }, + "node_modules/filter-obj": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/filter-obj/-/filter-obj-5.1.0.tgz", + "integrity": "sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -14539,6 +14672,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/query-string": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-8.2.0.tgz", + "integrity": "sha512-tUZIw8J0CawM5wyGBiDOAp7ObdRQh4uBor/fUR9ZjmbZVvw95OD9If4w3MQxr99rg0DJZ/9CIORcpEqU5hQG7g==", + "dependencies": { + "decode-uri-component": "^0.4.1", + "filter-obj": "^5.1.0", + "split-on-first": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/querystringify": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", @@ -14647,6 +14796,18 @@ "node": ">=14" } }, + "node_modules/react-async-script": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/react-async-script/-/react-async-script-1.2.0.tgz", + "integrity": "sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==", + "dependencies": { + "hoist-non-react-statics": "^3.3.0", + "prop-types": "^15.5.0" + }, + "peerDependencies": { + "react": ">=16.4.1" + } + }, "node_modules/react-dev-utils": { "version": "12.0.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-12.0.1.tgz", @@ -14781,6 +14942,18 @@ "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, + "node_modules/react-google-recaptcha": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/react-google-recaptcha/-/react-google-recaptcha-3.1.0.tgz", + "integrity": "sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==", + "dependencies": { + "prop-types": "^15.5.0", + "react-async-script": "^1.2.0" + }, + "peerDependencies": { + "react": ">=16.4.1" + } + }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -14824,78 +14997,6 @@ "react-dom": ">=16.8" } }, - "node_modules/react-scripts": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz", - "integrity": "sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==", - "dependencies": { - "@babel/core": "^7.16.0", - "@pmmmwh/react-refresh-webpack-plugin": "^0.5.3", - "@svgr/webpack": "^5.5.0", - "babel-jest": "^27.4.2", - "babel-loader": "^8.2.3", - "babel-plugin-named-asset-import": "^0.3.8", - "babel-preset-react-app": "^10.0.1", - "bfj": "^7.0.2", - "browserslist": "^4.18.1", - "camelcase": "^6.2.1", - "case-sensitive-paths-webpack-plugin": "^2.4.0", - "css-loader": "^6.5.1", - "css-minimizer-webpack-plugin": "^3.2.0", - "dotenv": "^10.0.0", - "dotenv-expand": "^5.1.0", - "eslint": "^8.3.0", - "eslint-config-react-app": "^7.0.1", - "eslint-webpack-plugin": "^3.1.1", - "file-loader": "^6.2.0", - "fs-extra": "^10.0.0", - "html-webpack-plugin": "^5.5.0", - "identity-obj-proxy": "^3.0.0", - "jest": "^27.4.3", - "jest-resolve": "^27.4.2", - "jest-watch-typeahead": "^1.0.0", - "mini-css-extract-plugin": "^2.4.5", - "postcss": "^8.4.4", - "postcss-flexbugs-fixes": "^5.0.2", - "postcss-loader": "^6.2.1", - "postcss-normalize": "^10.0.1", - "postcss-preset-env": "^7.0.1", - "prompts": "^2.4.2", - "react-app-polyfill": "^3.0.0", - "react-dev-utils": "^12.0.1", - "react-refresh": "^0.11.0", - "resolve": "^1.20.0", - "resolve-url-loader": "^4.0.0", - "sass-loader": "^12.3.0", - "semver": "^7.3.5", - "source-map-loader": "^3.0.0", - "style-loader": "^3.3.1", - "tailwindcss": "^3.0.2", - "terser-webpack-plugin": "^5.2.5", - "webpack": "^5.64.4", - "webpack-dev-server": "^4.6.0", - "webpack-manifest-plugin": "^4.0.2", - "workbox-webpack-plugin": "^6.4.1" - }, - "bin": { - "react-scripts": "bin/react-scripts.js" - }, - "engines": { - "node": ">=14.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - }, - "peerDependencies": { - "react": ">= 16", - "typescript": "^3.2.1 || ^4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, "node_modules/react-transition-group": { "version": "4.4.5", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", @@ -15794,6 +15895,17 @@ "wbuf": "^1.7.3" } }, + "node_modules/split-on-first": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-3.0.0.tgz", + "integrity": "sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -15873,6 +15985,18 @@ "resolved": "https://registry.npmjs.org/string-natural-compare/-/string-natural-compare-3.0.1.tgz", "integrity": "sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==" }, + "node_modules/string-replace-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-replace-loader/-/string-replace-loader-3.1.0.tgz", + "integrity": "sha512-5AOMUZeX5HE/ylKDnEa/KKBqvlnFmRZudSOjVJHxhoJg9QYTwl1rECx7SLR8BBH7tfxb4Rp7EM2XVfQFxIhsbQ==", + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "peerDependencies": { + "webpack": "^5" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", diff --git a/public/index.html b/public/index.html index 26e8166..be734ef 100644 --- a/public/index.html +++ b/public/index.html @@ -1,40 +1,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - Akatsuki + + + + Akatsuki + + + - - + + - - - - -
- - - + + + \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 4a99318..bd0d188 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -18,11 +18,12 @@ import { SettingsPage } from "./pages/SettingsPage"; import { DocumentationHomePage } from "./pages/DocumentationHomePage"; import Container from "@mui/material/Container"; import { UserContextProvider } from "./users"; +import { CssBaseline } from "@mui/material"; const AppLayout = () => ( <> - + @@ -45,15 +46,24 @@ const router = createBrowserRouter( const theme = createTheme({ palette: { + background: { + default: "#110e1b", + }, primary: { - main: "#1678c2", + main: "#151222", }, secondary: { - main: "#e03997", + main: "#15122233", + }, + text: { + primary: "#ffffff" }, }, typography: { - fontFamily: "Rubik", + fontFamily: "Nunito", + button: { + textTransform: 'none', + } }, }); @@ -61,6 +71,7 @@ export default function App() { return ( + diff --git a/src/components/Button.tsx b/src/components/Button.tsx new file mode 100644 index 0000000..d2f7054 --- /dev/null +++ b/src/components/Button.tsx @@ -0,0 +1,25 @@ +import { Button as MuiButton, Typography } from "@mui/material"; + +export const Button = ({ + text, + sx, +}: { + text: string; + sx: any | undefined; +}) => { + const defaultStyle = { + minHeight: 52, + minWidth: 128, + borderRadius: "10px", + }; + var styles = sx === undefined ? defaultStyle : { ...sx, ...defaultStyle }; + return ( + + {text} + + ) +}; \ No newline at end of file diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index 44521fd..68fc01b 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -3,6 +3,7 @@ import { Typography, Button, Stack, Container } from "@mui/material"; import { useUserContext, removeUserFromLocalStorage } from "../users"; import { Link } from "react-router-dom"; import { logout } from "../adapters/webSessions"; +import wordmark from "../content/wordmark.svg"; import { Paper, Avatar, @@ -42,115 +43,135 @@ export default function Navbar() { }; return ( - <> - - + + + + {/* Left Navbar */} - {/* Left Navbar */} - - - - - - - - - - - - - {/* Right Navbar */} - - {/* TODO: add user search bar */} - {user ? ( - <> - {/* TODO: player search bar with autocomplete functionality */} - {/* https://mui.com/material-ui/react-autocomplete/#search-as-you-type */} - {/* import { debounce } from '@mui/material/utils'; */} - - {/* TODO: heart emoji */} - - - - - - - - - - ) : ( - <> - - - - - - - - )} - + + + + + + + + + + + + + + + + - {user && ( - - - - - Profile + {/* Right Navbar */} + + {/* TODO: add user search bar */} + {user ? ( + <> + {/* TODO: player search bar with autocomplete functionality */} + {/* https://mui.com/material-ui/react-autocomplete/#search-as-you-type */} + {/* import { debounce } from '@mui/material/utils'; */} + + {/* TODO: heart emoji */} + + + + + + + + + + ) : ( + <> + + - - - - - - - - Settings + + - - - - - - Logout - - - )} - - - + + )} + + + {user && ( + + + + + Profile + + + + + + + + + Settings + + + + + + + Logout + + + )} + + ); } diff --git a/src/content/LE.png b/src/content/LE.png new file mode 100644 index 0000000..6fecd5b Binary files /dev/null and b/src/content/LE.png differ diff --git a/src/content/homepage.png b/src/content/homepage.png new file mode 100644 index 0000000..32d9d14 Binary files /dev/null and b/src/content/homepage.png differ diff --git a/src/content/homepage.svg b/src/content/homepage.svg new file mode 100644 index 0000000..7fda227 --- /dev/null +++ b/src/content/homepage.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/content/wordmark.svg b/src/content/wordmark.svg new file mode 100644 index 0000000..df7f039 --- /dev/null +++ b/src/content/wordmark.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/content/wordmark_transparent.svg b/src/content/wordmark_transparent.svg new file mode 100644 index 0000000..1d42976 --- /dev/null +++ b/src/content/wordmark_transparent.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/content/wordmark_white.svg b/src/content/wordmark_white.svg new file mode 100644 index 0000000..6c8a768 --- /dev/null +++ b/src/content/wordmark_white.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index ccb417d..3cbe565 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -1,44 +1,188 @@ -import { Button, Typography, Box } from "@mui/material"; +import { Container, Typography, Box, Avatar } from "@mui/material"; import { Link } from "react-router-dom"; import Stack from "@mui/material/Stack"; +import { visuallyHidden } from '@mui/utils'; import { useUserContext } from "../users"; +import Grid from '@mui/material/Unstable_Grid2'; // Grid version 2 +import { Button } from "../components/Button"; +import homepage from "../content/LE.png"; +import wordmarkWhite from "../content/wordmark_white.svg"; +import wordmarkTrans from "../content/wordmark_transparent.svg"; export const HomePage = () => { const { user } = useUserContext(); + const scores = [0, 1, 2, 3, 4, 5, 6, 7]; return ( - +
- Welcome to Akatsuki - The largest competitive osu! private server - - - {user ? ( - - - - ) : ( - - - - )} - - - + }}> + +
+ + + + Server Statistics + +
+ +
+ + 1.449.643 + pp earned + +
+ + + + 92.449.643 + scores set + +
+ +
+
+ + +
+ +
+ + 149.643 + users registered + +
+
+ + + + + Welcome to Akatsuki! + We are an osu! private server mainly based + around the relax mod - featuring score submission, leaderboards & + rankings, custom pp, and much more for relax, autopilot and vanilla osu! + + + {user ? ( + +