Browse Source

Pop out menu from left on phone screens.

main
Titouan Rigoudy 4 years ago
parent
commit
c80f9a183b
7 changed files with 116 additions and 53 deletions
  1. +37
    -16
      src/components/Menu.tsx
  2. +14
    -6
      src/components/SearchableList.tsx
  3. +32
    -11
      src/components/SolsticeApp.tsx
  4. +4
    -1
      src/modules/room/RoomList.tsx
  5. +11
    -7
      src/modules/room/RoomsPane.tsx
  6. +3
    -1
      src/modules/user/UserList.tsx
  7. +15
    -11
      src/modules/user/UsersPane.tsx

+ 37
- 16
src/components/Menu.tsx View File

@ -14,21 +14,42 @@ const Link: FC<LinkProps> = ({ to, children }) => (
</NavLink>
);
const Menu: FC = () => (
<header className="hidden md:flex p-4 items-center w-full overflow-hidden">
<h1
className={
"text-3xl font-bold text-yellow-800 bg-yellow-300 shadow " +
"mr-5 py-3 px-5 rounded-xl"
}
>
Solstice
</h1>
<nav className="flex items-center">
<Link to={roomListPath}>Rooms</Link>
<Link to={userListPath}>Users</Link>
</nav>
</header>
);
interface Props {
show: boolean;
onHide: () => void;
}
const Menu: FC<Props> = ({ show, onHide }) => {
let headerClass =
"absolute md:static flex flex-col md:flex-row items-center gap-5 p-4 " +
"w-80 min-h-full md:w-full md:min-h-0 overflow-hidden " +
"bg-yellow-100 border-r-2 border-yellow-400 ";
if (!show) {
headerClass += " -left-80 md:left-0";
}
return (
<header className={headerClass}>
<div className="flex items-center justify-between min-w-full md:min-w-0">
<h1
className={
"text-3xl font-bold text-yellow-800 bg-yellow-300 shadow " +
"mr-5 py-3 px-5 rounded-xl"
}
>
Solstice
</h1>
<button className="button md:hidden" onClick={onHide}>
Hide
</button>
</div>
<nav className="flex flex-col md:flex-row md:items-center gap-3">
<Link to={roomListPath}>Rooms</Link>
<Link to={userListPath}>Users</Link>
</nav>
</header>
);
};
export default Menu;

+ 14
- 6
src/components/SearchableList.tsx View File

