feat: add mobile responsive support (768px breakpoint)
- Add CSS media queries for all sections: sidebar overlay, navbar, calendar, kanban, dashboard, list view, drawer, modal, reports, team tasks, members - Add hamburger menu button (hidden on desktop, visible on mobile) - Add sidebar slide-in overlay with backdrop for mobile - Auto-close sidebar on navigation for mobile UX - Login card, drawer, and modal go full-width on mobile - Dashboard stats grid collapses to 2-column on mobile - Report charts stack to single column on mobile
This commit is contained in:
@@ -34,6 +34,7 @@ export default function App() {
|
|||||||
const [calView, setCalView] = useState('month');
|
const [calView, setCalView] = useState('month');
|
||||||
const [filterUser, setFilterUser] = useState<string | null>(null);
|
const [filterUser, setFilterUser] = useState<string | null>(null);
|
||||||
const [searchQuery, setSearchQuery] = useState('');
|
const [searchQuery, setSearchQuery] = useState('');
|
||||||
|
const [sidebarOpen, setSidebarOpen] = useState(false);
|
||||||
const [quickAddDay, setQuickAddDay] = useState<{ date: string; rect: { top: number; left: number } } | null>(null);
|
const [quickAddDay, setQuickAddDay] = useState<{ date: string; rect: { top: number; left: number } } | null>(null);
|
||||||
|
|
||||||
if (!currentUser) return <LoginPage onLogin={u => { setCurrentUser(u); setActivePage('calendar'); setActiveView('calendar'); }} />;
|
if (!currentUser) return <LoginPage onLogin={u => { setCurrentUser(u); setActivePage('calendar'); setActiveView('calendar'); }} />;
|
||||||
@@ -41,6 +42,7 @@ export default function App() {
|
|||||||
const handleNavigate = (page: string) => {
|
const handleNavigate = (page: string) => {
|
||||||
setActivePage(page);
|
setActivePage(page);
|
||||||
if (VIEW_PAGES.includes(page)) setActiveView(page);
|
if (VIEW_PAGES.includes(page)) setActiveView(page);
|
||||||
|
setSidebarOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleViewChange = (view: string) => {
|
const handleViewChange = (view: string) => {
|
||||||
@@ -88,10 +90,12 @@ export default function App() {
|
|||||||
return (
|
return (
|
||||||
<div className="app-shell">
|
<div className="app-shell">
|
||||||
<TopNavbar title={pageTitle} filterUser={filterUser} onFilterChange={setFilterUser}
|
<TopNavbar title={pageTitle} filterUser={filterUser} onFilterChange={setFilterUser}
|
||||||
searchQuery={searchQuery} onSearch={setSearchQuery} onNewTask={handleNewTask} />
|
searchQuery={searchQuery} onSearch={setSearchQuery} onNewTask={handleNewTask}
|
||||||
|
onOpenSidebar={() => setSidebarOpen(true)} />
|
||||||
<div className="app-body">
|
<div className="app-body">
|
||||||
<Sidebar currentUser={currentUser} activePage={activePage} onNavigate={handleNavigate}
|
<Sidebar currentUser={currentUser} activePage={activePage} onNavigate={handleNavigate}
|
||||||
onSignOut={() => { setCurrentUser(null); setActivePage('calendar'); setActiveView('calendar'); }} />
|
onSignOut={() => { setCurrentUser(null); setActivePage('calendar'); setActiveView('calendar'); setSidebarOpen(false); }}
|
||||||
|
isOpen={sidebarOpen} onClose={() => setSidebarOpen(false)} />
|
||||||
<div className="main-content">
|
<div className="main-content">
|
||||||
{displayPage === 'calendar' && (
|
{displayPage === 'calendar' && (
|
||||||
<CalendarView tasks={tasks} currentUser={currentUser} calMonth={calMonth} calView={calView}
|
<CalendarView tasks={tasks} currentUser={currentUser} calMonth={calMonth} calView={calView}
|
||||||
|
|||||||
@@ -8,11 +8,13 @@ interface TopNavbarProps {
|
|||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
onSearch: (q: string) => void;
|
onSearch: (q: string) => void;
|
||||||
onNewTask: () => void;
|
onNewTask: () => void;
|
||||||
|
onOpenSidebar: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TopNavbar({ title, filterUser, onFilterChange, searchQuery, onSearch, onNewTask }: TopNavbarProps) {
|
export function TopNavbar({ title, filterUser, onFilterChange, searchQuery, onSearch, onNewTask, onOpenSidebar }: TopNavbarProps) {
|
||||||
return (
|
return (
|
||||||
<div className="top-navbar">
|
<div className="top-navbar">
|
||||||
|
<button className="hamburger-btn" onClick={onOpenSidebar}>☰</button>
|
||||||
<span className="navbar-title">{title}</span>
|
<span className="navbar-title">{title}</span>
|
||||||
<div className="navbar-search">
|
<div className="navbar-search">
|
||||||
<span className="navbar-search-icon">🔍</span>
|
<span className="navbar-search-icon">🔍</span>
|
||||||
|
|||||||
@@ -17,12 +17,16 @@ interface SidebarProps {
|
|||||||
activePage: string;
|
activePage: string;
|
||||||
onNavigate: (page: string) => void;
|
onNavigate: (page: string) => void;
|
||||||
onSignOut: () => void;
|
onSignOut: () => void;
|
||||||
|
isOpen: boolean;
|
||||||
|
onClose: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Sidebar({ currentUser, activePage, onNavigate, onSignOut }: SidebarProps) {
|
export function Sidebar({ currentUser, activePage, onNavigate, onSignOut, isOpen, onClose }: SidebarProps) {
|
||||||
const filteredNav = NAV_ITEMS.filter(n => n.roles.includes(currentUser.role));
|
const filteredNav = NAV_ITEMS.filter(n => n.roles.includes(currentUser.role));
|
||||||
return (
|
return (
|
||||||
<div className="sidebar">
|
<>
|
||||||
|
{isOpen && <div className="sidebar-backdrop visible" onClick={onClose} />}
|
||||||
|
<div className={`sidebar ${isOpen ? 'sidebar-open' : ''}`}>
|
||||||
<div className="sidebar-logo">
|
<div className="sidebar-logo">
|
||||||
<div className="sidebar-logo-icon">⚡</div>
|
<div className="sidebar-logo-icon">⚡</div>
|
||||||
<span className="sidebar-logo-text">Scrum-manager</span>
|
<span className="sidebar-logo-text">Scrum-manager</span>
|
||||||
@@ -48,5 +52,7 @@ export function Sidebar({ currentUser, activePage, onNavigate, onSignOut }: Side
|
|||||||
<button className="sidebar-signout" onClick={onSignOut}>Sign Out</button>
|
<button className="sidebar-signout" onClick={onSignOut}>Sign Out</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2498
src/index.css
2498
src/index.css
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user