Put all user information (including locale) into a user context. Language can be changed, all pages access the user context now. Translated some stuff.

This commit is contained in:
Daniel Ledda
2020-05-24 11:37:04 +02:00
parent 7cb8a03c24
commit 0fe94c3066
21 changed files with 196 additions and 137 deletions

View File

@@ -7,7 +7,7 @@
"author": "Daniel Ledda", "author": "Daniel Ledda",
"scripts": { "scripts": {
"build": "webpack --mode development", "build": "webpack --mode development",
"postbuild": "rsync -avu --delete dist/ ../kadi_backend/dist/frontend/static", "postbuild": "rsync -avu --delete dist/ ../kadi_backend/static/frontend",
"start": "webpack-dev-server --mode development", "start": "webpack-dev-server --mode development",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },

View File

@@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="favicon.ico" /> <link rel="icon" href="static/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<meta <meta
@@ -17,6 +17,6 @@
<noscript> <noscript>
You need to enable JavaScript to run this app. You need to enable JavaScript to run this app.
</noscript> </noscript>
<script src="../dist/bundle.js"></script> <script src="static/bundle.js"></script>
</body> </body>
</html> </html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -1,25 +0,0 @@
{
"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"
}

View File

@@ -1,3 +0,0 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

View File

@@ -9,18 +9,16 @@ import HomePage from "./Components/HomePage";
import {SERVER_BASE_NAME} from "./index"; import {SERVER_BASE_NAME} from "./index";
import axios from "axios"; import axios from "axios";
import UserContext, {IUserContext} from "./Contexts/UserContext"; import UserContext, {IUserContext} from "./Contexts/UserContext";
import LocaleContext, {ILocaleContext} from "./Contexts/LocaleContext";
interface AppState { interface AppState {
userContext: IUserContext; userContext: IUserContext;
localeContext: ILocaleContext;
} }
interface AppProps {} interface AppProps {}
class App extends React.Component<AppProps, AppState> { class App extends React.Component<AppProps, AppState> {
private readonly updateUserContext: (username: string, loggedIn: boolean) => void; private readonly updateUserContext: (username: string, loggedIn: boolean) => void;
private readonly changeLang: (lang: SupportedLang) => void; private readonly changeLang: (lang: SupportedLang, submit?: boolean) => void;
constructor(props: AppProps) { constructor(props: AppProps) {
super(props); super(props);
@@ -28,16 +26,25 @@ class App extends React.Component<AppProps, AppState> {
this.setState({userContext: { this.setState({userContext: {
username: username, username: username,
loggedIn: loggedIn, loggedIn: loggedIn,
updateUserContext: this.updateUserContext updateUserContext: this.updateUserContext,
currentLang: this.state.userContext.currentLang,
strings: this.state.userContext.strings,
changeLang: this.state.userContext.changeLang,
}}); }});
}; };
this.changeLang = (lang: SupportedLang) => { this.changeLang = (lang: SupportedLang, submit=true) => {
this.setState({localeContext: { this.setState({userContext: {
strings: IntlStrings[lang], strings: IntlStrings[lang],
currentLang: lang, currentLang: lang,
changeLang: this.changeLang changeLang: this.changeLang,
username: this.state.userContext.username,
loggedIn: this.state.userContext.loggedIn,
updateUserContext: this.state.userContext.updateUserContext,
}}); }});
if (submit) {
this.submitLanguagePreference(lang);
}
}; };
this.state = { this.state = {
@@ -45,32 +52,40 @@ class App extends React.Component<AppProps, AppState> {
username: "", username: "",
loggedIn: false, loggedIn: false,
updateUserContext: this.updateUserContext, updateUserContext: this.updateUserContext,
},
localeContext: {
currentLang: SupportedLang.gb, currentLang: SupportedLang.gb,
strings: IntlStrings[SupportedLang.gb], strings: IntlStrings[SupportedLang.gb],
changeLang: this.changeLang, changeLang: this.changeLang,
} }
}; };
}
componentDidMount(): void {
this.getDefaultVals();
}
getDefaultVals(): void {
axios.get("/api/user", {baseURL: SERVER_BASE_NAME}) axios.get("/api/user", {baseURL: SERVER_BASE_NAME})
.then((res) => { .then((res) => {
const data = res.data as any; const data = res.data as any;
if (data.loggedIn) { if (data.loggedIn) {
this.updateUserContext(data.username, true); this.updateUserContext(data.username, data.loggedIn);
} this.changeLang(data.lang, false);
else {
this.updateUserContext("", false);
} }
}) })
.catch(err => console.log(err)); .catch(err => console.log(err));
} }
submitLanguagePreference(lang: SupportedLang) {
axios.post(SERVER_BASE_NAME + "/api/changeLang",
{lang: lang},
{headers: {"Content-Type": "application/json"}}
);
};
render(): ReactNode { render(): ReactNode {
return ( return (
<UserContext.Provider value={this.state.userContext}> <UserContext.Provider value={this.state.userContext}>
<LocaleContext.Provider value={this.state.localeContext}>
<Router basename={SERVER_BASE_NAME}> <Router basename={SERVER_BASE_NAME}>
<Route exact={true} path={"/"}> <Route exact={true} path={"/"}>
<KadiPage activePage={PageId.home}> <KadiPage activePage={PageId.home}>
@@ -90,7 +105,6 @@ class App extends React.Component<AppProps, AppState> {
/> />
</Route> </Route>
</Router> </Router>
</LocaleContext.Provider>
</UserContext.Provider> </UserContext.Provider>
); );
} }

View File

@@ -1,6 +1,6 @@
import React, {ReactElement} from "react"; import React, {ReactElement} from "react";
import KadiPage from "../Components/KadiPage";
import {Header} from "semantic-ui-react"; import {Header} from "semantic-ui-react";
import UserContext from "../Contexts/UserContext";
interface FriendsPageProps {} interface FriendsPageProps {}
@@ -16,12 +16,14 @@ class FriendsPage extends React.Component<FriendsPageProps, FriendsPageState> {
} }
render(): ReactElement { render(): ReactElement {
const Locale = this.context.strings;
return ( return (
<Header> <Header>
My Friends {Locale.friendsPage.title}
</Header> </Header>
); );
} }
} }
FriendsPage.contextType = UserContext;
export default FriendsPage; export default FriendsPage;

