mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-08-22 20:29:23 +00:00

Component Extraction & Context Refactor - Summary 🔧 What We Did - Extracted HomePage's 286-line monolithic component into focused parts - Created ToolPanel (105 lines) for tool selection UI - Created Workbench (203 lines) for view management - Created ToolWorkflowContext (220 lines) for centralized state - Reduced HomePage to 60 lines of provider setup - Eliminated all prop drilling - components use contexts directly 🏆 Why This is Good - Maintainability: Each component has single purpose, easy debugging/development - Architecture: Clean separation of concerns, future features easier to add - Code Quality: 105% more lines but organized/purposeful vs tangled spaghetti code --------- Co-authored-by: Connor Yoh <connor@stirlingpdf.com> Co-authored-by: James Brunton <jbrunton96@gmail.com>
89 lines
2.8 KiB
TypeScript
89 lines
2.8 KiB
TypeScript
import React from 'react';
|
|
import { TextInput } from '@mantine/core';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useRainbowThemeContext } from '../shared/RainbowThemeProvider';
|
|
import { useToolPanelState, useToolSelection, useWorkbenchState } from '../../contexts/ToolWorkflowContext';
|
|
import ToolPicker from './ToolPicker';
|
|
import ToolRenderer from './ToolRenderer';
|
|
import { useSidebarContext } from "../../contexts/SidebarContext";
|
|
import rainbowStyles from '../../styles/rainbow.module.css';
|
|
|
|
// No props needed - component uses context
|
|
|
|
export default function ToolPanel() {
|
|
const { t } = useTranslation();
|
|
const { isRainbowMode } = useRainbowThemeContext();
|
|
const { sidebarRefs } = useSidebarContext();
|
|
const { toolPanelRef } = sidebarRefs;
|
|
|
|
|
|
// Use context-based hooks to eliminate prop drilling
|
|
const {
|
|
leftPanelView,
|
|
isPanelVisible,
|
|
searchQuery,
|
|
filteredTools,
|
|
setSearchQuery,
|
|
handleBackToTools
|
|
} = useToolPanelState();
|
|
|
|
const { selectedToolKey, handleToolSelect } = useToolSelection();
|
|
const { setPreviewFile } = useWorkbenchState();
|
|
|
|
return (
|
|
<div
|
|
ref={toolPanelRef}
|
|
data-sidebar="tool-panel"
|
|
className={`h-screen flex flex-col overflow-hidden bg-[var(--bg-toolbar)] border-r border-[var(--border-subtle)] transition-all duration-300 ease-out ${
|
|
isRainbowMode ? rainbowStyles.rainbowPaper : ''
|
|
}`}
|
|
style={{
|
|
width: isPanelVisible ? '20rem' : '0',
|
|
padding: isPanelVisible ? '0.5rem' : '0'
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
opacity: isPanelVisible ? 1 : 0,
|
|
transition: 'opacity 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94)',
|
|
height: '100%',
|
|
display: 'flex',
|
|
flexDirection: 'column'
|
|
}}
|
|
>
|
|
{/* Search Bar - Always visible at the top */}
|
|
<div className="mb-4">
|
|
<TextInput
|
|
placeholder={t("toolPicker.searchPlaceholder", "Search tools...")}
|
|
value={searchQuery}
|
|
onChange={(e) => setSearchQuery(e.currentTarget.value)}
|
|
autoComplete="off"
|
|
size="sm"
|
|
/>
|
|
</div>
|
|
|
|
{leftPanelView === 'toolPicker' ? (
|
|
// Tool Picker View
|
|
<div className="flex-1 flex flex-col">
|
|
<ToolPicker
|
|
selectedToolKey={selectedToolKey}
|
|
onSelect={handleToolSelect}
|
|
filteredTools={filteredTools}
|
|
/>
|
|
</div>
|
|
) : (
|
|
// Selected Tool Content View
|
|
<div className="flex-1 flex flex-col">
|
|
{/* Tool content */}
|
|
<div className="flex-1 min-h-0">
|
|
<ToolRenderer
|
|
selectedToolKey={selectedToolKey}
|
|
onPreviewFile={setPreviewFile}
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
} |