base
@ -16,16 +16,20 @@
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"mobx": "^6.8.0",
|
||||
"mobx-react-lite": "^3.4.3",
|
||||
"react": "^18.2.0",
|
||||
"react-advanced-cropper": "^0.18.0",
|
||||
"react-colorful": "^5.6.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-error-boundary": "^3.1.4",
|
||||
"react-hook-form": "^7.43.7",
|
||||
"react-icons": "^4.8.0",
|
||||
"react-loading-skeleton": "^3.2.0",
|
||||
"react-responsive": "^9.0.2",
|
||||
"react-router-dom": "^6.9.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-spinkit": "^3.0.0",
|
||||
"react-spinners": "^0.13.8",
|
||||
"reoverlay": "^1.0.3",
|
||||
"slate": "^0.91.4",
|
||||
"slate-react": "^0.92.0",
|
||||
"styled-components": "^5.3.9",
|
||||
@ -57,6 +61,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@craco/craco": "^7.1.0",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"craco-esbuild": "^0.5.2"
|
||||
}
|
||||
}
|
||||
|
119
pnpm-lock.yaml
@ -14,18 +14,23 @@ specifiers:
|
||||
'@types/node': ^16.18.16
|
||||
'@types/react': ^18.0.28
|
||||
'@types/react-dom': ^18.0.11
|
||||
'@types/styled-components': ^5.1.26
|
||||
craco-esbuild: ^0.5.2
|
||||
mobx: ^6.8.0
|
||||
mobx-react-lite: ^3.4.3
|
||||
react: ^18.2.0
|
||||
react-advanced-cropper: ^0.18.0
|
||||
react-colorful: ^5.6.1
|
||||
react-dom: ^18.2.0
|
||||
react-error-boundary: ^3.1.4
|
||||
react-hook-form: ^7.43.7
|
||||
react-icons: ^4.8.0
|
||||
react-loading-skeleton: ^3.2.0
|
||||
react-responsive: ^9.0.2
|
||||
react-router-dom: ^6.9.0
|
||||
react-scripts: 5.0.1
|
||||
react-spinkit: ^3.0.0
|
||||
react-spinners: ^0.13.8
|
||||
reoverlay: ^1.0.3
|
||||
slate: ^0.91.4
|
||||
slate-react: ^0.92.0
|
||||
styled-components: ^5.3.9
|
||||
@ -45,16 +50,20 @@ dependencies:
|
||||
'@types/react': 18.0.28
|
||||
'@types/react-dom': 18.0.11
|
||||
mobx: 6.8.0
|
||||
mobx-react-lite: 3.4.3_woojb62cqeyk443mbl7msrwu2e
|
||||
react: 18.2.0
|
||||
react-advanced-cropper: 0.18.0_react@18.2.0
|
||||
react-colorful: 5.6.1_biqbaboplfbrettd7655fr4n2y
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
react-error-boundary: 3.1.4_react@18.2.0
|
||||
react-hook-form: 7.43.7_react@18.2.0
|
||||
react-icons: 4.8.0_react@18.2.0
|
||||
react-loading-skeleton: 3.2.0_react@18.2.0
|
||||
react-responsive: 9.0.2_react@18.2.0
|
||||
react-router-dom: 6.9.0_biqbaboplfbrettd7655fr4n2y
|
||||
react-scripts: 5.0.1_j5ip3o3v6sktjzl5cxtjyfbuo4
|
||||
react-spinkit: 3.0.0
|
||||
react-spinners: 0.13.8_biqbaboplfbrettd7655fr4n2y
|
||||
reoverlay: 1.0.3_biqbaboplfbrettd7655fr4n2y
|
||||
slate: 0.91.4
|
||||
slate-react: 0.92.0_6tgy34rvmll7duwkm4ydcekf3u
|
||||
styled-components: 5.3.9_biqbaboplfbrettd7655fr4n2y
|
||||
@ -62,6 +71,7 @@ dependencies:
|
||||
|
||||
devDependencies:
|
||||
'@craco/craco': 7.1.0_t5qpnnrvp3p35ejzfaqjqkexiq
|
||||
'@types/styled-components': 5.1.26
|
||||
craco-esbuild: 0.5.2_u2d5pzzfsjvcxtlxpwh3btnila
|
||||
|
||||
packages:
|
||||
@ -2458,6 +2468,11 @@ packages:
|
||||
resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==}
|
||||
dev: false
|
||||
|
||||
/@remix-run/router/1.4.0:
|
||||
resolution: {integrity: sha512-BJ9SxXux8zAg991UmT8slpwpsd31K1dHHbD3Ba4VzD+liLQ4WAMSxQp2d2ZPRPfN0jN2NPRowcSSoM7lCaF08Q==}
|
||||
engines: {node: '>=14'}
|
||||
dev: false
|
||||
|
||||
/@rollup/plugin-babel/5.3.1_hqhlikriuul7byjexqnpgcmenu:
|
||||
resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
@ -2795,6 +2810,13 @@ packages:
|
||||
dependencies:
|
||||
'@types/node': 16.18.16
|
||||
|
||||
/@types/hoist-non-react-statics/3.3.1:
|
||||
resolution: {integrity: sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==}
|
||||
dependencies:
|
||||
'@types/react': 18.0.28
|
||||
hoist-non-react-statics: 3.3.2
|
||||
dev: true
|
||||
|
||||
/@types/html-minifier-terser/6.1.0:
|
||||
resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==}
|
||||
|
||||
@ -2851,7 +2873,6 @@ packages:
|
||||
|
||||
/@types/prop-types/15.7.5:
|
||||
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
||||
dev: false
|
||||
|
||||
/@types/q/1.5.5:
|
||||
resolution: {integrity: sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==}
|
||||
@ -2886,7 +2907,6 @@ packages:
|
||||
'@types/prop-types': 15.7.5
|
||||
'@types/scheduler': 0.16.2
|
||||
csstype: 3.1.1
|
||||
dev: false
|
||||
|
||||
/@types/resolve/1.17.1:
|
||||
resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
|
||||
@ -2898,7 +2918,6 @@ packages:
|
||||
|
||||
/@types/scheduler/0.16.2:
|
||||
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
|
||||
dev: false
|
||||
|
||||
/@types/semver/7.3.13:
|
||||
resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==}
|
||||
@ -2922,6 +2941,14 @@ packages:
|
||||
/@types/stack-utils/2.0.1:
|
||||
resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==}
|
||||
|
||||
/@types/styled-components/5.1.26:
|
||||
resolution: {integrity: sha512-KuKJ9Z6xb93uJiIyxo/+ksS7yLjS1KzG6iv5i78dhVg/X3u5t1H7juRWqVmodIdz6wGVaIApo1u01kmFRdJHVw==}
|
||||
dependencies:
|
||||
'@types/hoist-non-react-statics': 3.3.1
|
||||
'@types/react': 18.0.28
|
||||
csstype: 3.1.1
|
||||
dev: true
|
||||
|
||||
/@types/testing-library__jest-dom/5.14.5:
|
||||
resolution: {integrity: sha512-SBwbxYoyPIvxHbeHxTZX2Pe/74F/tX2/D3mMvzabdeJ25bBojfW0TyB8BHrbq/9zaaKICJZjLP+8r6AeZMFCuQ==}
|
||||
dependencies:
|
||||
@ -4511,7 +4538,6 @@ packages:
|
||||
|
||||
/csstype/3.1.1:
|
||||
resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==}
|
||||
dev: false
|
||||
|
||||
/damerau-levenshtein/1.0.8:
|
||||
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
|
||||
@ -5969,7 +5995,6 @@ packages:
|
||||
resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
|
||||
dependencies:
|
||||
react-is: 16.13.1
|
||||
dev: false
|
||||
|
||||
/hoopy/0.1.4:
|
||||
resolution: {integrity: sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==}
|
||||
@ -7316,10 +7341,6 @@ packages:
|
||||
resolution: {integrity: sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==}
|
||||
engines: {node: '>= 12.13.0'}
|
||||
|
||||
/loaders.css/0.1.2:
|
||||
resolution: {integrity: sha512-Rhowlq24ey1VOeor+3wYOt9+MjaxBOJm1u4KlQgNC3+0xJ0LS4wq4iG57D/BPzvuD/7HHDGQOWJ+81oR2EI9bQ==}
|
||||
dev: false
|
||||
|
||||
/locate-path/3.0.0:
|
||||
resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==}
|
||||
engines: {node: '>=6'}
|
||||
@ -7544,6 +7565,24 @@ packages:
|
||||
dependencies:
|
||||
minimist: 1.2.8
|
||||
|
||||
/mobx-react-lite/3.4.3_woojb62cqeyk443mbl7msrwu2e:
|
||||
resolution: {integrity: sha512-NkJREyFTSUXR772Qaai51BnE1voWx56LOL80xG7qkZr6vo8vEaLF3sz1JNUVh+rxmUzxYaqOhfuxTfqUh0FXUg==}
|
||||
peerDependencies:
|
||||
mobx: ^6.1.0
|
||||
react: ^16.8.0 || ^17 || ^18
|
||||
react-dom: '*'
|
||||
react-native: '*'
|
||||
peerDependenciesMeta:
|
||||
react-dom:
|
||||
optional: true
|
||||
react-native:
|
||||
optional: true
|
||||
dependencies:
|
||||
mobx: 6.8.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/mobx/6.8.0:
|
||||
resolution: {integrity: sha512-+o/DrHa4zykFMSKfS8Z+CPSEg5LW9tSNGTuN8o6MF1GKxlfkSHSeJn5UtgxvPkGgaouplnrLXCF+duAsmm6FHQ==}
|
||||
dev: false
|
||||
@ -8877,6 +8916,16 @@ packages:
|
||||
scheduler: 0.23.0
|
||||
dev: false
|
||||
|
||||
/react-error-boundary/3.1.4_react@18.2.0:
|
||||
resolution: {integrity: sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==}
|
||||
engines: {node: '>=10', npm: '>=6'}
|
||||
peerDependencies:
|
||||
react: '>=16.13.1'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.21.0
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/react-error-overlay/6.0.11:
|
||||
resolution: {integrity: sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==}
|
||||
|
||||
@ -8931,6 +8980,29 @@ packages:
|
||||
shallow-equal: 1.2.1
|
||||
dev: false
|
||||
|
||||
/react-router-dom/6.9.0_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-/seUAPY01VAuwkGyVBPCn1OXfVbaWGGu4QN9uj0kCPcTyNYgL1ldZpxZUpRU7BLheKQI4Twtl/OW2nHRF1u26Q==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
react: '>=16.8'
|
||||
react-dom: '>=16.8'
|
||||
dependencies:
|
||||
'@remix-run/router': 1.4.0
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
react-router: 6.9.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/react-router/6.9.0_react@18.2.0:
|
||||
resolution: {integrity: sha512-51lKevGNUHrt6kLuX3e/ihrXoXCa9ixY/nVWRLlob4r/l0f45x3SzBvYJe3ctleLUQQ5fVa4RGgJOTH7D9Umhw==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
react: '>=16.8'
|
||||
dependencies:
|
||||
'@remix-run/router': 1.4.0
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/react-scripts/5.0.1_j5ip3o3v6sktjzl5cxtjyfbuo4:
|
||||
resolution: {integrity: sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
@ -9026,13 +9098,14 @@ packages:
|
||||
- webpack-hot-middleware
|
||||
- webpack-plugin-serve
|
||||
|
||||
/react-spinkit/3.0.0:
|
||||
resolution: {integrity: sha512-RrfGRPjqxHQiy7quPqhjPynTu0zobgQaZu1QYBMpJJ6pCSRRRK16EZMaxdE6fLVYFRJWpX/eGATWLMoVFFT5uQ==}
|
||||
/react-spinners/0.13.8_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==}
|
||||
peerDependencies:
|
||||
react: ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
classnames: 2.3.2
|
||||
loaders.css: 0.1.2
|
||||
object-assign: 4.1.1
|
||||
prop-types: 15.8.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/react-transition-group/4.4.5_biqbaboplfbrettd7655fr4n2y:
|
||||
@ -9169,6 +9242,18 @@ packages:
|
||||
lodash: 4.17.21
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
/reoverlay/1.0.3_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-KNk8JVf49+SS6qold8Hb6R/+Y1wti6qZfiA0YfqP+2gjWADUduM2HL2oDHQPS2HWcJLOBuGKUQF1/54DXIPEXw==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
react-dom: '>=16.8.0'
|
||||
dependencies:
|
||||
nanoid: 3.3.4
|
||||
prop-types: 15.8.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/repeat-element/1.1.4:
|
||||
resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 15 KiB |
@ -10,34 +10,20 @@
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>Fosscord</title>
|
||||
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
#root,
|
||||
#root > div {
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 19 KiB |
28
src/App.tsx
@ -1,14 +1,26 @@
|
||||
import Typography from "@mui/material/Typography";
|
||||
import "./App.css";
|
||||
import { Route, Routes } from "react-router-dom";
|
||||
import LoginPage from "./pages/LoginPage";
|
||||
import NotFoundPage from "./pages/NotFound";
|
||||
import RegistrationPage from "./pages/RegistrationPage";
|
||||
import RootPage from "./pages/RootPage";
|
||||
import RequireAuth from "./utils/RequireAuth";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<Typography variant="h1" component="h2">
|
||||
Fosscord Client
|
||||
</Typography>
|
||||
;
|
||||
</div>
|
||||
<Routes>
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<RequireAuth>
|
||||
<RootPage />
|
||||
</RequireAuth>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route path="/login" element={<LoginPage />} />
|
||||
<Route path="/register" element={<RegistrationPage />} />
|
||||
<Route path="*" element={<NotFoundPage />} />
|
||||
</Routes>
|
||||
);
|
||||
}
|
||||
|
||||
|
10
src/assets/images/logo/Fosscord-Icon-Rounded.svg
Normal file
@ -0,0 +1,10 @@
|
||||
<svg width="1148" height="1148" viewBox="0 0 1148 1148" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="1148" height="1148" rx="340" fill="url(#paint0_linear_6_79)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M285 283L862 283.003C862.022 322.978 857.961 362.849 849.881 401.987C803.291 627.415 627.023 804.889 403.157 851.801C364.29 859.935 324.697 864.023 285 864V283ZM403.157 630.815V742.76C557.555 683.015 679.971 558.361 737.447 401.983H403.157V507.046H560.653C517.925 554.691 467.668 594.894 411.915 626.03C409.017 627.648 406.097 629.243 403.157 630.815Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_6_79" x1="574" y1="0" x2="574" y2="1148" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#FF5F00"/>
|
||||
<stop offset="1" stop-color="#FF3D00"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 813 B |
6
src/components/Container.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
export default styled.div`
|
||||
background-color: var(--background);
|
||||
color: var(--text);
|
||||
`;
|
5
src/components/Text.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import styled from "styled-components";
|
||||
|
||||
export default styled.div`
|
||||
color: var(--text);
|
||||
`;
|
25
src/contexts/Auth.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import React from "react";
|
||||
|
||||
interface AuthContextType {
|
||||
user: any;
|
||||
signin: () => void;
|
||||
signout: () => void;
|
||||
}
|
||||
|
||||
export const AuthContext = React.createContext<AuthContextType>(null!);
|
||||
|
||||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||
let [user, setUser] = React.useState<any>(null);
|
||||
|
||||
let signin = () => {
|
||||
setUser("test");
|
||||
};
|
||||
|
||||
let signout = () => {
|
||||
setUser(null);
|
||||
};
|
||||
|
||||
let value = { user, signin, signout };
|
||||
|
||||
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
||||
}
|
57
src/contexts/Theme.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { createGlobalStyle } from "styled-components";
|
||||
import { useAppStore } from "../stores/AppStore";
|
||||
|
||||
export type ThemeVariables = "primary" | "secondary" | "background" | "text";
|
||||
|
||||
export type Overrides = {
|
||||
[variable in ThemeVariables]: string;
|
||||
};
|
||||
|
||||
export type Theme = Overrides & {
|
||||
light?: boolean;
|
||||
};
|
||||
|
||||
export const ThemePresets: Record<string, Theme> = {
|
||||
light: {
|
||||
primary: "#FF5F00",
|
||||
secondary: "#FF3D00",
|
||||
background: "#e9e2e1",
|
||||
text: "#000000",
|
||||
},
|
||||
dark: {
|
||||
primary: "#FF5F00",
|
||||
secondary: "#FF3D00",
|
||||
background: "#141212",
|
||||
text: "#e9e2e1",
|
||||
},
|
||||
};
|
||||
|
||||
const GlobalTheme = createGlobalStyle<{ theme: Theme }>`
|
||||
:root {
|
||||
${(props) => generateVariables(props.theme)}
|
||||
}
|
||||
`;
|
||||
|
||||
export const generateVariables = (theme: Theme) => {
|
||||
return (Object.keys(theme) as ThemeVariables[]).map((key) => {
|
||||
const colour = theme[key];
|
||||
try {
|
||||
const r = parseInt(colour.substring(1, 3), 16);
|
||||
const g = parseInt(colour.substring(3, 5), 16);
|
||||
const b = parseInt(colour.substring(5, 7), 16);
|
||||
return `--${key}: ${theme[key]}; --${key}-rgb: rgb(${r}, ${g}, ${b});`;
|
||||
} catch {
|
||||
return `--${key}: ${theme[key]};`;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export default observer(() => {
|
||||
const appStore = useAppStore();
|
||||
const theme = appStore.theme;
|
||||
|
||||
const variables = theme.computeVariables();
|
||||
|
||||
return <GlobalTheme theme={variables} />;
|
||||
});
|
6
src/hooks/useAuth.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import React from "react";
|
||||
import { AuthContext } from "../contexts/Auth";
|
||||
|
||||
export default function useAuth() {
|
||||
return React.useContext(AuthContext);
|
||||
}
|
@ -4,7 +4,10 @@ import "@fontsource/roboto/500.css";
|
||||
import "@fontsource/roboto/700.css";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import App from "./App";
|
||||
import { AuthProvider } from "./contexts/Auth";
|
||||
import Theme from "./contexts/Theme";
|
||||
import "./index.css";
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
@ -12,6 +15,11 @@ const root = ReactDOM.createRoot(
|
||||
);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
<BrowserRouter>
|
||||
<AuthProvider>
|
||||
<App />
|
||||
<Theme />
|
||||
</AuthProvider>
|
||||
</BrowserRouter>
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
17
src/pages/ErrorPage.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import Container from "../components/Container";
|
||||
import Text from "../components/Text";
|
||||
|
||||
interface Props {
|
||||
error: Error;
|
||||
}
|
||||
|
||||
function ErrorPage({ error }: Props) {
|
||||
return (
|
||||
<Container>
|
||||
<Text>Oops, Something went wrong!</Text>
|
||||
<pre>{error.message}</pre>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
||||
export default ErrorPage;
|
7
src/pages/LoginPage.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
import Container from "../components/Container";
|
||||
|
||||
function LoginPage() {
|
||||
return <Container>LoginPage</Container>;
|
||||
}
|
||||
|
||||
export default LoginPage;
|
7
src/pages/NotFound.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
import Container from "../components/Container";
|
||||
|
||||
function NotFoundPage() {
|
||||
return <Container>NotFound</Container>;
|
||||
}
|
||||
|
||||
export default NotFoundPage;
|
7
src/pages/RegistrationPage.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
import Container from "../components/Container";
|
||||
|
||||
function RegistrationPage() {
|
||||
return <Container>RegistrationPage</Container>;
|
||||
}
|
||||
|
||||
export default RegistrationPage;
|
7
src/pages/RootPage.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
import Container from "../components/Container";
|
||||
|
||||
function RootPage() {
|
||||
return <Container>RootPage</Container>;
|
||||
}
|
||||
|
||||
export default RootPage;
|
18
src/stores/AppStore.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { makeAutoObservable } from "mobx";
|
||||
import ThemeStore from "./ThemeStore";
|
||||
|
||||
export default class AppStore {
|
||||
theme: ThemeStore;
|
||||
|
||||
constructor() {
|
||||
this.theme = new ThemeStore();
|
||||
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
}
|
||||
|
||||
export const appStore = new AppStore();
|
||||
|
||||
export function useAppStore() {
|
||||
return appStore;
|
||||
}
|
24
src/stores/ThemeStore.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { computed, makeAutoObservable } from "mobx";
|
||||
import type { Theme } from "../contexts/Theme";
|
||||
import { ThemePresets } from "../contexts/Theme";
|
||||
|
||||
export default class ThemeStore {
|
||||
constructor() {
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
@computed
|
||||
getVariables(): Theme {
|
||||
return {
|
||||
...ThemePresets["dark"],
|
||||
light: false,
|
||||
};
|
||||
}
|
||||
|
||||
@computed
|
||||
computeVariables() {
|
||||
const variables = this.getVariables();
|
||||
|
||||
return variables as unknown as Theme;
|
||||
}
|
||||
}
|
15
src/utils/RequireAuth.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import { Navigate, useLocation } from "react-router-dom";
|
||||
import useAuth from "../hooks/useAuth";
|
||||
|
||||
function RequireAuth({ children }: { children: JSX.Element }) {
|
||||
let auth = useAuth();
|
||||
let location = useLocation();
|
||||
|
||||
if (!auth.user) {
|
||||
return <Navigate to="/login" state={{ from: location }} replace />;
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
export default RequireAuth;
|
@ -1,11 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
@ -18,9 +14,9 @@
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx"
|
||||
"jsx": "react-jsx",
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
"include": ["src"]
|
||||
}
|
||||
|