View File

@@ -2,6 +2,7 @@ import React, {ReactElement} from "react";
import {Header, List, ListItem} from "semantic-ui-react"; import {Header, List, ListItem} from "semantic-ui-react";
import axios from "axios"; import axios from "axios";
import {SERVER_BASE_NAME} from "../index"; import {SERVER_BASE_NAME} from "../index";
import UserContext from "../Contexts/UserContext";
interface HistoryPageProps { interface HistoryPageProps {
} }
@@ -22,10 +23,11 @@ class HistoryPage extends React.Component<HistoryPageProps, HistoryPageState> {
} }
componentDidMount(): void { componentDidMount(): void {
axios.get(SERVER_BASE_NAME + "/api/games/") axios.get(SERVER_BASE_NAME + "/api/games")
.then(response => this.setState({gameListings: response.data.games})) .then(response => this.setState({gameListings: response.data.games}))
.catch(error => this.handleError(error)) .catch(error => this.handleError(error))
.finally(() => this.setState({ loadingGames: false })); .finally(() => this.setState({ loadingGames: false }));
console.log(this.state.gameListings);
} }
handleError = (error: any) => void { handleError = (error: any) => void {
@@ -33,21 +35,32 @@ class HistoryPage extends React.Component<HistoryPageProps, HistoryPageState> {
}; };
render(): ReactElement { render(): ReactElement {
const Locale = this.context.strings;
return ( return (
<> <>
<Header size={"huge"}> <Header size={"huge"}>
History {Locale.historyPage.title}
</Header> </Header>
<List bulleted={true}> {
{ this.state.loadingGames ? (
this.state.gameListings.map(listing => { <p>
return <ListItem key={listing.createdAt}>Game played on: {listing.createdAt}</ListItem>; Loading games...
}) </p>
} ) :
</List> (
<List bulleted={true}>
{
this.state.gameListings.map(listing => {
return <ListItem key={listing.createdAt}>Game played on: {listing.createdAt}</ListItem>;
})
}
</List>
)
}
</> </>
); );
} }
} }
HistoryPage.contextType = UserContext;
export default HistoryPage; export default HistoryPage;

