New: Add button to close side bar

Closes #7757
This commit is contained in:
Mark McDowall 2025-10-01 20:14:30 -07:00
parent a4f210855e
commit 9484904f60
No known key found for this signature in database
4 changed files with 71 additions and 27 deletions

View file

@ -1,5 +1,4 @@
.header { .header {
z-index: 3;
display: flex; display: flex;
align-items: center; align-items: center;
flex: 0 0 auto; flex: 0 0 auto;

View file

@ -7,6 +7,40 @@
transform: translateX(0); transform: translateX(0);
} }
.sidebarHeader {
display: flex;
align-items: center;
justify-content: space-between;
height: $headerHeight;
}
.logoContainer {
display: flex;
align-items: center;
padding-left: 20px;
}
.logoLink {
line-height: 0;
}
.logo {
width: 32px;
height: 32px;
}
.sidebarCloseButton {
composes: button from '~Components/Link/IconButton.css';
margin-right: 15px;
color: #e1e2e3;
text-align: center;
&:hover {
color: var(--sonarrBlue);
}
}
.sidebar { .sidebar {
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View file

@ -1,8 +1,13 @@
// This file is automatically generated. // This file is automatically generated.
// Please do not change this file! // Please do not change this file!
interface CssExports { interface CssExports {
'logo': string;
'logoContainer': string;
'logoLink': string;
'sidebar': string; 'sidebar': string;
'sidebarCloseButton': string;
'sidebarContainer': string; 'sidebarContainer': string;
'sidebarHeader': string;
} }
export const cssExports: CssExports; export const cssExports: CssExports;
export default cssExports; export default cssExports;

View file

@ -1,4 +1,3 @@
import classNames from 'classnames';
import React, { import React, {
useCallback, useCallback,
useEffect, useEffect,
@ -11,6 +10,8 @@ import { useDispatch } from 'react-redux';
import { useLocation } from 'react-router'; import { useLocation } from 'react-router';
import QueueStatus from 'Activity/Queue/Status/QueueStatus'; import QueueStatus from 'Activity/Queue/Status/QueueStatus';
import { IconName } from 'Components/Icon'; import { IconName } from 'Components/Icon';
import IconButton from 'Components/Link/IconButton';
import Link from 'Components/Link/Link';
import OverlayScroller from 'Components/Scroller/OverlayScroller'; import OverlayScroller from 'Components/Scroller/OverlayScroller';
import Scroller from 'Components/Scroller/Scroller'; import Scroller from 'Components/Scroller/Scroller';
import usePrevious from 'Helpers/Hooks/usePrevious'; import usePrevious from 'Helpers/Hooks/usePrevious';
@ -230,10 +231,6 @@ function PageSidebar({ isSidebarVisible, isSmallScreen }: PageSidebarProps) {
transition: 'none', transition: 'none',
transform: isSidebarVisible ? 0 : SIDEBAR_WIDTH * -1, transform: isSidebarVisible ? 0 : SIDEBAR_WIDTH * -1,
}); });
const [sidebarStyle, setSidebarStyle] = useState({
top: dimensions.headerHeight,
height: `${window.innerHeight - HEADER_HEIGHT}px`,
});
const urlBase = window.Sonarr.urlBase; const urlBase = window.Sonarr.urlBase;
const pathname = urlBase const pathname = urlBase
@ -299,22 +296,6 @@ function PageSidebar({ isSidebarVisible, isSmallScreen }: PageSidebarProps) {
dispatch(setIsSidebarVisible({ isSidebarVisible: false })); dispatch(setIsSidebarVisible({ isSidebarVisible: false }));
}, [dispatch]); }, [dispatch]);
const handleWindowScroll = useCallback(() => {
const windowScroll =
window.scrollY == null
? document.documentElement.scrollTop
: window.scrollY;
const sidebarTop = Math.max(HEADER_HEIGHT - windowScroll, 0);
const sidebarHeight = window.innerHeight - sidebarTop;
if (isSmallScreen) {
setSidebarStyle({
top: `${sidebarTop}px`,
height: `${sidebarHeight}px`,
});
}
}, [isSmallScreen]);
const handleTouchStart = useCallback( const handleTouchStart = useCallback(
(event: TouchEvent) => { (event: TouchEvent) => {
const touches = event.touches; const touches = event.touches;
@ -396,10 +377,13 @@ function PageSidebar({ isSidebarVisible, isSmallScreen }: PageSidebarProps) {
touchStartY.current = null; touchStartY.current = null;
}, []); }, []);
const handleSidebarClosePress = useCallback(() => {
dispatch(setIsSidebarVisible({ isSidebarVisible: false }));
}, [dispatch]);
useEffect(() => { useEffect(() => {
if (isSmallScreen) { if (isSmallScreen) {
window.addEventListener('click', handleWindowClick, { capture: true }); window.addEventListener('click', handleWindowClick, { capture: true });
window.addEventListener('scroll', handleWindowScroll);
window.addEventListener('touchstart', handleTouchStart); window.addEventListener('touchstart', handleTouchStart);
window.addEventListener('touchmove', handleTouchMove); window.addEventListener('touchmove', handleTouchMove);
window.addEventListener('touchend', handleTouchEnd); window.addEventListener('touchend', handleTouchEnd);
@ -408,7 +392,6 @@ function PageSidebar({ isSidebarVisible, isSmallScreen }: PageSidebarProps) {
return () => { return () => {
window.removeEventListener('click', handleWindowClick, { capture: true }); window.removeEventListener('click', handleWindowClick, { capture: true });
window.removeEventListener('scroll', handleWindowScroll);
window.removeEventListener('touchstart', handleTouchStart); window.removeEventListener('touchstart', handleTouchStart);
window.removeEventListener('touchmove', handleTouchMove); window.removeEventListener('touchmove', handleTouchMove);
window.removeEventListener('touchend', handleTouchEnd); window.removeEventListener('touchend', handleTouchEnd);
@ -417,7 +400,6 @@ function PageSidebar({ isSidebarVisible, isSmallScreen }: PageSidebarProps) {
}, [ }, [
isSmallScreen, isSmallScreen,
handleWindowClick, handleWindowClick,
handleWindowScroll,
handleTouchStart, handleTouchStart,
handleTouchMove, handleTouchMove,
handleTouchEnd, handleTouchEnd,
@ -456,13 +438,37 @@ function PageSidebar({ isSidebarVisible, isSmallScreen }: PageSidebarProps) {
return ( return (
<div <div
ref={sidebarRef} ref={sidebarRef}
className={classNames(styles.sidebarContainer)} className={styles.sidebarContainer}
style={containerStyle} style={containerStyle}
> >
{isSmallScreen ? (
<div className={styles.sidebarHeader}>
<div className={styles.logoContainer}>
<Link className={styles.logoLink} to="/">
<img
className={styles.logo}
src={`${window.Sonarr.urlBase}/Content/Images/logo.svg`}
alt="Sonarr Logo"
/>
</Link>
</div>
<IconButton
className={styles.sidebarCloseButton}
name={icons.CLOSE}
aria-label={translate('Close')}
size={20}
onPress={handleSidebarClosePress}
/>
</div>
) : null}
<ScrollerComponent <ScrollerComponent
className={styles.sidebar} className={styles.sidebar}
scrollDirection="vertical" scrollDirection="vertical"
style={sidebarStyle} style={{
height: `${window.innerHeight - HEADER_HEIGHT}px`,
}}
> >
<div> <div>
{LINKS.map((link) => { {LINKS.map((link) => {