clarify what search results is doing, better variable names/function names and comments

This commit is contained in:
EthanHealy01 2025-08-15 17:48:19 +01:00
parent d664666ff8
commit 359a164751
5 changed files with 99 additions and 57 deletions

View File

@ -12,7 +12,7 @@ import { useToolWorkflow } from '../../contexts/ToolWorkflowContext';
import { ButtonConfig } from '../../types/sidebar';
import './quickAccessBar/QuickAccessBar.css';
import AllToolsNavButton from './AllToolsNavButton';
import TopToolIndicator from './quickAccessBar/TopToolIndicator';
import ActiveToolButton from "./quickAccessBar/ActiveToolButton";
import {
isNavButtonActive,
getNavButtonStyle,
@ -129,7 +129,7 @@ const QuickAccessBar = forwardRef<HTMLDivElement>(({
>
{/* Fixed header outside scrollable area */}
<div className="quick-access-header">
<TopToolIndicator activeButton={activeButton} setActiveButton={setActiveButton} />
<ActiveToolButton activeButton={activeButton} setActiveButton={setActiveButton} />
<AllToolsNavButton activeButton={activeButton} setActiveButton={setActiveButton} />
</div>

View File

@ -1,3 +1,17 @@
/**
* ActiveToolButton - Shows the currently selected tool at the top of the Quick Access Bar
*
* When a user selects a tool from the All Tools list, this component displays the tool's
* icon and name at the top of the navigation bar. It provides a quick way to see which
* tool is currently active and offers a back button to return to the All Tools list.
*
* Features:
* - Shows tool icon and name when a tool is selected
* - Hover to reveal back arrow for returning to All Tools
* - Smooth slide-down/slide-up animations
* - Only appears for tools that don't have dedicated nav buttons (read, sign, automate)
*/
import React, { useEffect, useRef, useState } from 'react';
import { ActionIcon, Divider } from '@mantine/core';
import ArrowBackRoundedIcon from '@mui/icons-material/ArrowBackRounded';
@ -5,14 +19,14 @@ import { useToolWorkflow } from '../../../contexts/ToolWorkflowContext';
import FitText from '../FitText';
import { Tooltip } from '../Tooltip';
interface TopToolIndicatorProps {
interface ActiveToolButtonProps {
activeButton: string;
setActiveButton: (id: string) => void;
}
const NAV_IDS = ['read','sign','automate'];
const NAV_IDS = ['read', 'sign', 'automate'];
const TopToolIndicator: React.FC<TopToolIndicatorProps> = ({ activeButton, setActiveButton }) => {
const ActiveToolButton: React.FC<ActiveToolButtonProps> = ({ activeButton, setActiveButton }) => {
const { selectedTool, selectedToolKey, leftPanelView, handleBackToTools } = useToolWorkflow();
// Determine if the indicator should be visible
@ -28,10 +42,10 @@ const TopToolIndicator: React.FC<TopToolIndicatorProps> = ({ activeButton, setAc
const [isBackHover, setIsBackHover] = useState<boolean>(false);
const prevKeyRef = useRef<string | null>(null);
useEffect(() => {
if (indicatorShouldShow) {
// If switching to a different tool while visible, replay the grow down
if (prevKeyRef.current && prevKeyRef.current !== selectedToolKey) {
const isSwitchingToNewTool = () => { return prevKeyRef.current && prevKeyRef.current !== selectedToolKey };
const playGrowDown = () => {
setIndicatorTool(selectedTool);
setIndicatorVisible(true);
setReplayAnim(true);
@ -42,15 +56,17 @@ const TopToolIndicator: React.FC<TopToolIndicatorProps> = ({ activeButton, setAc
}, 500);
return () => window.clearTimeout(t);
}
// First show
const firstShow = () => {
setIndicatorTool(selectedTool);
setIndicatorVisible(true);
setIsAnimating(true);
prevKeyRef.current = (selectedToolKey as string) || null;
const tShow = window.setTimeout(() => setIsAnimating(false), 500);
return () => window.clearTimeout(tShow);
} else if (indicatorTool) {
// trigger collapse
}
const triggerCollapse = () => {
setIndicatorVisible(false);
setIsAnimating(true);
const timeout = window.setTimeout(() => {
@ -60,11 +76,21 @@ const TopToolIndicator: React.FC<TopToolIndicatorProps> = ({ activeButton, setAc
}, 500); // match CSS transition duration
return () => window.clearTimeout(timeout);
}
useEffect(() => {
if (indicatorShouldShow) {
if (isSwitchingToNewTool()) {
playGrowDown();
}
firstShow()
} else if (indicatorTool) {
triggerCollapse();
}
}, [indicatorShouldShow, selectedTool, selectedToolKey]);
return (
<>
<div style={{overflow:'visible'}} className={`current-tool-slot ${indicatorVisible ? 'visible' : ''} ${replayAnim ? 'replay' : ''}`}>
<div style={{ overflow: 'visible' }} className={`current-tool-slot ${indicatorVisible ? 'visible' : ''} ${replayAnim ? 'replay' : ''}`}>
{indicatorTool && (
<div className="current-tool-content">
<div className="flex flex-col items-center gap-1">
@ -80,7 +106,7 @@ const TopToolIndicator: React.FC<TopToolIndicatorProps> = ({ activeButton, setAc
}}
aria-label={isBackHover ? 'Back to all tools' : indicatorTool.name}
style={{
backgroundColor: isBackHover ? '#9CA3AF' : 'var(--icon-tools-bg)',
backgroundColor: isBackHover ? 'var(--color-gray-300)' : 'var(--icon-tools-bg)',
color: isBackHover ? '#fff' : 'var(--icon-tools-color)',
border: 'none',
borderRadius: '8px',
@ -114,6 +140,6 @@ const TopToolIndicator: React.FC<TopToolIndicatorProps> = ({ activeButton, setAc
);
};
export default TopToolIndicator;
export default ActiveToolButton;

View File

@ -9,27 +9,38 @@ interface SearchResultsProps {
}
const SearchResults: React.FC<SearchResultsProps> = ({ filteredTools, onSelect }) => {
const groups = useMemo(() => {
const subMap: Record<string, Array<{ id: string; tool: ToolRegistryEntry }>> = {};
const seen = new Set<string>();
// Group tools by subcategory and remove duplicates
const groupedToolsByCategory = useMemo(() => {
const categoryToToolsMap: Record<string, Array<{ id: string; tool: ToolRegistryEntry }>> = {};
const processedToolIds = new Set<string>();
filteredTools.forEach(([id, tool]) => {
if (seen.has(id)) return;
seen.add(id);
const sub = tool?.subcategory || 'General';
if (!subMap[sub]) subMap[sub] = [];
subMap[sub].push({ id, tool });
// Process each tool, skipping duplicates and grouping by subcategory
filteredTools.forEach(([toolId, toolEntry]) => {
// Skip if we've already processed this tool ID (deduplication)
if (processedToolIds.has(toolId)) return;
processedToolIds.add(toolId);
// Use subcategory or default to 'General' if not specified
const categoryName = toolEntry?.subcategory || 'General';
// Initialize category array if it doesn't exist
if (!categoryToToolsMap[categoryName]) {
categoryToToolsMap[categoryName] = [];
}
categoryToToolsMap[categoryName].push({ id: toolId, tool: toolEntry });
});
return Object.entries(subMap)
.sort(([a], [b]) => a.localeCompare(b))
.map(([subcategory, tools]) => ({
subcategory,
tools
// Convert to sorted array format for rendering
return Object.entries(categoryToToolsMap)
.sort(([categoryA], [categoryB]) => categoryA.localeCompare(categoryB))
.map(([categoryName, toolsInCategory]) => ({
categoryName,
toolsInCategory
}));
}, [filteredTools]);
if (groups.length === 0) {
if (groupedToolsByCategory.length === 0) {
return (
<Text c="dimmed" size="sm" p="sm">
No tools found
@ -39,13 +50,13 @@ const SearchResults: React.FC<SearchResultsProps> = ({ filteredTools, onSelect }
return (
<Stack p="sm" gap="xs">
{groups.map(group => (
<Box key={group.subcategory} w="100%">
{groupedToolsByCategory.map(categoryGroup => (
<Box key={categoryGroup.categoryName} w="100%">
<Text size="sm" fw={500} mb="0.25rem" mt="1rem" className="tool-subcategory-title">
{group.subcategory}
{categoryGroup.categoryName}
</Text>
<Stack gap="xs">
{group.tools.map(({ id, tool }) => (
{categoryGroup.toolsInCategory.map(({ id, tool }) => (
<ToolButton
key={id}
id={id}
@ -59,7 +70,7 @@ const SearchResults: React.FC<SearchResultsProps> = ({ filteredTools, onSelect }
</Box>
))}
{/* global spacer to allow scrolling past last row in search mode */}
<div aria-hidden style={{ height: 44 * 4 }} />
<div aria-hidden style={{ height: 200 }} />
</Stack>
);
};

View File

@ -15,7 +15,6 @@ import rainbowStyles from '../../styles/rainbow.module.css';
export default function ToolPanel() {
const { t } = useTranslation();
const { isRainbowMode } = useRainbowThemeContext();
const { colorScheme } = useMantineColorScheme();
const { sidebarRefs } = useSidebarContext();
const { toolPanelRef } = sidebarRefs;
@ -55,7 +54,7 @@ export default function ToolPanel() {
{/* Search Bar - Always visible at the top */}
<div
style={{
backgroundColor: colorScheme === 'dark' ? '#1F2329' : '#EFF1F4',
backgroundColor: 'var(--tool-panel-search-bg)',
padding: '0.75rem 1rem',
marginBottom: (leftPanelView === 'toolContent') ? '1rem' : 0,
}}

View File

@ -138,6 +138,9 @@
/* Placeholder text colors */
--search-text-and-icon-color: #6B7382;
/* Tool panel search bar background colors */
--tool-panel-search-bg: #EFF1F4;
/* container */
--landing-paper-bg: var(--bg-surface);
--landing-inner-paper-bg: #EEF8FF;
@ -283,6 +286,9 @@
/* Placeholder text colors (dark mode) */
--search-text-and-icon-color: #FFFFFF !important;
/* Tool panel search bar background colors (dark mode) */
--tool-panel-search-bg: #1F2329;
}
/* Dropzone drop state styling */