Skip to content

Commit

Permalink
release 0.0.4 (#7)
Browse files Browse the repository at this point in the history
* feat: navigation bar (#6)
  • Loading branch information
SchneiderNicolas committed Sep 19, 2023
1 parent 9841180 commit 70f9c3c
Show file tree
Hide file tree
Showing 22 changed files with 498 additions and 45 deletions.
41 changes: 41 additions & 0 deletions front/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"react-cookie": "^6.1.1",
"react-dom": "^18.2.0",
"react-icons": "^4.11.0",
"react-responsive": "^9.0.2",
"react-router-dom": "^6.16.0",
"react-scripts": "^5.0.1",
"tailwindcss": "^3.3.3",
Expand Down
37 changes: 27 additions & 10 deletions front/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,41 @@
import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { BrowserRouter, Route, Routes, useLocation } from 'react-router-dom';
import Home from './pages/Home';
import SignIn from './pages/SignIn';
import SignUp from './pages/SignUp';
import ProtectedRoute from './components/ProtectedRoute';
import Sidebar from './components/Sidebar';
import Settings from './pages/Settings';

const App = () => {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/signin" element={<SignIn />} />
<Route path="/signup" element={<SignUp />} />

<Route path="/" element={<ProtectedRoute />}>
<Route index element={<Home />} />
</Route>
</Routes>
<div className="flex">
<ConditionalSidebar />
<div className="flex-grow">
<Routes>
<Route path="/signin" element={<SignIn />} />
<Route path="/signup" element={<SignUp />} />
<Route path="/" element={<ProtectedRoute />}>
<Route index element={<Home />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
</div>
</div>
</BrowserRouter>
);
};

const ConditionalSidebar = () => {
const location = useLocation();
const path = location.pathname;

if (path === '/signin' || path === '/signup') {
return null;
}

return <Sidebar />;
};

export default App;
4 changes: 2 additions & 2 deletions front/src/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ function Button({
let buttonClassName = '';
if (variant === 'text') {
buttonClassName +=
'font-semibold text-gray-400 hover:underline hover:underline-offset-4 hover:text-lime-500';
'font-semibold text-gray-400 hover:underline hover:underline-offset-4 hover:text-violet-500';
} else {
buttonClassName +=
'text-white bg-lime-500 hover:bg-lime-600 focus:ring-2 focus:outline-none focus:ring-lime-400 font-medium rounded-lg text-sm px-4 py-2 text-center mr-3 md:mr-0';
'text-white bg-violet-500 hover:bg-violet-600 focus:ring-2 focus:outline-none focus:ring-violet-600 font-medium rounded-lg text-sm px-4 py-2 text-center mr-3 md:mr-0';
}
if (disabled) {
buttonClassName =
Expand Down
4 changes: 2 additions & 2 deletions front/src/components/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function Input({
<input
value={inputValue}
type={inputType}
className="block px-2.5 pb-2.5 pt-4 w-full text-sm text-gray-900 bg-transparent rounded appearance-none focus:outline-none ring-2 ring-gray-200 focus:ring-lime-400 focus:border-lime-400 peer"
className="block px-2.5 pb-2.5 pt-4 w-full text-sm text-gray-900 bg-transparent rounded appearance-none focus:outline-none ring-2 ring-gray-200 focus:ring-violet-500 focus:border-violet-500 peer"
placeholder=" "
onChange={handleInputChange}
onFocus={onFocus}
Expand Down Expand Up @@ -90,7 +90,7 @@ function Input({
)}
<label
htmlFor={id}
className={`cursor-text absolute text-sm text-gray-400 duration-300 transform -translate-y-4 scale-75 top-2 z-10 origin-[0] ${labelBgColor} px-2 peer-focus:px-2 peer-focus:text-lime-400 peer-placeholder-shown:scale-100 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-1/2 peer-focus:top-2 peer-focus:scale-75 peer-focus:-translate-y-4 left-1`}
className={`cursor-text absolute text-sm text-gray-400 duration-300 transform -translate-y-4 scale-75 top-2 z-10 origin-[0] ${labelBgColor} px-2 peer-focus:px-2 peer-focus:text-violet-500 peer-placeholder-shown:scale-100 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-1/2 peer-focus:top-2 peer-focus:scale-75 peer-focus:-translate-y-4 left-1`}
>
{placeholder}
</label>
Expand Down
170 changes: 170 additions & 0 deletions front/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
import React, { ReactNode, useEffect, useState } from 'react';
import { useSideBar } from '../hooks/useSideBar';
import { useResponsive } from '../hooks/useResponsive';
import { RxArrowLeft, RxChatBubble, RxGear, RxExit } from 'react-icons/rx';
import { BsWifi, BsWifiOff } from 'react-icons/bs';
import { useNavigate, useLocation } from 'react-router-dom';
import { useCleanCookiesAndDisconnect } from '../hooks/useCleanCookiesAndDisconnect';
import { useCookies } from 'react-cookie';
import { TopBar } from './TopBar';
import Tooltip from './Tooltip';

export type SidebarButtonProps = {
name: string;
icon: ReactNode;
onClick: () => void;
isMobile: boolean;
path: string;
};

const SidebarButton = ({
name,
icon,
onClick,
isMobile,
path,
tooltipText,
}: SidebarButtonProps & { tooltipText?: string }) => {
const location = useLocation();
const isActive = location.pathname === path;

return (
<Tooltip
isMobile={isMobile}
tooltipText={tooltipText || name}
position="right"
>
<div
className={`cursor-pointer flex items-center p-2 text-base font-semibold text-violet-500 rounded-lg ${
isActive ? 'bg-violet-50' : ''
} hover:bg-violet-50`}
onClick={onClick}
>
{icon}
{isMobile && (
<span className="flex-1 ml-3 whitespace-nowrap">{name}</span>
)}
</div>
</Tooltip>
);
};

interface SidebarType {
children?: ReactNode;
}

const Sidebar = (props: SidebarType) => {
const { isOpen, toggle } = useSideBar();
const { isMobile } = useResponsive();
const [cookies] = useCookies(['userName']);
const cleanCookiesAndDisconnect = useCleanCookiesAndDisconnect();
const navigate = useNavigate();

const onClickHome = () => {
navigate('/');
};

const onClickSettings = () => {
navigate('/settings');
};

const onClickDisconnect = () => {
cleanCookiesAndDisconnect();
navigate('/signin');
};

const [isOnline, setIsOnline] = useState(navigator.onLine);

useEffect(() => {
const updateOnlineStatus = () => setIsOnline(navigator.onLine);

window.addEventListener('online', updateOnlineStatus);
window.addEventListener('offline', updateOnlineStatus);

return () => {
window.removeEventListener('online', updateOnlineStatus);
window.removeEventListener('offline', updateOnlineStatus);
};
}, []);

return (
<>
<TopBar toggle={toggle} isMobile={isMobile} />

<aside
id="default-sidebar"
className={`fixed top-0 left-0 z-40 h-screen transition-transform md:translate-x-0 ${
!isOpen ? '-translate-x-full' : ''
} ${isMobile ? 'w-60' : 'border-r border-gray-200'}`}
aria-label="Sidebar"
>
<div className="h-full px-2 py-2 md:py-0 overflow-y-auto bg-white">
<div className="flex items-center p-2">
{isMobile && (
<>
<div className="font-bold ml-2 text-lg text-violet-600">
{cookies.userName}
</div>
<RxArrowLeft
className="absolute right-0 mr-4 hover:bg-violet-50 rounded-md"
onClick={toggle}
size={30}
color={'#8b5cf6'}
/>
</>
)}
</div>

<div className={`space-y-3 ${isMobile ? 'mt-10' : ''}`}>
<SidebarButton
name="Discussions"
icon={<RxChatBubble size={24} color={'#8b5cf6'} />}
onClick={onClickHome}
isMobile={isMobile}
path="/"
tooltipText="Discussions"
/>
<SidebarButton
name="Settings"
icon={<RxGear size={24} color={'#8b5cf6'} />}
onClick={onClickSettings}
isMobile={isMobile}
path="/settings"
tooltipText="Settings"
/>
<SidebarButton
name="Disconnect"
icon={<RxExit size={24} color={'#8b5cf6'} />}
onClick={onClickDisconnect}
isMobile={isMobile}
path=""
tooltipText="Disconnect"
/>
<Tooltip
position="right"
tooltipText={isOnline ? 'Connected' : 'Offline'}
isMobile={isMobile}
>
<div className="flex items-center p-2">
{isOnline ? (
<BsWifi size={24} color={'#8b5cf6'} />
) : (
<BsWifiOff size={24} color={'#8b5cf6'} />
)}
{isMobile && (
<span className="flex-1 ml-3 whitespace-nowrap text-base font-semibold text-violet-500">
{isOnline ? 'Connected' : 'Offline'}
</span>
)}
</div>
</Tooltip>
</div>
</div>
</aside>

<div className="min-h-screen md:px-7 p-0">{props.children}</div>
</>
);
};

export default Sidebar;
Loading

0 comments on commit 70f9c3c

Please sign in to comment.