import React, { useEffect, useState } from 'react';
import { BrowserRouter, Navigate, Route, Routes } from 'react-router-dom';
+import Footer from './common/Footer';
import Header from './common/Header';
import AlttpSeed from './pages/AlttpSeed';
import Front from './pages/Front';
<Route path="/" element={<Front />} />
<Route path="*" element={<Navigate to="/" />} />
</Routes>
+ <Footer />
</UserContext.Provider>
</AlttpBaseRomProvider>
</BrowserRouter>;
--- /dev/null
+import React from 'react';
+import { Col, Nav, Row } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+import { LinkContainer } from 'react-router-bootstrap';
+
+import PrivacyDialog from './PrivacyDialog';
+
+const Footer = () => {
+ const [showDialog, setShowDialog] = React.useState(false);
+
+ const { t } = useTranslation();
+
+ return <footer className="bg-dark mt-5 px-3 py-5">
+ <Row>
+ <Col md={4}>
+ <h5>{t('footer.competitions')}</h5>
+ <Nav as="ul" className="flex-column">
+ <Nav.Item as="li">
+ <LinkContainer to="/tournaments/6">
+ <Nav.Link className="p-0 text-muted" href="/tournaments/6">
+ Deutsche ALttP Community - Seed der Woche
+ </Nav.Link>
+ </LinkContainer>
+ </Nav.Item>
+ <Nav.Item as="li">
+ <LinkContainer to="/tournaments/5">
+ <Nav.Link className="p-0 text-muted" href="/tournaments/5">
+ Wörterbuch - Super Metroid Async
+ </Nav.Link>
+ </LinkContainer>
+ </Nav.Item>
+ </Nav>
+ </Col>
+ <Col md={4}>
+ <h5>{t('footer.resources')}</h5>
+ <Nav as="ul" className="flex-column">
+ <Nav.Item as="li">
+ <Nav.Link
+ className="p-0 text-muted"
+ href="https://alttp-wiki.net/"
+ target="_blank"
+ >
+ {t('footer.alttpwiki')}
+ </Nav.Link>
+ </Nav.Item>
+ <Nav.Item as="li">
+ <LinkContainer to="/tech">
+ <Nav.Link className="p-0 text-muted" href="/tech">
+ ALttP Tech Index
+ </Nav.Link>
+ </LinkContainer>
+ </Nav.Item>
+ <Nav.Item as="li">
+ <Nav.Link
+ className="p-0 text-muted"
+ href="https://wiki.supermetroid.run/"
+ target="_blank"
+ >
+ {t('footer.smwiki')}
+ </Nav.Link>
+ </Nav.Item>
+ </Nav>
+ </Col>
+ <Col md={4}>
+ <h5>{t('footer.info')}</h5>
+ <Nav as="ul" className="flex-column">
+ <Nav.Item as="li">
+ <Nav.Link
+ className="p-0 text-muted"
+ onClick={() => { setShowDialog(true); }}
+ >
+ {t('footer.privacy')}
+ </Nav.Link>
+ </Nav.Item>
+ <Nav.Item as="li">
+ <Nav.Link
+ className="p-0 text-muted"
+ href="https://discord.gg/5zuANcS"
+ target="_blank"
+ >
+ {t('footer.alttpde')}
+ </Nav.Link>
+ </Nav.Item>
+ <Nav.Item as="li">
+ <Nav.Link
+ className="p-0 text-muted"
+ href="https://discord.com/invite/GGdrbnQmVs"
+ target="_blank"
+ >
+ {t('footer.smd')}
+ </Nav.Link>
+ </Nav.Item>
+ <Nav.Item as="li">
+ <Nav.Link
+ className="p-0 text-muted"
+ href="https://discord.gg/hVw5Zeq"
+ target="_blank"
+ >
+ {t('footer.connect')}
+ </Nav.Link>
+ </Nav.Item>
+ </Nav>
+ </Col>
+ </Row>
+ <p className="pt-5 text-center text-muted">{t('footer.contact')}</p>
+ <PrivacyDialog onHide={() => { setShowDialog(false); }} show={showDialog} />
+ </footer>;
+};
+
+export default Footer;
--- /dev/null
+import PropTypes from 'prop-types';
+import React from 'react';
+import { Button, Modal } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+const PrivacyDialog = ({
+ onHide,
+ show,
+}) => {
+ const { t } = useTranslation();
+
+ return <Modal onHide={onHide} show={show}>
+ <Modal.Header closeButton>
+ <Modal.Title>
+ {t('privacy.heading')}
+ </Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <p>{t('privacy.p1')}</p>
+ <p>{t('privacy.p2')}</p>
+ <p>{t('privacy.p3')}</p>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button onClick={onHide} variant="secondary">
+ {t('button.close')}
+ </Button>
+ </Modal.Footer>
+ </Modal>;
+};
+
+PrivacyDialog.propTypes = {
+ onHide: PropTypes.func,
+ show: PropTypes.bool,
+};
+
+export default PrivacyDialog;
heading: 'Serverfehler',
},
},
+ footer: {
+ alttpde: 'Deutscher ALttP Discord',
+ alttpwiki: 'ALttP Speedrunning Wiki',
+ competitions: 'Wettbewerbe',
+ connect: 'Connect Spedruns Discord',
+ contact: 'Wenn du gerne ein Turnier auf dieser Seite organisieren möchtest, wende dich bitte an HolySmoke#5229 im Discord.',
+ info: 'Infos',
+ privacy: 'Datenschutz',
+ resources: 'Ressourcen',
+ smd: 'Deutscher Super Metroid Discord',
+ smwiki: 'Super Metroid Speedrunning Wiki',
+ },
general: {
anonymous: 'Anonym',
appName: 'ALttP',
score: 'Punktzahl',
scoreShort: 'Punkte',
},
+ privacy: {
+ heading: 'Datenschutz',
+ p1: 'Wir benutzen Cookies und den Browserspeicher, um deine Anmeldung und die ausgewählte Sprache zu speichern, sowie XSRF zu verhinden.',
+ p2: 'Wenn du auf den Login Button klickst, wirst du auf eine Anmeldeseite von Discord weitergeleitet. Sofern du dich anmeldest, überträgt Discord und deinen Benutzernamen, Discriminator und ID.',
+ p3: 'Deine Eingaben bei Turnieren werden als Teil des Ergebnisses auf dieser Seite veröffenlicht und ggf. auf dem Discord-Server der entsprechenden Community geteilt.',
+ },
protocol: {
description: {
application: {
heading: 'Server error',
},
},
+ footer: {
+ alttpde: 'German ALttP Discord',
+ alttpwiki: 'ALttP Speedrunning Wiki',
+ competitions: 'Competitions',
+ connect: 'Connect Spedruns Discord',
+ contact: 'If you would like to organize a Tournament on this site, please contact HolySmoke#5229 on Discord.',
+ info: 'Infos',
+ privacy: 'Privacy',
+ resources: 'Resources',
+ smd: 'German Super Metroid Discord',
+ smwiki: 'Super Metroid Speedrunning Wiki',
+ },
general: {
anonymous: 'Anonym',
appName: 'ALttP',
score: 'Score',
scoreShort: 'Score',
},
+ privacy: {
+ heading: 'Privacy',
+ p1: 'We\'re utilizing cokes and your browser\'s storage to remember your login and preferred language as well as protect against XSRF.',
+ p2: 'If you click on Login, you wil be redirected to a discord portal. Once signed in, Discord will provide us with your username, discriminator and ID.',
+ p3: 'Any results you submit will be published on this site and may be shared with the Discord server of the respective community.',
+ },
protocol: {
description: {
application: {