forked from djeck1432/spotnet
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
512 additions
and
119 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
110 changes: 110 additions & 0 deletions
110
frontend/src/components/ui/Components/Sidebar/Sidebar.css
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,110 @@ | ||
.sidebar { | ||
background-color: black; | ||
border-right: 1px solid #300734; | ||
display: none; | ||
color: #83919F; | ||
} | ||
|
||
|
||
@media (min-width: 1024px) { | ||
.sidebar { | ||
display: block; | ||
} | ||
} | ||
|
||
.sidebar-sticky { | ||
position: absolute; | ||
top: 0px; | ||
height: calc(100vh - 50px); | ||
overflow-y: auto; | ||
width: 20%; | ||
} | ||
|
||
/* Title styles */ | ||
.sidebar-title { | ||
padding: 12px 8px; | ||
border-bottom: 1px solid #e5e7eb; | ||
} | ||
|
||
.sidebar-title h2 { | ||
font-size: 18px; | ||
font-weight: 600; | ||
color: #d6d6d6; | ||
} | ||
|
||
/* Navigation styles */ | ||
.sidebar-nav { | ||
display: flex; | ||
flex-direction: column; | ||
padding: 8px 0; | ||
} | ||
|
||
/* Item styles */ | ||
.sidebar-item-wrapper { | ||
width: 100%; | ||
} | ||
|
||
.sidebar-item { | ||
width: 100%; | ||
display: flex; | ||
align-items: center; | ||
padding: 8px 16px; | ||
font-size: 14px; | ||
color: #374151; | ||
text-decoration: none; | ||
transition: background-color 0.2s, color 0.2s; | ||
border: none; | ||
background: none; | ||
cursor: pointer; | ||
text-align: left; | ||
} | ||
|
||
.sidebar-item:hover { | ||
color: white; | ||
} | ||
|
||
.sidebar-item.active { | ||
color: white; | ||
} | ||
|
||
.sidebar-item.nested { | ||
padding-left: 32px; | ||
} | ||
|
||
/* Icon styles */ | ||
.item-icon { | ||
margin-right: 8px; | ||
display: flex; | ||
align-items: center; | ||
} | ||
|
||
.item-name { | ||
flex: 1; | ||
} | ||
|
||
.expand-icon { | ||
margin-left: 8px; | ||
} | ||
|
||
/* Nested items container */ | ||
.nested-items { | ||
margin-left: 16px; | ||
} | ||
|
||
/* Scrollbar styles */ | ||
.sidebar-sticky::-webkit-scrollbar { | ||
width: 4px; | ||
} | ||
|
||
.sidebar-sticky::-webkit-scrollbar-track { | ||
background: #f1f1f1; | ||
} | ||
|
||
.sidebar-sticky::-webkit-scrollbar-thumb { | ||
background: #888; | ||
border-radius: 4px; | ||
} | ||
|
||
.sidebar-sticky::-webkit-scrollbar-thumb:hover { | ||
background: #555; | ||
} |
130 changes: 130 additions & 0 deletions
130
frontend/src/components/ui/Components/Sidebar/Sidebar.jsx
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,130 @@ | ||
import React, { useState, useEffect } from 'react'; | ||
import { Link, useLocation } from 'react-router-dom'; | ||
import { ChevronDown, ChevronUp } from 'lucide-react'; | ||
import './Sidebar.css'; | ||
|
||
const Sidebar = ({ | ||
title, | ||
items, | ||
className = '' | ||
}) => { | ||
const location = useLocation(); | ||
const [activeItemId, setActiveItemId] = useState(''); | ||
const [expandedItems, setExpandedItems] = useState({}); | ||
|
||
useEffect(() => { | ||
// Handle hash changes for scroll navigation | ||
const hash = location.hash.replace('#', ''); | ||
if (hash) { | ||
setActiveItemId(hash); | ||
const element = document.getElementById(hash); | ||
if (element) { | ||
element.scrollIntoView({ behavior: 'smooth' }); | ||
} | ||
} | ||
|
||
// Find and set active item based on current path | ||
const currentPath = location.pathname; | ||
items.forEach(item => { | ||
if (item.link === currentPath) { | ||
setActiveItemId(item.id); | ||
} | ||
if (item.children) { | ||
item.children.forEach(child => { | ||
if (child.link === currentPath) { | ||
setActiveItemId(child.id); | ||
setExpandedItems(prev => ({ ...prev, [item.id]: true })); | ||
} | ||
}); | ||
} | ||
}); | ||
}, [location, items]); | ||
|
||
const handleItemClick = (item) => { | ||
if (item.children) { | ||
// Toggle expansion for items with children | ||
setExpandedItems(prev => ({ | ||
...prev, | ||
[item.id]: !prev[item.id] | ||
})); | ||
} else if (item.link.startsWith('#')) { | ||
// Handle hash navigation | ||
const elementId = item.link.replace('#', ''); | ||
const element = document.getElementById(elementId); | ||
if (element) { | ||
element.scrollIntoView({ behavior: 'smooth' }); | ||
setActiveItemId(item.id); | ||
// Update URL with hash | ||
window.history.pushState(null, '', item.link); | ||
} | ||
} | ||
}; | ||
|
||
const renderSidebarItem = (item, level = 0) => { | ||
const isActive = activeItemId === item.id; | ||
const isExpanded = expandedItems[item.id]; | ||
const hasChildren = item.children && item.children.length > 0; | ||
const itemClass = `sidebar-item ${isActive ? 'active' : ''} ${level > 0 ? 'nested' : ''}`; | ||
|
||
return ( | ||
<div key={item.id} className="sidebar-item-wrapper"> | ||
{item.link.startsWith('#') ? ( | ||
<button | ||
onClick={() => handleItemClick(item)} | ||
className={itemClass} | ||
> | ||
{item.icon && ( | ||
<span className="item-icon"> | ||
<img src={item.icon} alt={item.name} /> | ||
</span> | ||
)} | ||
<span className="item-name">{item.name}</span> | ||
{hasChildren && ( | ||
<span className="expand-icon"> | ||
{isExpanded ? <ChevronUp size={16} /> : <ChevronDown size={16} />} | ||
</span> | ||
)} | ||
</button> | ||
) : ( | ||
<Link | ||
to={item.link} | ||
className={itemClass} | ||
> | ||
{item.icon && ( | ||
<span className="item-icon"> | ||
<img src={item.icon} alt={item.name} /> | ||
</span> | ||
)} | ||
<span className="item-name">{item.name}</span> | ||
{hasChildren && ( | ||
<span className="expand-icon"> | ||
{isExpanded ? <ChevronUp size={16} /> : <ChevronDown size={16} />} | ||
</span> | ||
)} | ||
</Link> | ||
)} | ||
|
||
{hasChildren && isExpanded && ( | ||
<div className="nested-items"> | ||
{item.children.map(child => renderSidebarItem(child, level + 1))} | ||
</div> | ||
)} | ||
</div> | ||
); | ||
}; | ||
|
||
return ( | ||
<div className={`sidebar ${className}`}> | ||
{title && ( | ||
<div className="sidebar-title"> | ||
<h2>{title}</h2> | ||
</div> | ||
)} | ||
<nav className="sidebar-nav"> | ||
{items.map(item => renderSidebarItem(item))} | ||
</nav> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Sidebar; |
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
Oops, something went wrong.