View File

@@ -1,6 +1,6 @@
import React, {ReactElement} from "react"; import React, {ReactElement} from "react";
import KadiPage from "../Components/KadiPage";
import {Header} from "semantic-ui-react"; import {Header} from "semantic-ui-react";
import UserContext from "../Contexts/UserContext";
interface HomePageProps {} interface HomePageProps {}
@@ -16,12 +16,14 @@ class HomePage extends React.Component<HomePageProps, HomePageState> {
} }
render(): ReactElement { render(): ReactElement {
const Locale = this.context.strings;
return ( return (
<Header> <Header>
Home {Locale.homePage.title}
</Header> </Header>
); );
} }
} }
HomePage.contextType = UserContext;
export default HomePage; export default HomePage;

View File

@@ -4,6 +4,7 @@ import "../static/css/site.css";
import KadiSidebarNav from "../Components/KadiSidebarNav"; import KadiSidebarNav from "../Components/KadiSidebarNav";
import MainPageContent from "../Components/MainPageContent"; import MainPageContent from "../Components/MainPageContent";
import {PageId} from "../enums"; import {PageId} from "../enums";
import UserContext from "../Contexts/UserContext";
interface KadiPageProps { interface KadiPageProps {
activePage: PageId; activePage: PageId;
@@ -32,5 +33,6 @@ class KadiPage extends React.Component<KadiPageProps, KadiPageState> {
); );
} }
} }
KadiPage.contextType = UserContext;
export default KadiPage; export default KadiPage;

View File

