-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10 from farabi-deriv/farabi/grwt-4891/landscape-l…
…ayout Farabi/grwt-4891/landscape-layout
- Loading branch information
Showing
13 changed files
with
317 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
# SideNav Component | ||
|
||
## Overview | ||
A responsive navigation sidebar component that appears in landscape mode, providing easy access to main application routes. | ||
|
||
## Features | ||
- Landscape-mode specific display | ||
- Active route highlighting | ||
- Icon and label navigation | ||
- React Router integration | ||
- Responsive design with Tailwind CSS | ||
|
||
## Usage | ||
|
||
### Basic Usage | ||
```tsx | ||
import { SideNav } from "@/components/SideNav"; | ||
|
||
function MainLayout() { | ||
return ( | ||
<div className="flex"> | ||
<SideNav /> | ||
{/* Other content */} | ||
</div> | ||
); | ||
} | ||
``` | ||
|
||
## Navigation Structure | ||
|
||
```typescript | ||
interface NavigationItem { | ||
path: string; // Route path | ||
icon: LucideIcon; // Lucide icon component | ||
label: string; // Navigation label | ||
} | ||
|
||
// Available routes | ||
const routes = [ | ||
{ path: '/trade', icon: BarChart2, label: 'Trade' }, | ||
{ path: '/positions', icon: Clock, label: 'Positions' }, | ||
{ path: '/menu', icon: Menu, label: 'Menu' } | ||
]; | ||
``` | ||
|
||
## Responsive Behavior | ||
- Hidden by default on portrait mode: `hidden` | ||
- Visible in landscape mode: `landscape:flex` | ||
- Fixed width: `w-16` | ||
- Full height: `h-full` | ||
|
||
## Styling | ||
Uses Tailwind CSS for styling: | ||
```tsx | ||
// Container | ||
className="hidden landscape:flex flex-col h-full w-16 border-r bg-white" | ||
|
||
// Navigation buttons | ||
className="flex flex-col items-center gap-1" | ||
|
||
// Active route highlighting | ||
className="text-primary" // Active route | ||
className="text-gray-500" // Inactive route | ||
``` | ||
|
||
## Implementation Details | ||
|
||
### Route Handling | ||
```typescript | ||
const navigate = useNavigate(); | ||
const location = useLocation(); | ||
|
||
// Active route check | ||
const isActive = location.pathname === '/route'; | ||
``` | ||
|
||
### Button Structure | ||
```tsx | ||
<button | ||
onClick={() => navigate('/route')} | ||
className={`flex flex-col items-center gap-1 ${ | ||
isActive ? 'text-primary' : 'text-gray-500' | ||
}`} | ||
> | ||
<Icon className="w-5 h-5" /> | ||
<span className="text-xs">Label</span> | ||
</button> | ||
``` | ||
|
||
## Example | ||
|
||
```tsx | ||
import { SideNav } from "@/components/SideNav"; | ||
|
||
function App() { | ||
return ( | ||
<div className="flex min-h-screen"> | ||
<SideNav /> | ||
<main className="flex-1"> | ||
{/* Main content */} | ||
</main> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import React from "react"; | ||
import { BarChart2, Clock, Menu } from "lucide-react"; | ||
import { useNavigate, useLocation } from "react-router-dom"; | ||
|
||
export const SideNav: React.FC = () => { | ||
const navigate = useNavigate(); | ||
const location = useLocation(); | ||
|
||
return ( | ||
<nav className="hidden landscape:flex flex-col h-full w-16 border-r bg-white"> | ||
<div className="flex flex-col items-center gap-6 py-6"> | ||
<button | ||
onClick={() => navigate('/trade')} | ||
className={`flex flex-col items-center gap-1 ${ | ||
location.pathname === '/trade' ? 'text-primary' : 'text-gray-500' | ||
}`} | ||
> | ||
<BarChart2 className="w-5 h-5" /> | ||
<span className="text-xs">Trade</span> | ||
</button> | ||
<button | ||
onClick={() => navigate('/positions')} | ||
className={`flex flex-col items-center gap-1 ${ | ||
location.pathname === '/positions' ? 'text-primary' : 'text-gray-500' | ||
}`} | ||
> | ||
<Clock className="w-5 h-5" /> | ||
<span className="text-xs">Positions</span> | ||
</button> | ||
<button | ||
onClick={() => navigate('/menu')} | ||
className={`flex flex-col items-center gap-1 ${ | ||
location.pathname === '/menu' ? 'text-primary' : 'text-gray-500' | ||
}`} | ||
> | ||
<Menu className="w-5 h-5" /> | ||
<span className="text-xs">Menu</span> | ||
</button> | ||
</div> | ||
</nav> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { render, screen, fireEvent } from '@testing-library/react'; | ||
import { MemoryRouter, useLocation, useNavigate } from 'react-router-dom'; | ||
import { SideNav } from '../SideNav'; | ||
|
||
// Mock react-router-dom hooks | ||
jest.mock('react-router-dom', () => ({ | ||
...jest.requireActual('react-router-dom'), | ||
useNavigate: jest.fn(), | ||
useLocation: jest.fn(), | ||
})); | ||
|
||
describe('SideNav', () => { | ||
const mockNavigate = jest.fn(); | ||
const mockLocation = { pathname: '/trade' }; | ||
|
||
beforeEach(() => { | ||
(useNavigate as jest.Mock).mockReturnValue(mockNavigate); | ||
(useLocation as jest.Mock).mockReturnValue(mockLocation); | ||
}); | ||
|
||
it('renders navigation buttons', () => { | ||
render( | ||
<MemoryRouter> | ||
<SideNav /> | ||
</MemoryRouter> | ||
); | ||
|
||
expect(screen.getByText('Trade')).toBeInTheDocument(); | ||
expect(screen.getByText('Positions')).toBeInTheDocument(); | ||
expect(screen.getByText('Menu')).toBeInTheDocument(); | ||
}); | ||
|
||
it('navigates to correct routes when buttons are clicked', () => { | ||
render( | ||
<MemoryRouter> | ||
<SideNav /> | ||
</MemoryRouter> | ||
); | ||
|
||
fireEvent.click(screen.getByText('Trade')); | ||
expect(mockNavigate).toHaveBeenCalledWith('/trade'); | ||
|
||
fireEvent.click(screen.getByText('Positions')); | ||
expect(mockNavigate).toHaveBeenCalledWith('/positions'); | ||
|
||
fireEvent.click(screen.getByText('Menu')); | ||
expect(mockNavigate).toHaveBeenCalledWith('/menu'); | ||
}); | ||
|
||
it('highlights active route', () => { | ||
render( | ||
<MemoryRouter> | ||
<SideNav /> | ||
</MemoryRouter> | ||
); | ||
|
||
const tradeButton = screen.getByText('Trade').parentElement; | ||
expect(tradeButton).toHaveClass('text-primary'); | ||
|
||
const positionsButton = screen.getByText('Positions').parentElement; | ||
expect(positionsButton).toHaveClass('text-gray-500'); | ||
}); | ||
|
||
it('is hidden in portrait and visible in landscape', () => { | ||
render( | ||
<MemoryRouter> | ||
<SideNav /> | ||
</MemoryRouter> | ||
); | ||
|
||
const nav = screen.getByRole('navigation'); | ||
expect(nav).toHaveClass('hidden landscape:flex'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { SideNav } from './SideNav'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,23 @@ | ||
import React from "react"; | ||
import { Footer } from "./Footer"; | ||
import { Header } from "./Header"; | ||
import { SideNav } from "@/components/SideNav"; | ||
|
||
interface MainLayoutProps { | ||
children: React.ReactNode; | ||
} | ||
|
||
export const MainLayout: React.FC<MainLayoutProps> = ({ children }) => { | ||
return ( | ||
<div className="flex flex-col min-h-screen"> | ||
<Header balance="10,000 USD" /> | ||
<main className="flex-1 flex flex-col"> | ||
{children} | ||
</main> | ||
<Footer /> | ||
<div className="flex min-h-screen"> | ||
<SideNav /> | ||
<div className="flex flex-col flex-1"> | ||
<Header balance="10,000 USD" /> | ||
<main className="flex-1 flex flex-col"> | ||
{children} | ||
</main> | ||
<Footer /> | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.