mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-22 15:10:57 -05:00
Add bottom navigation and locale selector.
This commit is contained in:
parent
0115ace3fa
commit
3c6e3b9fbf
6 changed files with 137 additions and 5 deletions
42
src/components/common/LocaleSelector.tsx
Normal file
42
src/components/common/LocaleSelector.tsx
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import ComboBox from "../ui/ComboBox";
|
||||||
|
import { connectState } from "../../redux/connector";
|
||||||
|
import { WithDispatcher } from "../../redux/reducers";
|
||||||
|
import { LanguageEntry, Languages } from "../../context/Locale";
|
||||||
|
|
||||||
|
type Props = WithDispatcher & {
|
||||||
|
locale: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function LocaleSelector(props: Props) {
|
||||||
|
return (
|
||||||
|
<ComboBox
|
||||||
|
value={props.locale}
|
||||||
|
onChange={e =>
|
||||||
|
props.dispatcher &&
|
||||||
|
props.dispatcher({
|
||||||
|
type: "SET_LOCALE",
|
||||||
|
locale: e.currentTarget.value as any
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{Object.keys(Languages).map(x => {
|
||||||
|
const l = (Languages as any)[x] as LanguageEntry;
|
||||||
|
return (
|
||||||
|
<option value={x}>
|
||||||
|
{l.emoji} {l.display}
|
||||||
|
</option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ComboBox>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connectState(
|
||||||
|
LocaleSelector,
|
||||||
|
state => {
|
||||||
|
return {
|
||||||
|
locale: state.locale
|
||||||
|
};
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
72
src/components/navigation/BottomNavigation.tsx
Normal file
72
src/components/navigation/BottomNavigation.tsx
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
import styled, { css } from "styled-components";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import IconButton from "../ui/IconButton";
|
||||||
|
import UserIcon from "../common/user/UserIcon";
|
||||||
|
import { useSelf } from "../../context/revoltjs/hooks";
|
||||||
|
import { useHistory, useLocation } from "react-router";
|
||||||
|
import { MessageCircle, Users } from "@styled-icons/feather";
|
||||||
|
|
||||||
|
const NavigationBase = styled.div`
|
||||||
|
z-index: 10;
|
||||||
|
height: 50px;
|
||||||
|
display: flex;
|
||||||
|
background: var(--secondary-background);
|
||||||
|
`;
|
||||||
|
|
||||||
|
const Button = styled.a<{ active: boolean }>`
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
> a, > div, > a > div {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
${ props => props.active && css`
|
||||||
|
background: var(--hover);
|
||||||
|
` }
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default function BottomNavigation() {
|
||||||
|
const user = useSelf();
|
||||||
|
const history = useHistory();
|
||||||
|
const path = useLocation().pathname;
|
||||||
|
|
||||||
|
const friendsActive = path.startsWith("/friends");
|
||||||
|
const settingsActive = path.startsWith("/settings");
|
||||||
|
const homeActive = !(friendsActive || settingsActive);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NavigationBase>
|
||||||
|
<Button active={homeActive}>
|
||||||
|
<IconButton
|
||||||
|
onClick={() => {
|
||||||
|
if (!homeActive) {
|
||||||
|
if (settingsActive) {
|
||||||
|
if (history.length > 0) {
|
||||||
|
history.goBack();
|
||||||
|
} else {
|
||||||
|
history.push('/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<MessageCircle size={26} />
|
||||||
|
</IconButton>
|
||||||
|
</Button>
|
||||||
|
<Button active={friendsActive}>
|
||||||
|
<Link to="/friends">
|
||||||
|
<IconButton>
|
||||||
|
<Users size={26} />
|
||||||
|
</IconButton>
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
<Button active={settingsActive}>
|
||||||
|
<Link to="/settings">
|
||||||
|
<IconButton>
|
||||||
|
<UserIcon target={user} size={26} status={true} />
|
||||||
|
</IconButton>
|
||||||
|
</Link>
|
||||||
|
</Button>
|
||||||
|
</NavigationBase>
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import styled from "styled-components";
|
import styled, { css } from "styled-components";
|
||||||
|
import { isTouchscreenDevice } from "../../lib/isTouchscreenDevice";
|
||||||
|
|
||||||
export default styled.div`
|
export default styled.div`
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -6,4 +7,8 @@ export default styled.div`
|
||||||
user-select: none;
|
user-select: none;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
|
|
||||||
|
${ isTouchscreenDevice && css`
|
||||||
|
padding-bottom: 50px;
|
||||||
|
` }
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Docked, OverlappingPanels } from "react-overlapping-panels";
|
import { Docked, OverlappingPanels, ShowIf } from "react-overlapping-panels";
|
||||||
import { isTouchscreenDevice } from "../lib/isTouchscreenDevice";
|
import { isTouchscreenDevice } from "../lib/isTouchscreenDevice";
|
||||||
import { Switch, Route } from "react-router-dom";
|
import { Switch, Route, useLocation } from "react-router-dom";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
import ContextMenus from "../lib/ContextMenus";
|
import ContextMenus from "../lib/ContextMenus";
|
||||||
|
@ -11,6 +11,7 @@ import Notifications from "../context/revoltjs/Notifications";
|
||||||
|
|
||||||
import LeftSidebar from "../components/navigation/LeftSidebar";
|
import LeftSidebar from "../components/navigation/LeftSidebar";
|
||||||
import RightSidebar from "../components/navigation/RightSidebar";
|
import RightSidebar from "../components/navigation/RightSidebar";
|
||||||
|
import BottomNavigation from "../components/navigation/BottomNavigation";
|
||||||
|
|
||||||
import Home from './home/Home';
|
import Home from './home/Home';
|
||||||
import Friends from "./friends/Friends";
|
import Friends from "./friends/Friends";
|
||||||
|
@ -29,12 +30,20 @@ const Routes = styled.div`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
|
const path = useLocation().pathname;
|
||||||
|
const fixedBottomNav = (path === '/' || path === '/settings' || path.startsWith("/friends"));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OverlappingPanels
|
<OverlappingPanels
|
||||||
width="100vw"
|
width="100vw"
|
||||||
height="100vh"
|
height="100vh"
|
||||||
leftPanel={{ width: 292, component: <LeftSidebar /> }}
|
leftPanel={{ width: 292, component: <LeftSidebar /> }}
|
||||||
rightPanel={{ width: 240, component: <RightSidebar /> }}
|
rightPanel={{ width: 240, component: <RightSidebar /> }}
|
||||||
|
bottomNav={{
|
||||||
|
component: <BottomNavigation />,
|
||||||
|
showIf: fixedBottomNav ? ShowIf.Always : ShowIf.Left,
|
||||||
|
height: 50
|
||||||
|
}}
|
||||||
docked={isTouchscreenDevice ? Docked.None : Docked.Left}>
|
docked={isTouchscreenDevice ? Docked.None : Docked.Left}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Switch>
|
<Switch>
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { LIBRARY_VERSION } from "revolt.js";
|
||||||
import { Route, Switch } from "react-router-dom";
|
import { Route, Switch } from "react-router-dom";
|
||||||
import { ThemeContext } from "../../context/Theme";
|
import { ThemeContext } from "../../context/Theme";
|
||||||
import { AppContext } from "../../context/revoltjs/RevoltClient";
|
import { AppContext } from "../../context/revoltjs/RevoltClient";
|
||||||
|
import LocaleSelector from "../../components/common/LocaleSelector";
|
||||||
|
|
||||||
import background from "./background.jpg";
|
import background from "./background.jpg";
|
||||||
|
|
||||||
|
@ -33,7 +34,7 @@ export default function Login() {
|
||||||
· App: <code>{APP_VERSION}</code>
|
· App: <code>{APP_VERSION}</code>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
{/*<LocaleSelector />*/}
|
<LocaleSelector />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.modal}>
|
<div className={styles.modal}>
|
||||||
|
|
|
@ -6,8 +6,8 @@ import { useForm } from "react-hook-form";
|
||||||
import { MailProvider } from "./MailProvider";
|
import { MailProvider } from "./MailProvider";
|
||||||
import { useContext, useState } from "preact/hooks";
|
import { useContext, useState } from "preact/hooks";
|
||||||
import { CheckCircle, Mail } from "@styled-icons/feather";
|
import { CheckCircle, Mail } from "@styled-icons/feather";
|
||||||
import { CaptchaBlock, CaptchaProps } from "./CaptchaBlock";
|
|
||||||
import { takeError } from "../../../context/revoltjs/util";
|
import { takeError } from "../../../context/revoltjs/util";
|
||||||
|
import { CaptchaBlock, CaptchaProps } from "./CaptchaBlock";
|
||||||
import { AppContext } from "../../../context/revoltjs/RevoltClient";
|
import { AppContext } from "../../../context/revoltjs/RevoltClient";
|
||||||
|
|
||||||
import FormField from "../FormField";
|
import FormField from "../FormField";
|
||||||
|
@ -15,6 +15,8 @@ import Button from "../../../components/ui/Button";
|
||||||
import Overline from "../../../components/ui/Overline";
|
import Overline from "../../../components/ui/Overline";
|
||||||
import Preloader from "../../../components/ui/Preloader";
|
import Preloader from "../../../components/ui/Preloader";
|
||||||
|
|
||||||
|
import wideSVG from '../../../assets/wide.svg';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
page: "create" | "login" | "send_reset" | "reset" | "resend";
|
page: "create" | "login" | "send_reset" | "reset" | "resend";
|
||||||
callback: (fields: {
|
callback: (fields: {
|
||||||
|
@ -140,6 +142,7 @@ export function Form({ page, callback }: Props) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.form}>
|
<div className={styles.form}>
|
||||||
|
<img src={wideSVG} />
|
||||||
<form onSubmit={handleSubmit(onSubmit) as any}>
|
<form onSubmit={handleSubmit(onSubmit) as any}>
|
||||||
{page !== "reset" && (
|
{page !== "reset" && (
|
||||||
<FormField
|
<FormField
|
||||||
|
|
Loading…
Reference in a new issue