@@ -1,7 +1,7 @@
import {Header, HeaderContent, Icon, Image, Menu, Segment, Sidebar, SidebarPusher} from "semantic-ui-react"; import {Header, HeaderContent, Icon, Image, Menu} from "semantic-ui-react";
import logo from "../static/images/kadi.png"; import logo from "../static/images/kadi.png";
import React from "react"; import React from "react";
import LocaleContext from "../Contexts/LocaleContext"; import UserContext from "../Contexts/UserContext";
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
import {PageId} from "../enums"; import {PageId} from "../enums";
import {SERVER_BASE_NAME} from "../index"; import {SERVER_BASE_NAME} from "../index";
@@ -11,7 +11,7 @@ interface KadiSidebarNavProps {
} }
const KadiSidebarNav: React.FunctionComponent<KadiSidebarNavProps> = (props) => { const KadiSidebarNav: React.FunctionComponent<KadiSidebarNavProps> = (props) => {
const Locale = React.useContext(LocaleContext).strings; const Locale = React.useContext(UserContext).strings;
const {activeItem} = props; const {activeItem} = props;
return ( return (
<Menu <Menu
@@ -40,7 +40,7 @@ const KadiSidebarNav: React.FunctionComponent<KadiSidebarNavProps> = (props) =>
<Icon name={"game"} /> <Icon name={"game"} />
{Locale.menu.playTab} {Locale.menu.playTab}
</Menu.Item> </Menu.Item>
<Link to={"/" + PageId.profile}> <Link to={PageId.profile}>
<Menu.Item <Menu.Item
as={"a"} as={"a"}
icon={true} icon={true}
@@ -50,7 +50,7 @@ const KadiSidebarNav: React.FunctionComponent<KadiSidebarNavProps> = (props) =>
{Locale.menu.profileTab} {Locale.menu.profileTab}
</Menu.Item> </Menu.Item>
</Link> </Link>
<Link to={"/" + PageId.stats}> <Link to={PageId.stats}>
<Menu.Item <Menu.Item
as={"a"} as={"a"}
icon={true} icon={true}
@@ -60,7 +60,7 @@ const KadiSidebarNav: React.FunctionComponent<KadiSidebarNavProps> = (props) =>
{Locale.menu.statsTab} {Locale.menu.statsTab}
</Menu.Item> </Menu.Item>
</Link> </Link>
<Link to={"/" + PageId.rulesets}> <Link to={PageId.rulesets}>
<Menu.Item <Menu.Item
as={"a"} as={"a"}
icon={true} icon={true}
@@ -70,7 +70,7 @@ const KadiSidebarNav: React.FunctionComponent<KadiSidebarNavProps> = (props) =>
{Locale.menu.rulesetsTab} {Locale.menu.rulesetsTab}
</Menu.Item> </Menu.Item>
</Link> </Link>
<Link to={"/" + PageId.friends}> <Link to={PageId.friends}>
<Menu.Item <Menu.Item
as={"a"} as={"a"}
icon={true} icon={true}
@@ -80,7 +80,7 @@ const KadiSidebarNav: React.FunctionComponent<KadiSidebarNavProps> = (props) =>
{Locale.menu.friendsTab} {Locale.menu.friendsTab}
</Menu.Item> </Menu.Item>
</Link> </Link>
<Link to={"/" + PageId.history}> <Link to={PageId.history}>
<Menu.Item <Menu.Item
as={"a"} as={"a"}
icon={true} icon={true}

View File

@@ -1,7 +1,6 @@
import React, {ReactElement, SyntheticEvent} from "react"; import React, {ReactElement} from "react";
import {Dropdown, DropdownItemProps, DropdownProps, Flag, Icon, Menu} from "semantic-ui-react"; import {Dropdown, DropdownItemProps, Flag, Icon, Menu} from "semantic-ui-react";
import {SERVER_BASE_NAME} from "../index"; import {SERVER_BASE_NAME} from "../index";
import LocaleContext from "../Contexts/LocaleContext";
import {LanguageNames} from "../static/strings"; import {LanguageNames} from "../static/strings";
import {IUserContext} from "../Contexts/UserContext"; import {IUserContext} from "../Contexts/UserContext";
import {SupportedLang} from "../enums"; import {SupportedLang} from "../enums";
@@ -11,7 +10,6 @@ interface KadiTopMenuBarProps {
} }
interface KadiTopMenuBarState { interface KadiTopMenuBarState {
currentLangSelection: SupportedLang;
} }
class KadiTopMenuBar extends React.Component<KadiTopMenuBarProps, KadiTopMenuBarState> { class KadiTopMenuBar extends React.Component<KadiTopMenuBarProps, KadiTopMenuBarState> {
@@ -21,7 +19,6 @@ class KadiTopMenuBar extends React.Component<KadiTopMenuBarProps, KadiTopMenuBar
super(props); super(props);
this.state = { this.state = {
currentLangSelection: SupportedLang.gb,
}; };
this.changeLanguageGlobally = () => {}; this.changeLanguageGlobally = () => {};
@@ -33,19 +30,8 @@ class KadiTopMenuBar extends React.Component<KadiTopMenuBarProps, KadiTopMenuBar
} }
} }
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 { render(): ReactElement {
const {loggedIn, username} = this.props.user; const {loggedIn, username, strings: Locale, currentLang, changeLang} = this.props.user;
const Locale = this.context.strings;
return ( return (
<Menu <Menu
@@ -72,12 +58,12 @@ class KadiTopMenuBar extends React.Component<KadiTopMenuBarProps, KadiTopMenuBar
<Dropdown <Dropdown
trigger={( trigger={(
<span> <span>
<Flag name={this.state.currentLangSelection} /> <Flag name={currentLang} />
{LanguageNames[this.state.currentLangSelection]} {LanguageNames[currentLang]}
</span> </span>
)} )}
options={this.languageDropdowns} options={this.languageDropdowns}
onChange={this.handleLanguageChange} onChange={(e, d) => changeLang(d.value as SupportedLang)}
/> />
</Menu.Item> </Menu.Item>
</Menu.Menu> </Menu.Menu>
@@ -85,6 +71,5 @@ class KadiTopMenuBar extends React.Component<KadiTopMenuBarProps, KadiTopMenuBar
); );
} }
} }
KadiTopMenuBar.contextType = LocaleContext;
export default KadiTopMenuBar; export default KadiTopMenuBar;

View File

@@ -1,6 +1,6 @@
import React, {ReactElement} from "react"; import React, {ReactElement} from "react";
import KadiPage from "../Components/KadiPage";
import {Header} from "semantic-ui-react"; import {Header} from "semantic-ui-react";
import UserContext from "../Contexts/UserContext";
interface ProfilePageProps {} interface ProfilePageProps {}
@@ -16,12 +16,14 @@ class ProfilePage extends React.Component<ProfilePageProps, ProfilePageState> {
} }
render(): ReactElement { render(): ReactElement {
const Locale = this.context.strings;
return ( return (
<Header> <Header size={"huge"}>
My Profile {Locale.profilePage.title}
</Header> </Header>
); );
} }
} }
ProfilePage.contextType = UserContext;
export default ProfilePage; export default ProfilePage;

