stop using inline styling

This commit is contained in:
EthanHealy01 2025-07-24 16:55:11 +01:00
parent 9f58dc69e8
commit 63e2791a8b
3 changed files with 281 additions and 95 deletions

View File

@ -12,12 +12,118 @@
height: 32px; 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 { .quick-access-bar {
overflow-x: auto; overflow-x: auto;
overflow-y: hidden; overflow-y: auto;
scrollbar-gutter: stable both-edges; scrollbar-gutter: stable both-edges;
-webkit-overflow-scrolling: touch; -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) */ /* Hide scrollbar by default, show on scroll (Webkit browsers - Chrome, Safari, Edge) */

View File

@ -1,4 +1,4 @@
import React, { useState } from "react"; import React, { useState, useRef } from "react";
import { ActionIcon, Stack, Tooltip, Divider } from "@mantine/core"; import { ActionIcon, Stack, Tooltip, Divider } from "@mantine/core";
import MenuBookIcon from "@mui/icons-material/MenuBookRounded"; import MenuBookIcon from "@mui/icons-material/MenuBookRounded";
import AppsIcon from "@mui/icons-material/AppsRounded"; import AppsIcon from "@mui/icons-material/AppsRounded";
@ -10,6 +10,7 @@ import NotificationsIcon from "@mui/icons-material/NotificationsRounded";
import { useRainbowThemeContext } from "./RainbowThemeProvider"; import { useRainbowThemeContext } from "./RainbowThemeProvider";
import rainbowStyles from '../../styles/rainbow.module.css'; import rainbowStyles from '../../styles/rainbow.module.css';
import AppConfigModal from './AppConfigModal'; import AppConfigModal from './AppConfigModal';
import { useIsOverflow } from '../../hooks/useIsOverflow';
import './QuickAccessBar.css'; import './QuickAccessBar.css';
interface QuickAccessBarProps { interface QuickAccessBarProps {
@ -31,15 +32,17 @@ interface ButtonConfig {
onClick: () => void; onClick: () => void;
} }
const actionIconStyle = { function NavHeader({
backgroundColor: 'var(--icon-user-bg)', activeButton,
color: 'var(--icon-user-color)', setActiveButton,
borderRadius: '50%', onReaderToggle,
width: '1.5rem', onToolsClick
height: '1.5rem', }: {
}; activeButton: string;
setActiveButton: (id: string) => void;
function NavHeader() { onReaderToggle: () => void;
onToolsClick: () => void;
}) {
return ( return (
<> <>
<div className="flex flex-row items-center justify-center mb-0" style={{ gap: '0.5rem' }}> <div className="flex flex-row items-center justify-center mb-0" style={{ gap: '0.5rem' }}>
@ -47,7 +50,7 @@ function NavHeader() {
<ActionIcon <ActionIcon
size="md" size="md"
variant="subtle" variant="subtle"
style={actionIconStyle} className="action-icon-style"
> >
<PersonIcon sx={{ fontSize: "1rem" }} /> <PersonIcon sx={{ fontSize: "1rem" }} />
</ActionIcon> </ActionIcon>
@ -56,7 +59,7 @@ function NavHeader() {
<ActionIcon <ActionIcon
size="md" size="md"
variant="subtle" variant="subtle"
style={actionIconStyle} className="action-icon-style"
> >
<NotificationsIcon sx={{ fontSize: "1rem" }} /> <NotificationsIcon sx={{ fontSize: "1rem" }} />
</ActionIcon> </ActionIcon>
@ -65,11 +68,36 @@ function NavHeader() {
{/* Divider after top icons */} {/* Divider after top icons */}
<Divider <Divider
size="xs" size="xs"
style={{ className="nav-header-divider"
width: '3.75rem',
borderColor: 'var(--color-gray-300)'
}}
/> />
{/* All Tools button below divider */}
<Tooltip label="View all available tools" position="right">
<div className="flex flex-col items-center gap-1 mt-4 mb-2">
<ActionIcon
size="lg"
variant="subtle"
onClick={() => {
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' : ''}
>
<span className="iconContainer">
<AppsIcon sx={{ fontSize: 26 }} />
</span>
</ActionIcon>
<span className={`all-tools-text ${activeButton === 'tools' ? 'active' : 'inactive'}`}>
All Tools
</span>
</div>
</Tooltip>
</> </>
); );
} }
@ -85,21 +113,10 @@ const QuickAccessBar = ({
const { isRainbowMode } = useRainbowThemeContext(); const { isRainbowMode } = useRainbowThemeContext();
const [configModalOpen, setConfigModalOpen] = useState(false); const [configModalOpen, setConfigModalOpen] = useState(false);
const [activeButton, setActiveButton] = useState<string>('tools'); const [activeButton, setActiveButton] = useState<string>('tools');
const scrollableRef = useRef<HTMLDivElement>(null);
const isOverflow = useIsOverflow(scrollableRef);
const buttonConfigs: ButtonConfig[] = [ const buttonConfigs: ButtonConfig[] = [
{
id: 'tools',
name: 'All Tools',
icon: <AppsIcon sx={{ fontSize: 26 }} />,
tooltip: 'View all available tools',
size: 'lg',
isRound: false,
onClick: () => {
setActiveButton('tools');
onReaderToggle();
onToolsClick();
}
},
{ {
id: 'read', id: 'read',
name: 'Read', name: 'Read',
@ -194,41 +211,44 @@ 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 ( return (
<div <div
className={`h-screen flex flex-col w-20 quick-access-bar ${isRainbowMode ? rainbowStyles.rainbowPaper : ''}`} className={`h-screen flex flex-col w-20 quick-access-bar-main ${isRainbowMode ? rainbowStyles.rainbowPaper : ''}`}
style={{ >
padding: '1rem 0.5rem', {/* Fixed header outside scrollable area */}
backgroundColor: 'var(--bg-muted)', <div className="quick-access-header">
width: '5rem', <NavHeader
minWidth: '5rem', activeButton={activeButton}
maxWidth: '5rem', setActiveButton={setActiveButton}
position: 'relative', onReaderToggle={onReaderToggle}
zIndex: 10 onToolsClick={onToolsClick}
}} />
</div>
{/* Conditional divider when overflowing */}
{isOverflow && (
<Divider
size="xs"
className="overflow-divider"
/>
)}
{/* Scrollable content area */}
<div
ref={scrollableRef}
className="quick-access-bar flex-1"
onWheel={(e) => { onWheel={(e) => {
// Prevent the wheel event from bubbling up to parent containers // Prevent the wheel event from bubbling up to parent containers
e.stopPropagation(); e.stopPropagation();
}} }}
> >
<Stack gap="lg" align="center" className="flex-1"> <div className="scrollable-content">
<NavHeader /> {/* Top section with main buttons */}
{buttonConfigs.map((config, index) => ( <Stack gap="lg" align="center">
{buttonConfigs.slice(0, -1).map((config, index) => (
<React.Fragment key={config.id}> <React.Fragment key={config.id}>
<Tooltip label={config.tooltip} position="right"> <Tooltip label={config.tooltip} position="right">
<div className="flex flex-col items-center gap-1"> <div className="flex flex-col items-center gap-1" style={{ marginTop: index === 0 ? '0.5rem' : "0rem" }}>
<ActionIcon <ActionIcon
size={config.size || 'xl'} size={config.size || 'xl'}
variant="subtle" variant="subtle"
@ -240,29 +260,54 @@ const QuickAccessBar = ({
{config.icon} {config.icon}
</span> </span>
</ActionIcon> </ActionIcon>
<span className="text-xs text-center leading-tight" style={getTextStyle(config)}> <span className={`button-text ${activeButton === config.id ? 'active' : 'inactive'}`}>
{config.name} {config.name}
</span> </span>
</div> </div>
</Tooltip> </Tooltip>
{/* Add divider after Automate button (index 3) */} {/* Add divider after Automate button (index 2) */}
{index === 3 && ( {index === 2 && (
<Divider <Divider
size="xs" size="xs"
style={{ className="content-divider"
width: '3.75rem',
borderColor: 'var(--color-gray-300)'
}}
/> />
)} )}
{/* Add spacer before Config button (index 7) */}
{index === 5 && <div className="flex-1" />}
</React.Fragment> </React.Fragment>
))} ))}
</Stack> </Stack>
{/* Spacer to push Config button to bottom */}
<div className="spacer" />
{/* Config button at the bottom */}
<Tooltip label="Configure settings" position="right">
<div className="flex flex-col items-center gap-1">
<ActionIcon
size="lg"
variant="subtle"
onClick={() => {
setConfigModalOpen(true);
}}
style={{
backgroundColor: 'var(--icon-inactive-bg)',
color: 'var(--icon-inactive-color)',
border: 'none',
borderRadius: '8px',
}}
>
<span className="iconContainer">
<SettingsIcon sx={{ fontSize: 16 }} />
</span>
</ActionIcon>
<span className="config-button-text">
Config
</span>
</div>
</Tooltip>
</div>
</div>
<AppConfigModal <AppConfigModal
opened={configModalOpen} opened={configModalOpen}
onClose={() => setConfigModalOpen(false)} onClose={() => setConfigModalOpen(false)}

View File

@ -0,0 +1,35 @@
import * as React from 'react';
export const useIsOverflow = (ref: React.RefObject<HTMLElement | null>, callback?: (isOverflow: boolean) => void) => {
const [isOverflow, setIsOverflow] = React.useState<boolean | undefined>(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;
};