From 63e2791a8b83dd0e46f0beaa7acce29e06864372 Mon Sep 17 00:00:00 2001 From: EthanHealy01 Date: Thu, 24 Jul 2025 16:55:11 +0100 Subject: [PATCH] stop using inline styling --- .../src/components/shared/QuickAccessBar.css | 110 ++++++++- .../src/components/shared/QuickAccessBar.tsx | 231 +++++++++++------- frontend/src/hooks/useIsOverflow.ts | 35 +++ 3 files changed, 281 insertions(+), 95 deletions(-) create mode 100644 frontend/src/hooks/useIsOverflow.ts diff --git a/frontend/src/components/shared/QuickAccessBar.css b/frontend/src/components/shared/QuickAccessBar.css index 6f4a89aeb..b484132b8 100644 --- a/frontend/src/components/shared/QuickAccessBar.css +++ b/frontend/src/components/shared/QuickAccessBar.css @@ -12,12 +12,118 @@ height: 32px; } -/* Scrollable navbar styling - scrollbars only show when scrolling */ +/* Action icon styles */ +.action-icon-style { + background-color: var(--icon-user-bg); + color: var(--icon-user-color); + border-radius: 50%; + width: 1.5rem; + height: 1.5rem; +} + +/* Main container styles */ +.quick-access-bar-main { + background-color: var(--bg-muted); + width: 5rem; + min-width: 5rem; + max-width: 5rem; + position: relative; + z-index: 10; +} + +/* Header padding */ +.quick-access-header { + padding: 1rem 0.5rem 0.5rem 0.5rem; +} + +/* Nav header divider */ +.nav-header-divider { + width: 3.75rem; + border-color: var(--color-gray-300); + margin-top: 0.5rem; + margin-bottom: 1rem; +} + +/* All tools text styles */ +.all-tools-text { + margin-top: 0.75rem; + font-size: 0.75rem; + text-rendering: optimizeLegibility; + font-synthesis: none; +} + +.all-tools-text.active { + color: var(--text-primary); + font-weight: bold; +} + +.all-tools-text.inactive { + color: var(--color-gray-700); + font-weight: normal; +} + +/* Overflow divider */ +.overflow-divider { + width: 3.75rem; + border-color: var(--color-gray-300); + margin: 0 0.5rem; +} + +/* Scrollable content area */ .quick-access-bar { overflow-x: auto; - overflow-y: hidden; + overflow-y: auto; scrollbar-gutter: stable both-edges; -webkit-overflow-scrolling: touch; + padding: 0 0.5rem 1rem 0.5rem; +} + +/* Scrollable content container */ +.scrollable-content { + display: flex; + flex-direction: column; + height: 100%; + min-height: 100%; +} + +/* Button text styles */ +.button-text { + margin-top: 0.75rem; + font-size: 0.75rem; + text-rendering: optimizeLegibility; + font-synthesis: none; +} + +.button-text.active { + color: var(--text-primary); + font-weight: bold; +} + +.button-text.inactive { + color: var(--color-gray-700); + font-weight: normal; +} + +/* Content divider */ +.content-divider { + width: 3.75rem; + border-color: var(--color-gray-300); +} + +/* Spacer */ +.spacer { + flex: 1; + margin-top: 1rem; +} + +/* Config button text */ +.config-button-text { + margin-top: 0.75rem; + font-size: 0.75rem; + color: var(--color-gray-700); + font-weight: normal; + text-rendering: optimizeLegibility; + font-synthesis: none; } /* Hide scrollbar by default, show on scroll (Webkit browsers - Chrome, Safari, Edge) */ diff --git a/frontend/src/components/shared/QuickAccessBar.tsx b/frontend/src/components/shared/QuickAccessBar.tsx index 350e0f8e6..196fa01bb 100644 --- a/frontend/src/components/shared/QuickAccessBar.tsx +++ b/frontend/src/components/shared/QuickAccessBar.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useState, useRef } from "react"; import { ActionIcon, Stack, Tooltip, Divider } from "@mantine/core"; import MenuBookIcon from "@mui/icons-material/MenuBookRounded"; import AppsIcon from "@mui/icons-material/AppsRounded"; @@ -10,6 +10,7 @@ import NotificationsIcon from "@mui/icons-material/NotificationsRounded"; import { useRainbowThemeContext } from "./RainbowThemeProvider"; import rainbowStyles from '../../styles/rainbow.module.css'; import AppConfigModal from './AppConfigModal'; +import { useIsOverflow } from '../../hooks/useIsOverflow'; import './QuickAccessBar.css'; interface QuickAccessBarProps { @@ -31,15 +32,17 @@ interface ButtonConfig { onClick: () => void; } -const actionIconStyle = { - backgroundColor: 'var(--icon-user-bg)', - color: 'var(--icon-user-color)', - borderRadius: '50%', - width: '1.5rem', - height: '1.5rem', -}; - -function NavHeader() { +function NavHeader({ + activeButton, + setActiveButton, + onReaderToggle, + onToolsClick +}: { + activeButton: string; + setActiveButton: (id: string) => void; + onReaderToggle: () => void; + onToolsClick: () => void; +}) { return ( <>
@@ -47,7 +50,7 @@ function NavHeader() { @@ -56,7 +59,7 @@ function NavHeader() { @@ -65,11 +68,36 @@ function NavHeader() { {/* Divider after top icons */} + {/* All Tools button below divider */} + +
+ { + setActiveButton('tools'); + onReaderToggle(); + onToolsClick(); + }} + style={{ + backgroundColor: activeButton === 'tools' ? 'var(--icon-tools-bg)' : 'var(--icon-inactive-bg)', + color: activeButton === 'tools' ? 'var(--icon-tools-color)' : 'var(--icon-inactive-color)', + border: 'none', + borderRadius: '8px', + }} + className={activeButton === 'tools' ? 'activeIconScale' : ''} + > + + + + + + All Tools + +
+
); } @@ -85,21 +113,10 @@ const QuickAccessBar = ({ const { isRainbowMode } = useRainbowThemeContext(); const [configModalOpen, setConfigModalOpen] = useState(false); const [activeButton, setActiveButton] = useState('tools'); + const scrollableRef = useRef(null); + const isOverflow = useIsOverflow(scrollableRef); const buttonConfigs: ButtonConfig[] = [ - { - id: 'tools', - name: 'All Tools', - icon: , - tooltip: 'View all available tools', - size: 'lg', - isRound: false, - onClick: () => { - setActiveButton('tools'); - onReaderToggle(); - onToolsClick(); - } - }, { id: 'read', name: 'Read', @@ -194,74 +211,102 @@ const QuickAccessBar = ({ }; }; - const getTextStyle = (config: ButtonConfig) => { - const isActive = activeButton === config.id; - return { - marginTop: '0.75rem', - fontSize: '0.75rem', - color: isActive ? 'var(--text-primary)' : 'var(--color-gray-700)', - fontWeight: isActive ? 'bold' : 'normal', - textRendering: 'optimizeLegibility' as const, - fontSynthesis: 'none' as const - }; - }; - return (
{ - // Prevent the wheel event from bubbling up to parent containers - e.stopPropagation(); - }} + className={`h-screen flex flex-col w-20 quick-access-bar-main ${isRainbowMode ? rainbowStyles.rainbowPaper : ''}`} > - - - {buttonConfigs.map((config, index) => ( - - -
- - - {config.icon} - - - - {config.name} + {/* Fixed header outside scrollable area */} +
+ +
+ + {/* Conditional divider when overflowing */} + {isOverflow && ( + + )} + + {/* Scrollable content area */} +
{ + // Prevent the wheel event from bubbling up to parent containers + e.stopPropagation(); + }} + > +
+ {/* Top section with main buttons */} + + {buttonConfigs.slice(0, -1).map((config, index) => ( + + +
+ + + {config.icon} + + + + {config.name} + +
+
+ + {/* Add divider after Automate button (index 2) */} + {index === 2 && ( + + )} +
+ ))} +
+ + {/* Spacer to push Config button to bottom */} +
+ + {/* Config button at the bottom */} + +
+ { + setConfigModalOpen(true); + }} + style={{ + backgroundColor: 'var(--icon-inactive-bg)', + color: 'var(--icon-inactive-color)', + border: 'none', + borderRadius: '8px', + }} + > + + -
-
- - {/* Add divider after Automate button (index 3) */} - {index === 3 && ( - - )} - - {/* Add spacer before Config button (index 7) */} - {index === 5 &&
} - - ))} - + + + Config + +
+ +
+
, callback?: (isOverflow: boolean) => void) => { + const [isOverflow, setIsOverflow] = React.useState(undefined); + + React.useLayoutEffect(() => { + const { current } = ref; + + const trigger = () => { + if (!current) return; + + const hasOverflow = current.scrollHeight > current.clientHeight; + setIsOverflow(hasOverflow); + + if (callback) callback(hasOverflow); + }; + + if (current) { + if ('ResizeObserver' in window) { + const resizeObserver = new ResizeObserver(trigger); + resizeObserver.observe(current); + + // Cleanup function + return () => { + resizeObserver.disconnect(); + }; + } + + // Add a small delay to ensure the element is fully rendered + setTimeout(trigger, 0); + } + }, [callback, ref]); + + return isOverflow; +}; \ No newline at end of file