View File

@@ -1,6 +1,6 @@
import React, {ReactElement} from "react"; import React, {ReactElement} from "react";
import KadiPage from "../Components/KadiPage";
import {Header} from "semantic-ui-react"; import {Header} from "semantic-ui-react";
import UserContext from "../Contexts/UserContext";
interface RulesetsPageProps {} interface RulesetsPageProps {}
@@ -16,12 +16,14 @@ class RulesetsPage extends React.Component<RulesetsPageProps, RulesetsPageState>
} }
render(): ReactElement { render(): ReactElement {
const Locale = this.context.strings;
return ( return (
<Header> <Header>
My Rulesets {Locale.rulesetsPage.title}
</Header> </Header>
); );
} }
} }
RulesetsPage.contextType = UserContext;
export default RulesetsPage; export default RulesetsPage;

View File

@@ -1,7 +1,6 @@
import React, {ReactNode} from "react"; import React, {ReactNode} from "react";
import {BrowserRouter as Router, Link, Route} from "react-router-dom";
import {Header} from "semantic-ui-react"; import {Header} from "semantic-ui-react";
import KadiPage from "../Components/KadiPage"; import UserContext from "../Contexts/UserContext";
interface StatsPageProps {} interface StatsPageProps {}
@@ -17,12 +16,14 @@ class StatsPage extends React.Component<StatsPageProps, StatsPageState> {
} }
render(): ReactNode { render(): ReactNode {
const Locale = this.context.strings;
return ( return (
<Header> <Header>
My Stats {Locale.statsPage.title}
</Header> </Header>
); );
} }
} }
StatsPage.contextType = UserContext;
export default StatsPage; export default StatsPage;

View File

@@ -1,19 +0,0 @@
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;

View File

@@ -1,15 +1,23 @@
import React from "react"; import React from "react";
import {SupportedLang} from "../enums";
import {IntlStrings} from "../static/strings";
export interface IUserContext { export interface IUserContext {
username: string; username: string;
loggedIn: boolean; loggedIn: boolean;
updateUserContext: (username: string, loggedIn: boolean) => void; updateUserContext: (username: string, loggedIn: boolean) => void;
currentLang: SupportedLang;
strings: any;
changeLang: (lang: SupportedLang, submit?: boolean) => void;
} }
const userDefaultVal = { const userDefaultVal = {
loggedIn: false, loggedIn: false,
username: "", username: "",
updateUserContext: () => {}, updateUserContext: () => {},
currentLang: SupportedLang.gb,
strings: IntlStrings[SupportedLang.gb as SupportedLang],
changeLang: () => {},
} as IUserContext; } as IUserContext;
const UserContext = React.createContext(userDefaultVal); const UserContext = React.createContext(userDefaultVal);

View File

