First commit
This commit is contained in:
3
.babelrc
Executable file
3
.babelrc
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"presets": ["@babel/env", "@babel/preset-react"]
|
||||||
|
}
|
||||||
2
.gitignore
vendored
Executable file
2
.gitignore
vendored
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
2
.idea/.gitignore
generated
vendored
Executable file
2
.idea/.gitignore
generated
vendored
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/workspace.xml
|
||||||
7
.idea/dictionaries/ledda.xml
generated
Executable file
7
.idea/dictionaries/ledda.xml
generated
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
<component name="ProjectDictionaryState">
|
||||||
|
<dictionary name="ledda">
|
||||||
|
<words>
|
||||||
|
<w>kniffel</w>
|
||||||
|
</words>
|
||||||
|
</dictionary>
|
||||||
|
</component>
|
||||||
6
.idea/inspectionProfiles/Project_Default.xml
generated
Executable file
6
.idea/inspectionProfiles/Project_Default.xml
generated
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="TsLint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
85
.idea/jsLinters/jshint.xml
generated
Executable file
85
.idea/jsLinters/jshint.xml
generated
Executable file
@@ -0,0 +1,85 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JSHintConfiguration" version="2.9.5" use-config-file="false">
|
||||||
|
<option asi="false" />
|
||||||
|
<option bitwise="true" />
|
||||||
|
<option boss="false" />
|
||||||
|
<option browser="true" />
|
||||||
|
<option browserify="false" />
|
||||||
|
<option camelcase="false" />
|
||||||
|
<option couch="false" />
|
||||||
|
<option curly="true" />
|
||||||
|
<option debug="false" />
|
||||||
|
<option devel="false" />
|
||||||
|
<option dojo="false" />
|
||||||
|
<option elision="false" />
|
||||||
|
<option enforceall="false" />
|
||||||
|
<option eqeqeq="true" />
|
||||||
|
<option eqnull="false" />
|
||||||
|
<option es3="false" />
|
||||||
|
<option es5="false" />
|
||||||
|
<option esnext="false" />
|
||||||
|
<option evil="false" />
|
||||||
|
<option expr="false" />
|
||||||
|
<option forin="true" />
|
||||||
|
<option freeze="false" />
|
||||||
|
<option funcscope="false" />
|
||||||
|
<option futurehostile="false" />
|
||||||
|
<option gcl="false" />
|
||||||
|
<option globalstrict="false" />
|
||||||
|
<option immed="false" />
|
||||||
|
<option iterator="false" />
|
||||||
|
<option jasmine="false" />
|
||||||
|
<option jquery="false" />
|
||||||
|
<option lastsemic="false" />
|
||||||
|
<option latedef="false" />
|
||||||
|
<option laxbreak="false" />
|
||||||
|
<option laxcomma="false" />
|
||||||
|
<option loopfunc="false" />
|
||||||
|
<option maxerr="50" />
|
||||||
|
<option mocha="false" />
|
||||||
|
<option module="true" />
|
||||||
|
<option mootools="false" />
|
||||||
|
<option moz="false" />
|
||||||
|
<option multistr="false" />
|
||||||
|
<option newcap="false" />
|
||||||
|
<option noarg="true" />
|
||||||
|
<option nocomma="false" />
|
||||||
|
<option node="false" />
|
||||||
|
<option noempty="true" />
|
||||||
|
<option nomen="false" />
|
||||||
|
<option nonbsp="false" />
|
||||||
|
<option nonew="true" />
|
||||||
|
<option nonstandard="false" />
|
||||||
|
<option notypeof="false" />
|
||||||
|
<option noyield="false" />
|
||||||
|
<option onevar="false" />
|
||||||
|
<option passfail="false" />
|
||||||
|
<option phantom="false" />
|
||||||
|
<option plusplus="false" />
|
||||||
|
<option proto="false" />
|
||||||
|
<option prototypejs="false" />
|
||||||
|
<option qunit="false" />
|
||||||
|
<option quotmark="false" />
|
||||||
|
<option rhino="false" />
|
||||||
|
<option scripturl="false" />
|
||||||
|
<option shadow="false" />
|
||||||
|
<option shelljs="false" />
|
||||||
|
<option singleGroups="false" />
|
||||||
|
<option smarttabs="false" />
|
||||||
|
<option strict="true" />
|
||||||
|
<option sub="false" />
|
||||||
|
<option supernew="false" />
|
||||||
|
<option trailing="false" />
|
||||||
|
<option typed="false" />
|
||||||
|
<option undef="true" />
|
||||||
|
<option unused="false" />
|
||||||
|
<option validthis="false" />
|
||||||
|
<option varstmt="false" />
|
||||||
|
<option white="false" />
|
||||||
|
<option withstmt="false" />
|
||||||
|
<option worker="false" />
|
||||||
|
<option wsh="false" />
|
||||||
|
<option yui="false" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
10
.idea/jsLinters/jslint.xml
generated
Executable file
10
.idea/jsLinters/jslint.xml
generated
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JSLintConfiguration">
|
||||||
|
<option browser="true" />
|
||||||
|
<option es6="true" />
|
||||||
|
<option maxerr="50" />
|
||||||
|
<option maxlen="80" />
|
||||||
|
<option node="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
12
.idea/kadi_frontend.iml
generated
Executable file
12
.idea/kadi_frontend.iml
generated
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
10
.idea/kniffel.iml
generated
Executable file
10
.idea/kniffel.iml
generated
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="module" module-name="kadi_backend" />
|
||||||
|
<orderEntry type="module" module-name="kadi_frontend" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
12
.idea/kniffel_react_board.iml
generated
Executable file
12
.idea/kniffel_react_board.iml
generated
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
6
.idea/misc.xml
generated
Executable file
6
.idea/misc.xml
generated
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="JSX" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
10
.idea/modules.xml
generated
Executable file
10
.idea/modules.xml
generated
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/../kadi_frontend/.idea/kadi_frontend.iml" filepath="$PROJECT_DIR$/../kadi_frontend/.idea/kadi_frontend.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/kniffel.iml" filepath="$PROJECT_DIR$/.idea/kniffel.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/../../expressjs/kniffel_backend/.idea/kniffel_backend.iml" filepath="$PROJECT_DIR$/../../expressjs/kniffel_backend/.idea/kniffel_backend.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Executable file
6
.idea/vcs.xml
generated
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8015
package-lock.json
generated
Executable file
8015
package-lock.json
generated
Executable file
File diff suppressed because it is too large
Load Diff
46
package.json
Executable file
46
package.json
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"name": "kadi-frontend",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"homepage": "/kadi",
|
||||||
|
"proxy": "http://localhost:3000",
|
||||||
|
"license": "ISC",
|
||||||
|
"author": "Daniel Ledda",
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack --mode development",
|
||||||
|
"postbuild": "rsync -avu --delete dist/ ../kadi_backend/dist/frontend/static",
|
||||||
|
"start": "webpack-dev-server --mode development",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^0.19.2",
|
||||||
|
"react": "^16.13.1",
|
||||||
|
"react-dom": "^16.13.1",
|
||||||
|
"react-router-dom": "^5.1.2",
|
||||||
|
"semantic-ui-css": "^2.4.1",
|
||||||
|
"semantic-ui-react": "^0.88.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/cli": "^7.8.4",
|
||||||
|
"@babel/core": "^7.9.6",
|
||||||
|
"@babel/preset-env": "^7.9.6",
|
||||||
|
"@babel/preset-react": "^7.9.4",
|
||||||
|
"@types/node": "^13.11.1",
|
||||||
|
"@types/react": "^16.9.34",
|
||||||
|
"@types/react-dom": "^16.9.7",
|
||||||
|
"@types/react-router-dom": "^5.1.5",
|
||||||
|
"ignore-loader": "^0.1.2",
|
||||||
|
"font-loader": "^0.1.2",
|
||||||
|
"babel-loader": "^8.1.0",
|
||||||
|
"css-loader": "^3.5.3",
|
||||||
|
"file-loader": "^6.0.0",
|
||||||
|
"react-hot-loader": "^4.12.21",
|
||||||
|
"style-loader": "^1.2.1",
|
||||||
|
"ts-loader": "^7.0.3",
|
||||||
|
"tslint": "^6.1.1",
|
||||||
|
"tslint-react": "^4.2.0",
|
||||||
|
"typescript": "^3.8.3",
|
||||||
|
"webpack": "^4.43.0",
|
||||||
|
"webpack-cli": "^3.3.11",
|
||||||
|
"webpack-dev-server": "^3.11.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
22
public/index.html
Executable file
22
public/index.html
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<link rel="icon" href="favicon.ico" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<meta name="theme-color" content="#000000" />
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content="Score dice games with K A D I"
|
||||||
|
/>
|
||||||
|
<link rel="manifest" href="manifest.json" />
|
||||||
|
<title>K A D I - Digital Dice</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<noscript>
|
||||||
|
You need to enable JavaScript to run this app.
|
||||||
|
</noscript>
|
||||||
|
<script src="../dist/bundle.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
public/static/favicon.ico
Executable file
BIN
public/static/favicon.ico
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
25
public/static/manifest.json
Executable file
25
public/static/manifest.json
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"short_name": "React App",
|
||||||
|
"name": "Create React App Sample",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "favicon.ico",
|
||||||
|
"sizes": "64x64 32x32 24x24 16x16",
|
||||||
|
"type": "image/x-icon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "logo192.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "192x192"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "logo512.png",
|
||||||
|
"type": "image/png",
|
||||||
|
"sizes": "512x512"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"start_url": ".",
|
||||||
|
"display": "standalone",
|
||||||
|
"theme_color": "#000000",
|
||||||
|
"background_color": "#ffffff"
|
||||||
|
}
|
||||||
3
public/static/robots.txt
Executable file
3
public/static/robots.txt
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
# https://www.robotstxt.org/robotstxt.html
|
||||||
|
User-agent: *
|
||||||
|
Disallow:
|
||||||
9
src/App.test.js
Executable file
9
src/App.test.js
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { render } from '@testing-library/react';
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
test('renders learn react link', () => {
|
||||||
|
const { getByText } = render(<App />);
|
||||||
|
const linkElement = getByText(/learn react/i);
|
||||||
|
expect(linkElement).toBeInTheDocument();
|
||||||
|
});
|
||||||
116
src/App.tsx
Executable file
116
src/App.tsx
Executable file
@@ -0,0 +1,116 @@
|
|||||||
|
import React, {ReactNode} from "react";
|
||||||
|
import {BrowserRouter as Router, Link, Route} from "react-router-dom";
|
||||||
|
import {Redirect, Switch} from "react-router";
|
||||||
|
import {IntlStrings} from "./static/strings";
|
||||||
|
import {PageId, SupportedLang} from "./enums";
|
||||||
|
import {pageComponentFromId} from "./pageListings";
|
||||||
|
import KadiPage from "./Components/KadiPage";
|
||||||
|
import HomePage from "./Components/HomePage";
|
||||||
|
import {SERVER_BASE_NAME} from "./index";
|
||||||
|
import axios from "axios";
|
||||||
|
import UserContext, {IUserContext} from "./Contexts/UserContext";
|
||||||
|
import LocaleContext, {ILocaleContext} from "./Contexts/LocaleContext";
|
||||||
|
|
||||||
|
interface AppState {
|
||||||
|
userContext: IUserContext;
|
||||||
|
localeContext: ILocaleContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AppProps {}
|
||||||
|
|
||||||
|
class App extends React.Component<AppProps, AppState> {
|
||||||
|
private readonly updateUserContext: (username: string, loggedIn: boolean) => void;
|
||||||
|
private readonly changeLang: (lang: SupportedLang) => void;
|
||||||
|
constructor(props: AppProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.updateUserContext = (username, loggedIn) => {
|
||||||
|
this.setState({userContext: {
|
||||||
|
username: username,
|
||||||
|
loggedIn: loggedIn,
|
||||||
|
updateUserContext: this.updateUserContext
|
||||||
|
}});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.changeLang = (lang: SupportedLang) => {
|
||||||
|
this.setState({localeContext: {
|
||||||
|
strings: IntlStrings[lang],
|
||||||
|
currentLang: lang,
|
||||||
|
changeLang: this.changeLang
|
||||||
|
}});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
userContext: {
|
||||||
|
username: "",
|
||||||
|
loggedIn: false,
|
||||||
|
updateUserContext: this.updateUserContext,
|
||||||
|
},
|
||||||
|
localeContext: {
|
||||||
|
currentLang: SupportedLang.gb,
|
||||||
|
strings: IntlStrings[SupportedLang.gb],
|
||||||
|
changeLang: this.changeLang,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
axios.get("/api/user", {baseURL: SERVER_BASE_NAME})
|
||||||
|
.then((res) => {
|
||||||
|
const data = res.data as any;
|
||||||
|
if (data.loggedIn) {
|
||||||
|
this.updateUserContext(data.username, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.updateUserContext("", false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => console.log(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): ReactNode {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UserContext.Provider value={this.state.userContext}>
|
||||||
|
<LocaleContext.Provider value={this.state.localeContext}>
|
||||||
|
<Router basename={SERVER_BASE_NAME}>
|
||||||
|
<Route exact={true} path={"/"}>
|
||||||
|
<KadiPage activePage={PageId.home}>
|
||||||
|
<HomePage/>
|
||||||
|
</KadiPage>
|
||||||
|
</Route>
|
||||||
|
<KadiPageRoute pageId={PageId.history}/>
|
||||||
|
<KadiPageRoute pageId={PageId.friends}/>
|
||||||
|
<KadiPageRoute pageId={PageId.stats}/>
|
||||||
|
<KadiPageRoute pageId={PageId.profile}/>
|
||||||
|
<KadiPageRoute pageId={PageId.rulesets}/>
|
||||||
|
<Route path={"/"}>
|
||||||
|
<Redirect
|
||||||
|
to={{
|
||||||
|
pathname: "/",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Route>
|
||||||
|
</Router>
|
||||||
|
</LocaleContext.Provider>
|
||||||
|
</UserContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KadiPageRouteProps {
|
||||||
|
pageId: PageId
|
||||||
|
}
|
||||||
|
|
||||||
|
const KadiPageRoute: React.FunctionComponent<KadiPageRouteProps> = (props: KadiPageRouteProps) => {
|
||||||
|
const {pageId} = props;
|
||||||
|
const PageComponent = pageComponentFromId[pageId];
|
||||||
|
return (
|
||||||
|
<Route path={"/" + pageId}>
|
||||||
|
<KadiPage activePage={pageId}>
|
||||||
|
<PageComponent/>
|
||||||
|
</KadiPage>
|
||||||
|
</Route>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default App;
|
||||||
27
src/Components/FriendsPage.tsx
Executable file
27
src/Components/FriendsPage.tsx
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
import React, {ReactElement} from "react";
|
||||||
|
import KadiPage from "../Components/KadiPage";
|
||||||
|
import {Header} from "semantic-ui-react";
|
||||||
|
|
||||||
|
interface FriendsPageProps {}
|
||||||
|
|
||||||
|
interface FriendsPageState {
|
||||||
|
}
|
||||||
|
|
||||||
|
class FriendsPage extends React.Component<FriendsPageProps, FriendsPageState> {
|
||||||
|
constructor(props: FriendsPageProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): ReactElement {
|
||||||
|
return (
|
||||||
|
<Header>
|
||||||
|
My Friends
|
||||||
|
</Header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FriendsPage;
|
||||||
53
src/Components/HistoryPage.tsx
Executable file
53
src/Components/HistoryPage.tsx
Executable file
@@ -0,0 +1,53 @@
|
|||||||
|
import React, {ReactElement} from "react";
|
||||||
|
import {Header, List, ListItem} from "semantic-ui-react";
|
||||||
|
import axios from "axios";
|
||||||
|
import {SERVER_BASE_NAME} from "../index";
|
||||||
|
|
||||||
|
interface HistoryPageProps {
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HistoryPageState {
|
||||||
|
loadingGames: boolean;
|
||||||
|
gameListings: any[];
|
||||||
|
}
|
||||||
|
|
||||||
|
class HistoryPage extends React.Component<HistoryPageProps, HistoryPageState> {
|
||||||
|
constructor(props: HistoryPageProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
loadingGames: true,
|
||||||
|
gameListings: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount(): void {
|
||||||
|
axios.get(SERVER_BASE_NAME + "/api/games/")
|
||||||
|
.then(response => this.setState({gameListings: response.data.games}))
|
||||||
|
.catch(error => this.handleError(error))
|
||||||
|
.finally(() => this.setState({ loadingGames: false }));
|
||||||
|
}
|
||||||
|
|
||||||
|
handleError = (error: any) => void {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
render(): ReactElement {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header size={"huge"}>
|
||||||
|
History
|
||||||
|
</Header>
|
||||||
|
<List bulleted={true}>
|
||||||
|
{
|
||||||
|
this.state.gameListings.map(listing => {
|
||||||
|
return <ListItem key={listing.createdAt}>Game played on: {listing.createdAt}</ListItem>;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</List>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HistoryPage;
|
||||||
27
src/Components/HomePage.tsx
Executable file
27
src/Components/HomePage.tsx
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
import React, {ReactElement} from "react";
|
||||||
|
import KadiPage from "../Components/KadiPage";
|
||||||
|
import {Header} from "semantic-ui-react";
|
||||||
|
|
||||||
|
interface HomePageProps {}
|
||||||
|
|
||||||
|
interface HomePageState {
|
||||||
|
}
|
||||||
|
|
||||||
|
class HomePage extends React.Component<HomePageProps, HomePageState> {
|
||||||
|
constructor(props: HomePageProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): ReactElement {
|
||||||
|
return (
|
||||||
|
<Header>
|
||||||
|
Home
|
||||||
|
</Header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HomePage;
|
||||||
36
src/Components/KadiPage.tsx
Executable file
36
src/Components/KadiPage.tsx
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
import React, {ReactElement} from "react";
|
||||||
|
import {Segment} from "semantic-ui-react";
|
||||||
|
import "../static/css/site.css";
|
||||||
|
import KadiSidebarNav from "../Components/KadiSidebarNav";
|
||||||
|
import MainPageContent from "../Components/MainPageContent";
|
||||||
|
import {PageId} from "../enums";
|
||||||
|
|
||||||
|
interface KadiPageProps {
|
||||||
|
activePage: PageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KadiPageState {
|
||||||
|
}
|
||||||
|
|
||||||
|
class KadiPage extends React.Component<KadiPageProps, KadiPageState> {
|
||||||
|
constructor(props: KadiPageProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): ReactElement {
|
||||||
|
const {children, activePage} = this.props;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<KadiSidebarNav activeItem={activePage}/>
|
||||||
|
<MainPageContent>
|
||||||
|
{children}
|
||||||
|
</MainPageContent>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default KadiPage;
|
||||||
97
src/Components/KadiSidebarNav.tsx
Executable file
97
src/Components/KadiSidebarNav.tsx
Executable file
@@ -0,0 +1,97 @@
|
|||||||
|
import {Header, HeaderContent, Icon, Image, Menu, Segment, Sidebar, SidebarPusher} from "semantic-ui-react";
|
||||||
|
import logo from "../static/images/kadi.png";
|
||||||
|
import React from "react";
|
||||||
|
import LocaleContext from "../Contexts/LocaleContext";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import {PageId} from "../enums";
|
||||||
|
import {SERVER_BASE_NAME} from "../index";
|
||||||
|
|
||||||
|
interface KadiSidebarNavProps {
|
||||||
|
activeItem: PageId;
|
||||||
|
}
|
||||||
|
|
||||||
|
const KadiSidebarNav: React.FunctionComponent<KadiSidebarNavProps> = (props) => {
|
||||||
|
const Locale = React.useContext(LocaleContext).strings;
|
||||||
|
const {activeItem} = props;
|
||||||
|
return (
|
||||||
|
<Menu
|
||||||
|
borderless={true}
|
||||||
|
vertical={true}
|
||||||
|
stackable={true}
|
||||||
|
fixed={"left"}
|
||||||
|
inverted={true}
|
||||||
|
className={"kadiSidebarNav"}
|
||||||
|
>
|
||||||
|
<Link to={"/"}>
|
||||||
|
<Menu.Item>
|
||||||
|
<Header inverted={true} size={"huge"}>
|
||||||
|
<Image src={logo} size={"tiny"} spaced={true} />
|
||||||
|
<HeaderContent>
|
||||||
|
<span className={"brandname"}>K A D I</span>
|
||||||
|
</HeaderContent>
|
||||||
|
</Header>
|
||||||
|
</Menu.Item>
|
||||||
|
</Link>
|
||||||
|
<Menu.Item
|
||||||
|
as={"a"}
|
||||||
|
icon={true}
|
||||||
|
href={SERVER_BASE_NAME + "/game"}
|
||||||
|
>
|
||||||
|
<Icon name={"game"} />
|
||||||
|
{Locale.menu.playTab}
|
||||||
|
</Menu.Item>
|
||||||
|
<Link to={"/" + PageId.profile}>
|
||||||
|
<Menu.Item
|
||||||
|
as={"a"}
|
||||||
|
icon={true}
|
||||||
|
active={activeItem === PageId.profile}
|
||||||
|
>
|
||||||
|
<Icon name={"user circle"} />
|
||||||
|
{Locale.menu.profileTab}
|
||||||
|
</Menu.Item>
|
||||||
|
</Link>
|
||||||
|
<Link to={"/" + PageId.stats}>
|
||||||
|
<Menu.Item
|
||||||
|
as={"a"}
|
||||||
|
icon={true}
|
||||||
|
active={activeItem === PageId.stats}
|
||||||
|
>
|
||||||
|
<Icon name={"chart pie"} />
|
||||||
|
{Locale.menu.statsTab}
|
||||||
|
</Menu.Item>
|
||||||
|
</Link>
|
||||||
|
<Link to={"/" + PageId.rulesets}>
|
||||||
|
<Menu.Item
|
||||||
|
as={"a"}
|
||||||
|
icon={true}
|
||||||
|
active={activeItem === PageId.rulesets}
|
||||||
|
>
|
||||||
|
<Icon name={"book"} />
|
||||||
|
{Locale.menu.rulesetsTab}
|
||||||
|
</Menu.Item>
|
||||||
|
</Link>
|
||||||
|
<Link to={"/" + PageId.friends}>
|
||||||
|
<Menu.Item
|
||||||
|
as={"a"}
|
||||||
|
icon={true}
|
||||||
|
active={activeItem === PageId.friends}
|
||||||
|
>
|
||||||
|
<Icon name={"group"} />
|
||||||
|
{Locale.menu.friendsTab}
|
||||||
|
</Menu.Item>
|
||||||
|
</Link>
|
||||||
|
<Link to={"/" + PageId.history}>
|
||||||
|
<Menu.Item
|
||||||
|
as={"a"}
|
||||||
|
icon={true}
|
||||||
|
active={activeItem === PageId.history}
|
||||||
|
>
|
||||||
|
<Icon name={"history"} />
|
||||||
|
{Locale.menu.historyTab}
|
||||||
|
</Menu.Item>
|
||||||
|
</Link>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default KadiSidebarNav;
|
||||||
90
src/Components/KadiTopMenuBar.tsx
Executable file
90
src/Components/KadiTopMenuBar.tsx
Executable file
@@ -0,0 +1,90 @@
|
|||||||
|
import React, {ReactElement, SyntheticEvent} from "react";
|
||||||
|
import {Dropdown, DropdownItemProps, DropdownProps, Flag, Icon, Menu} from "semantic-ui-react";
|
||||||
|
import {SERVER_BASE_NAME} from "../index";
|
||||||
|
import LocaleContext from "../Contexts/LocaleContext";
|
||||||
|
import {LanguageNames} from "../static/strings";
|
||||||
|
import {IUserContext} from "../Contexts/UserContext";
|
||||||
|
import {SupportedLang} from "../enums";
|
||||||
|
|
||||||
|
interface KadiTopMenuBarProps {
|
||||||
|
user: IUserContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface KadiTopMenuBarState {
|
||||||
|
currentLangSelection: SupportedLang;
|
||||||
|
}
|
||||||
|
|
||||||
|
class KadiTopMenuBar extends React.Component<KadiTopMenuBarProps, KadiTopMenuBarState> {
|
||||||
|
private readonly languageDropdowns: DropdownItemProps[];
|
||||||
|
private changeLanguageGlobally: (newLang: SupportedLang) => void;
|
||||||
|
constructor(props: KadiTopMenuBarProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
currentLangSelection: SupportedLang.gb,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.changeLanguageGlobally = () => {};
|
||||||
|
this.languageDropdowns = [];
|
||||||
|
for (const lang in LanguageNames) {
|
||||||
|
this.languageDropdowns.push(
|
||||||
|
{ key: lang, value: lang, flag: lang, text: LanguageNames[lang as SupportedLang] }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount(): void {
|
||||||
|
this.changeLanguageGlobally = this.context.changeLang;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleLanguageChange: (e: SyntheticEvent, data: DropdownProps) => void = (event, data) => {
|
||||||
|
const lang = data.value as SupportedLang;
|
||||||
|
this.setState({currentLangSelection: lang});
|
||||||
|
this.changeLanguageGlobally(lang);
|
||||||
|
};
|
||||||
|
|
||||||
|
render(): ReactElement {
|
||||||
|
const {loggedIn, username} = this.props.user;
|
||||||
|
const Locale = this.context.strings;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Menu
|
||||||
|
secondary={true}
|
||||||
|
pointing={true}
|
||||||
|
attached={"top"}
|
||||||
|
>
|
||||||
|
<Menu.Menu
|
||||||
|
position={"right"}
|
||||||
|
>
|
||||||
|
{ loggedIn && (
|
||||||
|
<Menu.Item>
|
||||||
|
{Locale.menu.userWelcome + username + "!"}
|
||||||
|
</Menu.Item>
|
||||||
|
)}
|
||||||
|
<Menu.Item
|
||||||
|
as={"a"}
|
||||||
|
href={SERVER_BASE_NAME + "/account/" + (loggedIn ? "logout" : "login")}
|
||||||
|
>
|
||||||
|
<Icon spaced={true} name={loggedIn ? "sign out" : "sign in"} />
|
||||||
|
{loggedIn ? Locale.menu.logoutButton : Locale.menu.loginButton}
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item>
|
||||||
|
<Dropdown
|
||||||
|
trigger={(
|
||||||
|
<span>
|
||||||
|
<Flag name={this.state.currentLangSelection} />
|
||||||
|
{LanguageNames[this.state.currentLangSelection]}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
options={this.languageDropdowns}
|
||||||
|
onChange={this.handleLanguageChange}
|
||||||
|
/>
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu.Menu>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KadiTopMenuBar.contextType = LocaleContext;
|
||||||
|
|
||||||
|
export default KadiTopMenuBar;
|
||||||
29
src/Components/MainPageContent.tsx
Executable file
29
src/Components/MainPageContent.tsx
Executable file
@@ -0,0 +1,29 @@
|
|||||||
|
import {Container, Segment} from "semantic-ui-react";
|
||||||
|
import React from "react";
|
||||||
|
import KadiTopMenuBar from "./KadiTopMenuBar";
|
||||||
|
import UserContext from "../Contexts/UserContext";
|
||||||
|
|
||||||
|
interface KadiPageMainContentProps {
|
||||||
|
}
|
||||||
|
|
||||||
|
const KadiPageMainContent: React.FunctionComponent<KadiPageMainContentProps> = (props) => {
|
||||||
|
const {children} = props;
|
||||||
|
return (
|
||||||
|
<div className={"mainPageContent"}>
|
||||||
|
<UserContext.Consumer>
|
||||||
|
{ user => (
|
||||||
|
<KadiTopMenuBar user={user}/>
|
||||||
|
)}
|
||||||
|
</UserContext.Consumer>
|
||||||
|
<Container
|
||||||
|
className={"mainPageContentContainer"}
|
||||||
|
>
|
||||||
|
<Segment>
|
||||||
|
{children}
|
||||||
|
</Segment>
|
||||||
|
</Container>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default KadiPageMainContent;
|
||||||
27
src/Components/ProfilePage.tsx
Executable file
27
src/Components/ProfilePage.tsx
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
import React, {ReactElement} from "react";
|
||||||
|
import KadiPage from "../Components/KadiPage";
|
||||||
|
import {Header} from "semantic-ui-react";
|
||||||
|
|
||||||
|
interface ProfilePageProps {}
|
||||||
|
|
||||||
|
interface ProfilePageState {
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProfilePage extends React.Component<ProfilePageProps, ProfilePageState> {
|
||||||
|
constructor(props: ProfilePageProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): ReactElement {
|
||||||
|
return (
|
||||||
|
<Header>
|
||||||
|
My Profile
|
||||||
|
</Header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProfilePage;
|
||||||
27
src/Components/RulesetsPage.tsx
Executable file
27
src/Components/RulesetsPage.tsx
Executable file
@@ -0,0 +1,27 @@
|
|||||||
|
import React, {ReactElement} from "react";
|
||||||
|
import KadiPage from "../Components/KadiPage";
|
||||||
|
import {Header} from "semantic-ui-react";
|
||||||
|
|
||||||
|
interface RulesetsPageProps {}
|
||||||
|
|
||||||
|
interface RulesetsPageState {
|
||||||
|
}
|
||||||
|
|
||||||
|
class RulesetsPage extends React.Component<RulesetsPageProps, RulesetsPageState> {
|
||||||
|
constructor(props: RulesetsPageProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): ReactElement {
|
||||||
|
return (
|
||||||
|
<Header>
|
||||||
|
My Rulesets
|
||||||
|
</Header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RulesetsPage;
|
||||||
28
src/Components/StatsPage.tsx
Executable file
28
src/Components/StatsPage.tsx
Executable file
@@ -0,0 +1,28 @@
|
|||||||
|
import React, {ReactNode} from "react";
|
||||||
|
import {BrowserRouter as Router, Link, Route} from "react-router-dom";
|
||||||
|
import {Header} from "semantic-ui-react";
|
||||||
|
import KadiPage from "../Components/KadiPage";
|
||||||
|
|
||||||
|
interface StatsPageProps {}
|
||||||
|
|
||||||
|
interface StatsPageState {
|
||||||
|
}
|
||||||
|
|
||||||
|
class StatsPage extends React.Component<StatsPageProps, StatsPageState> {
|
||||||
|
constructor(props: StatsPageProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): ReactNode {
|
||||||
|
return (
|
||||||
|
<Header>
|
||||||
|
My Stats
|
||||||
|
</Header>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StatsPage;
|
||||||
19
src/Contexts/LocaleContext.ts
Executable file
19
src/Contexts/LocaleContext.ts
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
import {SupportedLang} from "../enums";
|
||||||
|
import React from "react";
|
||||||
|
import {IntlStrings} from "../static/strings";
|
||||||
|
|
||||||
|
export interface ILocaleContext {
|
||||||
|
currentLang: SupportedLang;
|
||||||
|
strings: any;
|
||||||
|
changeLang: (lang: SupportedLang) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const localeDefaultVal: ILocaleContext = {
|
||||||
|
currentLang: SupportedLang.gb,
|
||||||
|
strings: IntlStrings[SupportedLang.gb as SupportedLang],
|
||||||
|
changeLang: () => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const LocaleContext = React.createContext(localeDefaultVal);
|
||||||
|
|
||||||
|
export default LocaleContext;
|
||||||
17
src/Contexts/UserContext.ts
Executable file
17
src/Contexts/UserContext.ts
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export interface IUserContext {
|
||||||
|
username: string;
|
||||||
|
loggedIn: boolean;
|
||||||
|
updateUserContext: (username: string, loggedIn: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userDefaultVal = {
|
||||||
|
loggedIn: false,
|
||||||
|
username: "",
|
||||||
|
updateUserContext: () => {},
|
||||||
|
} as IUserContext;
|
||||||
|
|
||||||
|
const UserContext = React.createContext(userDefaultVal);
|
||||||
|
|
||||||
|
export default UserContext;
|
||||||
14
src/enums.ts
Executable file
14
src/enums.ts
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
export enum SupportedLang {
|
||||||
|
gb = "gb",
|
||||||
|
de = "de",
|
||||||
|
it = "it",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum PageId {
|
||||||
|
profile = "profile",
|
||||||
|
rulesets = "rulesets",
|
||||||
|
friends = "friends",
|
||||||
|
stats = "stats",
|
||||||
|
home = "home",
|
||||||
|
history = "history",
|
||||||
|
}
|
||||||
16
src/filetypes.d.ts
vendored
Executable file
16
src/filetypes.d.ts
vendored
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
declare module '*.jpg' {
|
||||||
|
const value: any;
|
||||||
|
export = value;
|
||||||
|
}
|
||||||
|
declare module '*.gif' {
|
||||||
|
const value: any;
|
||||||
|
export = value;
|
||||||
|
}
|
||||||
|
declare module '*.png' {
|
||||||
|
const value: any;
|
||||||
|
export = value;
|
||||||
|
}
|
||||||
|
declare module '*.css' {
|
||||||
|
const value: any;
|
||||||
|
export = value;
|
||||||
|
}
|
||||||
20
src/index.tsx
Executable file
20
src/index.tsx
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ReactDOM from "react-dom";
|
||||||
|
import "semantic-ui-css/semantic.min.css";
|
||||||
|
import App from "./App";
|
||||||
|
import * as serviceWorker from "./serviceWorker";
|
||||||
|
|
||||||
|
export const SERVER_BASE_NAME = "/kadi";
|
||||||
|
|
||||||
|
ReactDOM.render((
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>
|
||||||
|
),
|
||||||
|
document.getElementById('root')
|
||||||
|
);
|
||||||
|
|
||||||
|
// If you want your app to work offline and load faster, you can change
|
||||||
|
// unregister() to register() below. Note this comes with some pitfalls.
|
||||||
|
// Learn more about service workers: https://bit.ly/CRA-PWA
|
||||||
|
serviceWorker.unregister();
|
||||||
21
src/pageListings.ts
Executable file
21
src/pageListings.ts
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
import {PageId} from "./enums";
|
||||||
|
import {Component as ReactComponent} from "react";
|
||||||
|
import ProfilePage from "./Components/ProfilePage";
|
||||||
|
import RulesetsPage from "./Components/RulesetsPage";
|
||||||
|
import FriendsPage from "./Components/FriendsPage";
|
||||||
|
import StatsPage from "./Components/StatsPage";
|
||||||
|
import HistoryPage from "./Components/HistoryPage";
|
||||||
|
import HomePage from "./Components/HomePage";
|
||||||
|
|
||||||
|
type PageComponentFromIdType = {
|
||||||
|
[key in PageId]: new (...args: any[]) => ReactComponent;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const pageComponentFromId: PageComponentFromIdType = {
|
||||||
|
[PageId.profile]: ProfilePage,
|
||||||
|
[PageId.rulesets]: RulesetsPage,
|
||||||
|
[PageId.friends]: FriendsPage,
|
||||||
|
[PageId.stats]: StatsPage,
|
||||||
|
[PageId.home]: HomePage,
|
||||||
|
[PageId.history]: HistoryPage,
|
||||||
|
};
|
||||||
141
src/serviceWorker.js
Executable file
141
src/serviceWorker.js
Executable file
@@ -0,0 +1,141 @@
|
|||||||
|
// This optional code is used to register a service worker.
|
||||||
|
// register() is not called by default.
|
||||||
|
|
||||||
|
// This lets the app load faster on subsequent visits in production, and gives
|
||||||
|
// it offline capabilities. However, it also means that developers (and users)
|
||||||
|
// will only see deployed updates on subsequent visits to a page, after all the
|
||||||
|
// existing tabs open on the page have been closed, since previously cached
|
||||||
|
// resources are updated in the background.
|
||||||
|
|
||||||
|
// To learn more about the benefits of this model and instructions on how to
|
||||||
|
// opt-in, read https://bit.ly/CRA-PWA
|
||||||
|
|
||||||
|
const isLocalhost = Boolean(
|
||||||
|
window.location.hostname === 'localhost' ||
|
||||||
|
// [::1] is the IPv6 localhost address.
|
||||||
|
window.location.hostname === '[::1]' ||
|
||||||
|
// 127.0.0.0/8 are considered localhost for IPv4.
|
||||||
|
window.location.hostname.match(
|
||||||
|
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
export function register(config) {
|
||||||
|
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||||
|
// The URL constructor is available in all browsers that support SW.
|
||||||
|
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
|
||||||
|
if (publicUrl.origin !== window.location.origin) {
|
||||||
|
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||||
|
// from what our page is served on. This might happen if a CDN is used to
|
||||||
|
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||||
|
|
||||||
|
if (isLocalhost) {
|
||||||
|
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||||
|
checkValidServiceWorker(swUrl, config);
|
||||||
|
|
||||||
|
// Add some additional logging to localhost, pointing developers to the
|
||||||
|
// service worker/PWA documentation.
|
||||||
|
navigator.serviceWorker.ready.then(() => {
|
||||||
|
console.log(
|
||||||
|
'This web app is being served cache-first by a service ' +
|
||||||
|
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Is not localhost. Just register service worker
|
||||||
|
registerValidSW(swUrl, config);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerValidSW(swUrl, config) {
|
||||||
|
navigator.serviceWorker
|
||||||
|
.register(swUrl)
|
||||||
|
.then(registration => {
|
||||||
|
registration.onupdatefound = () => {
|
||||||
|
const installingWorker = registration.installing;
|
||||||
|
if (installingWorker == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
installingWorker.onstatechange = () => {
|
||||||
|
if (installingWorker.state === 'installed') {
|
||||||
|
if (navigator.serviceWorker.controller) {
|
||||||
|
// At this point, the updated precached content has been fetched,
|
||||||
|
// but the previous service worker will still serve the older
|
||||||
|
// content until all client tabs are closed.
|
||||||
|
console.log(
|
||||||
|
'New content is available and will be used when all ' +
|
||||||
|
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Execute callback
|
||||||
|
if (config && config.onUpdate) {
|
||||||
|
config.onUpdate(registration);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// At this point, everything has been precached.
|
||||||
|
// It's the perfect time to display a
|
||||||
|
// "Content is cached for offline use." message.
|
||||||
|
console.log('Content is cached for offline use.');
|
||||||
|
|
||||||
|
// Execute callback
|
||||||
|
if (config && config.onSuccess) {
|
||||||
|
config.onSuccess(registration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error during service worker registration:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkValidServiceWorker(swUrl, config) {
|
||||||
|
// Check if the service worker can be found. If it can't reload the page.
|
||||||
|
fetch(swUrl, {
|
||||||
|
headers: { 'Service-Worker': 'script' },
|
||||||
|
})
|
||||||
|
.then(response => {
|
||||||
|
// Ensure service worker exists, and that we really are getting a JS file.
|
||||||
|
const contentType = response.headers.get('content-type');
|
||||||
|
if (
|
||||||
|
response.status === 404 ||
|
||||||
|
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||||
|
) {
|
||||||
|
// No service worker found. Probably a different app. Reload the page.
|
||||||
|
navigator.serviceWorker.ready.then(registration => {
|
||||||
|
registration.unregister().then(() => {
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Service worker found. Proceed as normal.
|
||||||
|
registerValidSW(swUrl, config);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
console.log(
|
||||||
|
'No internet connection found. App is running in offline mode.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unregister() {
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.ready
|
||||||
|
.then(registration => {
|
||||||
|
registration.unregister();
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error(error.message);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/setupTests.js
Executable file
5
src/setupTests.js
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||||
|
// allows you to do things like:
|
||||||
|
// expect(element).toHaveTextContent(/react/i)
|
||||||
|
// learn more: https://github.com/testing-library/jest-dom
|
||||||
|
import '@testing-library/jest-dom/extend-expect';
|
||||||
23
src/static/css/site.css
Executable file
23
src/static/css/site.css
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
@font-face {
|
||||||
|
font-family: "Athiti";
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-display: swap;
|
||||||
|
src: url("../fonts/Athiti-ExtraLight.ttf") format("truetype");
|
||||||
|
}
|
||||||
|
|
||||||
|
.brandname {
|
||||||
|
font-family: "Athiti", monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainPageContent {
|
||||||
|
margin-left: 15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mainPageContentContainer {
|
||||||
|
margin-top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.kadiSidebarNav {
|
||||||
|
width: 15rem !important;
|
||||||
|
}
|
||||||
BIN
src/static/fonts/Athiti-ExtraLight.ttf
Executable file
BIN
src/static/fonts/Athiti-ExtraLight.ttf
Executable file
Binary file not shown.
BIN
src/static/fonts/Athiti-Light.ttf
Executable file
BIN
src/static/fonts/Athiti-Light.ttf
Executable file
Binary file not shown.
BIN
src/static/images/kadi.png
Executable file
BIN
src/static/images/kadi.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 120 KiB |
690
src/static/images/kadi.svg
Executable file
690
src/static/images/kadi.svg
Executable file
@@ -0,0 +1,690 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:osb="http://www.openswatchbook.org/uri/2009/osb"
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
inkscape:export-ydpi="96"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-filename="/home/ledda/Desktop/kadi.png"
|
||||||
|
inkscape:version="1.0 (5b275a35d9, 2020-05-03)"
|
||||||
|
sodipodi:docname="kadi.svg"
|
||||||
|
width="1024px"
|
||||||
|
height="1024px"
|
||||||
|
viewBox="0 0 1024 1024"
|
||||||
|
version="1.1"
|
||||||
|
id="SVGRoot">
|
||||||
|
<defs
|
||||||
|
id="defs462">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient5683"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
id="stop5679"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#000000;stop-opacity:1" />
|
||||||
|
<stop
|
||||||
|
id="stop5681"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#606060;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient3028-6"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
id="stop3024"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#000000;stop-opacity:1" />
|
||||||
|
<stop
|
||||||
|
id="stop3026"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#747474;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient2980"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
id="stop2976"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#fdfdfd;stop-opacity:1" />
|
||||||
|
<stop
|
||||||
|
id="stop2978"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#f1e6cc;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
osb:paint="solid"
|
||||||
|
id="linearGradient2927">
|
||||||
|
<stop
|
||||||
|
id="stop2925"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#dbdbe3;stop-opacity:1;" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="246.16356"
|
||||||
|
x2="130.00171"
|
||||||
|
y1="429.99353"
|
||||||
|
x1="313.83167"
|
||||||
|
id="linearGradient2968-2-6"
|
||||||
|
xlink:href="#linearGradient2980"
|
||||||
|
inkscape:collect="always"
|
||||||
|
gradientTransform="matrix(1.8567885,0,0,1.8567885,-241.38568,-457.07369)" />
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="matrix(1.7800144,0,0,1.7800142,-537.16575,-357.11616)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="375.14923"
|
||||||
|
x2="476.29993"
|
||||||
|
y1="217.86031"
|
||||||
|
x1="319.01102"
|
||||||
|
id="linearGradient2955-9-2"
|
||||||
|
xlink:href="#linearGradient2980"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
id="radialGradient3042-3-1-6"
|
||||||
|
cx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
fy="327.62778"
|
||||||
|
r="14.615433"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,-437.11911,-747.09584)" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(1.4862264,0,0,1.4862264,-311.26294,-478.20534)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-8"
|
||||||
|
xlink:href="#linearGradient3028-6"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="matrix(1.8567885,0,0,1.8567885,-241.38568,-115.74038)"
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2980"
|
||||||
|
id="linearGradient2968-2-6-2"
|
||||||
|
x1="313.83167"
|
||||||
|
y1="429.99353"
|
||||||
|
x2="130.00171"
|
||||||
|
y2="246.16356"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2980"
|
||||||
|
id="linearGradient2955-9-2-6"
|
||||||
|
x1="319.01102"
|
||||||
|
y1="217.86031"
|
||||||
|
x2="476.29993"
|
||||||
|
y2="375.14923"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.7800144,0,0,1.7800142,-537.16577,-15.78284)" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,-355.60638,-321.15806)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-0-1-1"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,-518.81782,-491.17479)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-64-8-0"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="matrix(1.8567885,0,0,1.8567885,441.281,-457.07369)"
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2980"
|
||||||
|
id="linearGradient2968-2-6-21"
|
||||||
|
x1="313.83167"
|
||||||
|
y1="429.99353"
|
||||||
|
x2="130.00171"
|
||||||
|
y2="246.16356"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2980"
|
||||||
|
id="linearGradient2955-9-2-9"
|
||||||
|
x1="319.01102"
|
||||||
|
y1="217.86031"
|
||||||
|
x2="476.29993"
|
||||||
|
y2="375.14923"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.7800144,0,0,1.7800142,145.50095,-357.11614)" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,245.54758,-747.09584)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-1"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,163.84889,-661.68358)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-64-9-8"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,327.06032,-662.49138)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-0-1-7"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,163.84889,-832.50814)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-64-8-4"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,327.06032,-833.31592)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-0-4-8"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="matrix(1.8567885,0,0,1.8567885,99.947664,-115.74034)"
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2980"
|
||||||
|
id="linearGradient2968-2-6-29"
|
||||||
|
x1="313.83167"
|
||||||
|
y1="429.99353"
|
||||||
|
x2="130.00171"
|
||||||
|
y2="246.16356"
|
||||||
|
gradientUnits="userSpaceOnUse" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient2980"
|
||||||
|
id="linearGradient2955-9-2-8"
|
||||||
|
x1="319.01102"
|
||||||
|
y1="217.86031"
|
||||||
|
x2="476.29993"
|
||||||
|
y2="375.14923"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.7800144,0,0,1.7800142,-195.8324,-15.782803)" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,-177.48445,-320.35023)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-64-9-2"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,-14.273021,-321.15803)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-0-1-5"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,-177.48445,-491.17477)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-64-8-49"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,-14.273021,-491.98258)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-0-4-9"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="246.16356"
|
||||||
|
x2="130.00171"
|
||||||
|
y1="429.99353"
|
||||||
|
x1="313.83167"
|
||||||
|
id="linearGradient2968-2-6-2-9"
|
||||||
|
xlink:href="#linearGradient2980"
|
||||||
|
inkscape:collect="always"
|
||||||
|
gradientTransform="matrix(1.8567885,0,0,1.8567885,-241.38568,225.59301)" />
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="matrix(1.7800144,0,0,1.7800142,-537.16577,325.55054)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="375.14923"
|
||||||
|
x2="476.29993"
|
||||||
|
y1="217.86031"
|
||||||
|
x1="319.01102"
|
||||||
|
id="linearGradient2955-9-2-6-2"
|
||||||
|
xlink:href="#linearGradient2980"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
id="radialGradient3042-3-1-6-2-8"
|
||||||
|
cx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
fy="327.62778"
|
||||||
|
r="14.615433"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,-437.11913,-64.429122)" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
id="radialGradient3042-3-1-6-0-1-1-1"
|
||||||
|
cx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
fy="327.62778"
|
||||||
|
r="14.615433"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,-355.60638,20.175318)" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
id="radialGradient3042-3-1-6-64-8-0-4"
|
||||||
|
cx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
fy="327.62778"
|
||||||
|
r="14.615433"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,-518.81782,-149.84141)" />
|
||||||
|
<linearGradient
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="246.16356"
|
||||||
|
x2="130.00171"
|
||||||
|
y1="429.99353"
|
||||||
|
x1="313.83167"
|
||||||
|
id="linearGradient2968-2-6-3-7"
|
||||||
|
xlink:href="#linearGradient2980"
|
||||||
|
inkscape:collect="always"
|
||||||
|
gradientTransform="matrix(1.8567885,0,0,1.8567885,441.28102,225.59303)" />
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="matrix(1.7800144,0,0,1.7800142,145.50095,325.55056)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
y2="375.14923"
|
||||||
|
x2="476.29993"
|
||||||
|
y1="217.86031"
|
||||||
|
x1="319.01102"
|
||||||
|
id="linearGradient2955-9-2-69-0"
|
||||||
|
xlink:href="#linearGradient2980"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,163.84889,-64.42914)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-64-6-1"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,327.06034,-65.236936)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
r="14.615433"
|
||||||
|
fy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
cx="216.74664"
|
||||||
|
id="radialGradient3042-3-1-6-0-41-9"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
id="radialGradient3042-3-1-6-64-9-88-7"
|
||||||
|
cx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
fy="327.62778"
|
||||||
|
r="14.615433"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,163.84889,20.983132)" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
id="radialGradient3042-3-1-6-0-1-9-8"
|
||||||
|
cx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
fy="327.62778"
|
||||||
|
r="14.615433"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,327.06034,20.175336)" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
id="radialGradient3042-3-1-6-64-8-88-5"
|
||||||
|
cx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
fy="327.62778"
|
||||||
|
r="14.615433"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,163.84889,-149.84141)" />
|
||||||
|
<radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5683"
|
||||||
|
id="radialGradient3042-3-1-6-0-4-86-3"
|
||||||
|
cx="216.74664"
|
||||||
|
cy="327.62778"
|
||||||
|
fx="216.74664"
|
||||||
|
fy="327.62778"
|
||||||
|
r="14.615433"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(2.7596081,0,0,2.7596081,327.06034,-150.64921)" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
inkscape:object-paths="true"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-x="67"
|
||||||
|
inkscape:window-height="1023"
|
||||||
|
inkscape:window-width="1439"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:cy="653.82099"
|
||||||
|
inkscape:cx="654.51751"
|
||||||
|
inkscape:zoom="0.35355339"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
borderopacity="1.0"
|
||||||
|
bordercolor="#666666"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
id="base" />
|
||||||
|
<metadata
|
||||||
|
id="metadata465">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title></dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<g
|
||||||
|
id="layer1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
inkscape:label="Layer 1">
|
||||||
|
<rect
|
||||||
|
ry="61.433502"
|
||||||
|
y="0"
|
||||||
|
x="0"
|
||||||
|
height="341.33334"
|
||||||
|
width="341.33334"
|
||||||
|
id="rect58-6-9"
|
||||||
|
style="fill:url(#linearGradient2968-2-6);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.94172;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
style="fill:url(#linearGradient2955-9-2);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:9.59501;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect58-5-2-5"
|
||||||
|
width="279.97653"
|
||||||
|
height="279.97647"
|
||||||
|
x="30.678432"
|
||||||
|
y="30.678488"
|
||||||
|
ry="50.39043" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
id="path2986-9-6-9-0"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
cy="170.66669"
|
||||||
|
cx="170.66669" />
|
||||||
|
<rect
|
||||||
|
style="fill:url(#linearGradient2968-2-6-2);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.94172;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect58-6-9-4"
|
||||||
|
width="341.33334"
|
||||||
|
height="341.33334"
|
||||||
|
x="0"
|
||||||
|
y="341.33334"
|
||||||
|
ry="61.433502" />
|
||||||
|
<rect
|
||||||
|
ry="50.39043"
|
||||||
|
y="372.01187"
|
||||||
|
x="30.678432"
|
||||||
|
height="279.97647"
|
||||||
|
width="279.97653"
|
||||||
|
id="rect58-5-2-5-0"
|
||||||
|
style="fill:url(#linearGradient2955-9-2-6);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:9.59501;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
cx="252.17938"
|
||||||
|
cy="596.60443"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-0-1-1);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
id="path2986-9-6-9-0-54-0-3" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
cx="88.967949"
|
||||||
|
cy="426.58774"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-64-8-0);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
id="path2986-9-6-9-0-3-84-8" />
|
||||||
|
<rect
|
||||||
|
style="fill:url(#linearGradient2968-2-6-21);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.94172;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect58-6-9-0"
|
||||||
|
width="341.33334"
|
||||||
|
height="341.33334"
|
||||||
|
x="682.66669"
|
||||||
|
y="0"
|
||||||
|
ry="61.433502" />
|
||||||
|
<rect
|
||||||
|
ry="50.39043"
|
||||||
|
y="30.678488"
|
||||||
|
x="713.34515"
|
||||||
|
height="279.97647"
|
||||||
|
width="279.97653"
|
||||||
|
id="rect58-5-2-5-4"
|
||||||
|
style="fill:url(#linearGradient2955-9-2-9);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:9.59501;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
cx="853.33337"
|
||||||
|
cy="170.66669"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-1);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
id="path2986-9-6-9-0-29" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
cx="771.63464"
|
||||||
|
cy="256.07895"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-64-9-8);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
id="path2986-9-6-9-0-3-8-22" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
cx="934.84607"
|
||||||
|
cy="255.27113"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-0-1-7);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
id="path2986-9-6-9-0-54-0-2" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
cx="771.63464"
|
||||||
|
cy="85.254402"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-64-8-4);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
id="path2986-9-6-9-0-3-84-5" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
cx="934.84607"
|
||||||
|
cy="84.446587"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-0-4-8);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
id="path2986-9-6-9-0-54-7-5" />
|
||||||
|
<rect
|
||||||
|
style="fill:url(#linearGradient2968-2-6-29);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.94172;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect58-6-9-3"
|
||||||
|
width="341.33334"
|
||||||
|
height="341.33334"
|
||||||
|
x="341.33334"
|
||||||
|
y="341.33334"
|
||||||
|
ry="61.433502" />
|
||||||
|
<rect
|
||||||
|
ry="50.39043"
|
||||||
|
y="372.01187"
|
||||||
|
x="372.01175"
|
||||||
|
height="279.97647"
|
||||||
|
width="279.97653"
|
||||||
|
id="rect58-5-2-5-6"
|
||||||
|
style="fill:url(#linearGradient2955-9-2-8);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:9.59501;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
cx="430.30133"
|
||||||
|
cy="597.41235"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-64-9-2);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
id="path2986-9-6-9-0-3-8-4" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
cx="593.5127"
|
||||||
|
cy="596.60443"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-0-1-5);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
id="path2986-9-6-9-0-54-0-35" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
cx="430.30133"
|
||||||
|
cy="426.58774"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-64-8-49);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
id="path2986-9-6-9-0-3-84-7" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
cx="593.5127"
|
||||||
|
cy="425.77991"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-0-4-9);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
id="path2986-9-6-9-0-54-7-4" />
|
||||||
|
<rect
|
||||||
|
ry="61.433502"
|
||||||
|
y="682.66669"
|
||||||
|
x="0"
|
||||||
|
height="341.33334"
|
||||||
|
width="341.33334"
|
||||||
|
id="rect58-6-9-4-4"
|
||||||
|
style="fill:url(#linearGradient2968-2-6-2-9);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.94172;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
style="fill:url(#linearGradient2955-9-2-6-2);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:9.59501;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect58-5-2-5-0-9"
|
||||||
|
width="279.97653"
|
||||||
|
height="279.97647"
|
||||||
|
x="30.678432"
|
||||||
|
y="713.34515"
|
||||||
|
ry="50.39043" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
id="path2986-9-6-9-0-39-0"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-2-8);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
cy="853.33337"
|
||||||
|
cx="170.66666" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
id="path2986-9-6-9-0-54-0-3-6"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-0-1-1-1);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
cy="937.93781"
|
||||||
|
cx="252.17938" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
id="path2986-9-6-9-0-3-84-8-1"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-64-8-0-4);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
cy="767.92108"
|
||||||
|
cx="88.967972" />
|
||||||
|
<rect
|
||||||
|
ry="61.433502"
|
||||||
|
y="682.66669"
|
||||||
|
x="682.66669"
|
||||||
|
height="341.33334"
|
||||||
|
width="341.33334"
|
||||||
|
id="rect58-6-9-8-4"
|
||||||
|
style="fill:url(#linearGradient2968-2-6-3-7);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:5.94172;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<rect
|
||||||
|
style="fill:url(#linearGradient2955-9-2-69-0);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:9.59501;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect58-5-2-5-3-0"
|
||||||
|
width="279.97653"
|
||||||
|
height="279.97647"
|
||||||
|
x="713.34515"
|
||||||
|
y="713.34515"
|
||||||
|
ry="50.39043" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
cx="771.63464"
|
||||||
|
cy="853.33337"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-64-6-1);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
id="path2986-9-6-9-0-3-3-4" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
cx="934.84607"
|
||||||
|
cy="852.52551"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-0-41-9);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
id="path2986-9-6-9-0-54-3-7" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
id="path2986-9-6-9-0-3-8-8-8"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-64-9-88-7);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
cy="938.74567"
|
||||||
|
cx="771.63464" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
id="path2986-9-6-9-0-54-0-0-5"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-0-1-9-8);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
cy="937.93781"
|
||||||
|
cx="934.84607" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
id="path2986-9-6-9-0-3-84-76-2"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-64-8-88-5);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
cy="767.92108"
|
||||||
|
cx="771.63464" />
|
||||||
|
<ellipse
|
||||||
|
r="29.836327"
|
||||||
|
id="path2986-9-6-9-0-54-7-8-6"
|
||||||
|
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:url(#radialGradient3042-3-1-6-0-4-86-3);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:4.448;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1"
|
||||||
|
cy="767.11328"
|
||||||
|
cx="934.84607" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 28 KiB |
69
src/static/strings.ts
Executable file
69
src/static/strings.ts
Executable file
@@ -0,0 +1,69 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {SupportedLang} from "../enums";
|
||||||
|
|
||||||
|
// Formats strings
|
||||||
|
// formatUnicorn("Hello, {0}!", ["World"]) becomes "Hello, World!"
|
||||||
|
// {0} is the first entry in args, {1} the second, etc.
|
||||||
|
export function formatUnicorn(fmt: string, ...args: string[]): string {
|
||||||
|
if (!fmt.match(/^(?:(?:(?:[^{}]|(?:\{\{)|(?:\}\}))+)|(?:\{[0-9]+\}))+$/)) {
|
||||||
|
throw new Error('Invalid formatUnicorn input string.');
|
||||||
|
}
|
||||||
|
return fmt.replace(/((?:[^{}]|(?:\{\{)|(?:\}\}))+)|(?:\{([0-9]+)\})/g, (m: string, str: string, index: number) => {
|
||||||
|
if (str) {
|
||||||
|
return str.replace(/(?:{{)|(?:}})/g, m => m[0]);
|
||||||
|
} else {
|
||||||
|
if (index >= args.length) {
|
||||||
|
throw new Error('Argument index is out of range in formatUnicorn call.');
|
||||||
|
}
|
||||||
|
return args[index];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LanguageNames: Record<SupportedLang, string> = {
|
||||||
|
gb: "English",
|
||||||
|
de: "Deutsch",
|
||||||
|
it: "Italiano",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const IntlStrings = {
|
||||||
|
gb: {
|
||||||
|
menu: {
|
||||||
|
profileTab: "Profile",
|
||||||
|
statsTab: "Stats",
|
||||||
|
playTab: "Play",
|
||||||
|
rulesetsTab: "Rulesets",
|
||||||
|
friendsTab: "Friends",
|
||||||
|
historyTab: "History",
|
||||||
|
loginButton: "Login",
|
||||||
|
logoutButton: "Logout",
|
||||||
|
userWelcome: "Hi, ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
de: {
|
||||||
|
menu: {
|
||||||
|
profileTab: "Profil",
|
||||||
|
statsTab: "Statistiken",
|
||||||
|
playTab: "Spielen",
|
||||||
|
rulesetsTab: "Regelwerke",
|
||||||
|
friendsTab: "Freunde",
|
||||||
|
historyTab: "Spielverlauf",
|
||||||
|
loginButton: "Anmelden",
|
||||||
|
logoutButton: "Abmelden",
|
||||||
|
userWelcome: "Hallo, ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
it: {
|
||||||
|
menu: {
|
||||||
|
profileTab: "Profilo",
|
||||||
|
statsTab: "Statistiche",
|
||||||
|
playTab: "Gioca",
|
||||||
|
rulesetsTab: "Regolamenti",
|
||||||
|
friendsTab: "Amici",
|
||||||
|
historyTab: "Storia",
|
||||||
|
loginButton: "Accedi",
|
||||||
|
logoutButton: "Esci",
|
||||||
|
userWelcome: "Ciao, ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
23
tsconfig.json
Executable file
23
tsconfig.json
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist/",
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "es5",
|
||||||
|
"jsx": "react",
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"allowSyntheticDefaultImports": true,
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true
|
||||||
|
},
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
]
|
||||||
|
}
|
||||||
33
tslint.json
Executable file
33
tslint.json
Executable file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"defaultSeverity": "error",
|
||||||
|
"extends": [
|
||||||
|
"tslint-react"
|
||||||
|
],
|
||||||
|
"jsRules": {
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"jsx-no-multiline-js": false,
|
||||||
|
"member-access": false,
|
||||||
|
"prefer-for-of": true,
|
||||||
|
"prefer-const": true,
|
||||||
|
"prefer-readonly": true,
|
||||||
|
"typedef": [
|
||||||
|
true,
|
||||||
|
"call-signature",
|
||||||
|
"property-declaration"
|
||||||
|
],
|
||||||
|
"ordered-imports": false,
|
||||||
|
"quotemark": false,
|
||||||
|
"no-console": false,
|
||||||
|
"jsx-no-lambda": false
|
||||||
|
},
|
||||||
|
"rulesDirectory": [
|
||||||
|
],
|
||||||
|
"linterOptions": {
|
||||||
|
"exclude": [
|
||||||
|
"build/**/*.js",
|
||||||
|
"config/**/*.js",
|
||||||
|
"node_modules/**/*.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
51
webpack.config.js
Executable file
51
webpack.config.js
Executable file
@@ -0,0 +1,51 @@
|
|||||||
|
const path = require("path");
|
||||||
|
const webpack = require("webpack");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: "./src/index.tsx",
|
||||||
|
mode: "development",
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
exclude: /(node_modules|bower_components|\.d\.ts$)/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "babel-loader",
|
||||||
|
options: { presets: ["@babel/env"] },
|
||||||
|
},
|
||||||
|
{ loader: "ts-loader" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.d\.ts$/,
|
||||||
|
loader: 'ignore-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: ["style-loader", "css-loader"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpe?g|gif|ttf|woff2?|eot|svg)$/i,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'file-loader',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
resolve: { extensions: [".tsx", ".ts", ".js", "*"] },
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, "dist/"),
|
||||||
|
publicPath: "/kadi/static/",
|
||||||
|
filename: "bundle.js"
|
||||||
|
},
|
||||||
|
devServer: {
|
||||||
|
contentBase: path.join(__dirname, "public/"),
|
||||||
|
port: 3000,
|
||||||
|
publicPath: "http://localhost:3000/dist/",
|
||||||
|
hotOnly: true
|
||||||
|
},
|
||||||
|
plugins: [new webpack.HotModuleReplacementPlugin()]
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user