@ -14,6 +14,8 @@ interface ItemProps<Item> {
interface ListProps<Item> {
title: string;
onRefresh: ReactEventHandler;
// TODO: Make required.
onShowMenu?: () => void;
component: FC<ItemProps<Item>>;
map: { [key: string]: Item };
}
@ -21,6 +23,7 @@ interface ListProps<Item> {
function SearchableList<Item>({
title,
onRefresh,
onShowMenu,
component,
map,
}: ListProps<Item>): ReactElement {
@ -39,13 +42,18 @@ function SearchableList<Item>({
return (
<div className="flex flex-col px-3 h-full">
<div className="flex justify-between p-3">
<h1 className="pl-3 text-2xl font-bold text-yellow-800 text-center">
{title}
</h1>
<button onClick={onRefresh} className="button">
Refresh
<div className="flex p-3 gap-3 items-center">
<button onClick={onShowMenu} className="button md:hidden">
Menu
</button>
<div className="flex-grow flex items-center gap-3 justify-between">
<h1 className="pl-3 text-2xl font-bold text-yellow-800 text-center">
{title}
</h1>
<button onClick={onRefresh} className="button">
Refresh
</button>
</div>
</div>
<form className="flex gap-3 p-3">
<label htmlFor="filter" className="self-center">


+ 32
- 11
src/components/SolsticeApp.tsx View File

@ -1,4 +1,4 @@
import { FC } from "react";
import { FC, useState } from "react";
import { Switch, Redirect, Route, useLocation } from "react-router-dom";
import { useAppSelector } from "app/hooks";
@ -11,22 +11,47 @@ import { userListPath } from "modules/user/paths";
import UsersPane from "modules/user/UsersPane";
import { selectSocket, SocketState } from "modules/socket/slice";
const MainPane: FC = () => {
interface MainProps {
onShowMenu: () => void;
}
const MainPane: FC<MainProps> = ({ onShowMenu }) => {
return (
<main className="flex-1 min-h-0 w-full">
<Switch>
<Route path={roomListPath}>
<RoomsPane />
<RoomsPane onShowMenu={onShowMenu} />
</Route>
<Route path={userListPath}>
<UsersPane />
<UsersPane onShowMenu={onShowMenu} />
</Route>
</Switch>
</main>
);
};
const ConnectedApp: FC = ({ children }) => {
const InnerApp: FC<{}> = () => {
const [showMenu, setShowMenu] = useState(false);
return (
<div className="h-full w-full flex flex-col">
<Menu
show={showMenu}
onHide={() => {
setShowMenu(false);
}}
/>
<MainPane
onShowMenu={() => {
setShowMenu(true);
}}
/>
<Footer />
</div>
);
};
const ConnectedApp: FC<{}> = () => {
const socket = useAppSelector(selectSocket);
const location = useLocation();
@ -41,7 +66,7 @@ const ConnectedApp: FC = ({ children }) => {
);
}
return <div className="h-full w-full flex flex-col">{children}</div>;
return <InnerApp />;
};
const SolsticeApp = () => (
@ -50,11 +75,7 @@ const SolsticeApp = () => (
<ConnectPage />
</Route>
<Route path="/">
<ConnectedApp>
<Menu />
<MainPane />
<Footer />
</ConnectedApp>
<ConnectedApp />
</Route>
</Switch>
);


+ 4
- 1
src/modules/room/RoomList.tsx View File

@ -7,9 +7,10 @@ import { RoomMap, roomGetAll } from "modules/room/slice";
interface Props {
rooms: RoomMap;
onShowMenu: () => void;
}
const RoomList: FC<Props> = ({ rooms }) => {
const RoomList: FC<Props> = ({ rooms, onShowMenu }) => {
const dispatch = useAppDispatch();
const onRefresh: ReactEventHandler = (event) => {
@ -17,9 +18,11 @@ const RoomList: FC<Props> = ({ rooms }) => {
dispatch(roomGetAll());
};
// TODO: Move header out of SearchableList component.
return (
<SearchableList
title="Chat Rooms"
onShowMenu={onShowMenu}
onRefresh={onRefresh}
component={RoomListEntry}
map={rooms}


+ 11
- 7
src/modules/room/RoomsPane.tsx View File

@ -28,11 +28,15 @@ const RoomChatPane: FC<ChatProps> = ({ loginUserName, roomName, room }) => {
return <RoomChat loginUserName={loginUserName} room={room} />;
};
interface Props {
onShowMenu: () => void;
}
interface UrlParams {
roomId: string;
}
const RoomsPaneInner: FC<{}> = () => {
const RoomsPaneInner: FC<Props> = ({ onShowMenu }) => {
const login = useAppSelector(selectLogin);
const rooms = useAppSelector(selectAllRooms);
const { roomId } = useParams<UrlParams>();
@ -55,7 +59,7 @@ const RoomsPaneInner: FC<{}> = () => {
return (
<div className="h-full w-full flex">
<div className={listClass}>
<RoomList rooms={rooms} />
<RoomList rooms={rooms} onShowMenu={onShowMenu} />
</div>
<div className="flex-1 overflow-auto">
<RoomChatPane
@ -68,17 +72,17 @@ const RoomsPaneInner: FC<{}> = () => {
);
};
const RoomsPane: FC<{}> = () => {
const RoomsPane: FC<Props> = ({ onShowMenu }) => {
const { path } = useRouteMatch();
const inner = <RoomsPaneInner onShowMenu={onShowMenu} />;
return (
<Switch>
<Route exact path={path}>
<RoomsPaneInner />
</Route>
<Route path={`${path}/:roomId`}>
<RoomsPaneInner />
{inner}
</Route>
<Route path={`${path}/:roomId`}>{inner}</Route>
</Switch>
);
};


+ 3
- 1
src/modules/user/UserList.tsx View File

@ -7,9 +7,10 @@ import UserListEntry from "modules/user/UserListEntry";
interface Props {
users: UserMap;
onShowMenu: () => void;
}
const UserList: FC<Props> = ({ users }) => {
const UserList: FC<Props> = ({ users, onShowMenu }) => {
const dispatch = useAppDispatch();
const onRefresh: ReactEventHandler = (event) => {
@ -21,6 +22,7 @@ const UserList: FC<Props> = ({ users }) => {
<SearchableList
title="Users"
onRefresh={onRefresh}
onShowMenu={onShowMenu}
component={UserListEntry}
map={users}
/>


+ 15
- 11
src/modules/user/UsersPane.tsx View File

@ -8,14 +8,6 @@ import { UserMap, selectAllUsers } from "modules/user/slice";
import UserDetails from "modules/user/UserDetails";
import UserList from "modules/user/UserList";
interface Props {
users: UserMap;
}
interface UrlParams {
userId: string;
}
interface BannerProps {
title: string;
}
@ -28,7 +20,15 @@ const UserInfoBanner: FC<BannerProps> = ({ title }) => {
);
};
const UserInfoPane: FC<Props> = ({ users }) => {
interface InfoProps {
users: UserMap;
}
interface UrlParams {
userId: string;
}
const UserInfoPane: FC<InfoProps> = ({ users }) => {
const { userId } = useParams<UrlParams>();
if (userId === undefined) {
@ -44,14 +44,18 @@ const UserInfoPane: FC<Props> = ({ users }) => {
return <UserDetails user={user} />;
};
const UsersPane: FC<{}> = () => {
interface Props {
onShowMenu: () => void;
}
const UsersPane: FC<Props> = ({ onShowMenu }) => {
const { path } = useRouteMatch();
const users = useAppSelector(selectAllUsers);
return (
<div className="h-full w-full flex">
<div className="w-80">
<UserList users={users} />
<UserList users={users} onShowMenu={onShowMenu} />
</div>
<div className="flex-grow">
<Switch>


Loading…
Cancel
Save