@@ -481,7 +481,8 @@
y="30.678488" y="30.678488"
ry="50.39043" /> ry="50.39043" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
id="path2986-9-6-9-0" 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" 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" cy="170.66669"
@@ -503,13 +504,15 @@
id="rect58-5-2-5-0" 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" /> 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 <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
cx="252.17938" cx="252.17938"
cy="596.60443" 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" 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" /> id="path2986-9-6-9-0-54-0-3" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
cx="88.967949" cx="88.967949"
cy="426.58774" 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" 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"
@@ -531,31 +534,36 @@
id="rect58-5-2-5-4" 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" /> 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 <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
cx="853.33337" cx="853.33337"
cy="170.66669" 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" 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" /> id="path2986-9-6-9-0-29" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
cx="771.63464" cx="771.63464"
cy="256.07895" 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" 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" /> id="path2986-9-6-9-0-3-8-22" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
cx="934.84607" cx="934.84607"
cy="255.27113" 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" 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" /> id="path2986-9-6-9-0-54-0-2" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
cx="771.63464" cx="771.63464"
cy="85.254402" 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" 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" /> id="path2986-9-6-9-0-3-84-5" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
cx="934.84607" cx="934.84607"
cy="84.446587" 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" 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"
@@ -577,25 +585,29 @@
id="rect58-5-2-5-6" 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" /> 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 <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
cx="430.30133" cx="430.30133"
cy="597.41235" 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" 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" /> id="path2986-9-6-9-0-3-8-4" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
cx="593.5127" cx="593.5127"
cy="596.60443" 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" 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" /> id="path2986-9-6-9-0-54-0-35" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
cx="430.30133" cx="430.30133"
cy="426.58774" 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" 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" /> id="path2986-9-6-9-0-3-84-7" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
cx="593.5127" cx="593.5127"
cy="425.77991" 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" 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"
@@ -617,19 +629,22 @@
y="713.34515" y="713.34515"
ry="50.39043" /> ry="50.39043" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
id="path2986-9-6-9-0-39-0" 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" 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" cy="853.33337"
cx="170.66666" /> cx="170.66666" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
id="path2986-9-6-9-0-54-0-3-6" 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" 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" cy="937.93781"
cx="252.17938" /> cx="252.17938" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
id="path2986-9-6-9-0-3-84-8-1" 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" 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" cy="767.92108"
@@ -651,37 +666,43 @@
y="713.34515" y="713.34515"
ry="50.39043" /> ry="50.39043" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
cx="771.63464" cx="771.63464"
cy="853.33337" 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" 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" /> id="path2986-9-6-9-0-3-3-4" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
cx="934.84607" cx="934.84607"
cy="852.52551" 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" 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" /> id="path2986-9-6-9-0-54-3-7" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
id="path2986-9-6-9-0-3-8-8-8" 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" 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" cy="938.74567"
cx="771.63464" /> cx="771.63464" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
id="path2986-9-6-9-0-54-0-0-5" 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" 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" cy="937.93781"
cx="934.84607" /> cx="934.84607" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
id="path2986-9-6-9-0-3-84-76-2" 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" 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" cy="767.92108"
cx="771.63464" /> cx="771.63464" />
<ellipse <ellipse
r="29.836327" rx="29.836327"
ry="29.836327"
id="path2986-9-6-9-0-54-7-8-6" 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" 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" cy="767.11328"

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -39,6 +39,24 @@ export const IntlStrings = {
logoutButton: "Logout", logoutButton: "Logout",
userWelcome: "Hi, ", userWelcome: "Hi, ",
}, },
homePage: {
title: "Home",
},
profilePage: {
title: "Profile",
},
statsPage: {
title: "Stats",
},
rulesetsPage: {
title: "Rulesets",
},
friendsPage: {
title: "Friends",
},
historyPage: {
title: "History",
},
}, },
de: { de: {
menu: { menu: {
@@ -52,6 +70,24 @@ export const IntlStrings = {
logoutButton: "Abmelden", logoutButton: "Abmelden",
userWelcome: "Hallo, ", userWelcome: "Hallo, ",
}, },
homePage: {
title: "Startseite",
},
profilePage: {
title: "Profil",
},
statsPage: {
title: "Statistiken",
},
rulesetsPage: {
title: "Regelwerke",
},
friendsPage: {
title: "Freunde",
},
historyPage: {
title: "Spielverlauf",
},
}, },
it: { it: {
menu: { menu: {
@@ -65,5 +101,23 @@ export const IntlStrings = {
logoutButton: "Esci", logoutButton: "Esci",
userWelcome: "Ciao, ", userWelcome: "Ciao, ",
}, },
homePage: {
title: "Home",
},
profilePage: {
title: "Profilo",
},
statsPage: {
title: "Statistiche",
},
rulesetsPage: {
title: "Regolamenti",
},
friendsPage: {
title: "Amici",
},
historyPage: {
title: "Storia",
},
}, },
} as const; } as const;

View File

@@ -38,7 +38,7 @@ module.exports = {
resolve: { extensions: [".tsx", ".ts", ".js", "*"] }, resolve: { extensions: [".tsx", ".ts", ".js", "*"] },
output: { output: {
path: path.resolve(__dirname, "dist/"), path: path.resolve(__dirname, "dist/"),
publicPath: "/kadi/static/", publicPath: "/kadi/static/frontend/",
filename: "bundle.js" filename: "bundle.js"
}, },
devServer: { devServer: {